webrtc_m130/api/transport/test/network_control_tester.cc
Sebastian Jansson fb4d66be97 Improves buffer time calculation in network control tester.
The previous solution caused packet reordering if the bandwidth changed
with large buffers. To avoid this, the buffer time is tracked instead.
This means the the bandwidth is applied per packet and can't be
retroactively changed for packets already handled.

Bug: webrtc:8415
Change-Id: Ib6c97ba9b948220e88c79776aa8d96de289dcfb5
Reviewed-on: https://webrtc-review.googlesource.com/83723
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23629}
2018-06-15 12:39:59 +00:00

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