This makes it safer to reason about the common case where send time information is available. We don't have to either assume that it's available, or check it everywhere the PacketResult struct is used. To achieve this, a new field is added to TransportPacketsFeedback and a new interface is introduced to clearly separate which field is used. A possible followup would be to introduce a separate struct. That would complicate the signature of ProcessTransportFeedback. Bug: webrtc:9934 Change-Id: I2b319e4df2b557fbd4de66b812744bca7d91ca15 Reviewed-on: https://webrtc-review.googlesource.com/c/107080 Commit-Queue: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Björn Terelius <terelius@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25465}
148 lines
5.8 KiB
C++
148 lines
5.8 KiB
C++
/*
|
|
* 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
|