Move SimulatedNetwork class to separate file.
Bug: webrtc:9467 Change-Id: Iaf91f27ea7ad9e9e59991bbeb0ef3868578e6a8f Reviewed-on: https://webrtc-review.googlesource.com/92884 Reviewed-by: Niels Moller <nisse@webrtc.org> Commit-Queue: Sebastian Jansson <srte@webrtc.org> Cr-Commit-Position: refs/heads/master@{#24221}
This commit is contained in:

committed by
Commit Bot

parent
d528ad542e
commit
f96b1ca609
@ -247,6 +247,19 @@ rtc_source_set("video_stream_api") {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtc_source_set("simulated_network") {
|
||||||
|
sources = [
|
||||||
|
"simulated_network.cc",
|
||||||
|
"simulated_network.h",
|
||||||
|
]
|
||||||
|
deps = [
|
||||||
|
"../api:simulated_network_api",
|
||||||
|
"../rtc_base:rtc_base_approved",
|
||||||
|
"//third_party/abseil-cpp/absl/memory",
|
||||||
|
"//third_party/abseil-cpp/absl/types:optional",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
rtc_source_set("fake_network") {
|
rtc_source_set("fake_network") {
|
||||||
sources = [
|
sources = [
|
||||||
"fake_network_pipe.cc",
|
"fake_network_pipe.cc",
|
||||||
@ -254,6 +267,7 @@ rtc_source_set("fake_network") {
|
|||||||
]
|
]
|
||||||
deps = [
|
deps = [
|
||||||
":call_interfaces",
|
":call_interfaces",
|
||||||
|
":simulated_network",
|
||||||
"..:webrtc_common",
|
"..:webrtc_common",
|
||||||
"../api:simulated_network_api",
|
"../api:simulated_network_api",
|
||||||
"../api:transport_api",
|
"../api:transport_api",
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
@ -159,98 +158,10 @@ void FakeNetworkPipe::SetClockOffset(int64_t offset_ms) {
|
|||||||
clock_offset_ms_ = offset_ms;
|
clock_offset_ms_ = offset_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulatedNetwork::SimulatedNetwork(SimulatedNetwork::Config config,
|
|
||||||
uint64_t random_seed)
|
|
||||||
: random_(random_seed), bursting_(false) {
|
|
||||||
SetConfig(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
SimulatedNetwork::~SimulatedNetwork() = default;
|
|
||||||
|
|
||||||
void FakeNetworkPipe::SetConfig(const FakeNetworkPipe::Config& config) {
|
void FakeNetworkPipe::SetConfig(const FakeNetworkPipe::Config& config) {
|
||||||
network_simulation_->SetConfig(config);
|
network_simulation_->SetConfig(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatedNetwork::SetConfig(const SimulatedNetwork::Config& config) {
|
|
||||||
rtc::CritScope crit(&config_lock_);
|
|
||||||
config_ = config; // Shallow copy of the struct.
|
|
||||||
double prob_loss = config.loss_percent / 100.0;
|
|
||||||
if (config_.avg_burst_loss_length == -1) {
|
|
||||||
// Uniform loss
|
|
||||||
prob_loss_bursting_ = prob_loss;
|
|
||||||
prob_start_bursting_ = prob_loss;
|
|
||||||
} else {
|
|
||||||
// Lose packets according to a gilbert-elliot model.
|
|
||||||
int avg_burst_loss_length = config.avg_burst_loss_length;
|
|
||||||
int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss));
|
|
||||||
|
|
||||||
RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length)
|
|
||||||
<< "For a total packet loss of " << config.loss_percent << "%% then"
|
|
||||||
<< " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1
|
|
||||||
<< " or higher.";
|
|
||||||
|
|
||||||
prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length);
|
|
||||||
prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedNetwork::PauseTransmissionUntil(int64_t until_us) {
|
|
||||||
rtc::CritScope crit(&config_lock_);
|
|
||||||
pause_transmission_until_us_ = until_us;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SimulatedNetwork::EnqueuePacket(PacketInFlightInfo packet) {
|
|
||||||
Config config;
|
|
||||||
{
|
|
||||||
rtc::CritScope crit(&config_lock_);
|
|
||||||
config = config_;
|
|
||||||
}
|
|
||||||
rtc::CritScope crit(&process_lock_);
|
|
||||||
if (config.queue_length_packets > 0 &&
|
|
||||||
capacity_link_.size() >= config.queue_length_packets) {
|
|
||||||
// Too many packet on the link, drop this one.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delay introduced by the link capacity.
|
|
||||||
int64_t capacity_delay_ms = 0;
|
|
||||||
if (config.link_capacity_kbps > 0) {
|
|
||||||
// Using bytes per millisecond to avoid losing precision.
|
|
||||||
const int64_t bytes_per_millisecond = config.link_capacity_kbps / 8;
|
|
||||||
// To round to the closest millisecond we add half a milliseconds worth of
|
|
||||||
// bytes to the delay calculation.
|
|
||||||
capacity_delay_ms = (packet.size + capacity_delay_error_bytes_ +
|
|
||||||
bytes_per_millisecond / 2) /
|
|
||||||
bytes_per_millisecond;
|
|
||||||
capacity_delay_error_bytes_ +=
|
|
||||||
packet.size - capacity_delay_ms * bytes_per_millisecond;
|
|
||||||
}
|
|
||||||
int64_t network_start_time_us = packet.send_time_us;
|
|
||||||
|
|
||||||
{
|
|
||||||
rtc::CritScope crit(&config_lock_);
|
|
||||||
if (pause_transmission_until_us_) {
|
|
||||||
network_start_time_us =
|
|
||||||
std::max(network_start_time_us, *pause_transmission_until_us_);
|
|
||||||
pause_transmission_until_us_.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check if there already are packets on the link and change network start
|
|
||||||
// time forward if there is.
|
|
||||||
if (!capacity_link_.empty() &&
|
|
||||||
network_start_time_us < capacity_link_.back().arrival_time_us)
|
|
||||||
network_start_time_us = capacity_link_.back().arrival_time_us;
|
|
||||||
|
|
||||||
int64_t arrival_time_us = network_start_time_us + capacity_delay_ms * 1000;
|
|
||||||
capacity_link_.push({packet, arrival_time_us});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
absl::optional<int64_t> SimulatedNetwork::NextDeliveryTimeUs() const {
|
|
||||||
if (!delay_link_.empty())
|
|
||||||
return delay_link_.begin()->arrival_time_us;
|
|
||||||
return absl::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
FakeNetworkPipe::StoredPacket::StoredPacket(NetworkPacket&& packet)
|
FakeNetworkPipe::StoredPacket::StoredPacket(NetworkPacket&& packet)
|
||||||
: packet(std::move(packet)) {}
|
: packet(std::move(packet)) {}
|
||||||
@ -320,85 +231,6 @@ size_t FakeNetworkPipe::SentPackets() {
|
|||||||
return sent_packets_;
|
return sent_packets_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<PacketDeliveryInfo> SimulatedNetwork::DequeueDeliverablePackets(
|
|
||||||
int64_t receive_time_us) {
|
|
||||||
int64_t time_now_us = receive_time_us;
|
|
||||||
Config config;
|
|
||||||
double prob_loss_bursting;
|
|
||||||
double prob_start_bursting;
|
|
||||||
{
|
|
||||||
rtc::CritScope crit(&config_lock_);
|
|
||||||
config = config_;
|
|
||||||
prob_loss_bursting = prob_loss_bursting_;
|
|
||||||
prob_start_bursting = prob_start_bursting_;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
rtc::CritScope crit(&process_lock_);
|
|
||||||
// Check the capacity link first.
|
|
||||||
if (!capacity_link_.empty()) {
|
|
||||||
int64_t last_arrival_time_us =
|
|
||||||
delay_link_.empty() ? -1 : delay_link_.back().arrival_time_us;
|
|
||||||
bool needs_sort = false;
|
|
||||||
while (!capacity_link_.empty() &&
|
|
||||||
time_now_us >= capacity_link_.front().arrival_time_us) {
|
|
||||||
// Time to get this packet.
|
|
||||||
PacketInfo packet = std::move(capacity_link_.front());
|
|
||||||
capacity_link_.pop();
|
|
||||||
|
|
||||||
// Drop packets at an average rate of |config_.loss_percent| with
|
|
||||||
// and average loss burst length of |config_.avg_burst_loss_length|.
|
|
||||||
if ((bursting_ && random_.Rand<double>() < prob_loss_bursting) ||
|
|
||||||
(!bursting_ && random_.Rand<double>() < prob_start_bursting)) {
|
|
||||||
bursting_ = true;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
bursting_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t arrival_time_jitter_us = std::max(
|
|
||||||
random_.Gaussian(config.queue_delay_ms * 1000,
|
|
||||||
config.delay_standard_deviation_ms * 1000),
|
|
||||||
0.0);
|
|
||||||
|
|
||||||
// If reordering is not allowed then adjust arrival_time_jitter
|
|
||||||
// to make sure all packets are sent in order.
|
|
||||||
if (!config.allow_reordering && !delay_link_.empty() &&
|
|
||||||
packet.arrival_time_us + arrival_time_jitter_us <
|
|
||||||
last_arrival_time_us) {
|
|
||||||
arrival_time_jitter_us =
|
|
||||||
last_arrival_time_us - packet.arrival_time_us;
|
|
||||||
}
|
|
||||||
packet.arrival_time_us += arrival_time_jitter_us;
|
|
||||||
if (packet.arrival_time_us >= last_arrival_time_us) {
|
|
||||||
last_arrival_time_us = packet.arrival_time_us;
|
|
||||||
} else {
|
|
||||||
needs_sort = true;
|
|
||||||
}
|
|
||||||
delay_link_.emplace_back(std::move(packet));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needs_sort) {
|
|
||||||
// Packet(s) arrived out of order, make sure list is sorted.
|
|
||||||
std::sort(delay_link_.begin(), delay_link_.end(),
|
|
||||||
[](const PacketInfo& p1, const PacketInfo& p2) {
|
|
||||||
return p1.arrival_time_us < p2.arrival_time_us;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<PacketDeliveryInfo> packets_to_deliver;
|
|
||||||
// Check the extra delay queue.
|
|
||||||
while (!delay_link_.empty() &&
|
|
||||||
time_now_us >= delay_link_.front().arrival_time_us) {
|
|
||||||
PacketInfo packet_info = delay_link_.front();
|
|
||||||
packets_to_deliver.emplace_back(
|
|
||||||
PacketDeliveryInfo(packet_info.packet, packet_info.arrival_time_us));
|
|
||||||
delay_link_.pop_front();
|
|
||||||
}
|
|
||||||
return packets_to_deliver;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FakeNetworkPipe::Process() {
|
void FakeNetworkPipe::Process() {
|
||||||
int64_t time_now_us = clock_->TimeInMicroseconds();
|
int64_t time_now_us = clock_->TimeInMicroseconds();
|
||||||
std::queue<NetworkPacket> packets_to_deliver;
|
std::queue<NetworkPacket> packets_to_deliver;
|
||||||
|
@ -22,11 +22,11 @@
|
|||||||
#include "api/call/transport.h"
|
#include "api/call/transport.h"
|
||||||
#include "api/test/simulated_network.h"
|
#include "api/test/simulated_network.h"
|
||||||
#include "call/call.h"
|
#include "call/call.h"
|
||||||
|
#include "call/simulated_network.h"
|
||||||
#include "common_types.h" // NOLINT(build/include)
|
#include "common_types.h" // NOLINT(build/include)
|
||||||
#include "modules/include/module.h"
|
#include "modules/include/module.h"
|
||||||
#include "rtc_base/constructormagic.h"
|
#include "rtc_base/constructormagic.h"
|
||||||
#include "rtc_base/criticalsection.h"
|
#include "rtc_base/criticalsection.h"
|
||||||
#include "rtc_base/random.h"
|
|
||||||
#include "rtc_base/thread_annotations.h"
|
#include "rtc_base/thread_annotations.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@ -98,58 +98,6 @@ class NetworkPacket {
|
|||||||
absl::optional<int64_t> packet_time_us_;
|
absl::optional<int64_t> packet_time_us_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Class simulating a network link. This is a simple and naive solution just
|
|
||||||
// faking capacity and adding an extra transport delay in addition to the
|
|
||||||
// capacity introduced delay.
|
|
||||||
class SimulatedNetwork : public NetworkSimulationInterface {
|
|
||||||
public:
|
|
||||||
using Config = NetworkSimulationInterface::SimulatedNetworkConfig;
|
|
||||||
explicit SimulatedNetwork(Config config, uint64_t random_seed = 1);
|
|
||||||
~SimulatedNetwork() override;
|
|
||||||
|
|
||||||
// Sets a new configuration. This won't affect packets already in the pipe.
|
|
||||||
void SetConfig(const Config& config);
|
|
||||||
void PauseTransmissionUntil(int64_t until_us);
|
|
||||||
|
|
||||||
// NetworkSimulationInterface
|
|
||||||
bool EnqueuePacket(PacketInFlightInfo packet) override;
|
|
||||||
std::vector<PacketDeliveryInfo> DequeueDeliverablePackets(
|
|
||||||
int64_t receive_time_us) override;
|
|
||||||
|
|
||||||
absl::optional<int64_t> NextDeliveryTimeUs() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct PacketInfo {
|
|
||||||
PacketInFlightInfo packet;
|
|
||||||
int64_t arrival_time_us;
|
|
||||||
};
|
|
||||||
rtc::CriticalSection config_lock_;
|
|
||||||
|
|
||||||
// |process_lock| guards the data structures involved in delay and loss
|
|
||||||
// processes, such as the packet queues.
|
|
||||||
rtc::CriticalSection process_lock_;
|
|
||||||
std::queue<PacketInfo> capacity_link_ RTC_GUARDED_BY(process_lock_);
|
|
||||||
Random random_;
|
|
||||||
|
|
||||||
std::deque<PacketInfo> delay_link_;
|
|
||||||
|
|
||||||
// Link configuration.
|
|
||||||
Config config_ RTC_GUARDED_BY(config_lock_);
|
|
||||||
absl::optional<int64_t> pause_transmission_until_us_
|
|
||||||
RTC_GUARDED_BY(config_lock_);
|
|
||||||
|
|
||||||
// Are we currently dropping a burst of packets?
|
|
||||||
bool bursting_;
|
|
||||||
|
|
||||||
// The probability to drop the packet if we are currently dropping a
|
|
||||||
// burst of packet
|
|
||||||
double prob_loss_bursting_ RTC_GUARDED_BY(config_lock_);
|
|
||||||
|
|
||||||
// The probability to drop a burst of packets.
|
|
||||||
double prob_start_bursting_ RTC_GUARDED_BY(config_lock_);
|
|
||||||
int64_t capacity_delay_error_bytes_ = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Class faking a network link, internally is uses an implementation of a
|
// Class faking a network link, internally is uses an implementation of a
|
||||||
// SimulatedNetworkInterface to simulate network behavior.
|
// SimulatedNetworkInterface to simulate network behavior.
|
||||||
class FakeNetworkPipe : public Transport, public PacketReceiver, public Module {
|
class FakeNetworkPipe : public Transport, public PacketReceiver, public Module {
|
||||||
|
186
call/simulated_network.cc
Normal file
186
call/simulated_network.cc
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 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 "call/simulated_network.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
SimulatedNetwork::SimulatedNetwork(SimulatedNetwork::Config config,
|
||||||
|
uint64_t random_seed)
|
||||||
|
: random_(random_seed), bursting_(false) {
|
||||||
|
SetConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimulatedNetwork::~SimulatedNetwork() = default;
|
||||||
|
|
||||||
|
void SimulatedNetwork::SetConfig(const SimulatedNetwork::Config& config) {
|
||||||
|
rtc::CritScope crit(&config_lock_);
|
||||||
|
config_ = config; // Shallow copy of the struct.
|
||||||
|
double prob_loss = config.loss_percent / 100.0;
|
||||||
|
if (config_.avg_burst_loss_length == -1) {
|
||||||
|
// Uniform loss
|
||||||
|
prob_loss_bursting_ = prob_loss;
|
||||||
|
prob_start_bursting_ = prob_loss;
|
||||||
|
} else {
|
||||||
|
// Lose packets according to a gilbert-elliot model.
|
||||||
|
int avg_burst_loss_length = config.avg_burst_loss_length;
|
||||||
|
int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss));
|
||||||
|
|
||||||
|
RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length)
|
||||||
|
<< "For a total packet loss of " << config.loss_percent << "%% then"
|
||||||
|
<< " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1
|
||||||
|
<< " or higher.";
|
||||||
|
|
||||||
|
prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length);
|
||||||
|
prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimulatedNetwork::PauseTransmissionUntil(int64_t until_us) {
|
||||||
|
rtc::CritScope crit(&config_lock_);
|
||||||
|
pause_transmission_until_us_ = until_us;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimulatedNetwork::EnqueuePacket(PacketInFlightInfo packet) {
|
||||||
|
Config config;
|
||||||
|
{
|
||||||
|
rtc::CritScope crit(&config_lock_);
|
||||||
|
config = config_;
|
||||||
|
}
|
||||||
|
rtc::CritScope crit(&process_lock_);
|
||||||
|
if (config.queue_length_packets > 0 &&
|
||||||
|
capacity_link_.size() >= config.queue_length_packets) {
|
||||||
|
// Too many packet on the link, drop this one.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay introduced by the link capacity.
|
||||||
|
int64_t capacity_delay_ms = 0;
|
||||||
|
if (config.link_capacity_kbps > 0) {
|
||||||
|
// Using bytes per millisecond to avoid losing precision.
|
||||||
|
const int64_t bytes_per_millisecond = config.link_capacity_kbps / 8;
|
||||||
|
// To round to the closest millisecond we add half a milliseconds worth of
|
||||||
|
// bytes to the delay calculation.
|
||||||
|
capacity_delay_ms = (packet.size + capacity_delay_error_bytes_ +
|
||||||
|
bytes_per_millisecond / 2) /
|
||||||
|
bytes_per_millisecond;
|
||||||
|
capacity_delay_error_bytes_ +=
|
||||||
|
packet.size - capacity_delay_ms * bytes_per_millisecond;
|
||||||
|
}
|
||||||
|
int64_t network_start_time_us = packet.send_time_us;
|
||||||
|
|
||||||
|
{
|
||||||
|
rtc::CritScope crit(&config_lock_);
|
||||||
|
if (pause_transmission_until_us_) {
|
||||||
|
network_start_time_us =
|
||||||
|
std::max(network_start_time_us, *pause_transmission_until_us_);
|
||||||
|
pause_transmission_until_us_.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if there already are packets on the link and change network start
|
||||||
|
// time forward if there is.
|
||||||
|
if (!capacity_link_.empty() &&
|
||||||
|
network_start_time_us < capacity_link_.back().arrival_time_us)
|
||||||
|
network_start_time_us = capacity_link_.back().arrival_time_us;
|
||||||
|
|
||||||
|
int64_t arrival_time_us = network_start_time_us + capacity_delay_ms * 1000;
|
||||||
|
capacity_link_.push({packet, arrival_time_us});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
absl::optional<int64_t> SimulatedNetwork::NextDeliveryTimeUs() const {
|
||||||
|
if (!delay_link_.empty())
|
||||||
|
return delay_link_.begin()->arrival_time_us;
|
||||||
|
return absl::nullopt;
|
||||||
|
}
|
||||||
|
std::vector<PacketDeliveryInfo> SimulatedNetwork::DequeueDeliverablePackets(
|
||||||
|
int64_t receive_time_us) {
|
||||||
|
int64_t time_now_us = receive_time_us;
|
||||||
|
Config config;
|
||||||
|
double prob_loss_bursting;
|
||||||
|
double prob_start_bursting;
|
||||||
|
{
|
||||||
|
rtc::CritScope crit(&config_lock_);
|
||||||
|
config = config_;
|
||||||
|
prob_loss_bursting = prob_loss_bursting_;
|
||||||
|
prob_start_bursting = prob_start_bursting_;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
rtc::CritScope crit(&process_lock_);
|
||||||
|
// Check the capacity link first.
|
||||||
|
if (!capacity_link_.empty()) {
|
||||||
|
int64_t last_arrival_time_us =
|
||||||
|
delay_link_.empty() ? -1 : delay_link_.back().arrival_time_us;
|
||||||
|
bool needs_sort = false;
|
||||||
|
while (!capacity_link_.empty() &&
|
||||||
|
time_now_us >= capacity_link_.front().arrival_time_us) {
|
||||||
|
// Time to get this packet.
|
||||||
|
PacketInfo packet = std::move(capacity_link_.front());
|
||||||
|
capacity_link_.pop();
|
||||||
|
|
||||||
|
// Drop packets at an average rate of |config_.loss_percent| with
|
||||||
|
// and average loss burst length of |config_.avg_burst_loss_length|.
|
||||||
|
if ((bursting_ && random_.Rand<double>() < prob_loss_bursting) ||
|
||||||
|
(!bursting_ && random_.Rand<double>() < prob_start_bursting)) {
|
||||||
|
bursting_ = true;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
bursting_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t arrival_time_jitter_us = std::max(
|
||||||
|
random_.Gaussian(config.queue_delay_ms * 1000,
|
||||||
|
config.delay_standard_deviation_ms * 1000),
|
||||||
|
0.0);
|
||||||
|
|
||||||
|
// If reordering is not allowed then adjust arrival_time_jitter
|
||||||
|
// to make sure all packets are sent in order.
|
||||||
|
if (!config.allow_reordering && !delay_link_.empty() &&
|
||||||
|
packet.arrival_time_us + arrival_time_jitter_us <
|
||||||
|
last_arrival_time_us) {
|
||||||
|
arrival_time_jitter_us =
|
||||||
|
last_arrival_time_us - packet.arrival_time_us;
|
||||||
|
}
|
||||||
|
packet.arrival_time_us += arrival_time_jitter_us;
|
||||||
|
if (packet.arrival_time_us >= last_arrival_time_us) {
|
||||||
|
last_arrival_time_us = packet.arrival_time_us;
|
||||||
|
} else {
|
||||||
|
needs_sort = true;
|
||||||
|
}
|
||||||
|
delay_link_.emplace_back(std::move(packet));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needs_sort) {
|
||||||
|
// Packet(s) arrived out of order, make sure list is sorted.
|
||||||
|
std::sort(delay_link_.begin(), delay_link_.end(),
|
||||||
|
[](const PacketInfo& p1, const PacketInfo& p2) {
|
||||||
|
return p1.arrival_time_us < p2.arrival_time_us;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<PacketDeliveryInfo> packets_to_deliver;
|
||||||
|
// Check the extra delay queue.
|
||||||
|
while (!delay_link_.empty() &&
|
||||||
|
time_now_us >= delay_link_.front().arrival_time_us) {
|
||||||
|
PacketInfo packet_info = delay_link_.front();
|
||||||
|
packets_to_deliver.emplace_back(
|
||||||
|
PacketDeliveryInfo(packet_info.packet, packet_info.arrival_time_us));
|
||||||
|
delay_link_.pop_front();
|
||||||
|
}
|
||||||
|
return packets_to_deliver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
80
call/simulated_network.h
Normal file
80
call/simulated_network.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 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.
|
||||||
|
*/
|
||||||
|
#ifndef CALL_SIMULATED_NETWORK_H_
|
||||||
|
#define CALL_SIMULATED_NETWORK_H_
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <queue>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
|
#include "absl/types/optional.h"
|
||||||
|
#include "api/test/simulated_network.h"
|
||||||
|
#include "rtc_base/criticalsection.h"
|
||||||
|
#include "rtc_base/random.h"
|
||||||
|
#include "rtc_base/thread_annotations.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
// Class simulating a network link. This is a simple and naive solution just
|
||||||
|
// faking capacity and adding an extra transport delay in addition to the
|
||||||
|
// capacity introduced delay.
|
||||||
|
class SimulatedNetwork : public NetworkSimulationInterface {
|
||||||
|
public:
|
||||||
|
using Config = NetworkSimulationInterface::SimulatedNetworkConfig;
|
||||||
|
explicit SimulatedNetwork(Config config, uint64_t random_seed = 1);
|
||||||
|
~SimulatedNetwork() override;
|
||||||
|
|
||||||
|
// Sets a new configuration. This won't affect packets already in the pipe.
|
||||||
|
void SetConfig(const Config& config);
|
||||||
|
void PauseTransmissionUntil(int64_t until_us);
|
||||||
|
|
||||||
|
// NetworkSimulationInterface
|
||||||
|
bool EnqueuePacket(PacketInFlightInfo packet) override;
|
||||||
|
std::vector<PacketDeliveryInfo> DequeueDeliverablePackets(
|
||||||
|
int64_t receive_time_us) override;
|
||||||
|
|
||||||
|
absl::optional<int64_t> NextDeliveryTimeUs() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PacketInfo {
|
||||||
|
PacketInFlightInfo packet;
|
||||||
|
int64_t arrival_time_us;
|
||||||
|
};
|
||||||
|
rtc::CriticalSection config_lock_;
|
||||||
|
|
||||||
|
// |process_lock| guards the data structures involved in delay and loss
|
||||||
|
// processes, such as the packet queues.
|
||||||
|
rtc::CriticalSection process_lock_;
|
||||||
|
std::queue<PacketInfo> capacity_link_ RTC_GUARDED_BY(process_lock_);
|
||||||
|
Random random_;
|
||||||
|
|
||||||
|
std::deque<PacketInfo> delay_link_;
|
||||||
|
|
||||||
|
// Link configuration.
|
||||||
|
Config config_ RTC_GUARDED_BY(config_lock_);
|
||||||
|
absl::optional<int64_t> pause_transmission_until_us_
|
||||||
|
RTC_GUARDED_BY(config_lock_);
|
||||||
|
|
||||||
|
// Are we currently dropping a burst of packets?
|
||||||
|
bool bursting_;
|
||||||
|
|
||||||
|
// The probability to drop the packet if we are currently dropping a
|
||||||
|
// burst of packet
|
||||||
|
double prob_loss_bursting_ RTC_GUARDED_BY(config_lock_);
|
||||||
|
|
||||||
|
// The probability to drop a burst of packets.
|
||||||
|
double prob_start_bursting_ RTC_GUARDED_BY(config_lock_);
|
||||||
|
int64_t capacity_delay_error_bytes_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
#endif // CALL_SIMULATED_NETWORK_H_
|
Reference in New Issue
Block a user