Removes SimulatedTimeClient
Bug: webrtc:9883 Change-Id: Id6e760b37360e7dafc67ded99e06128be20797d1 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/141417 Commit-Queue: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Jonas Olsson <jonasolsson@webrtc.org> Cr-Commit-Position: refs/heads/master@{#28269}
This commit is contained in:

committed by
Commit Bot

parent
6fd67f086c
commit
5740afa0a4
@ -59,10 +59,23 @@ const uint32_t kInitialBitrateKbps = 60;
|
|||||||
const DataRate kInitialBitrate = DataRate::kbps(kInitialBitrateKbps);
|
const DataRate kInitialBitrate = DataRate::kbps(kInitialBitrateKbps);
|
||||||
const float kDefaultPacingRate = 2.5f;
|
const float kDefaultPacingRate = 2.5f;
|
||||||
|
|
||||||
|
CallClient* CreateVideoSendingClient(
|
||||||
|
Scenario* s,
|
||||||
|
CallClientConfig config,
|
||||||
|
std::vector<EmulatedNetworkNode*> send_link,
|
||||||
|
std::vector<EmulatedNetworkNode*> return_link) {
|
||||||
|
auto* client = s->CreateClient("send", std::move(config));
|
||||||
|
auto* route = s->CreateRoutes(client, send_link,
|
||||||
|
s->CreateClient("return", CallClientConfig()),
|
||||||
|
return_link);
|
||||||
|
s->CreateVideoStream(route->forward(), VideoStreamConfig());
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
void UpdatesTargetRateBasedOnLinkCapacity(std::string test_name = "") {
|
void UpdatesTargetRateBasedOnLinkCapacity(std::string test_name = "") {
|
||||||
auto factory = CreateFeedbackOnlyFactory();
|
auto factory = CreateFeedbackOnlyFactory();
|
||||||
Scenario s("googcc_unit/target_capacity" + test_name, false);
|
Scenario s("googcc_unit/target_capacity" + test_name, false);
|
||||||
SimulatedTimeClientConfig config;
|
CallClientConfig config;
|
||||||
config.transport.cc_factory = &factory;
|
config.transport.cc_factory = &factory;
|
||||||
config.transport.rates.min_rate = DataRate::kbps(10);
|
config.transport.rates.min_rate = DataRate::kbps(10);
|
||||||
config.transport.rates.max_rate = DataRate::kbps(1500);
|
config.transport.rates.max_rate = DataRate::kbps(1500);
|
||||||
@ -76,14 +89,14 @@ void UpdatesTargetRateBasedOnLinkCapacity(std::string test_name = "") {
|
|||||||
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(100); });
|
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(100); });
|
||||||
StatesPrinter* truth = s.CreatePrinter(
|
StatesPrinter* truth = s.CreatePrinter(
|
||||||
"send.truth.txt", TimeDelta::PlusInfinity(), {send_net->ConfigPrinter()});
|
"send.truth.txt", TimeDelta::PlusInfinity(), {send_net->ConfigPrinter()});
|
||||||
SimulatedTimeClient* client =
|
|
||||||
s.CreateSimulatedTimeClient("send", config, {PacketStreamConfig()},
|
auto* client = CreateVideoSendingClient(&s, config, {send_net->node()},
|
||||||
{send_net->node()}, {ret_net->node()});
|
{ret_net->node()});
|
||||||
|
|
||||||
truth->PrintRow();
|
truth->PrintRow();
|
||||||
s.RunFor(TimeDelta::seconds(25));
|
s.RunFor(TimeDelta::seconds(25));
|
||||||
truth->PrintRow();
|
truth->PrintRow();
|
||||||
EXPECT_NEAR(client->target_rate_kbps(), 450, 100);
|
EXPECT_NEAR(client->target_rate().kbps(), 450, 100);
|
||||||
|
|
||||||
send_net->UpdateConfig([](NetworkSimulationConfig* c) {
|
send_net->UpdateConfig([](NetworkSimulationConfig* c) {
|
||||||
c->bandwidth = DataRate::kbps(800);
|
c->bandwidth = DataRate::kbps(800);
|
||||||
@ -93,7 +106,7 @@ void UpdatesTargetRateBasedOnLinkCapacity(std::string test_name = "") {
|
|||||||
truth->PrintRow();
|
truth->PrintRow();
|
||||||
s.RunFor(TimeDelta::seconds(20));
|
s.RunFor(TimeDelta::seconds(20));
|
||||||
truth->PrintRow();
|
truth->PrintRow();
|
||||||
EXPECT_NEAR(client->target_rate_kbps(), 750, 150);
|
EXPECT_NEAR(client->target_rate().kbps(), 750, 150);
|
||||||
|
|
||||||
send_net->UpdateConfig([](NetworkSimulationConfig* c) {
|
send_net->UpdateConfig([](NetworkSimulationConfig* c) {
|
||||||
c->bandwidth = DataRate::kbps(100);
|
c->bandwidth = DataRate::kbps(100);
|
||||||
@ -105,7 +118,7 @@ void UpdatesTargetRateBasedOnLinkCapacity(std::string test_name = "") {
|
|||||||
truth->PrintRow();
|
truth->PrintRow();
|
||||||
s.RunFor(TimeDelta::seconds(50));
|
s.RunFor(TimeDelta::seconds(50));
|
||||||
truth->PrintRow();
|
truth->PrintRow();
|
||||||
EXPECT_NEAR(client->target_rate_kbps(), 90, 20);
|
EXPECT_NEAR(client->target_rate().kbps(), 90, 20);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -252,14 +265,15 @@ TEST_F(GoogCcNetworkControllerTest, CongestionWindowPushbackOnNetworkDelay) {
|
|||||||
});
|
});
|
||||||
auto ret_net = s.CreateSimulationNode(
|
auto ret_net = s.CreateSimulationNode(
|
||||||
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(100); });
|
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(100); });
|
||||||
SimulatedTimeClientConfig config;
|
CallClientConfig config;
|
||||||
config.transport.cc_factory = &factory;
|
config.transport.cc_factory = &factory;
|
||||||
// Start high so bandwidth drop has max effect.
|
// Start high so bandwidth drop has max effect.
|
||||||
config.transport.rates.start_rate = DataRate::kbps(300);
|
config.transport.rates.start_rate = DataRate::kbps(300);
|
||||||
config.transport.rates.max_rate = DataRate::kbps(2000);
|
config.transport.rates.max_rate = DataRate::kbps(2000);
|
||||||
config.transport.rates.min_rate = DataRate::kbps(10);
|
config.transport.rates.min_rate = DataRate::kbps(10);
|
||||||
SimulatedTimeClient* client = s.CreateSimulatedTimeClient(
|
|
||||||
"send", config, {PacketStreamConfig()}, {send_net->node()}, {ret_net});
|
auto* client = CreateVideoSendingClient(&s, std::move(config),
|
||||||
|
{send_net->node()}, {ret_net});
|
||||||
|
|
||||||
s.RunFor(TimeDelta::seconds(10));
|
s.RunFor(TimeDelta::seconds(10));
|
||||||
send_net->PauseTransmissionUntil(s.Now() + TimeDelta::seconds(10));
|
send_net->PauseTransmissionUntil(s.Now() + TimeDelta::seconds(10));
|
||||||
@ -269,7 +283,7 @@ TEST_F(GoogCcNetworkControllerTest, CongestionWindowPushbackOnNetworkDelay) {
|
|||||||
// target rate is reduced to the minimum pushback threshold
|
// target rate is reduced to the minimum pushback threshold
|
||||||
// kDefaultMinPushbackTargetBitrateBps, which is defined as 30 kbps in
|
// kDefaultMinPushbackTargetBitrateBps, which is defined as 30 kbps in
|
||||||
// congestion_window_pushback_controller.
|
// congestion_window_pushback_controller.
|
||||||
EXPECT_LT(client->target_rate_kbps(), 40);
|
EXPECT_LT(client->target_rate().kbps(), 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(GoogCcNetworkControllerTest, OnNetworkRouteChanged) {
|
TEST_F(GoogCcNetworkControllerTest, OnNetworkRouteChanged) {
|
||||||
@ -338,22 +352,27 @@ TEST_F(GoogCcNetworkControllerTest,
|
|||||||
});
|
});
|
||||||
auto ret_net = s.CreateSimulationNode(
|
auto ret_net = s.CreateSimulationNode(
|
||||||
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(100); });
|
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(100); });
|
||||||
SimulatedTimeClientConfig config;
|
CallClientConfig config;
|
||||||
// Start high so bandwidth drop has max effect.
|
// Start high so bandwidth drop has max effect.
|
||||||
config.transport.rates.start_rate = DataRate::kbps(1000);
|
config.transport.rates.start_rate = DataRate::kbps(1000);
|
||||||
config.transport.rates.max_rate = DataRate::kbps(2000);
|
config.transport.rates.max_rate = DataRate::kbps(2000);
|
||||||
config.transport.rates.max_padding_rate = config.transport.rates.max_rate;
|
auto* client = s.CreateClient("send", config);
|
||||||
SimulatedTimeClient* client = s.CreateSimulatedTimeClient(
|
auto* route =
|
||||||
"send", config, {PacketStreamConfig()}, {send_net->node()}, {ret_net});
|
s.CreateRoutes(client, {send_net->node()},
|
||||||
|
s.CreateClient("return", CallClientConfig()), {ret_net});
|
||||||
|
VideoStreamConfig video;
|
||||||
|
video.stream.pad_to_rate = config.transport.rates.max_rate;
|
||||||
|
s.CreateVideoStream(route->forward(), video);
|
||||||
|
|
||||||
// Run for a few seconds to allow the controller to stabilize.
|
// Run for a few seconds to allow the controller to stabilize.
|
||||||
s.RunFor(TimeDelta::seconds(10));
|
s.RunFor(TimeDelta::seconds(10));
|
||||||
|
|
||||||
// Check that padding rate matches target rate.
|
// Check that padding rate matches target rate.
|
||||||
EXPECT_NEAR(client->padding_rate().kbps(), client->target_rate_kbps(), 1);
|
EXPECT_NEAR(client->padding_rate().kbps(), client->target_rate().kbps(), 1);
|
||||||
|
|
||||||
// Check this is also the case when congestion window pushback kicks in.
|
// Check this is also the case when congestion window pushback kicks in.
|
||||||
send_net->PauseTransmissionUntil(s.Now() + TimeDelta::seconds(1));
|
send_net->PauseTransmissionUntil(s.Now() + TimeDelta::seconds(1));
|
||||||
EXPECT_NEAR(client->padding_rate().kbps(), client->target_rate_kbps(), 1);
|
EXPECT_NEAR(client->padding_rate().kbps(), client->target_rate().kbps(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(GoogCcNetworkControllerTest, LimitsToFloorIfRttIsHighInTrial) {
|
TEST_F(GoogCcNetworkControllerTest, LimitsToFloorIfRttIsHighInTrial) {
|
||||||
@ -376,10 +395,10 @@ TEST_F(GoogCcNetworkControllerTest, LimitsToFloorIfRttIsHighInTrial) {
|
|||||||
});
|
});
|
||||||
auto ret_net = s.CreateSimulationNode(
|
auto ret_net = s.CreateSimulationNode(
|
||||||
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(100); });
|
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(100); });
|
||||||
SimulatedTimeClientConfig config;
|
CallClientConfig config;
|
||||||
config.transport.rates.start_rate = kLinkCapacity;
|
config.transport.rates.start_rate = kLinkCapacity;
|
||||||
SimulatedTimeClient* client = s.CreateSimulatedTimeClient(
|
|
||||||
"send", config, {PacketStreamConfig()}, {send_net}, {ret_net});
|
auto* client = CreateVideoSendingClient(&s, config, {send_net}, {ret_net});
|
||||||
// Run for a few seconds to allow the controller to stabilize.
|
// Run for a few seconds to allow the controller to stabilize.
|
||||||
s.RunFor(TimeDelta::seconds(10));
|
s.RunFor(TimeDelta::seconds(10));
|
||||||
const DataSize kBloatPacketSize = DataSize::bytes(1000);
|
const DataSize kBloatPacketSize = DataSize::bytes(1000);
|
||||||
@ -390,7 +409,7 @@ TEST_F(GoogCcNetworkControllerTest, LimitsToFloorIfRttIsHighInTrial) {
|
|||||||
// Wait to allow the high RTT to be detected and acted upon.
|
// Wait to allow the high RTT to be detected and acted upon.
|
||||||
s.RunFor(TimeDelta::seconds(4));
|
s.RunFor(TimeDelta::seconds(4));
|
||||||
// By now the target rate should have dropped to the minimum configured rate.
|
// By now the target rate should have dropped to the minimum configured rate.
|
||||||
EXPECT_NEAR(client->target_rate_kbps(), kBandwidthFloor.kbps(), 1);
|
EXPECT_NEAR(client->target_rate().kbps(), kBandwidthFloor.kbps(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(GoogCcNetworkControllerTest, UpdatesTargetRateBasedOnLinkCapacity) {
|
TEST_F(GoogCcNetworkControllerTest, UpdatesTargetRateBasedOnLinkCapacity) {
|
||||||
@ -401,15 +420,15 @@ TEST_F(GoogCcNetworkControllerTest, DefaultEstimateVariesInSteadyState) {
|
|||||||
auto factory = CreateFeedbackOnlyFactory();
|
auto factory = CreateFeedbackOnlyFactory();
|
||||||
ScopedFieldTrials trial("WebRTC-Bwe-StableBandwidthEstimate/Disabled/");
|
ScopedFieldTrials trial("WebRTC-Bwe-StableBandwidthEstimate/Disabled/");
|
||||||
Scenario s("googcc_unit/no_stable_varies", false);
|
Scenario s("googcc_unit/no_stable_varies", false);
|
||||||
SimulatedTimeClientConfig config;
|
CallClientConfig config;
|
||||||
config.transport.cc_factory = &factory;
|
config.transport.cc_factory = &factory;
|
||||||
NetworkSimulationConfig net_conf;
|
NetworkSimulationConfig net_conf;
|
||||||
net_conf.bandwidth = DataRate::kbps(500);
|
net_conf.bandwidth = DataRate::kbps(500);
|
||||||
net_conf.delay = TimeDelta::ms(100);
|
net_conf.delay = TimeDelta::ms(100);
|
||||||
auto send_net = s.CreateSimulationNode(net_conf);
|
auto send_net = s.CreateSimulationNode(net_conf);
|
||||||
auto ret_net = s.CreateSimulationNode(net_conf);
|
auto ret_net = s.CreateSimulationNode(net_conf);
|
||||||
SimulatedTimeClient* client = s.CreateSimulatedTimeClient(
|
|
||||||
"send", config, {PacketStreamConfig()}, {send_net}, {ret_net});
|
auto* client = CreateVideoSendingClient(&s, config, {send_net}, {ret_net});
|
||||||
// Run for a while to allow the estimate to stabilize.
|
// Run for a while to allow the estimate to stabilize.
|
||||||
s.RunFor(TimeDelta::seconds(20));
|
s.RunFor(TimeDelta::seconds(20));
|
||||||
DataRate min_estimate = DataRate::PlusInfinity();
|
DataRate min_estimate = DataRate::PlusInfinity();
|
||||||
@ -428,15 +447,15 @@ TEST_F(GoogCcNetworkControllerTest, StableEstimateDoesNotVaryInSteadyState) {
|
|||||||
auto factory = CreateFeedbackOnlyFactory();
|
auto factory = CreateFeedbackOnlyFactory();
|
||||||
ScopedFieldTrials trial("WebRTC-Bwe-StableBandwidthEstimate/Enabled/");
|
ScopedFieldTrials trial("WebRTC-Bwe-StableBandwidthEstimate/Enabled/");
|
||||||
Scenario s("googcc_unit/stable_is_stable", false);
|
Scenario s("googcc_unit/stable_is_stable", false);
|
||||||
SimulatedTimeClientConfig config;
|
CallClientConfig config;
|
||||||
config.transport.cc_factory = &factory;
|
config.transport.cc_factory = &factory;
|
||||||
NetworkSimulationConfig net_conf;
|
NetworkSimulationConfig net_conf;
|
||||||
net_conf.bandwidth = DataRate::kbps(500);
|
net_conf.bandwidth = DataRate::kbps(500);
|
||||||
net_conf.delay = TimeDelta::ms(100);
|
net_conf.delay = TimeDelta::ms(100);
|
||||||
auto send_net = s.CreateSimulationNode(net_conf);
|
auto send_net = s.CreateSimulationNode(net_conf);
|
||||||
auto ret_net = s.CreateSimulationNode(net_conf);
|
auto ret_net = s.CreateSimulationNode(net_conf);
|
||||||
SimulatedTimeClient* client = s.CreateSimulatedTimeClient(
|
|
||||||
"send", config, {PacketStreamConfig()}, {send_net}, {ret_net});
|
auto* client = CreateVideoSendingClient(&s, config, {send_net}, {ret_net});
|
||||||
// Run for a while to allow the estimate to stabilize.
|
// Run for a while to allow the estimate to stabilize.
|
||||||
s.RunFor(TimeDelta::seconds(30));
|
s.RunFor(TimeDelta::seconds(30));
|
||||||
DataRate min_estimate = DataRate::PlusInfinity();
|
DataRate min_estimate = DataRate::PlusInfinity();
|
||||||
@ -460,11 +479,9 @@ TEST_F(GoogCcNetworkControllerTest,
|
|||||||
|
|
||||||
TEST_F(GoogCcNetworkControllerTest,
|
TEST_F(GoogCcNetworkControllerTest,
|
||||||
LossBasedControlDoesModestBackoffToHighLoss) {
|
LossBasedControlDoesModestBackoffToHighLoss) {
|
||||||
auto factory = CreateFeedbackOnlyFactory();
|
|
||||||
ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/");
|
ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/");
|
||||||
Scenario s("googcc_unit/high_loss_channel", false);
|
Scenario s("googcc_unit/high_loss_channel", false);
|
||||||
SimulatedTimeClientConfig config;
|
CallClientConfig config;
|
||||||
config.transport.cc_factory = &factory;
|
|
||||||
config.transport.rates.min_rate = DataRate::kbps(10);
|
config.transport.rates.min_rate = DataRate::kbps(10);
|
||||||
config.transport.rates.max_rate = DataRate::kbps(1500);
|
config.transport.rates.max_rate = DataRate::kbps(1500);
|
||||||
config.transport.rates.start_rate = DataRate::kbps(300);
|
config.transport.rates.start_rate = DataRate::kbps(300);
|
||||||
@ -475,12 +492,12 @@ TEST_F(GoogCcNetworkControllerTest,
|
|||||||
});
|
});
|
||||||
auto ret_net = s.CreateSimulationNode(
|
auto ret_net = s.CreateSimulationNode(
|
||||||
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(200); });
|
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(200); });
|
||||||
SimulatedTimeClient* client = s.CreateSimulatedTimeClient(
|
|
||||||
"send", config, {PacketStreamConfig()}, {send_net}, {ret_net});
|
auto* client = CreateVideoSendingClient(&s, config, {send_net}, {ret_net});
|
||||||
|
|
||||||
s.RunFor(TimeDelta::seconds(120));
|
s.RunFor(TimeDelta::seconds(120));
|
||||||
// Without LossBasedControl trial, bandwidth drops to ~10 kbps.
|
// Without LossBasedControl trial, bandwidth drops to ~10 kbps.
|
||||||
EXPECT_GT(client->target_rate_kbps(), 100);
|
EXPECT_GT(client->target_rate().kbps(), 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(GoogCcNetworkControllerTest, LossBasedEstimatorCapsRateAtModerateLoss) {
|
TEST_F(GoogCcNetworkControllerTest, LossBasedEstimatorCapsRateAtModerateLoss) {
|
||||||
|
@ -75,7 +75,7 @@ TEST(PccNetworkControllerTest, SendsConfigurationOnFirstProcess) {
|
|||||||
TEST(PccNetworkControllerTest, UpdatesTargetSendRate) {
|
TEST(PccNetworkControllerTest, UpdatesTargetSendRate) {
|
||||||
PccNetworkControllerFactory factory;
|
PccNetworkControllerFactory factory;
|
||||||
Scenario s("pcc_unit/updates_rate", false);
|
Scenario s("pcc_unit/updates_rate", false);
|
||||||
SimulatedTimeClientConfig config;
|
CallClientConfig config;
|
||||||
config.transport.cc_factory = &factory;
|
config.transport.cc_factory = &factory;
|
||||||
config.transport.rates.min_rate = DataRate::kbps(10);
|
config.transport.rates.min_rate = DataRate::kbps(10);
|
||||||
config.transport.rates.max_rate = DataRate::kbps(1500);
|
config.transport.rates.max_rate = DataRate::kbps(1500);
|
||||||
@ -86,30 +86,28 @@ TEST(PccNetworkControllerTest, UpdatesTargetSendRate) {
|
|||||||
});
|
});
|
||||||
auto ret_net = s.CreateMutableSimulationNode(
|
auto ret_net = s.CreateMutableSimulationNode(
|
||||||
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(100); });
|
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(100); });
|
||||||
SimulatedTimeClient* client =
|
|
||||||
s.CreateSimulatedTimeClient("send", config, {PacketStreamConfig()},
|
|
||||||
{send_net->node()}, {ret_net->node()});
|
|
||||||
|
|
||||||
s.RunFor(TimeDelta::seconds(25));
|
|
||||||
EXPECT_NEAR(client->target_rate_kbps(), 450, 100);
|
|
||||||
|
|
||||||
|
auto* client = s.CreateClient("send", config);
|
||||||
|
auto* route = s.CreateRoutes(client, {send_net->node()},
|
||||||
|
s.CreateClient("return", CallClientConfig()),
|
||||||
|
{ret_net->node()});
|
||||||
|
s.CreateVideoStream(route->forward(), VideoStreamConfig());
|
||||||
|
s.RunFor(TimeDelta::seconds(30));
|
||||||
|
EXPECT_NEAR(client->target_rate().kbps(), 450, 100);
|
||||||
send_net->UpdateConfig([](NetworkSimulationConfig* c) {
|
send_net->UpdateConfig([](NetworkSimulationConfig* c) {
|
||||||
c->bandwidth = DataRate::kbps(800);
|
c->bandwidth = DataRate::kbps(800);
|
||||||
c->delay = TimeDelta::ms(100);
|
c->delay = TimeDelta::ms(100);
|
||||||
});
|
});
|
||||||
|
|
||||||
s.RunFor(TimeDelta::seconds(20));
|
s.RunFor(TimeDelta::seconds(20));
|
||||||
EXPECT_NEAR(client->target_rate_kbps(), 750, 150);
|
EXPECT_NEAR(client->target_rate().kbps(), 750, 150);
|
||||||
|
|
||||||
send_net->UpdateConfig([](NetworkSimulationConfig* c) {
|
send_net->UpdateConfig([](NetworkSimulationConfig* c) {
|
||||||
c->bandwidth = DataRate::kbps(200);
|
c->bandwidth = DataRate::kbps(200);
|
||||||
c->delay = TimeDelta::ms(200);
|
c->delay = TimeDelta::ms(200);
|
||||||
});
|
});
|
||||||
ret_net->UpdateConfig(
|
ret_net->UpdateConfig(
|
||||||
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(200); });
|
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(200); });
|
||||||
|
s.RunFor(TimeDelta::seconds(35));
|
||||||
s.RunFor(TimeDelta::seconds(20));
|
EXPECT_NEAR(client->target_rate().kbps(), 180, 40);
|
||||||
EXPECT_NEAR(client->target_rate_kbps(), 200, 40);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
@ -65,8 +65,6 @@ if (rtc_include_tests) {
|
|||||||
"scenario.h",
|
"scenario.h",
|
||||||
"scenario_config.cc",
|
"scenario_config.cc",
|
||||||
"scenario_config.h",
|
"scenario_config.h",
|
||||||
"simulated_time.cc",
|
|
||||||
"simulated_time.h",
|
|
||||||
"stats_collection.cc",
|
"stats_collection.cc",
|
||||||
"stats_collection.h",
|
"stats_collection.h",
|
||||||
"video_frame_matcher.cc",
|
"video_frame_matcher.cc",
|
||||||
|
@ -166,34 +166,6 @@ void Scenario::ChangeRoute(std::pair<CallClient*, CallClient*> clients,
|
|||||||
clients.first->transport_->Connect(over_nodes.front(), route_ip, overhead);
|
clients.first->transport_->Connect(over_nodes.front(), route_ip, overhead);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulatedTimeClient* Scenario::CreateSimulatedTimeClient(
|
|
||||||
std::string name,
|
|
||||||
SimulatedTimeClientConfig config,
|
|
||||||
std::vector<PacketStreamConfig> stream_configs,
|
|
||||||
std::vector<EmulatedNetworkNode*> send_link,
|
|
||||||
std::vector<EmulatedNetworkNode*> return_link) {
|
|
||||||
rtc::IPAddress send_ip(next_route_id_++);
|
|
||||||
rtc::IPAddress return_ip(next_route_id_++);
|
|
||||||
SimulatedTimeClient* client = new SimulatedTimeClient(
|
|
||||||
time_controller_.get(), GetLogWriterFactory(name), config, stream_configs,
|
|
||||||
send_link, return_link, send_ip, return_ip, Now());
|
|
||||||
if (log_writer_factory_ && !name.empty() &&
|
|
||||||
config.transport.state_log_interval.IsFinite()) {
|
|
||||||
Every(config.transport.state_log_interval, [this, client]() {
|
|
||||||
client->network_controller_factory_.LogCongestionControllerStats(Now());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (client->GetNetworkControllerProcessInterval().IsFinite()) {
|
|
||||||
Every(client->GetNetworkControllerProcessInterval(),
|
|
||||||
[this, client] { client->CongestionProcess(Now()); });
|
|
||||||
} else {
|
|
||||||
task_queue_.PostTask([this, client] { client->CongestionProcess(Now()); });
|
|
||||||
}
|
|
||||||
Every(TimeDelta::ms(5), [this, client] { client->PacerProcess(Now()); });
|
|
||||||
simulated_time_clients_.emplace_back(client);
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
EmulatedNetworkNode* Scenario::CreateSimulationNode(
|
EmulatedNetworkNode* Scenario::CreateSimulationNode(
|
||||||
std::function<void(NetworkSimulationConfig*)> config_modifier) {
|
std::function<void(NetworkSimulationConfig*)> config_modifier) {
|
||||||
NetworkSimulationConfig config;
|
NetworkSimulationConfig config;
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include "test/scenario/network/network_emulation_manager.h"
|
#include "test/scenario/network/network_emulation_manager.h"
|
||||||
#include "test/scenario/network_node.h"
|
#include "test/scenario/network_node.h"
|
||||||
#include "test/scenario/scenario_config.h"
|
#include "test/scenario/scenario_config.h"
|
||||||
#include "test/scenario/simulated_time.h"
|
|
||||||
#include "test/scenario/video_stream.h"
|
#include "test/scenario/video_stream.h"
|
||||||
#include "test/time_controller/time_controller.h"
|
#include "test/time_controller/time_controller.h"
|
||||||
|
|
||||||
@ -83,13 +82,6 @@ class Scenario {
|
|||||||
std::vector<EmulatedNetworkNode*> over_nodes,
|
std::vector<EmulatedNetworkNode*> over_nodes,
|
||||||
DataSize overhead);
|
DataSize overhead);
|
||||||
|
|
||||||
SimulatedTimeClient* CreateSimulatedTimeClient(
|
|
||||||
std::string name,
|
|
||||||
SimulatedTimeClientConfig config,
|
|
||||||
std::vector<PacketStreamConfig> stream_configs,
|
|
||||||
std::vector<EmulatedNetworkNode*> send_link,
|
|
||||||
std::vector<EmulatedNetworkNode*> return_link);
|
|
||||||
|
|
||||||
VideoStreamPair* CreateVideoStream(
|
VideoStreamPair* CreateVideoStream(
|
||||||
std::pair<CallClient*, CallClient*> clients,
|
std::pair<CallClient*, CallClient*> clients,
|
||||||
std::function<void(VideoStreamConfig*)> config_modifier);
|
std::function<void(VideoStreamConfig*)> config_modifier);
|
||||||
@ -171,7 +163,6 @@ class Scenario {
|
|||||||
std::vector<std::unique_ptr<CallClientPair>> client_pairs_;
|
std::vector<std::unique_ptr<CallClientPair>> client_pairs_;
|
||||||
std::vector<std::unique_ptr<VideoStreamPair>> video_streams_;
|
std::vector<std::unique_ptr<VideoStreamPair>> video_streams_;
|
||||||
std::vector<std::unique_ptr<AudioStreamPair>> audio_streams_;
|
std::vector<std::unique_ptr<AudioStreamPair>> audio_streams_;
|
||||||
std::vector<std::unique_ptr<SimulatedTimeClient>> simulated_time_clients_;
|
|
||||||
std::vector<std::unique_ptr<SimulationNode>> simulation_nodes_;
|
std::vector<std::unique_ptr<SimulationNode>> simulation_nodes_;
|
||||||
std::vector<std::unique_ptr<StatesPrinter>> printers_;
|
std::vector<std::unique_ptr<StatesPrinter>> printers_;
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ struct TransportControllerConfig {
|
|||||||
DataRate min_rate = DataRate::kbps(30);
|
DataRate min_rate = DataRate::kbps(30);
|
||||||
DataRate max_rate = DataRate::kbps(3000);
|
DataRate max_rate = DataRate::kbps(3000);
|
||||||
DataRate start_rate = DataRate::kbps(300);
|
DataRate start_rate = DataRate::kbps(300);
|
||||||
DataRate max_padding_rate = DataRate::Zero();
|
|
||||||
} rates;
|
} rates;
|
||||||
NetworkControllerFactoryInterface* cc_factory = nullptr;
|
NetworkControllerFactoryInterface* cc_factory = nullptr;
|
||||||
TimeDelta state_log_interval = TimeDelta::ms(100);
|
TimeDelta state_log_interval = TimeDelta::ms(100);
|
||||||
@ -57,13 +56,6 @@ struct CallClientConfig {
|
|||||||
TransportControllerConfig transport;
|
TransportControllerConfig transport;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SimulatedTimeClientConfig {
|
|
||||||
TransportControllerConfig transport;
|
|
||||||
struct Feedback {
|
|
||||||
TimeDelta interval = TimeDelta::ms(100);
|
|
||||||
} feedback;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PacketStreamConfig {
|
struct PacketStreamConfig {
|
||||||
PacketStreamConfig();
|
PacketStreamConfig();
|
||||||
PacketStreamConfig(const PacketStreamConfig&);
|
PacketStreamConfig(const PacketStreamConfig&);
|
||||||
|
@ -1,392 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "test/scenario/simulated_time.h"
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "absl/memory/memory.h"
|
|
||||||
#include "absl/types/optional.h"
|
|
||||||
#include "api/rtc_event_log/rtc_event_log_factory.h"
|
|
||||||
#include "rtc_base/checks.h"
|
|
||||||
#include "rtc_base/socket_address.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
namespace test {
|
|
||||||
namespace {
|
|
||||||
constexpr int kEventLogOutputIntervalMs = 5000;
|
|
||||||
struct RawFeedbackReportPacket {
|
|
||||||
static constexpr int MAX_FEEDBACKS = 10;
|
|
||||||
struct Feedback {
|
|
||||||
int16_t seq_offset;
|
|
||||||
int32_t recv_offset_ms;
|
|
||||||
};
|
|
||||||
uint8_t count;
|
|
||||||
int64_t first_seq_num;
|
|
||||||
int64_t first_recv_time_ms;
|
|
||||||
Feedback feedbacks[MAX_FEEDBACKS - 1];
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<RtcEventLog> CreateEventLog(
|
|
||||||
TaskQueueFactory* task_queue_factory,
|
|
||||||
LogWriterFactoryInterface* log_writer_factory) {
|
|
||||||
if (!log_writer_factory) {
|
|
||||||
return absl::make_unique<RtcEventLogNull>();
|
|
||||||
}
|
|
||||||
auto event_log = RtcEventLogFactory(task_queue_factory)
|
|
||||||
.CreateRtcEventLog(RtcEventLog::EncodingType::NewFormat);
|
|
||||||
bool success = event_log->StartLogging(log_writer_factory->Create(".rtc.dat"),
|
|
||||||
kEventLogOutputIntervalMs);
|
|
||||||
RTC_CHECK(success);
|
|
||||||
return event_log;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
PacketStream::PacketStream(PacketStreamConfig config) : config_(config) {}
|
|
||||||
|
|
||||||
std::vector<int64_t> PacketStream::PullPackets(Timestamp at_time) {
|
|
||||||
if (next_frame_time_.IsInfinite())
|
|
||||||
next_frame_time_ = at_time;
|
|
||||||
|
|
||||||
TimeDelta frame_interval = TimeDelta::seconds(1) / config_.frame_rate;
|
|
||||||
int64_t frame_allowance = (frame_interval * target_rate_).bytes();
|
|
||||||
|
|
||||||
if (next_frame_is_keyframe_) {
|
|
||||||
frame_allowance *= config_.keyframe_multiplier;
|
|
||||||
next_frame_is_keyframe_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int64_t> packets;
|
|
||||||
while (at_time >= next_frame_time_) {
|
|
||||||
next_frame_time_ += frame_interval;
|
|
||||||
|
|
||||||
int64_t frame_size = budget_ + frame_allowance;
|
|
||||||
frame_size = std::max(frame_size, config_.min_frame_size.bytes());
|
|
||||||
budget_ += frame_allowance - frame_size;
|
|
||||||
|
|
||||||
int64_t packet_budget = frame_size;
|
|
||||||
int64_t max_packet_size = config_.max_packet_size.bytes();
|
|
||||||
while (packet_budget > max_packet_size) {
|
|
||||||
packets.push_back(max_packet_size);
|
|
||||||
packet_budget -= max_packet_size;
|
|
||||||
}
|
|
||||||
packets.push_back(packet_budget);
|
|
||||||
}
|
|
||||||
for (int64_t& packet : packets)
|
|
||||||
packet += config_.packet_overhead.bytes();
|
|
||||||
return packets;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PacketStream::OnTargetRateUpdate(DataRate target_rate) {
|
|
||||||
target_rate_ = std::min(target_rate, config_.max_data_rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleFeedbackReportPacket FeedbackFromBuffer(
|
|
||||||
rtc::CopyOnWriteBuffer raw_buffer) {
|
|
||||||
RTC_CHECK_LE(sizeof(RawFeedbackReportPacket), raw_buffer.size());
|
|
||||||
const RawFeedbackReportPacket& raw_packet =
|
|
||||||
*reinterpret_cast<const RawFeedbackReportPacket*>(raw_buffer.cdata());
|
|
||||||
RTC_CHECK_GE(raw_packet.count, 1);
|
|
||||||
SimpleFeedbackReportPacket packet;
|
|
||||||
packet.receive_times.emplace_back(SimpleFeedbackReportPacket::ReceiveInfo{
|
|
||||||
raw_packet.first_seq_num, Timestamp::ms(raw_packet.first_recv_time_ms)});
|
|
||||||
for (int i = 1; i < raw_packet.count; ++i)
|
|
||||||
packet.receive_times.emplace_back(SimpleFeedbackReportPacket::ReceiveInfo{
|
|
||||||
raw_packet.first_seq_num + raw_packet.feedbacks[i - 1].seq_offset,
|
|
||||||
Timestamp::ms(raw_packet.first_recv_time_ms +
|
|
||||||
raw_packet.feedbacks[i - 1].recv_offset_ms)});
|
|
||||||
return packet;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtc::CopyOnWriteBuffer FeedbackToBuffer(
|
|
||||||
const SimpleFeedbackReportPacket packet) {
|
|
||||||
RTC_CHECK_LE(packet.receive_times.size(),
|
|
||||||
RawFeedbackReportPacket::MAX_FEEDBACKS);
|
|
||||||
RawFeedbackReportPacket report;
|
|
||||||
report.count = packet.receive_times.size();
|
|
||||||
RTC_CHECK(!packet.receive_times.empty());
|
|
||||||
report.first_seq_num = packet.receive_times.front().sequence_number;
|
|
||||||
report.first_recv_time_ms = packet.receive_times.front().receive_time.ms();
|
|
||||||
|
|
||||||
for (int i = 1; i < report.count; ++i) {
|
|
||||||
report.feedbacks[i - 1].seq_offset = static_cast<int16_t>(
|
|
||||||
packet.receive_times[i].sequence_number - report.first_seq_num);
|
|
||||||
report.feedbacks[i - 1].recv_offset_ms = static_cast<int32_t>(
|
|
||||||
packet.receive_times[i].receive_time.ms() - report.first_recv_time_ms);
|
|
||||||
}
|
|
||||||
return rtc::CopyOnWriteBuffer(reinterpret_cast<uint8_t*>(&report),
|
|
||||||
sizeof(RawFeedbackReportPacket));
|
|
||||||
}
|
|
||||||
|
|
||||||
SimulatedSender::SimulatedSender(EmulatedNetworkNode* send_node,
|
|
||||||
rtc::IPAddress send_receiver_ip)
|
|
||||||
: send_node_(send_node), send_receiver_address_(send_receiver_ip, 0) {}
|
|
||||||
|
|
||||||
SimulatedSender::~SimulatedSender() {}
|
|
||||||
|
|
||||||
TransportPacketsFeedback SimulatedSender::PullFeedbackReport(
|
|
||||||
SimpleFeedbackReportPacket packet,
|
|
||||||
Timestamp at_time) {
|
|
||||||
TransportPacketsFeedback report;
|
|
||||||
report.prior_in_flight = data_in_flight_;
|
|
||||||
report.feedback_time = at_time;
|
|
||||||
|
|
||||||
for (auto& receive_info : packet.receive_times) {
|
|
||||||
// Look up sender side information for all packets up to and including each
|
|
||||||
// packet with feedback in the report.
|
|
||||||
for (; next_feedback_seq_num_ <= receive_info.sequence_number;
|
|
||||||
++next_feedback_seq_num_) {
|
|
||||||
PacketResult feedback;
|
|
||||||
if (next_feedback_seq_num_ == receive_info.sequence_number) {
|
|
||||||
feedback.receive_time = receive_info.receive_time;
|
|
||||||
} else {
|
|
||||||
// If we did not get any feedback for this packet, mark it as lost by
|
|
||||||
// setting receive time to infinity. Note that this can also happen due
|
|
||||||
// to reordering, we will newer send feedback out of order. In this case
|
|
||||||
// the packet was not really lost, but we don't have that information.
|
|
||||||
feedback.receive_time = Timestamp::PlusInfinity();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Looking up send side information.
|
|
||||||
for (auto it = sent_packets_.begin(); it != sent_packets_.end(); ++it) {
|
|
||||||
if (it->sequence_number == next_feedback_seq_num_) {
|
|
||||||
feedback.sent_packet = *it;
|
|
||||||
if (feedback.receive_time.IsFinite())
|
|
||||||
sent_packets_.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data_in_flight_ -= feedback.sent_packet.size;
|
|
||||||
report.packet_feedbacks.push_back(feedback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
report.data_in_flight = data_in_flight_;
|
|
||||||
return report;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Applies pacing and congetsion window based on the configuration from the
|
|
||||||
// congestion controller. This is not a complete implementation of the real
|
|
||||||
// pacer but useful for unit tests since it isn't limited to real time.
|
|
||||||
std::vector<SimulatedSender::PacketReadyToSend>
|
|
||||||
SimulatedSender::PaceAndPullSendPackets(Timestamp at_time) {
|
|
||||||
// TODO(srte): Extract the behavior of PacedSender to a threading and time
|
|
||||||
// independent component and use that here to allow a truthful simulation.
|
|
||||||
if (last_update_.IsInfinite()) {
|
|
||||||
pacing_budget_ = 0;
|
|
||||||
} else {
|
|
||||||
TimeDelta delta = at_time - last_update_;
|
|
||||||
pacing_budget_ += (delta * pacer_config_.data_rate()).bytes();
|
|
||||||
}
|
|
||||||
std::vector<PacketReadyToSend> to_send;
|
|
||||||
while (data_in_flight_ <= max_in_flight_ && pacing_budget_ >= 0 &&
|
|
||||||
!packet_queue_.empty()) {
|
|
||||||
PendingPacket pending = packet_queue_.front();
|
|
||||||
pacing_budget_ -= pending.size;
|
|
||||||
packet_queue_.pop_front();
|
|
||||||
SentPacket sent;
|
|
||||||
sent.sequence_number = next_sequence_number_++;
|
|
||||||
sent.size = DataSize::bytes(pending.size);
|
|
||||||
data_in_flight_ += sent.size;
|
|
||||||
sent.data_in_flight = data_in_flight_;
|
|
||||||
sent.pacing_info = PacedPacketInfo();
|
|
||||||
sent.send_time = at_time;
|
|
||||||
sent_packets_.push_back(sent);
|
|
||||||
rtc::CopyOnWriteBuffer packet(
|
|
||||||
std::max<size_t>(pending.size, sizeof(sent.sequence_number)));
|
|
||||||
memcpy(packet.data(), &sent.sequence_number, sizeof(sent.sequence_number));
|
|
||||||
to_send.emplace_back(PacketReadyToSend{sent, packet});
|
|
||||||
}
|
|
||||||
pacing_budget_ = std::min<int64_t>(pacing_budget_, 0);
|
|
||||||
last_update_ = at_time;
|
|
||||||
return to_send;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedSender::Update(NetworkControlUpdate update) {
|
|
||||||
if (update.pacer_config)
|
|
||||||
pacer_config_ = *update.pacer_config;
|
|
||||||
if (update.congestion_window)
|
|
||||||
max_in_flight_ = *update.congestion_window;
|
|
||||||
}
|
|
||||||
|
|
||||||
SimulatedFeedback::SimulatedFeedback(SimulatedTimeClientConfig config,
|
|
||||||
rtc::IPAddress return_receiver_ip,
|
|
||||||
EmulatedNetworkNode* return_node)
|
|
||||||
: config_(config),
|
|
||||||
return_receiver_address_(return_receiver_ip, 0),
|
|
||||||
return_node_(return_node) {}
|
|
||||||
|
|
||||||
// Polls receiver side for a feedback report and sends it to the stream sender
|
|
||||||
// via return_node_,
|
|
||||||
void SimulatedFeedback::OnPacketReceived(EmulatedIpPacket packet) {
|
|
||||||
int64_t sequence_number;
|
|
||||||
memcpy(&sequence_number, packet.cdata(), sizeof(sequence_number));
|
|
||||||
receive_times_.insert({sequence_number, packet.arrival_time});
|
|
||||||
if (last_feedback_time_.IsInfinite())
|
|
||||||
last_feedback_time_ = packet.arrival_time;
|
|
||||||
if (packet.arrival_time >= last_feedback_time_ + config_.feedback.interval) {
|
|
||||||
SimpleFeedbackReportPacket report;
|
|
||||||
for (; next_feedback_seq_num_ <= sequence_number;
|
|
||||||
++next_feedback_seq_num_) {
|
|
||||||
auto it = receive_times_.find(next_feedback_seq_num_);
|
|
||||||
if (it != receive_times_.end()) {
|
|
||||||
report.receive_times.emplace_back(
|
|
||||||
SimpleFeedbackReportPacket::ReceiveInfo{next_feedback_seq_num_,
|
|
||||||
it->second});
|
|
||||||
receive_times_.erase(it);
|
|
||||||
}
|
|
||||||
if (report.receive_times.size() >=
|
|
||||||
RawFeedbackReportPacket::MAX_FEEDBACKS) {
|
|
||||||
return_node_->OnPacketReceived(
|
|
||||||
EmulatedIpPacket(packet.to, return_receiver_address_,
|
|
||||||
FeedbackToBuffer(report), packet.arrival_time));
|
|
||||||
report = SimpleFeedbackReportPacket();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!report.receive_times.empty())
|
|
||||||
return_node_->OnPacketReceived(
|
|
||||||
EmulatedIpPacket(packet.to, return_receiver_address_,
|
|
||||||
FeedbackToBuffer(report), packet.arrival_time));
|
|
||||||
last_feedback_time_ = packet.arrival_time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SimulatedTimeClient::SimulatedTimeClient(
|
|
||||||
TimeController* time_controller,
|
|
||||||
std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
|
|
||||||
SimulatedTimeClientConfig config,
|
|
||||||
std::vector<PacketStreamConfig> stream_configs,
|
|
||||||
std::vector<EmulatedNetworkNode*> send_link,
|
|
||||||
std::vector<EmulatedNetworkNode*> return_link,
|
|
||||||
rtc::IPAddress send_receiver_ip,
|
|
||||||
rtc::IPAddress return_receiver_ip,
|
|
||||||
Timestamp at_time)
|
|
||||||
: log_writer_factory_(std::move(log_writer_factory)),
|
|
||||||
event_log_(CreateEventLog(time_controller->GetTaskQueueFactory(),
|
|
||||||
log_writer_factory_.get())),
|
|
||||||
network_controller_factory_(log_writer_factory_.get(), config.transport),
|
|
||||||
send_link_(send_link),
|
|
||||||
return_link_(return_link),
|
|
||||||
sender_(send_link.front(), send_receiver_ip),
|
|
||||||
feedback_(config, return_receiver_ip, return_link.front()) {
|
|
||||||
current_contraints_.at_time = at_time;
|
|
||||||
current_contraints_.starting_rate = config.transport.rates.start_rate;
|
|
||||||
current_contraints_.min_data_rate = config.transport.rates.min_rate;
|
|
||||||
current_contraints_.max_data_rate = config.transport.rates.max_rate;
|
|
||||||
NetworkControllerConfig initial_config;
|
|
||||||
initial_config.constraints = current_contraints_;
|
|
||||||
initial_config.stream_based_config.max_padding_rate =
|
|
||||||
config.transport.rates.max_padding_rate;
|
|
||||||
initial_config.event_log = event_log_.get();
|
|
||||||
congestion_controller_ = network_controller_factory_.Create(initial_config);
|
|
||||||
for (auto& stream_config : stream_configs)
|
|
||||||
packet_streams_.emplace_back(new PacketStream(stream_config));
|
|
||||||
EmulatedNetworkNode::CreateRoute(send_receiver_ip, send_link, &feedback_);
|
|
||||||
EmulatedNetworkNode::CreateRoute(return_receiver_ip, return_link, this);
|
|
||||||
|
|
||||||
CongestionProcess(at_time);
|
|
||||||
network_controller_factory_.LogCongestionControllerStats(at_time);
|
|
||||||
if (log_writer_factory_) {
|
|
||||||
packet_log_ = log_writer_factory_->Create(".packets.txt");
|
|
||||||
packet_log_->Write(
|
|
||||||
"transport_seq packet_size send_time recv_time feed_time\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pulls feedback reports from sender side based on the recieved feedback
|
|
||||||
// packet. Updates congestion controller with the resulting report.
|
|
||||||
void SimulatedTimeClient::OnPacketReceived(EmulatedIpPacket packet) {
|
|
||||||
auto report = sender_.PullFeedbackReport(FeedbackFromBuffer(packet.data),
|
|
||||||
packet.arrival_time);
|
|
||||||
for (PacketResult& feedback : report.packet_feedbacks) {
|
|
||||||
if (packet_log_)
|
|
||||||
LogWriteFormat(packet_log_.get(),
|
|
||||||
"%" PRId64 " %" PRId64 " %.3lf %.3lf %.3lf\n",
|
|
||||||
feedback.sent_packet.sequence_number,
|
|
||||||
feedback.sent_packet.size.bytes(),
|
|
||||||
feedback.sent_packet.send_time.seconds<double>(),
|
|
||||||
feedback.receive_time.seconds<double>(),
|
|
||||||
packet.arrival_time.seconds<double>());
|
|
||||||
}
|
|
||||||
Update(congestion_controller_->OnTransportPacketsFeedback(report));
|
|
||||||
}
|
|
||||||
SimulatedTimeClient::~SimulatedTimeClient() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedTimeClient::Update(NetworkControlUpdate update) {
|
|
||||||
sender_.Update(update);
|
|
||||||
if (update.target_rate) {
|
|
||||||
// TODO(srte): Implement more realistic distribution of bandwidths between
|
|
||||||
// streams. Either using BitrateAllocationStrategy directly or using
|
|
||||||
// BitrateAllocation.
|
|
||||||
double ratio_per_stream = 1.0 / packet_streams_.size();
|
|
||||||
DataRate rate_per_stream =
|
|
||||||
update.target_rate->target_rate * ratio_per_stream;
|
|
||||||
target_rate_ = update.target_rate->target_rate;
|
|
||||||
link_capacity_ = update.target_rate->network_estimate.bandwidth;
|
|
||||||
for (auto& stream : packet_streams_)
|
|
||||||
stream->OnTargetRateUpdate(rate_per_stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedTimeClient::CongestionProcess(Timestamp at_time) {
|
|
||||||
ProcessInterval msg;
|
|
||||||
msg.at_time = at_time;
|
|
||||||
Update(congestion_controller_->OnProcessInterval(msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedTimeClient::PacerProcess(Timestamp at_time) {
|
|
||||||
ProcessFrames(at_time);
|
|
||||||
for (const auto& to_send : sender_.PaceAndPullSendPackets(at_time)) {
|
|
||||||
sender_.send_node_->OnPacketReceived(EmulatedIpPacket(
|
|
||||||
/*from=*/rtc::SocketAddress(), sender_.send_receiver_address_,
|
|
||||||
to_send.data, at_time));
|
|
||||||
Update(congestion_controller_->OnSentPacket(to_send.send_info));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedTimeClient::ProcessFrames(Timestamp at_time) {
|
|
||||||
for (auto& stream : packet_streams_) {
|
|
||||||
for (int64_t packet_size : stream->PullPackets(at_time)) {
|
|
||||||
sender_.packet_queue_.push_back(
|
|
||||||
SimulatedSender::PendingPacket{packet_size});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedTimeClient::TriggerFakeReroute(Timestamp at_time) {
|
|
||||||
NetworkRouteChange msg;
|
|
||||||
msg.at_time = at_time;
|
|
||||||
msg.constraints = current_contraints_;
|
|
||||||
msg.constraints.at_time = at_time;
|
|
||||||
Update(congestion_controller_->OnNetworkRouteChange(msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeDelta SimulatedTimeClient::GetNetworkControllerProcessInterval() const {
|
|
||||||
return network_controller_factory_.GetProcessInterval();
|
|
||||||
}
|
|
||||||
|
|
||||||
DataRate SimulatedTimeClient::link_capacity() const {
|
|
||||||
return link_capacity_;
|
|
||||||
}
|
|
||||||
|
|
||||||
double SimulatedTimeClient::target_rate_kbps() const {
|
|
||||||
return target_rate_.kbps<double>();
|
|
||||||
}
|
|
||||||
|
|
||||||
DataRate SimulatedTimeClient::padding_rate() const {
|
|
||||||
return sender_.pacer_config_.pad_rate();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace test
|
|
||||||
} // namespace webrtc
|
|
@ -1,168 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 TEST_SCENARIO_SIMULATED_TIME_H_
|
|
||||||
#define TEST_SCENARIO_SIMULATED_TIME_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <deque>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "api/transport/network_control.h"
|
|
||||||
#include "api/transport/network_types.h"
|
|
||||||
#include "api/units/data_rate.h"
|
|
||||||
#include "api/units/data_size.h"
|
|
||||||
#include "api/units/time_delta.h"
|
|
||||||
#include "api/units/timestamp.h"
|
|
||||||
#include "rtc_base/copy_on_write_buffer.h"
|
|
||||||
#include "test/logging/log_writer.h"
|
|
||||||
#include "test/scenario/call_client.h"
|
|
||||||
#include "test/scenario/network_node.h"
|
|
||||||
#include "test/scenario/scenario_config.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
namespace test {
|
|
||||||
class PacketStream {
|
|
||||||
public:
|
|
||||||
explicit PacketStream(PacketStreamConfig config);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<int64_t> PullPackets(Timestamp at_time);
|
|
||||||
void OnTargetRateUpdate(DataRate target_rate);
|
|
||||||
|
|
||||||
friend class SimulatedTimeClient;
|
|
||||||
PacketStreamConfig config_;
|
|
||||||
bool next_frame_is_keyframe_ = true;
|
|
||||||
Timestamp next_frame_time_ = Timestamp::MinusInfinity();
|
|
||||||
DataRate target_rate_ = DataRate::Zero();
|
|
||||||
int64_t budget_ = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SimulatedFeedback : EmulatedNetworkReceiverInterface {
|
|
||||||
public:
|
|
||||||
SimulatedFeedback(SimulatedTimeClientConfig config,
|
|
||||||
rtc::IPAddress return_receiver_ip,
|
|
||||||
EmulatedNetworkNode* return_node);
|
|
||||||
|
|
||||||
void OnPacketReceived(EmulatedIpPacket packet) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class SimulatedTimeClient;
|
|
||||||
const SimulatedTimeClientConfig config_;
|
|
||||||
const rtc::SocketAddress return_receiver_address_;
|
|
||||||
EmulatedNetworkNode* return_node_;
|
|
||||||
Timestamp last_feedback_time_ = Timestamp::MinusInfinity();
|
|
||||||
int32_t next_feedback_seq_num_ = 1;
|
|
||||||
std::map<int64_t, Timestamp> receive_times_;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SimpleFeedbackReportPacket {
|
|
||||||
struct ReceiveInfo {
|
|
||||||
int64_t sequence_number;
|
|
||||||
Timestamp receive_time;
|
|
||||||
};
|
|
||||||
std::vector<ReceiveInfo> receive_times;
|
|
||||||
};
|
|
||||||
|
|
||||||
SimpleFeedbackReportPacket FeedbackFromBuffer(
|
|
||||||
rtc::CopyOnWriteBuffer raw_buffer);
|
|
||||||
rtc::CopyOnWriteBuffer FeedbackToBuffer(
|
|
||||||
const SimpleFeedbackReportPacket packet);
|
|
||||||
|
|
||||||
class SimulatedSender {
|
|
||||||
public:
|
|
||||||
struct PacketReadyToSend {
|
|
||||||
SentPacket send_info;
|
|
||||||
rtc::CopyOnWriteBuffer data;
|
|
||||||
};
|
|
||||||
struct PendingPacket {
|
|
||||||
int64_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
SimulatedSender(EmulatedNetworkNode* send_node,
|
|
||||||
rtc::IPAddress send_receiver_ip);
|
|
||||||
SimulatedSender(const SimulatedSender&) = delete;
|
|
||||||
~SimulatedSender();
|
|
||||||
TransportPacketsFeedback PullFeedbackReport(SimpleFeedbackReportPacket report,
|
|
||||||
Timestamp at_time);
|
|
||||||
std::vector<PacketReadyToSend> PaceAndPullSendPackets(Timestamp at_time);
|
|
||||||
void Update(NetworkControlUpdate update);
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class SimulatedTimeClient;
|
|
||||||
EmulatedNetworkNode* send_node_;
|
|
||||||
const rtc::SocketAddress send_receiver_address_;
|
|
||||||
PacerConfig pacer_config_;
|
|
||||||
DataSize max_in_flight_ = DataSize::Infinity();
|
|
||||||
|
|
||||||
std::deque<PendingPacket> packet_queue_;
|
|
||||||
std::vector<SentPacket> sent_packets_;
|
|
||||||
|
|
||||||
Timestamp last_update_ = Timestamp::MinusInfinity();
|
|
||||||
int64_t pacing_budget_ = 0;
|
|
||||||
int64_t next_sequence_number_ = 1;
|
|
||||||
int64_t next_feedback_seq_num_ = 1;
|
|
||||||
DataSize data_in_flight_ = DataSize::Zero();
|
|
||||||
};
|
|
||||||
|
|
||||||
// SimulatedTimeClient emulates core parts of the behavior of WebRTC from the
|
|
||||||
// perspective of congestion controllers. This is intended for use in functional
|
|
||||||
// unit tests to ensure that congestion controllers behave in a reasonable way.
|
|
||||||
// It does not, however, completely simulate the actual behavior of WebRTC. For
|
|
||||||
// a more accurate simulation, use the real time only CallClient.
|
|
||||||
class SimulatedTimeClient : EmulatedNetworkReceiverInterface {
|
|
||||||
public:
|
|
||||||
SimulatedTimeClient(
|
|
||||||
TimeController* time_controller,
|
|
||||||
std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
|
|
||||||
SimulatedTimeClientConfig config,
|
|
||||||
std::vector<PacketStreamConfig> stream_configs,
|
|
||||||
std::vector<EmulatedNetworkNode*> send_link,
|
|
||||||
std::vector<EmulatedNetworkNode*> return_link,
|
|
||||||
rtc::IPAddress send_receiver_ip,
|
|
||||||
rtc::IPAddress return_receiver_ip,
|
|
||||||
Timestamp at_time);
|
|
||||||
SimulatedTimeClient(const SimulatedTimeClient&) = delete;
|
|
||||||
~SimulatedTimeClient();
|
|
||||||
void Update(NetworkControlUpdate update);
|
|
||||||
void CongestionProcess(Timestamp at_time);
|
|
||||||
void PacerProcess(Timestamp at_time);
|
|
||||||
void ProcessFrames(Timestamp at_time);
|
|
||||||
void TriggerFakeReroute(Timestamp at_time);
|
|
||||||
TimeDelta GetNetworkControllerProcessInterval() const;
|
|
||||||
double target_rate_kbps() const;
|
|
||||||
DataRate link_capacity() const;
|
|
||||||
DataRate padding_rate() const;
|
|
||||||
|
|
||||||
void OnPacketReceived(EmulatedIpPacket packet) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class Scenario;
|
|
||||||
std::unique_ptr<LogWriterFactoryInterface> log_writer_factory_;
|
|
||||||
std::unique_ptr<RtcEventLog> event_log_;
|
|
||||||
LoggingNetworkControllerFactory network_controller_factory_;
|
|
||||||
std::unique_ptr<NetworkControllerInterface> congestion_controller_;
|
|
||||||
std::vector<EmulatedNetworkNode*> send_link_;
|
|
||||||
std::vector<EmulatedNetworkNode*> return_link_;
|
|
||||||
SimulatedSender sender_;
|
|
||||||
SimulatedFeedback feedback_;
|
|
||||||
TargetRateConstraints current_contraints_;
|
|
||||||
DataRate target_rate_ = DataRate::Infinity();
|
|
||||||
DataRate link_capacity_ = DataRate::Infinity();
|
|
||||||
std::unique_ptr<RtcEventLogOutput> packet_log_;
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<PacketStream>> packet_streams_;
|
|
||||||
};
|
|
||||||
} // namespace test
|
|
||||||
} // namespace webrtc
|
|
||||||
|
|
||||||
#endif // TEST_SCENARIO_SIMULATED_TIME_H_
|
|
Reference in New Issue
Block a user