2018-03-27 11:19:29 +02:00
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2018-05-09 10:33:39 +02:00
|
|
|
#include "api/transport/test/network_control_tester.h"
|
2018-03-27 11:19:29 +02:00
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
2018-05-09 10:33:39 +02:00
|
|
|
#include "api/transport/network_control.h"
|
2018-03-27 11:19:29 +02:00
|
|
|
#include "rtc_base/logging.h"
|
2018-04-13 13:56:17 +02:00
|
|
|
|
2018-03-27 11:19:29 +02:00
|
|
|
namespace webrtc {
|
|
|
|
|
namespace test {
|
2018-04-09 13:21:35 +02:00
|
|
|
namespace {
|
|
|
|
|
void Update(NetworkControlUpdate* target, const NetworkControlUpdate& update) {
|
|
|
|
|
if (update.congestion_window) {
|
|
|
|
|
RTC_LOG(LS_INFO) << "Received window="
|
2018-05-22 11:03:32 +02:00
|
|
|
<< ToString(*update.congestion_window);
|
2018-04-09 13:21:35 +02:00
|
|
|
target->congestion_window = update.congestion_window;
|
|
|
|
|
}
|
|
|
|
|
if (update.pacer_config) {
|
2018-04-09 14:41:57 +02:00
|
|
|
RTC_LOG(LS_INFO) << "Received pacing at:"
|
|
|
|
|
<< ToString(update.pacer_config->at_time)
|
|
|
|
|
<< ": rate=" << ToString(update.pacer_config->data_rate())
|
2018-05-22 11:03:32 +02:00
|
|
|
<< ", pad=" << ToString(update.pacer_config->pad_rate());
|
2018-04-09 13:21:35 +02:00
|
|
|
target->pacer_config = update.pacer_config;
|
|
|
|
|
}
|
|
|
|
|
if (update.target_rate) {
|
2018-05-22 11:03:32 +02:00
|
|
|
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);
|
2018-04-09 13:21:35 +02:00
|
|
|
target->target_rate = update.target_rate;
|
|
|
|
|
}
|
|
|
|
|
for (const auto& probe : update.probe_cluster_configs) {
|
|
|
|
|
target->probe_cluster_configs.push_back(probe);
|
2018-04-09 14:41:57 +02:00
|
|
|
RTC_LOG(LS_INFO) << "Received probe at:" << ToString(probe.at_time)
|
2018-05-22 11:03:32 +02:00
|
|
|
<< ": target=" << ToString(probe.target_data_rate);
|
2018-04-09 13:21:35 +02:00
|
|
|
}
|
2018-03-27 11:19:29 +02:00
|
|
|
}
|
2018-04-09 13:21:35 +02:00
|
|
|
} // namespace
|
2018-03-27 11:19:29 +02:00
|
|
|
|
|
|
|
|
SentPacket SimpleTargetRateProducer::ProduceNext(
|
2018-04-09 13:21:35 +02:00
|
|
|
const NetworkControlUpdate& cache,
|
2018-03-27 11:19:29 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-06 11:19:50 +02:00
|
|
|
NetworkControllerTester::NetworkControllerTester(
|
2018-03-27 11:19:29 +02:00
|
|
|
NetworkControllerFactoryInterface* factory,
|
|
|
|
|
NetworkControllerConfig initial_config)
|
|
|
|
|
: current_time_(Timestamp::seconds(100000)),
|
2018-05-22 11:03:12 +02:00
|
|
|
packet_sequence_number_(1),
|
2018-06-15 14:16:44 +02:00
|
|
|
accumulated_buffer_(TimeDelta::Zero()) {
|
2018-03-27 11:19:29 +02:00
|
|
|
initial_config.constraints.at_time = current_time_;
|
2018-04-09 13:21:35 +02:00
|
|
|
controller_ = factory->Create(initial_config);
|
2018-03-27 11:19:29 +02:00
|
|
|
process_interval_ = factory->GetProcessInterval();
|
2018-04-09 13:21:35 +02:00
|
|
|
ProcessInterval interval_msg;
|
|
|
|
|
interval_msg.at_time = current_time_;
|
2018-05-22 11:03:32 +02:00
|
|
|
Update(&state_, controller_->OnProcessInterval(interval_msg));
|
2018-03-27 11:19:29 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-06 11:19:50 +02:00
|
|
|
NetworkControllerTester::~NetworkControllerTester() = default;
|
2018-03-27 11:19:29 +02:00
|
|
|
|
2018-04-06 11:19:50 +02:00
|
|
|
void NetworkControllerTester::RunSimulation(TimeDelta duration,
|
|
|
|
|
TimeDelta packet_interval,
|
|
|
|
|
DataRate actual_bandwidth,
|
|
|
|
|
TimeDelta propagation_delay,
|
|
|
|
|
PacketProducer next_packet) {
|
2018-06-15 14:16:44 +02:00
|
|
|
RTC_CHECK(actual_bandwidth.bps() > 0);
|
2018-03-27 11:19:29 +02:00
|
|
|
Timestamp start_time = current_time_;
|
|
|
|
|
Timestamp last_process_time = current_time_;
|
|
|
|
|
while (current_time_ - start_time < duration) {
|
2018-03-27 14:01:24 +02:00
|
|
|
bool send_packet = true;
|
2018-05-04 17:07:16 +02:00
|
|
|
if (state_.congestion_window && state_.congestion_window->IsFinite()) {
|
2018-03-27 14:01:24 +02:00
|
|
|
DataSize data_in_flight = DataSize::Zero();
|
|
|
|
|
for (PacketResult& packet : outstanding_packets_)
|
|
|
|
|
data_in_flight += packet.sent_packet->size;
|
2018-05-04 17:07:16 +02:00
|
|
|
if (data_in_flight > *state_.congestion_window)
|
2018-03-27 14:01:24 +02:00
|
|
|
send_packet = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (send_packet) {
|
2018-05-22 11:03:12 +02:00
|
|
|
SentPacket sent_packet;
|
|
|
|
|
sent_packet = next_packet(state_, current_time_, packet_interval);
|
|
|
|
|
sent_packet.sequence_number = packet_sequence_number_++;
|
2018-05-28 16:38:46 +02:00
|
|
|
sent_packet.data_in_flight = sent_packet.size;
|
|
|
|
|
for (PacketResult& packet : outstanding_packets_)
|
|
|
|
|
sent_packet.data_in_flight += packet.sent_packet->size;
|
2018-04-09 13:21:35 +02:00
|
|
|
Update(&state_, controller_->OnSentPacket(sent_packet));
|
2018-05-22 11:03:32 +02:00
|
|
|
|
2018-06-15 14:16:44 +02:00
|
|
|
TimeDelta time_in_flight = sent_packet.size / actual_bandwidth;
|
|
|
|
|
accumulated_buffer_ += time_in_flight;
|
|
|
|
|
TimeDelta total_delay = propagation_delay + accumulated_buffer_;
|
2018-05-22 11:03:32 +02:00
|
|
|
PacketResult result;
|
|
|
|
|
result.sent_packet = sent_packet;
|
|
|
|
|
result.receive_time = sent_packet.send_time + total_delay;
|
|
|
|
|
|
|
|
|
|
outstanding_packets_.push_back(result);
|
2018-03-27 14:01:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-06-15 14:16:44 +02:00
|
|
|
TimeDelta buffer_consumed = std::min(accumulated_buffer_, packet_interval);
|
2018-05-22 11:03:32 +02:00
|
|
|
accumulated_buffer_ -= buffer_consumed;
|
|
|
|
|
|
2018-03-27 14:01:24 +02:00
|
|
|
if (outstanding_packets_.size() >= 2 &&
|
2018-03-27 11:19:29 +02:00
|
|
|
current_time_ >=
|
2018-03-27 14:01:24 +02:00
|
|
|
outstanding_packets_[1].receive_time + propagation_delay) {
|
2018-03-27 11:19:29 +02:00
|
|
|
TransportPacketsFeedback feedback;
|
|
|
|
|
feedback.prior_in_flight = DataSize::Zero();
|
2018-03-27 14:01:24 +02:00
|
|
|
for (PacketResult& packet : outstanding_packets_)
|
2018-03-27 11:19:29 +02:00
|
|
|
feedback.prior_in_flight += packet.sent_packet->size;
|
2018-03-27 14:01:24 +02:00
|
|
|
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();
|
2018-03-27 11:19:29 +02:00
|
|
|
}
|
|
|
|
|
feedback.feedback_time =
|
|
|
|
|
feedback.packet_feedbacks.back().receive_time + propagation_delay;
|
|
|
|
|
feedback.data_in_flight = DataSize::Zero();
|
2018-03-27 14:01:24 +02:00
|
|
|
for (PacketResult& packet : outstanding_packets_)
|
2018-03-27 11:19:29 +02:00
|
|
|
feedback.data_in_flight += packet.sent_packet->size;
|
2018-04-09 13:21:35 +02:00
|
|
|
Update(&state_, controller_->OnTransportPacketsFeedback(feedback));
|
2018-03-27 11:19:29 +02:00
|
|
|
}
|
|
|
|
|
current_time_ += packet_interval;
|
|
|
|
|
if (current_time_ - last_process_time > process_interval_) {
|
|
|
|
|
ProcessInterval interval_msg;
|
|
|
|
|
interval_msg.at_time = current_time_;
|
2018-04-09 13:21:35 +02:00
|
|
|
Update(&state_, controller_->OnProcessInterval(interval_msg));
|
2018-03-27 11:19:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace test
|
|
|
|
|
} // namespace webrtc
|