From 3525f86c42604fbd9d5a4e197150dfa007707594 Mon Sep 17 00:00:00 2001 From: Sebastian Jansson Date: Fri, 17 May 2019 17:44:04 +0200 Subject: [PATCH] Adds feedback generator. This is a useful tool to use for unittests of code that uses TransportFeedback as input. Bug: webrtc:10498 Change-Id: I171b22841eb9e16a5d5b785ff45ae9df5a6ccd7f Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/137423 Commit-Queue: Sebastian Jansson Reviewed-by: Jonas Olsson Cr-Commit-Position: refs/heads/master@{#27975} --- api/transport/BUILD.gn | 24 +++++ .../test/create_feedback_generator.cc | 23 +++++ .../test/create_feedback_generator.h | 21 ++++ .../test/feedback_generator_interface.h | 37 +++++++ test/scenario/network/BUILD.gn | 28 ++++++ test/scenario/network/feedback_generator.cc | 99 +++++++++++++++++++ test/scenario/network/feedback_generator.h | 93 +++++++++++++++++ .../network/feedback_generator_unittest.cc | 31 ++++++ 8 files changed, 356 insertions(+) create mode 100644 api/transport/test/create_feedback_generator.cc create mode 100644 api/transport/test/create_feedback_generator.h create mode 100644 api/transport/test/feedback_generator_interface.h create mode 100644 test/scenario/network/feedback_generator.cc create mode 100644 test/scenario/network/feedback_generator.h create mode 100644 test/scenario/network/feedback_generator_unittest.cc diff --git a/api/transport/BUILD.gn b/api/transport/BUILD.gn index 5c40debbcb..03a779e653 100644 --- a/api/transport/BUILD.gn +++ b/api/transport/BUILD.gn @@ -85,6 +85,30 @@ rtc_static_library("goog_cc") { } if (rtc_include_tests) { + rtc_source_set("test_feedback_generator_interface") { + testonly = true + sources = [ + "test/feedback_generator_interface.h", + ] + deps = [ + ":network_control", + "..:simulated_network_api", + ] + } + rtc_source_set("test_feedback_generator") { + testonly = true + sources = [ + "test/create_feedback_generator.cc", + "test/create_feedback_generator.h", + ] + visibility = [ "*" ] + deps = [ + ":network_control", + ":test_feedback_generator_interface", + "../../test/scenario/network:feedback_generator", + "//third_party/abseil-cpp/absl/memory", + ] + } rtc_source_set("network_control_test") { testonly = true sources = [ diff --git a/api/transport/test/create_feedback_generator.cc b/api/transport/test/create_feedback_generator.cc new file mode 100644 index 0000000000..873a79aba1 --- /dev/null +++ b/api/transport/test/create_feedback_generator.cc @@ -0,0 +1,23 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "api/transport/test/create_feedback_generator.h" + +#include "absl/memory/memory.h" + +#include "test/scenario/network/feedback_generator.h" + +namespace webrtc { + +std::unique_ptr CreateFeedbackGenerator( + FeedbackGenerator::Config confg) { + return absl::make_unique(confg); +} + +} // namespace webrtc diff --git a/api/transport/test/create_feedback_generator.h b/api/transport/test/create_feedback_generator.h new file mode 100644 index 0000000000..a1a2226496 --- /dev/null +++ b/api/transport/test/create_feedback_generator.h @@ -0,0 +1,21 @@ +/* + * Copyright 2019 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_TRANSPORT_TEST_CREATE_FEEDBACK_GENERATOR_H_ +#define API_TRANSPORT_TEST_CREATE_FEEDBACK_GENERATOR_H_ + +#include + +#include "api/transport/test/feedback_generator_interface.h" + +namespace webrtc { +std::unique_ptr CreateFeedbackGenerator( + FeedbackGenerator::Config confg); +} // namespace webrtc +#endif // API_TRANSPORT_TEST_CREATE_FEEDBACK_GENERATOR_H_ diff --git a/api/transport/test/feedback_generator_interface.h b/api/transport/test/feedback_generator_interface.h new file mode 100644 index 0000000000..cff67dd1df --- /dev/null +++ b/api/transport/test/feedback_generator_interface.h @@ -0,0 +1,37 @@ +/* + * Copyright 2019 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_TRANSPORT_TEST_FEEDBACK_GENERATOR_INTERFACE_H_ +#define API_TRANSPORT_TEST_FEEDBACK_GENERATOR_INTERFACE_H_ + +#include + +#include "api/test/simulated_network.h" +#include "api/transport/network_types.h" + +namespace webrtc { +class FeedbackGenerator { + public: + struct Config { + BuiltInNetworkBehaviorConfig send_link; + BuiltInNetworkBehaviorConfig return_link; + TimeDelta feedback_interval = TimeDelta::ms(50); + DataSize feedback_packet_size = DataSize::bytes(20); + }; + virtual ~FeedbackGenerator() = default; + virtual Timestamp Now() = 0; + virtual void Sleep(TimeDelta duration) = 0; + virtual void SendPacket(size_t size) = 0; + virtual std::vector PopFeedback() = 0; + virtual void SetSendConfig(BuiltInNetworkBehaviorConfig config) = 0; + virtual void SetReturnConfig(BuiltInNetworkBehaviorConfig config) = 0; + virtual void SetSendLinkCapacity(DataRate capacity) = 0; +}; +} // namespace webrtc +#endif // API_TRANSPORT_TEST_FEEDBACK_GENERATOR_INTERFACE_H_ diff --git a/test/scenario/network/BUILD.gn b/test/scenario/network/BUILD.gn index 7b4b504993..35b0df43e8 100644 --- a/test/scenario/network/BUILD.gn +++ b/test/scenario/network/BUILD.gn @@ -122,10 +122,38 @@ rtc_source_set("cross_traffic_unittest") { ] } +rtc_source_set("feedback_generator") { + testonly = true + sources = [ + "feedback_generator.cc", + "feedback_generator.h", + ] + deps = [ + "../../../api/transport:test_feedback_generator_interface", + "../../../call:simulated_network", + "../../../rtc_base:checks", + "../../../test/scenario/network:emulated_network", + "../../../test/time_controller", + "//third_party/abseil-cpp/absl/memory", + ] +} + +rtc_source_set("feedback_generator_unittest") { + testonly = true + sources = [ + "feedback_generator_unittest.cc", + ] + deps = [ + "../../../api/transport:test_feedback_generator", + "../../../test:test_support", + ] +} + rtc_source_set("network_emulation_unittests") { testonly = true deps = [ ":cross_traffic_unittest", + ":feedback_generator_unittest", ":network_emulation_pc_unittest", ":network_emulation_unittest", ] diff --git a/test/scenario/network/feedback_generator.cc b/test/scenario/network/feedback_generator.cc new file mode 100644 index 0000000000..4ab7c2efc0 --- /dev/null +++ b/test/scenario/network/feedback_generator.cc @@ -0,0 +1,99 @@ +/* + * Copyright 2019 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/network/feedback_generator.h" + +#include "absl/memory/memory.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +FeedbackGeneratorImpl::FeedbackGeneratorImpl( + FeedbackGeneratorImpl::Config config) + : conf_(config), + time_controller_{Timestamp::seconds(100000)}, + net_{&time_controller_}, + send_link_{new SimulatedNetwork(conf_.send_link)}, + ret_link_{new SimulatedNetwork(conf_.return_link)}, + send_ep_{net_.CreateEndpoint(EmulatedEndpointConfig())}, + ret_ep_{net_.CreateEndpoint(EmulatedEndpointConfig())}, + send_route_{net_.CreateRoute( + send_ep_, + {net_.CreateEmulatedNode(absl::WrapUnique(send_link_))}, + ret_ep_)}, + ret_route_{net_.CreateRoute( + ret_ep_, + {net_.CreateEmulatedNode(absl::WrapUnique(ret_link_))}, + send_ep_)}, + send_addr_{rtc::SocketAddress(send_ep_->GetPeerLocalAddress(), 0)}, + ret_addr_{rtc::SocketAddress(ret_ep_->GetPeerLocalAddress(), 0)}, + received_packet_handler_{send_route_, + [&](SentPacket packet, Timestamp arrival_time) { + OnPacketReceived(std::move(packet), + arrival_time); + }}, + received_feedback_handler_{ + ret_route_, + [&](TransportPacketsFeedback packet, Timestamp arrival_time) { + packet.feedback_time = arrival_time; + feedback_.push_back(packet); + }} {} + +Timestamp FeedbackGeneratorImpl::Now() { + return Timestamp::ms(time_controller_.GetClock()->TimeInMilliseconds()); +} + +void FeedbackGeneratorImpl::Sleep(TimeDelta duration) { + time_controller_.Sleep(duration); +} + +void FeedbackGeneratorImpl::SendPacket(size_t size) { + SentPacket sent; + sent.send_time = Now(); + sent.size = DataSize::bytes(size); + received_packet_handler_.SendPacket(send_ep_, size, sent); +} + +std::vector FeedbackGeneratorImpl::PopFeedback() { + std::vector ret; + ret.swap(feedback_); + return ret; +} + +void FeedbackGeneratorImpl::SetSendConfig(BuiltInNetworkBehaviorConfig config) { + conf_.send_link = config; + send_link_->SetConfig(conf_.send_link); +} + +void FeedbackGeneratorImpl::SetReturnConfig( + BuiltInNetworkBehaviorConfig config) { + conf_.return_link = config; + ret_link_->SetConfig(conf_.return_link); +} + +void FeedbackGeneratorImpl::SetSendLinkCapacity(DataRate capacity) { + conf_.send_link.link_capacity_kbps = capacity.kbps(); + send_link_->SetConfig(conf_.send_link); +} + +void FeedbackGeneratorImpl::OnPacketReceived(SentPacket packet, + Timestamp arrival_time) { + PacketResult result; + result.sent_packet = packet; + result.receive_time = arrival_time; + builder_.packet_feedbacks.push_back(result); + Timestamp first_recv = builder_.packet_feedbacks.front().receive_time; + if (Now() - first_recv > conf_.feedback_interval) { + received_feedback_handler_.SendPacket( + ret_ep_, conf_.feedback_packet_size.bytes(), builder_); + builder_ = {}; + } +} + +} // namespace webrtc diff --git a/test/scenario/network/feedback_generator.h b/test/scenario/network/feedback_generator.h new file mode 100644 index 0000000000..5ff69a9883 --- /dev/null +++ b/test/scenario/network/feedback_generator.h @@ -0,0 +1,93 @@ +/* + * Copyright 2019 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_NETWORK_FEEDBACK_GENERATOR_H_ +#define TEST_SCENARIO_NETWORK_FEEDBACK_GENERATOR_H_ + +#include +#include +#include + +#include "api/transport/test/feedback_generator_interface.h" +#include "call/simulated_network.h" +#include "test/scenario/network/network_emulation.h" +#include "test/scenario/network/network_emulation_manager.h" +#include "test/time_controller/simulated_time_controller.h" + +namespace webrtc { + +template +class FakePacketRoute : public EmulatedNetworkReceiverInterface { + public: + FakePacketRoute(EmulatedRoute* route, + std::function action) + : route_(route), + action_(std::move(action)), + send_addr_(route_->from->GetPeerLocalAddress(), 0), + recv_addr_(route_->to->GetPeerLocalAddress(), + *route_->to->BindReceiver(0, this)) {} + + void SendPacket(EmulatedEndpoint* from, size_t size, FakePacketType packet) { + RTC_CHECK_GE(size, sizeof(int)); + sent_.emplace(next_packet_id_, packet); + rtc::CopyOnWriteBuffer buf(size); + reinterpret_cast(buf.data())[0] = next_packet_id_++; + from->SendPacket(send_addr_, recv_addr_, buf); + } + + void OnPacketReceived(EmulatedIpPacket packet) override { + int packet_id = reinterpret_cast(packet.data.data())[0]; + action_(std::move(sent_[packet_id]), packet.arrival_time); + sent_.erase(packet_id); + } + + private: + EmulatedRoute* const route_; + const std::function action_; + const rtc::SocketAddress send_addr_; + const rtc::SocketAddress recv_addr_; + + int next_packet_id_ = 0; + std::map sent_; +}; + +class FeedbackGeneratorImpl : public FeedbackGenerator { + public: + explicit FeedbackGeneratorImpl(Config config); + Timestamp Now() override; + void Sleep(TimeDelta duration) override; + void SendPacket(size_t size) override; + std::vector PopFeedback() override; + + void SetSendConfig(BuiltInNetworkBehaviorConfig config) override; + void SetReturnConfig(BuiltInNetworkBehaviorConfig config) override; + + void SetSendLinkCapacity(DataRate capacity) override; + + private: + void OnPacketReceived(SentPacket packet, Timestamp arrival_time); + Config conf_; + GlobalSimulatedTimeController time_controller_; + ::webrtc::test::NetworkEmulationManagerImpl net_; + SimulatedNetwork* const send_link_; + SimulatedNetwork* const ret_link_; + EmulatedEndpoint* const send_ep_; + EmulatedEndpoint* const ret_ep_; + EmulatedRoute* const send_route_; + EmulatedRoute* const ret_route_; + const rtc::SocketAddress send_addr_; + const rtc::SocketAddress ret_addr_; + FakePacketRoute received_packet_handler_; + FakePacketRoute received_feedback_handler_; + + TransportPacketsFeedback builder_; + std::vector feedback_; +}; +} // namespace webrtc +#endif // TEST_SCENARIO_NETWORK_FEEDBACK_GENERATOR_H_ diff --git a/test/scenario/network/feedback_generator_unittest.cc b/test/scenario/network/feedback_generator_unittest.cc new file mode 100644 index 0000000000..54029d0d22 --- /dev/null +++ b/test/scenario/network/feedback_generator_unittest.cc @@ -0,0 +1,31 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/transport/test/create_feedback_generator.h" +#include "test/gtest.h" + +namespace webrtc { +TEST(FeedbackGeneratorTest, ReportsFeedbackForSentPackets) { + size_t kPacketSize = 1000; + auto gen = CreateFeedbackGenerator(FeedbackGenerator::Config()); + for (int i = 0; i < 10; ++i) { + gen->SendPacket(kPacketSize); + gen->Sleep(TimeDelta::ms(50)); + } + auto feedback_list = gen->PopFeedback(); + EXPECT_GT(feedback_list.size(), 0u); + for (const auto& feedback : feedback_list) { + EXPECT_GT(feedback.packet_feedbacks.size(), 0u); + for (const auto& packet : feedback.packet_feedbacks) { + EXPECT_EQ(packet.sent_packet.size.bytes(), kPacketSize); + } + } +} +} // namespace webrtc