Add SchedulableNetworkBehavior and tests.
This is a network behaviour that can change its parameters over time as specified with a schedule proto. Bug: webrtc:14525 Change-Id: Idd34cc48c8e3e8311975615f2c3dc3ffb522a708 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/352140 Reviewed-by: Björn Terelius <terelius@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Commit-Queue: Per Kjellander <perkj@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42390}
This commit is contained in:
parent
ab4a67055c
commit
06815534d2
5
BUILD.gn
5
BUILD.gn
@ -678,7 +678,10 @@ if (rtc_include_tests && !build_with_chromium) {
|
|||||||
data = rtc_unittests_resources
|
data = rtc_unittests_resources
|
||||||
|
|
||||||
if (rtc_enable_protobuf) {
|
if (rtc_enable_protobuf) {
|
||||||
deps += [ "logging:rtc_event_log_tests" ]
|
deps += [
|
||||||
|
"api/test/network_emulation:network_config_schedule_proto",
|
||||||
|
"logging:rtc_event_log_tests",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_ios) {
|
if (is_ios) {
|
||||||
|
|||||||
@ -6,8 +6,30 @@
|
|||||||
# in the file PATENTS. All contributing project authors may
|
# in the file PATENTS. All contributing project authors may
|
||||||
# be found in the AUTHORS file in the root of the source tree.
|
# be found in the AUTHORS file in the root of the source tree.
|
||||||
|
|
||||||
|
import("//third_party/protobuf/proto_library.gni")
|
||||||
import("../../../webrtc.gni")
|
import("../../../webrtc.gni")
|
||||||
|
|
||||||
|
if (rtc_enable_protobuf) {
|
||||||
|
proto_library("network_config_schedule_proto") {
|
||||||
|
visibility = [ "*" ]
|
||||||
|
sources = [ "network_config_schedule.proto" ]
|
||||||
|
proto_out_dir = "api/test/network_emulation/"
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc_source_set("schedulable_network_node_builder") {
|
||||||
|
visibility = [ "*" ]
|
||||||
|
sources = [
|
||||||
|
"schedulable_network_node_builder.cc",
|
||||||
|
"schedulable_network_node_builder.h",
|
||||||
|
]
|
||||||
|
deps = [
|
||||||
|
":network_config_schedule_proto",
|
||||||
|
"../..:network_emulation_manager_api",
|
||||||
|
"../../../test/network:schedulable_network_behavior",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rtc_library("network_emulation") {
|
rtc_library("network_emulation") {
|
||||||
visibility = [ "*" ]
|
visibility = [ "*" ]
|
||||||
|
|
||||||
|
|||||||
27
api/test/network_emulation/network_config_schedule.proto
Normal file
27
api/test/network_emulation/network_config_schedule.proto
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
option optimize_for = LITE_RUNTIME;
|
||||||
|
package webrtc.network_behaviour;
|
||||||
|
|
||||||
|
message NetworkConfigScheduleItem {
|
||||||
|
// Time since the first sent packet when this item should be applied.
|
||||||
|
// This should typically be 0 for the first item in the schedule.
|
||||||
|
optional int64 time_since_first_sent_packet_ms = 1;
|
||||||
|
|
||||||
|
// Network parameters, See webrtc::BuiltInNetworkBehaviorConfig.
|
||||||
|
optional int64 queue_length_packets = 2;
|
||||||
|
optional int64 queue_delay_ms = 3;
|
||||||
|
optional int64 link_capacity_kbps = 4;
|
||||||
|
optional int64 loss_percent = 5;
|
||||||
|
optional int64 delay_standard_deviation_ms = 6;
|
||||||
|
optional bool allow_reordering = 7;
|
||||||
|
optional int64 avg_burst_loss_length = 8;
|
||||||
|
optional int64 packet_overhead = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule describing network parameters in a simulated network.
|
||||||
|
message NetworkConfigSchedule {
|
||||||
|
optional int64 repeat_schedule_after_last_ms = 1;
|
||||||
|
// Items should be sorted by time_since_first_sent_packet_ms.
|
||||||
|
repeated NetworkConfigScheduleItem item = 2;
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
#include "api/test/network_emulation/schedulable_network_node_builder.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "api/test/network_emulation/network_config_schedule.pb.h"
|
||||||
|
#include "api/test/network_emulation_manager.h"
|
||||||
|
#include "test/network/schedulable_network_behavior.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
SchedulableNetworkNodeBuilder::SchedulableNetworkNodeBuilder(
|
||||||
|
webrtc::NetworkEmulationManager& net,
|
||||||
|
network_behaviour::NetworkConfigSchedule schedule)
|
||||||
|
: net_(net), schedule_(std::move(schedule)) {}
|
||||||
|
|
||||||
|
webrtc::EmulatedNetworkNode* SchedulableNetworkNodeBuilder::Build() {
|
||||||
|
return net_.CreateEmulatedNode(std::make_unique<SchedulableNetworkBehavior>(
|
||||||
|
std::move(schedule_), *net_.time_controller()->GetClock()));
|
||||||
|
}
|
||||||
|
} // namespace webrtc
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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 API_TEST_NETWORK_EMULATION_SCHEDULABLE_NETWORK_NODE_BUILDER_H_
|
||||||
|
#define API_TEST_NETWORK_EMULATION_SCHEDULABLE_NETWORK_NODE_BUILDER_H_
|
||||||
|
|
||||||
|
#include "api/test/network_emulation/network_config_schedule.pb.h"
|
||||||
|
#include "api/test/network_emulation_manager.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
class SchedulableNetworkNodeBuilder {
|
||||||
|
public:
|
||||||
|
SchedulableNetworkNodeBuilder(
|
||||||
|
webrtc::NetworkEmulationManager& net,
|
||||||
|
network_behaviour::NetworkConfigSchedule schedule);
|
||||||
|
|
||||||
|
webrtc::EmulatedNetworkNode* Build();
|
||||||
|
|
||||||
|
private:
|
||||||
|
webrtc::NetworkEmulationManager& net_;
|
||||||
|
network_behaviour::NetworkConfigSchedule schedule_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
#endif // API_TEST_NETWORK_EMULATION_SCHEDULABLE_NETWORK_NODE_BUILDER_H_
|
||||||
@ -199,6 +199,9 @@ if (rtc_include_tests) {
|
|||||||
":network_emulation_unittest",
|
":network_emulation_unittest",
|
||||||
":simulated_network_unittest",
|
":simulated_network_unittest",
|
||||||
]
|
]
|
||||||
|
if (rtc_enable_protobuf) {
|
||||||
|
deps += [ ":schedulable_network_behavior_test" ]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,3 +244,49 @@ if (rtc_include_tests) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rtc_enable_protobuf) {
|
||||||
|
rtc_library("schedulable_network_behavior") {
|
||||||
|
sources = [
|
||||||
|
"schedulable_network_behavior.cc",
|
||||||
|
"schedulable_network_behavior.h",
|
||||||
|
]
|
||||||
|
deps = [
|
||||||
|
":simulated_network",
|
||||||
|
"../../api:network_emulation_manager_api",
|
||||||
|
"../../api:sequence_checker",
|
||||||
|
"../../api:simulated_network_api",
|
||||||
|
"../../api/task_queue:task_queue",
|
||||||
|
"../../api/test/network_emulation:network_config_schedule_proto",
|
||||||
|
"../../api/units:data_rate",
|
||||||
|
"../../api/units:time_delta",
|
||||||
|
"../../api/units:timestamp",
|
||||||
|
"../../api/units:timestamp",
|
||||||
|
"../../rtc_base:macromagic",
|
||||||
|
"../../rtc_base/task_utils:repeating_task",
|
||||||
|
"../../system_wrappers",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtc_include_tests) {
|
||||||
|
rtc_library("schedulable_network_behavior_test") {
|
||||||
|
testonly = true
|
||||||
|
sources = [ "schedulable_network_behavior_test.cc" ]
|
||||||
|
deps = [
|
||||||
|
":schedulable_network_behavior",
|
||||||
|
"../:test_support",
|
||||||
|
"../../api:create_network_emulation_manager",
|
||||||
|
"../../api:network_emulation_manager_api",
|
||||||
|
"../../api:simulated_network_api",
|
||||||
|
"../../api/test/network_emulation:network_config_schedule_proto",
|
||||||
|
"../../api/units:data_rate",
|
||||||
|
"../../api/units:data_size",
|
||||||
|
"../../api/units:time_delta",
|
||||||
|
"../../api/units:timestamp",
|
||||||
|
"../../system_wrappers",
|
||||||
|
"//testing/gtest",
|
||||||
|
"//third_party/abseil-cpp/absl/algorithm:container",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
138
test/network/schedulable_network_behavior.cc
Normal file
138
test/network/schedulable_network_behavior.cc
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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/network/schedulable_network_behavior.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "api/sequence_checker.h"
|
||||||
|
#include "api/task_queue/task_queue_base.h"
|
||||||
|
#include "api/test/network_emulation/network_config_schedule.pb.h"
|
||||||
|
#include "api/test/simulated_network.h"
|
||||||
|
#include "api/units/data_rate.h"
|
||||||
|
#include "api/units/time_delta.h"
|
||||||
|
#include "api/units/timestamp.h"
|
||||||
|
#include "rtc_base/task_utils/repeating_task.h"
|
||||||
|
#include "system_wrappers/include/clock.h"
|
||||||
|
#include "test/network/simulated_network.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ::webrtc::BuiltInNetworkBehaviorConfig;
|
||||||
|
|
||||||
|
void UpdateConfigFromSchedule(
|
||||||
|
const network_behaviour::NetworkConfigScheduleItem& schedule_item,
|
||||||
|
BuiltInNetworkBehaviorConfig& config) {
|
||||||
|
if (schedule_item.has_queue_length_packets()) {
|
||||||
|
config.queue_length_packets = schedule_item.queue_length_packets();
|
||||||
|
}
|
||||||
|
if (schedule_item.has_queue_delay_ms()) {
|
||||||
|
config.queue_delay_ms = schedule_item.queue_delay_ms();
|
||||||
|
}
|
||||||
|
if (schedule_item.has_link_capacity_kbps()) {
|
||||||
|
config.link_capacity =
|
||||||
|
DataRate::KilobitsPerSec(schedule_item.link_capacity_kbps());
|
||||||
|
}
|
||||||
|
if (schedule_item.has_loss_percent()) {
|
||||||
|
config.loss_percent = schedule_item.loss_percent();
|
||||||
|
}
|
||||||
|
if (schedule_item.has_delay_standard_deviation_ms()) {
|
||||||
|
config.delay_standard_deviation_ms =
|
||||||
|
schedule_item.delay_standard_deviation_ms();
|
||||||
|
}
|
||||||
|
if (schedule_item.has_allow_reordering()) {
|
||||||
|
config.allow_reordering = schedule_item.allow_reordering();
|
||||||
|
}
|
||||||
|
if (schedule_item.has_avg_burst_loss_length()) {
|
||||||
|
config.avg_burst_loss_length = schedule_item.avg_burst_loss_length();
|
||||||
|
}
|
||||||
|
if (schedule_item.has_packet_overhead()) {
|
||||||
|
config.packet_overhead = schedule_item.packet_overhead();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BuiltInNetworkBehaviorConfig GetInitialConfig(
|
||||||
|
const network_behaviour::NetworkConfigSchedule& schedule) {
|
||||||
|
BuiltInNetworkBehaviorConfig config;
|
||||||
|
if (!schedule.item().empty()) {
|
||||||
|
UpdateConfigFromSchedule(schedule.item(0), config);
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
SchedulableNetworkBehavior::SchedulableNetworkBehavior(
|
||||||
|
network_behaviour::NetworkConfigSchedule schedule,
|
||||||
|
webrtc::Clock& clock)
|
||||||
|
: SimulatedNetwork(GetInitialConfig(schedule)),
|
||||||
|
schedule_(std::move(schedule)),
|
||||||
|
clock_(clock),
|
||||||
|
config_(GetInitialConfig(schedule_)) {
|
||||||
|
if (schedule_.item().size() > 1) {
|
||||||
|
next_schedule_index_ = 1;
|
||||||
|
}
|
||||||
|
sequence_checker_.Detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SchedulableNetworkBehavior::EnqueuePacket(
|
||||||
|
webrtc::PacketInFlightInfo packet_info) {
|
||||||
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||||
|
if (first_send_time_.IsMinusInfinity()) {
|
||||||
|
first_send_time_ = webrtc::Timestamp::Micros(packet_info.send_time_us);
|
||||||
|
if (schedule_.item().size() > 1) {
|
||||||
|
RTC_CHECK_LT(next_schedule_index_, schedule_.item().size());
|
||||||
|
webrtc::TimeDelta delay =
|
||||||
|
webrtc::TimeDelta::Millis(schedule_.item()[next_schedule_index_]
|
||||||
|
.time_since_first_sent_packet_ms());
|
||||||
|
schedule_task_ = RepeatingTaskHandle::DelayedStart(
|
||||||
|
webrtc::TaskQueueBase::Current(), delay,
|
||||||
|
[this] { return UpdateConfigAndReschedule(); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SimulatedNetwork::EnqueuePacket(packet_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeDelta SchedulableNetworkBehavior::UpdateConfigAndReschedule() {
|
||||||
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||||
|
Timestamp reschedule_time = clock_.CurrentTime();
|
||||||
|
RTC_CHECK_LT(next_schedule_index_, schedule_.item().size());
|
||||||
|
|
||||||
|
auto next_config = schedule_.item()[next_schedule_index_];
|
||||||
|
UpdateConfigFromSchedule(next_config, config_);
|
||||||
|
SimulatedNetwork::SetConfig(config_, reschedule_time);
|
||||||
|
next_schedule_index_ = ++next_schedule_index_ % schedule_.item().size();
|
||||||
|
webrtc::TimeDelta delay = webrtc::TimeDelta::Zero();
|
||||||
|
webrtc::TimeDelta time_since_first_sent_packet =
|
||||||
|
reschedule_time - first_send_time_;
|
||||||
|
if (next_schedule_index_ != 0) {
|
||||||
|
delay = webrtc::TimeDelta::Millis(schedule_.item()[next_schedule_index_]
|
||||||
|
.time_since_first_sent_packet_ms()) -
|
||||||
|
(time_since_first_sent_packet - wrap_time_delta_);
|
||||||
|
} else if (!schedule_.has_repeat_schedule_after_last_ms()) {
|
||||||
|
// No more schedule items.
|
||||||
|
schedule_task_.Stop();
|
||||||
|
return TimeDelta::Zero(); // This is ignored.
|
||||||
|
} else {
|
||||||
|
// Wrap around to the first schedule item.
|
||||||
|
wrap_time_delta_ +=
|
||||||
|
TimeDelta::Millis(schedule_.repeat_schedule_after_last_ms()) +
|
||||||
|
TimeDelta::Millis(schedule_.item()[schedule_.item().size() - 1]
|
||||||
|
.time_since_first_sent_packet_ms());
|
||||||
|
delay =
|
||||||
|
webrtc::TimeDelta::Millis(schedule_.repeat_schedule_after_last_ms());
|
||||||
|
RTC_DCHECK_GE(delay, TimeDelta::Zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
56
test/network/schedulable_network_behavior.h
Normal file
56
test/network/schedulable_network_behavior.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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_NETWORK_SCHEDULABLE_NETWORK_BEHAVIOR_H_
|
||||||
|
#define TEST_NETWORK_SCHEDULABLE_NETWORK_BEHAVIOR_H_
|
||||||
|
|
||||||
|
#include "api/sequence_checker.h"
|
||||||
|
#include "api/test/network_emulation/network_config_schedule.pb.h"
|
||||||
|
#include "api/test/simulated_network.h"
|
||||||
|
#include "api/units/time_delta.h"
|
||||||
|
#include "api/units/timestamp.h"
|
||||||
|
#include "rtc_base/task_utils/repeating_task.h"
|
||||||
|
#include "rtc_base/thread_annotations.h"
|
||||||
|
#include "system_wrappers/include/clock.h"
|
||||||
|
#include "test/network/simulated_network.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
// Network behaviour implementation where parameters change over time as
|
||||||
|
// specified with a schedule proto.
|
||||||
|
class SchedulableNetworkBehavior : public SimulatedNetwork {
|
||||||
|
public:
|
||||||
|
SchedulableNetworkBehavior(network_behaviour::NetworkConfigSchedule schedule,
|
||||||
|
Clock& clock);
|
||||||
|
|
||||||
|
bool EnqueuePacket(PacketInFlightInfo packet_info) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TimeDelta UpdateConfigAndReschedule();
|
||||||
|
|
||||||
|
SequenceChecker sequence_checker_;
|
||||||
|
const network_behaviour::NetworkConfigSchedule schedule_;
|
||||||
|
Timestamp first_send_time_ RTC_GUARDED_BY(&sequence_checker_) =
|
||||||
|
Timestamp::MinusInfinity();
|
||||||
|
|
||||||
|
Clock& clock_ RTC_GUARDED_BY(&sequence_checker_);
|
||||||
|
BuiltInNetworkBehaviorConfig config_ RTC_GUARDED_BY(&sequence_checker_);
|
||||||
|
// Index of the next schedule item to apply.
|
||||||
|
int next_schedule_index_ RTC_GUARDED_BY(&sequence_checker_) = 0;
|
||||||
|
// Total time from the first sent packet, until the last time the schedule
|
||||||
|
// repeat.
|
||||||
|
TimeDelta wrap_time_delta_ RTC_GUARDED_BY(&sequence_checker_) =
|
||||||
|
TimeDelta::Zero();
|
||||||
|
RepeatingTaskHandle schedule_task_ RTC_GUARDED_BY(&sequence_checker_);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
#endif // TEST_NETWORK_SCHEDULABLE_NETWORK_BEHAVIOR_H_
|
||||||
241
test/network/schedulable_network_behavior_test.cc
Normal file
241
test/network/schedulable_network_behavior_test.cc
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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/network/schedulable_network_behavior.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "api/test/create_network_emulation_manager.h"
|
||||||
|
#include "api/test/network_emulation_manager.h"
|
||||||
|
#include "api/test/simulated_network.h"
|
||||||
|
#include "api/units/time_delta.h"
|
||||||
|
#include "api/units/timestamp.h"
|
||||||
|
#include "system_wrappers/include/clock.h"
|
||||||
|
#include "test/gmock.h"
|
||||||
|
#include "test/gtest.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ::testing::Mock;
|
||||||
|
using ::testing::MockFunction;
|
||||||
|
using ::testing::SizeIs;
|
||||||
|
|
||||||
|
class SchedulableNetworkBehaviorTestFixture {
|
||||||
|
public:
|
||||||
|
SchedulableNetworkBehaviorTestFixture()
|
||||||
|
: manager_(webrtc::CreateNetworkEmulationManager(
|
||||||
|
{.time_mode = TimeMode::kSimulated})) {}
|
||||||
|
|
||||||
|
webrtc::Clock& clock() const {
|
||||||
|
return *manager_->time_controller()->GetClock();
|
||||||
|
}
|
||||||
|
void AdvanceTime(webrtc::TimeDelta delta) {
|
||||||
|
manager_->time_controller()->AdvanceTime(delta);
|
||||||
|
}
|
||||||
|
void AdvanceTimeTo(int64_t timestamp_us) {
|
||||||
|
TimeDelta delta = Timestamp::Micros(timestamp_us) - TimeNow();
|
||||||
|
ASSERT_GE(delta, TimeDelta::Zero());
|
||||||
|
manager_->time_controller()->AdvanceTime(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
webrtc::Timestamp TimeNow() const {
|
||||||
|
return manager_->time_controller()->GetClock()->CurrentTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::unique_ptr<webrtc::NetworkEmulationManager> manager_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(SchedulableNetworkBehaviorTest, NoSchedule) {
|
||||||
|
SchedulableNetworkBehaviorTestFixture fixture;
|
||||||
|
|
||||||
|
network_behaviour::NetworkConfigSchedule schedule;
|
||||||
|
SchedulableNetworkBehavior network_behaviour(schedule, fixture.clock());
|
||||||
|
webrtc::Timestamp send_time = fixture.TimeNow();
|
||||||
|
EXPECT_TRUE(network_behaviour.EnqueuePacket({/*size=*/1000 / 8,
|
||||||
|
/*send_time_us=*/send_time.us(),
|
||||||
|
/*packet_id=*/1}));
|
||||||
|
ASSERT_TRUE(network_behaviour.NextDeliveryTimeUs().has_value());
|
||||||
|
fixture.AdvanceTimeTo(*network_behaviour.NextDeliveryTimeUs());
|
||||||
|
EXPECT_THAT(
|
||||||
|
network_behaviour.DequeueDeliverablePackets(fixture.TimeNow().us()),
|
||||||
|
SizeIs(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SchedulableNetworkBehaviorTest, ScheduleWithoutUpdates) {
|
||||||
|
SchedulableNetworkBehaviorTestFixture fixture;
|
||||||
|
|
||||||
|
network_behaviour::NetworkConfigSchedule schedule;
|
||||||
|
auto initial_config = schedule.add_item();
|
||||||
|
initial_config->set_link_capacity_kbps(10);
|
||||||
|
initial_config->set_queue_delay_ms(70);
|
||||||
|
|
||||||
|
SchedulableNetworkBehavior network_behaviour(schedule, fixture.clock());
|
||||||
|
webrtc::Timestamp send_time = fixture.TimeNow();
|
||||||
|
EXPECT_TRUE(network_behaviour.EnqueuePacket({/*size=*/1000 / 8,
|
||||||
|
/*send_time_us=*/send_time.us(),
|
||||||
|
/*packet_id=*/1}));
|
||||||
|
|
||||||
|
// 1000 bits, on a 10kbps link should take 100ms + 70 extra.
|
||||||
|
// The network_behaviour at the time of writing this test needs two calls
|
||||||
|
// to NextDeliveryTimeUs to before the packet is delivered (one for the link
|
||||||
|
// capacity queue and one for the queue delay).
|
||||||
|
std::vector<webrtc::PacketDeliveryInfo> packet_delivery_infos;
|
||||||
|
while (packet_delivery_infos.empty()) {
|
||||||
|
ASSERT_TRUE(network_behaviour.NextDeliveryTimeUs().has_value());
|
||||||
|
fixture.AdvanceTimeTo(*network_behaviour.NextDeliveryTimeUs());
|
||||||
|
packet_delivery_infos =
|
||||||
|
network_behaviour.DequeueDeliverablePackets(fixture.TimeNow().us());
|
||||||
|
}
|
||||||
|
EXPECT_EQ(fixture.TimeNow(), send_time + TimeDelta::Millis(170));
|
||||||
|
ASSERT_THAT(packet_delivery_infos, SizeIs(1));
|
||||||
|
EXPECT_EQ(packet_delivery_infos[0].packet_id, 1u);
|
||||||
|
EXPECT_EQ(packet_delivery_infos[0].receive_time_us, send_time.us() + 170'000);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SchedulableNetworkBehaviorTest,
|
||||||
|
TriggersDeliveryTimeChangedCallbackOnScheduleIfPacketInLinkCapacityQueue) {
|
||||||
|
SchedulableNetworkBehaviorTestFixture fixture;
|
||||||
|
network_behaviour::NetworkConfigSchedule schedule;
|
||||||
|
auto initial_config = schedule.add_item();
|
||||||
|
// A packet of size 1000 bits should take 100ms to send.
|
||||||
|
initial_config->set_link_capacity_kbps(10);
|
||||||
|
initial_config->set_queue_delay_ms(10);
|
||||||
|
auto updated_capacity = schedule.add_item();
|
||||||
|
updated_capacity->set_time_since_first_sent_packet_ms(50);
|
||||||
|
// A packet of size 1000 bits should take 10ms to send. But since "half" the
|
||||||
|
// first packet has passed the narrow section, it should take 50ms + 500/100 =
|
||||||
|
// 55ms.
|
||||||
|
updated_capacity->set_link_capacity_kbps(100);
|
||||||
|
|
||||||
|
SchedulableNetworkBehavior network_behaviour(schedule, fixture.clock());
|
||||||
|
MockFunction<void()> delivery_time_changed_callback;
|
||||||
|
network_behaviour.RegisterDeliveryTimeChangedCallback(
|
||||||
|
delivery_time_changed_callback.AsStdFunction());
|
||||||
|
|
||||||
|
webrtc::Timestamp first_packet_send_time = fixture.TimeNow();
|
||||||
|
EXPECT_CALL(delivery_time_changed_callback, Call).WillOnce([&]() {
|
||||||
|
EXPECT_EQ(fixture.TimeNow(),
|
||||||
|
first_packet_send_time + TimeDelta::Millis(50));
|
||||||
|
ASSERT_TRUE(network_behaviour.NextDeliveryTimeUs().has_value());
|
||||||
|
});
|
||||||
|
EXPECT_TRUE(network_behaviour.EnqueuePacket(
|
||||||
|
{/*size=*/1000 / 8,
|
||||||
|
/*send_time_us=*/first_packet_send_time.us(),
|
||||||
|
/*packet_id=*/1}));
|
||||||
|
fixture.AdvanceTime(
|
||||||
|
TimeDelta::Millis(updated_capacity->time_since_first_sent_packet_ms()));
|
||||||
|
Mock::VerifyAndClearExpectations(&delivery_time_changed_callback);
|
||||||
|
ASSERT_TRUE(network_behaviour.NextDeliveryTimeUs().has_value());
|
||||||
|
fixture.AdvanceTime(
|
||||||
|
TimeDelta::Micros(*network_behaviour.NextDeliveryTimeUs()));
|
||||||
|
std::vector<PacketDeliveryInfo> dequeued_packets =
|
||||||
|
network_behaviour.DequeueDeliverablePackets(fixture.TimeNow().us());
|
||||||
|
ASSERT_FALSE(dequeued_packets.empty());
|
||||||
|
EXPECT_EQ(dequeued_packets[0].receive_time_us,
|
||||||
|
(first_packet_send_time + TimeDelta::Millis(55) +
|
||||||
|
/*queue_delay=*/TimeDelta::Millis(10))
|
||||||
|
.us());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SchedulableNetworkBehaviorTest, ScheduleWithRepeat) {
|
||||||
|
SchedulableNetworkBehaviorTestFixture fixture;
|
||||||
|
network_behaviour::NetworkConfigSchedule schedule;
|
||||||
|
auto initial_config = schedule.add_item();
|
||||||
|
// A packet of size 1000 bits should take 100ms to send.
|
||||||
|
initial_config->set_link_capacity_kbps(10);
|
||||||
|
auto updated_capacity = schedule.add_item();
|
||||||
|
updated_capacity->set_time_since_first_sent_packet_ms(150);
|
||||||
|
// A packet of size 1000 bits should take 10ms to send.
|
||||||
|
updated_capacity->set_link_capacity_kbps(100);
|
||||||
|
// A packet of size 1000 bits, scheduled 200ms after the last update to the
|
||||||
|
// config should again take 100ms to send.
|
||||||
|
schedule.set_repeat_schedule_after_last_ms(200);
|
||||||
|
|
||||||
|
SchedulableNetworkBehavior network_behaviour(schedule, fixture.clock());
|
||||||
|
|
||||||
|
webrtc::Timestamp first_packet_send_time = fixture.TimeNow();
|
||||||
|
EXPECT_TRUE(network_behaviour.EnqueuePacket(
|
||||||
|
{/*size=*/1000 / 8,
|
||||||
|
/*send_time_us=*/first_packet_send_time.us(),
|
||||||
|
/*packet_id=*/1}));
|
||||||
|
ASSERT_TRUE(network_behaviour.NextDeliveryTimeUs().has_value());
|
||||||
|
EXPECT_EQ(*network_behaviour.NextDeliveryTimeUs(),
|
||||||
|
fixture.TimeNow().us() + TimeDelta::Millis(100).us());
|
||||||
|
fixture.AdvanceTimeTo(*network_behaviour.NextDeliveryTimeUs());
|
||||||
|
EXPECT_THAT(
|
||||||
|
network_behaviour.DequeueDeliverablePackets(fixture.TimeNow().us()),
|
||||||
|
SizeIs(1));
|
||||||
|
fixture.AdvanceTime(
|
||||||
|
TimeDelta::Millis(updated_capacity->time_since_first_sent_packet_ms() +
|
||||||
|
schedule.repeat_schedule_after_last_ms() -
|
||||||
|
/*time already advanced*/ 100));
|
||||||
|
// Schedule should be repeated.
|
||||||
|
// A packet of size 1000 bits should take 100ms to send.
|
||||||
|
EXPECT_TRUE(
|
||||||
|
network_behaviour.EnqueuePacket({/*size=*/1000 / 8,
|
||||||
|
/*send_time_us=*/fixture.TimeNow().us(),
|
||||||
|
/*packet_id=*/2}));
|
||||||
|
ASSERT_TRUE(network_behaviour.NextDeliveryTimeUs().has_value());
|
||||||
|
EXPECT_EQ(*network_behaviour.NextDeliveryTimeUs(),
|
||||||
|
fixture.TimeNow().us() + TimeDelta::Millis(100).us());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SchedulableNetworkBehaviorTest, ScheduleWithoutRepeat) {
|
||||||
|
SchedulableNetworkBehaviorTestFixture fixture;
|
||||||
|
network_behaviour::NetworkConfigSchedule schedule;
|
||||||
|
auto initial_config = schedule.add_item();
|
||||||
|
// A packet of size 1000 bits should take 100ms to send.
|
||||||
|
initial_config->set_link_capacity_kbps(10);
|
||||||
|
auto updated_capacity = schedule.add_item();
|
||||||
|
updated_capacity->set_time_since_first_sent_packet_ms(150);
|
||||||
|
// A packet of size 1000 bits should take 10ms to send.
|
||||||
|
updated_capacity->set_link_capacity_kbps(100);
|
||||||
|
|
||||||
|
SchedulableNetworkBehavior network_behaviour(schedule, fixture.clock());
|
||||||
|
|
||||||
|
webrtc::Timestamp first_packet_send_time = fixture.TimeNow();
|
||||||
|
EXPECT_TRUE(network_behaviour.EnqueuePacket(
|
||||||
|
{/*size=*/1000 / 8,
|
||||||
|
/*send_time_us=*/first_packet_send_time.us(),
|
||||||
|
/*packet_id=*/1}));
|
||||||
|
ASSERT_TRUE(network_behaviour.NextDeliveryTimeUs().has_value());
|
||||||
|
EXPECT_EQ(*network_behaviour.NextDeliveryTimeUs(),
|
||||||
|
fixture.TimeNow().us() + TimeDelta::Millis(100).us());
|
||||||
|
fixture.AdvanceTimeTo(*network_behaviour.NextDeliveryTimeUs());
|
||||||
|
EXPECT_THAT(
|
||||||
|
network_behaviour.DequeueDeliverablePackets(fixture.TimeNow().us()),
|
||||||
|
SizeIs(1));
|
||||||
|
// Advance time to when the updated capacity should be in effect and add one
|
||||||
|
// minute. The updated capacity should still be in affect.
|
||||||
|
fixture.AdvanceTime(
|
||||||
|
TimeDelta::Millis(updated_capacity->time_since_first_sent_packet_ms() -
|
||||||
|
/*time already advanced*/ 100) +
|
||||||
|
TimeDelta::Minutes(1));
|
||||||
|
|
||||||
|
// Schedule should not be repeated.
|
||||||
|
// A packet of size 1000 bits should take 10ms to send.
|
||||||
|
EXPECT_TRUE(
|
||||||
|
network_behaviour.EnqueuePacket({/*size=*/1000 / 8,
|
||||||
|
/*send_time_us=*/fixture.TimeNow().us(),
|
||||||
|
/*packet_id=*/2}));
|
||||||
|
ASSERT_TRUE(network_behaviour.NextDeliveryTimeUs().has_value());
|
||||||
|
EXPECT_EQ(*network_behaviour.NextDeliveryTimeUs(),
|
||||||
|
fixture.TimeNow().us() + TimeDelta::Millis(10).us());
|
||||||
|
fixture.AdvanceTimeTo(*network_behaviour.NextDeliveryTimeUs());
|
||||||
|
EXPECT_THAT(
|
||||||
|
network_behaviour.DequeueDeliverablePackets(fixture.TimeNow().us()),
|
||||||
|
SizeIs(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace webrtc
|
||||||
@ -19,6 +19,7 @@ if (rtc_include_tests) {
|
|||||||
]
|
]
|
||||||
deps = [
|
deps = [
|
||||||
"..:peer_scenario",
|
"..:peer_scenario",
|
||||||
|
"../../:create_frame_generator_capturer",
|
||||||
"../../:field_trial",
|
"../../:field_trial",
|
||||||
"../../:test_support",
|
"../../:test_support",
|
||||||
"../../../api:rtc_stats_api",
|
"../../../api:rtc_stats_api",
|
||||||
@ -30,5 +31,11 @@ if (rtc_include_tests) {
|
|||||||
"../../../pc:pc_test_utils",
|
"../../../pc:pc_test_utils",
|
||||||
"../../../pc:session_description",
|
"../../../pc:session_description",
|
||||||
]
|
]
|
||||||
|
if (rtc_enable_protobuf) {
|
||||||
|
deps += [
|
||||||
|
"../../../api/test/network_emulation:network_config_schedule_proto",
|
||||||
|
"../../../api/test/network_emulation:schedulable_network_node_builder",
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,9 @@
|
|||||||
* be found in the AUTHORS file in the root of the source tree.
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "api/stats/rtcstats_objects.h"
|
#include "api/stats/rtcstats_objects.h"
|
||||||
#include "api/units/data_rate.h"
|
#include "api/units/data_rate.h"
|
||||||
#include "api/units/time_delta.h"
|
#include "api/units/time_delta.h"
|
||||||
@ -16,11 +19,16 @@
|
|||||||
#include "modules/rtp_rtcp/source/rtp_util.h"
|
#include "modules/rtp_rtcp/source/rtp_util.h"
|
||||||
#include "pc/media_session.h"
|
#include "pc/media_session.h"
|
||||||
#include "pc/test/mock_peer_connection_observers.h"
|
#include "pc/test/mock_peer_connection_observers.h"
|
||||||
|
#include "test/create_frame_generator_capturer.h"
|
||||||
#include "test/gmock.h"
|
#include "test/gmock.h"
|
||||||
#include "test/gtest.h"
|
#include "test/gtest.h"
|
||||||
#include "test/peer_scenario/peer_scenario.h"
|
#include "test/peer_scenario/peer_scenario.h"
|
||||||
#include "test/peer_scenario/peer_scenario_client.h"
|
#include "test/peer_scenario/peer_scenario_client.h"
|
||||||
|
|
||||||
|
#if WEBRTC_ENABLE_PROTOBUF
|
||||||
|
#include "api/test/network_emulation/schedulable_network_node_builder.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
@ -49,6 +57,55 @@ DataRate GetAvailableSendBitrate(
|
|||||||
return DataRate::BitsPerSec(*stats[0]->available_outgoing_bitrate);
|
return DataRate::BitsPerSec(*stats[0]->available_outgoing_bitrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if WEBRTC_ENABLE_PROTOBUF
|
||||||
|
TEST(BweRampupTest, BweRampUpWhenCapacityIncrease) {
|
||||||
|
PeerScenario s(*test_info_);
|
||||||
|
|
||||||
|
PeerScenarioClient* caller = s.CreateClient({});
|
||||||
|
PeerScenarioClient* callee = s.CreateClient({});
|
||||||
|
|
||||||
|
network_behaviour::NetworkConfigSchedule schedule;
|
||||||
|
auto initial_config = schedule.add_item();
|
||||||
|
initial_config->set_link_capacity_kbps(500);
|
||||||
|
auto updated_capacity = schedule.add_item();
|
||||||
|
updated_capacity->set_time_since_first_sent_packet_ms(3000);
|
||||||
|
updated_capacity->set_link_capacity_kbps(3000);
|
||||||
|
SchedulableNetworkNodeBuilder schedulable_builder(*s.net(),
|
||||||
|
std::move(schedule));
|
||||||
|
|
||||||
|
auto caller_node = schedulable_builder.Build();
|
||||||
|
auto callee_node = s.net()->NodeBuilder().capacity_kbps(5000).Build().node;
|
||||||
|
s.net()->CreateRoute(caller->endpoint(), {caller_node}, callee->endpoint());
|
||||||
|
s.net()->CreateRoute(callee->endpoint(), {callee_node}, caller->endpoint());
|
||||||
|
|
||||||
|
FrameGeneratorCapturerConfig::SquaresVideo video_resolution = {
|
||||||
|
.framerate = 30, .width = 1280, .height = 720};
|
||||||
|
PeerScenarioClient::VideoSendTrack track = caller->CreateVideo(
|
||||||
|
"VIDEO", {.generator = {.squares_video = video_resolution}});
|
||||||
|
|
||||||
|
auto signaling =
|
||||||
|
s.ConnectSignaling(caller, callee, {caller_node}, {callee_node});
|
||||||
|
|
||||||
|
signaling.StartIceSignaling();
|
||||||
|
|
||||||
|
std::atomic<bool> offer_exchange_done(false);
|
||||||
|
signaling.NegotiateSdp([&](const SessionDescriptionInterface& answer) {
|
||||||
|
offer_exchange_done = true;
|
||||||
|
});
|
||||||
|
// Wait for SDP negotiation.
|
||||||
|
s.WaitAndProcess(&offer_exchange_done);
|
||||||
|
|
||||||
|
s.ProcessMessages(TimeDelta::Seconds(5));
|
||||||
|
DataRate bwe_before_capacity_increase =
|
||||||
|
GetAvailableSendBitrate(GetStatsAndProcess(s, caller));
|
||||||
|
EXPECT_GT(bwe_before_capacity_increase.kbps(), 300);
|
||||||
|
EXPECT_LT(bwe_before_capacity_increase.kbps(), 650);
|
||||||
|
s.ProcessMessages(TimeDelta::Seconds(15));
|
||||||
|
EXPECT_GT(GetAvailableSendBitrate(GetStatsAndProcess(s, caller)).kbps(),
|
||||||
|
1000);
|
||||||
|
}
|
||||||
|
#endif // WEBRTC_ENABLE_PROTOBUF
|
||||||
|
|
||||||
// Test that caller BWE can rampup even if callee can not demux incoming RTP
|
// Test that caller BWE can rampup even if callee can not demux incoming RTP
|
||||||
// packets.
|
// packets.
|
||||||
TEST(BweRampupTest, RampUpWithUndemuxableRtpPackets) {
|
TEST(BweRampupTest, RampUpWithUndemuxableRtpPackets) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user