Using NetworkEmulationManager in Scenario tests.
Bug: webrtc:9510 Change-Id: Ib619526269c58f0c46c0c1f01ba6c0efa5f79ba5 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/132781 Commit-Queue: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Artem Titov <titovartem@webrtc.org> Cr-Commit-Position: refs/heads/master@{#27635}
This commit is contained in:
parent
884adca3a0
commit
a4c22b9662
@ -33,35 +33,26 @@ SimulatedNetwork::Config CreateSimulationConfig(
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void NullReceiver::OnPacketReceived(EmulatedIpPacket packet) {}
|
||||
SimulationNode::SimulationNode(NetworkSimulationConfig config,
|
||||
SimulatedNetwork* behavior,
|
||||
EmulatedNetworkNode* network_node)
|
||||
: config_(config), simulation_(behavior), network_node_(network_node) {}
|
||||
|
||||
ActionReceiver::ActionReceiver(std::function<void()> action)
|
||||
: action_(action) {}
|
||||
|
||||
void ActionReceiver::OnPacketReceived(EmulatedIpPacket packet) {
|
||||
action_();
|
||||
}
|
||||
|
||||
std::unique_ptr<SimulationNode> SimulationNode::Create(
|
||||
Clock* clock,
|
||||
rtc::TaskQueue* task_queue,
|
||||
std::unique_ptr<SimulatedNetwork> SimulationNode::CreateBehavior(
|
||||
NetworkSimulationConfig config) {
|
||||
SimulatedNetwork::Config sim_config = CreateSimulationConfig(config);
|
||||
auto network = absl::make_unique<SimulatedNetwork>(sim_config);
|
||||
SimulatedNetwork* simulation_ptr = network.get();
|
||||
return std::unique_ptr<SimulationNode>(new SimulationNode(
|
||||
clock, task_queue, config, std::move(network), simulation_ptr));
|
||||
return absl::make_unique<SimulatedNetwork>(sim_config);
|
||||
}
|
||||
|
||||
void SimulationNode::UpdateConfig(
|
||||
std::function<void(NetworkSimulationConfig*)> modifier) {
|
||||
modifier(&config_);
|
||||
SimulatedNetwork::Config sim_config = CreateSimulationConfig(config_);
|
||||
simulated_network_->SetConfig(sim_config);
|
||||
simulation_->SetConfig(sim_config);
|
||||
}
|
||||
|
||||
void SimulationNode::PauseTransmissionUntil(Timestamp until) {
|
||||
simulated_network_->PauseTransmissionUntil(until.us());
|
||||
simulation_->PauseTransmissionUntil(until.us());
|
||||
}
|
||||
|
||||
ColumnPrinter SimulationNode::ConfigPrinter() const {
|
||||
@ -73,15 +64,6 @@ ColumnPrinter SimulationNode::ConfigPrinter() const {
|
||||
});
|
||||
}
|
||||
|
||||
SimulationNode::SimulationNode(
|
||||
Clock* clock,
|
||||
rtc::TaskQueue* task_queue,
|
||||
NetworkSimulationConfig config,
|
||||
std::unique_ptr<NetworkBehaviorInterface> behavior,
|
||||
SimulatedNetwork* simulation)
|
||||
: EmulatedNetworkNode(clock, task_queue, std::move(behavior)),
|
||||
simulated_network_(simulation),
|
||||
config_(config) {}
|
||||
|
||||
NetworkNodeTransport::NetworkNodeTransport(Clock* sender_clock,
|
||||
Call* sender_call)
|
||||
@ -162,57 +144,5 @@ void NetworkNodeTransport::Disconnect() {
|
||||
send_net_ = nullptr;
|
||||
}
|
||||
|
||||
CrossTrafficSource::CrossTrafficSource(EmulatedNetworkReceiverInterface* target,
|
||||
rtc::IPAddress receiver_ip,
|
||||
CrossTrafficConfig config)
|
||||
: target_(target),
|
||||
receiver_address_(receiver_ip, 0),
|
||||
config_(config),
|
||||
random_(config.random_seed) {}
|
||||
|
||||
CrossTrafficSource::~CrossTrafficSource() = default;
|
||||
|
||||
DataRate CrossTrafficSource::TrafficRate() const {
|
||||
return config_.peak_rate * intensity_;
|
||||
}
|
||||
|
||||
void CrossTrafficSource::Process(Timestamp at_time, TimeDelta delta) {
|
||||
time_since_update_ += delta;
|
||||
if (config_.mode == CrossTrafficConfig::Mode::kRandomWalk) {
|
||||
if (time_since_update_ >= config_.random_walk.update_interval) {
|
||||
intensity_ += random_.Gaussian(config_.random_walk.bias,
|
||||
config_.random_walk.variance) *
|
||||
time_since_update_.seconds<double>();
|
||||
intensity_ = rtc::SafeClamp(intensity_, 0.0, 1.0);
|
||||
time_since_update_ = TimeDelta::Zero();
|
||||
}
|
||||
} else if (config_.mode == CrossTrafficConfig::Mode::kPulsedPeaks) {
|
||||
if (intensity_ == 0 && time_since_update_ >= config_.pulsed.hold_duration) {
|
||||
intensity_ = 1;
|
||||
time_since_update_ = TimeDelta::Zero();
|
||||
} else if (intensity_ == 1 &&
|
||||
time_since_update_ >= config_.pulsed.send_duration) {
|
||||
intensity_ = 0;
|
||||
time_since_update_ = TimeDelta::Zero();
|
||||
}
|
||||
}
|
||||
pending_size_ += TrafficRate() * delta;
|
||||
if (pending_size_ > config_.min_packet_size) {
|
||||
target_->OnPacketReceived(EmulatedIpPacket(
|
||||
/*from=*/rtc::SocketAddress(), receiver_address_,
|
||||
rtc::CopyOnWriteBuffer(pending_size_.bytes()), at_time));
|
||||
pending_size_ = DataSize::Zero();
|
||||
}
|
||||
}
|
||||
|
||||
ColumnPrinter CrossTrafficSource::StatsPrinter() {
|
||||
return ColumnPrinter::Lambda("cross_traffic_rate",
|
||||
[this](rtc::SimpleStringBuilder& sb) {
|
||||
sb.AppendFormat("%.0lf",
|
||||
TrafficRate().bps() / 8.0);
|
||||
},
|
||||
32);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
@ -30,42 +30,23 @@
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
class NullReceiver : public EmulatedNetworkReceiverInterface {
|
||||
class SimulationNode {
|
||||
public:
|
||||
void OnPacketReceived(EmulatedIpPacket packet) override;
|
||||
};
|
||||
class ActionReceiver : public EmulatedNetworkReceiverInterface {
|
||||
public:
|
||||
explicit ActionReceiver(std::function<void()> action);
|
||||
virtual ~ActionReceiver() = default;
|
||||
SimulationNode(NetworkSimulationConfig config,
|
||||
SimulatedNetwork* behavior,
|
||||
EmulatedNetworkNode* network_node);
|
||||
static std::unique_ptr<SimulatedNetwork> CreateBehavior(
|
||||
NetworkSimulationConfig config);
|
||||
|
||||
void OnPacketReceived(EmulatedIpPacket packet) override;
|
||||
|
||||
private:
|
||||
std::function<void()> action_;
|
||||
};
|
||||
|
||||
class SimulationNode : public EmulatedNetworkNode {
|
||||
public:
|
||||
void UpdateConfig(std::function<void(NetworkSimulationConfig*)> modifier);
|
||||
void PauseTransmissionUntil(Timestamp until);
|
||||
ColumnPrinter ConfigPrinter() const;
|
||||
EmulatedNetworkNode* node() { return this; }
|
||||
EmulatedNetworkNode* node() { return network_node_; }
|
||||
|
||||
private:
|
||||
friend class Scenario;
|
||||
|
||||
SimulationNode(Clock* clock,
|
||||
rtc::TaskQueue* task_queue,
|
||||
NetworkSimulationConfig config,
|
||||
std::unique_ptr<NetworkBehaviorInterface> behavior,
|
||||
SimulatedNetwork* simulation);
|
||||
static std::unique_ptr<SimulationNode> Create(Clock* clock,
|
||||
rtc::TaskQueue* task_queue,
|
||||
NetworkSimulationConfig config);
|
||||
|
||||
SimulatedNetwork* const simulated_network_;
|
||||
NetworkSimulationConfig config_;
|
||||
SimulatedNetwork* const simulation_;
|
||||
EmulatedNetworkNode* const network_node_;
|
||||
};
|
||||
|
||||
class NetworkNodeTransport : public Transport {
|
||||
@ -99,31 +80,6 @@ class NetworkNodeTransport : public Transport {
|
||||
DataSize packet_overhead_ RTC_GUARDED_BY(crit_sect_) = DataSize::Zero();
|
||||
rtc::NetworkRoute current_network_route_ RTC_GUARDED_BY(crit_sect_);
|
||||
};
|
||||
|
||||
// CrossTrafficSource is created by a Scenario and generates cross traffic. It
|
||||
// provides methods to access and print internal state.
|
||||
class CrossTrafficSource {
|
||||
public:
|
||||
DataRate TrafficRate() const;
|
||||
ColumnPrinter StatsPrinter();
|
||||
~CrossTrafficSource();
|
||||
|
||||
private:
|
||||
friend class Scenario;
|
||||
CrossTrafficSource(EmulatedNetworkReceiverInterface* target,
|
||||
rtc::IPAddress receiver_ip,
|
||||
CrossTrafficConfig config);
|
||||
void Process(Timestamp at_time, TimeDelta delta);
|
||||
|
||||
EmulatedNetworkReceiverInterface* const target_;
|
||||
const rtc::SocketAddress receiver_address_;
|
||||
CrossTrafficConfig config_;
|
||||
webrtc::Random random_;
|
||||
|
||||
TimeDelta time_since_update_ = TimeDelta::Zero();
|
||||
double intensity_ = 0;
|
||||
DataSize pending_size_ = DataSize::Zero();
|
||||
};
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
#endif // TEST_SCENARIO_NETWORK_NODE_H_
|
||||
|
||||
@ -73,6 +73,7 @@ Scenario::Scenario(
|
||||
clock_(time_controller_->GetClock()),
|
||||
audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()),
|
||||
audio_encoder_factory_(CreateBuiltinAudioEncoderFactory()),
|
||||
network_manager_(time_controller_.get()),
|
||||
task_queue_(time_controller_->GetTaskQueueFactory()->CreateTaskQueue(
|
||||
"Scenario",
|
||||
TaskQueueFactory::Priority::NORMAL)) {}
|
||||
@ -192,6 +193,7 @@ SimulatedTimeClient* Scenario::CreateSimulatedTimeClient(
|
||||
simulated_time_clients_.emplace_back(client);
|
||||
return client;
|
||||
}
|
||||
|
||||
EmulatedNetworkNode* Scenario::CreateSimulationNode(
|
||||
std::function<void(NetworkSimulationConfig*)> config_modifier) {
|
||||
NetworkSimulationConfig config;
|
||||
@ -201,7 +203,8 @@ EmulatedNetworkNode* Scenario::CreateSimulationNode(
|
||||
|
||||
EmulatedNetworkNode* Scenario::CreateSimulationNode(
|
||||
NetworkSimulationConfig config) {
|
||||
return CreateMutableSimulationNode(config);
|
||||
return network_manager_.CreateEmulatedNode(
|
||||
SimulationNode::CreateBehavior(config));
|
||||
}
|
||||
|
||||
SimulationNode* Scenario::CreateMutableSimulationNode(
|
||||
@ -213,55 +216,29 @@ SimulationNode* Scenario::CreateMutableSimulationNode(
|
||||
|
||||
SimulationNode* Scenario::CreateMutableSimulationNode(
|
||||
NetworkSimulationConfig config) {
|
||||
auto network_node = SimulationNode::Create(clock_, &task_queue_, config);
|
||||
SimulationNode* sim_node = network_node.get();
|
||||
network_nodes_.emplace_back(std::move(network_node));
|
||||
return sim_node;
|
||||
std::unique_ptr<SimulatedNetwork> behavior =
|
||||
SimulationNode::CreateBehavior(config);
|
||||
SimulatedNetwork* behavior_ptr = behavior.get();
|
||||
auto* emulated_node =
|
||||
network_manager_.CreateEmulatedNode(std::move(behavior));
|
||||
simulation_nodes_.emplace_back(
|
||||
new SimulationNode(config, behavior_ptr, emulated_node));
|
||||
return simulation_nodes_.back().get();
|
||||
}
|
||||
|
||||
void Scenario::TriggerPacketBurst(std::vector<EmulatedNetworkNode*> over_nodes,
|
||||
size_t num_packets,
|
||||
size_t packet_size) {
|
||||
rtc::IPAddress route_ip(next_route_id_++);
|
||||
EmulatedNetworkNode::CreateRoute(route_ip, over_nodes, &null_receiver_);
|
||||
for (size_t i = 0; i < num_packets; ++i)
|
||||
over_nodes[0]->OnPacketReceived(EmulatedIpPacket(
|
||||
/*from=*/rtc::SocketAddress(), /*to=*/rtc::SocketAddress(route_ip, 0),
|
||||
rtc::CopyOnWriteBuffer(packet_size), Now()));
|
||||
network_manager_.CreateTrafficRoute(over_nodes)
|
||||
->TriggerPacketBurst(num_packets, packet_size);
|
||||
}
|
||||
|
||||
void Scenario::NetworkDelayedAction(
|
||||
std::vector<EmulatedNetworkNode*> over_nodes,
|
||||
size_t packet_size,
|
||||
std::function<void()> action) {
|
||||
rtc::IPAddress route_ip(next_route_id_++);
|
||||
action_receivers_.emplace_back(new ActionReceiver(action));
|
||||
EmulatedNetworkNode::CreateRoute(route_ip, over_nodes,
|
||||
action_receivers_.back().get());
|
||||
over_nodes[0]->OnPacketReceived(EmulatedIpPacket(
|
||||
/*from=*/rtc::SocketAddress(), /*to=*/rtc::SocketAddress(route_ip, 0),
|
||||
rtc::CopyOnWriteBuffer(packet_size), Now()));
|
||||
}
|
||||
|
||||
CrossTrafficSource* Scenario::CreateCrossTraffic(
|
||||
std::vector<EmulatedNetworkNode*> over_nodes,
|
||||
std::function<void(CrossTrafficConfig*)> config_modifier) {
|
||||
CrossTrafficConfig cross_config;
|
||||
config_modifier(&cross_config);
|
||||
return CreateCrossTraffic(over_nodes, cross_config);
|
||||
}
|
||||
|
||||
CrossTrafficSource* Scenario::CreateCrossTraffic(
|
||||
std::vector<EmulatedNetworkNode*> over_nodes,
|
||||
CrossTrafficConfig config) {
|
||||
rtc::IPAddress route_ip(next_route_id_++);
|
||||
cross_traffic_sources_.emplace_back(
|
||||
new CrossTrafficSource(over_nodes.front(), route_ip, config));
|
||||
CrossTrafficSource* node = cross_traffic_sources_.back().get();
|
||||
EmulatedNetworkNode::CreateRoute(route_ip, over_nodes, &null_receiver_);
|
||||
Every(config.min_packet_interval,
|
||||
[this, node](TimeDelta delta) { node->Process(Now(), delta); });
|
||||
return node;
|
||||
network_manager_.CreateTrafficRoute(over_nodes)
|
||||
->NetworkDelayedAction(packet_size, action);
|
||||
}
|
||||
|
||||
VideoStreamPair* Scenario::CreateVideoStream(
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "test/scenario/audio_stream.h"
|
||||
#include "test/scenario/call_client.h"
|
||||
#include "test/scenario/column_printer.h"
|
||||
#include "test/scenario/network/network_emulation_manager.h"
|
||||
#include "test/scenario/network_node.h"
|
||||
#include "test/scenario/scenario_config.h"
|
||||
#include "test/scenario/simulated_time.h"
|
||||
@ -48,6 +49,7 @@ class Scenario {
|
||||
bool real_time);
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(Scenario);
|
||||
~Scenario();
|
||||
NetworkEmulationManagerImpl* net() { return &network_manager_; }
|
||||
|
||||
EmulatedNetworkNode* CreateSimulationNode(NetworkSimulationConfig config);
|
||||
EmulatedNetworkNode* CreateSimulationNode(
|
||||
@ -102,13 +104,6 @@ class Scenario {
|
||||
std::pair<CallClient*, CallClient*> clients,
|
||||
AudioStreamConfig config);
|
||||
|
||||
CrossTrafficSource* CreateCrossTraffic(
|
||||
std::vector<EmulatedNetworkNode*> over_nodes,
|
||||
std::function<void(CrossTrafficConfig*)> config_modifier);
|
||||
CrossTrafficSource* CreateCrossTraffic(
|
||||
std::vector<EmulatedNetworkNode*> over_nodes,
|
||||
CrossTrafficConfig config);
|
||||
|
||||
// Runs the provided function with a fixed interval. For real time tests,
|
||||
// |function| starts being called after |interval| from the call to Every().
|
||||
void Every(TimeDelta interval, std::function<void(TimeDelta)> function);
|
||||
@ -168,21 +163,16 @@ class Scenario {
|
||||
private:
|
||||
TimeDelta TimeUntilTarget(TimeDelta target_time_offset);
|
||||
|
||||
NullReceiver null_receiver_;
|
||||
const std::unique_ptr<LogWriterFactoryInterface> log_writer_factory_;
|
||||
std::unique_ptr<TimeController> time_controller_;
|
||||
Clock* clock_;
|
||||
|
||||
std::vector<std::unique_ptr<CallClient>> clients_;
|
||||
std::vector<std::unique_ptr<CallClientPair>> client_pairs_;
|
||||
std::vector<std::unique_ptr<EmulatedNetworkNode>> network_nodes_;
|
||||
std::vector<std::unique_ptr<CrossTrafficSource>> cross_traffic_sources_;
|
||||
std::vector<std::unique_ptr<VideoStreamPair>> video_streams_;
|
||||
std::vector<std::unique_ptr<AudioStreamPair>> audio_streams_;
|
||||
|
||||
std::vector<std::unique_ptr<SimulatedTimeClient>> simulated_time_clients_;
|
||||
|
||||
std::vector<std::unique_ptr<ActionReceiver>> action_receivers_;
|
||||
std::vector<std::unique_ptr<SimulationNode>> simulation_nodes_;
|
||||
std::vector<std::unique_ptr<StatesPrinter>> printers_;
|
||||
|
||||
int64_t next_route_id_ = 40000;
|
||||
@ -190,6 +180,7 @@ class Scenario {
|
||||
rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory_;
|
||||
|
||||
Timestamp start_time_ = Timestamp::PlusInfinity();
|
||||
NetworkEmulationManagerImpl network_manager_;
|
||||
// Defined last so it's destroyed first.
|
||||
rtc::TaskQueue task_queue_;
|
||||
};
|
||||
|
||||
@ -43,9 +43,5 @@ AudioStreamConfig::Stream::Stream() = default;
|
||||
AudioStreamConfig::Stream::Stream(const AudioStreamConfig::Stream&) = default;
|
||||
AudioStreamConfig::Stream::~Stream() = default;
|
||||
|
||||
CrossTrafficConfig::CrossTrafficConfig() = default;
|
||||
CrossTrafficConfig::CrossTrafficConfig(const CrossTrafficConfig&) = default;
|
||||
CrossTrafficConfig::~CrossTrafficConfig() = default;
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
@ -237,26 +237,6 @@ struct NetworkSimulationConfig {
|
||||
bool codel_active_queue_management = false;
|
||||
DataSize packet_overhead = DataSize::Zero();
|
||||
};
|
||||
|
||||
struct CrossTrafficConfig {
|
||||
CrossTrafficConfig();
|
||||
CrossTrafficConfig(const CrossTrafficConfig&);
|
||||
~CrossTrafficConfig();
|
||||
enum Mode { kRandomWalk, kPulsedPeaks } mode = kRandomWalk;
|
||||
int random_seed = 1;
|
||||
DataRate peak_rate = DataRate::kbps(100);
|
||||
DataSize min_packet_size = DataSize::bytes(200);
|
||||
TimeDelta min_packet_interval = TimeDelta::ms(1);
|
||||
struct RandomWalk {
|
||||
TimeDelta update_interval = TimeDelta::ms(200);
|
||||
double variance = 0.6;
|
||||
double bias = -0.1;
|
||||
} random_walk;
|
||||
struct PulsedPeaks {
|
||||
TimeDelta send_duration = TimeDelta::ms(100);
|
||||
TimeDelta hold_duration = TimeDelta::ms(2000);
|
||||
} pulsed;
|
||||
};
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
@ -191,11 +191,11 @@ TEST_P(BbrScenarioTest, ReceivesVideo) {
|
||||
}
|
||||
});
|
||||
}
|
||||
CrossTrafficConfig cross_config;
|
||||
RandomWalkConfig cross_config;
|
||||
cross_config.peak_rate = conf_.scenario.cross_traffic;
|
||||
cross_config.random_seed = conf_.scenario.random_seed;
|
||||
CrossTrafficSource* cross_traffic =
|
||||
s.CreateCrossTraffic({send_net}, cross_config);
|
||||
auto* cross_traffic = s.net()->CreateRandomWalkCrossTraffic(
|
||||
s.net()->CreateTrafficRoute({send_net->node()}), cross_config);
|
||||
|
||||
s.CreatePrinter("send.stats.txt", TimeDelta::ms(100),
|
||||
{alice->StatsPrinter(), alice_video->send()->StatsPrinter(),
|
||||
|
||||
@ -40,8 +40,9 @@ TEST(ScenarioTest, StartsAndStopsWithoutErrors) {
|
||||
s.CreateAudioStream(route->forward(), audio_stream_config);
|
||||
s.CreateAudioStream(route->reverse(), audio_stream_config);
|
||||
|
||||
CrossTrafficConfig cross_traffic_config;
|
||||
s.CreateCrossTraffic({alice_net}, cross_traffic_config);
|
||||
RandomWalkConfig cross_traffic_config;
|
||||
s.net()->CreateRandomWalkCrossTraffic(
|
||||
s.net()->CreateTrafficRoute({alice_net}), cross_traffic_config);
|
||||
|
||||
s.NetworkDelayedAction({alice_net, bob_net}, 100,
|
||||
[&packet_received] { packet_received = true; });
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user