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 <srte@webrtc.org>
Reviewed-by: Jonas Olsson <jonasolsson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27975}
diff --git a/api/transport/BUILD.gn b/api/transport/BUILD.gn
index 5c40deb..03a779e 100644
--- a/api/transport/BUILD.gn
+++ b/api/transport/BUILD.gn
@@ -85,6 +85,30 @@
 }
 
 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 0000000..873a79a
--- /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<FeedbackGenerator> CreateFeedbackGenerator(
+    FeedbackGenerator::Config confg) {
+  return absl::make_unique<FeedbackGeneratorImpl>(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 0000000..a1a2226
--- /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 <memory>
+
+#include "api/transport/test/feedback_generator_interface.h"
+
+namespace webrtc {
+std::unique_ptr<FeedbackGenerator> 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 0000000..cff67dd
--- /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 <vector>
+
+#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<TransportPacketsFeedback> 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 7b4b504..35b0df4 100644
--- a/test/scenario/network/BUILD.gn
+++ b/test/scenario/network/BUILD.gn
@@ -122,10 +122,38 @@
   ]
 }
 
+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 0000000..4ab7c2e
--- /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<TransportPacketsFeedback> FeedbackGeneratorImpl::PopFeedback() {
+  std::vector<TransportPacketsFeedback> 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<int>();
+  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<size_t>(), 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 0000000..5ff69a9
--- /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 <map>
+#include <utility>
+#include <vector>
+
+#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 <typename FakePacketType>
+class FakePacketRoute : public EmulatedNetworkReceiverInterface {
+ public:
+  FakePacketRoute(EmulatedRoute* route,
+                  std::function<void(FakePacketType, Timestamp)> 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<int*>(buf.data())[0] = next_packet_id_++;
+    from->SendPacket(send_addr_, recv_addr_, buf);
+  }
+
+  void OnPacketReceived(EmulatedIpPacket packet) override {
+    int packet_id = reinterpret_cast<int*>(packet.data.data())[0];
+    action_(std::move(sent_[packet_id]), packet.arrival_time);
+    sent_.erase(packet_id);
+  }
+
+ private:
+  EmulatedRoute* const route_;
+  const std::function<void(FakePacketType, Timestamp)> action_;
+  const rtc::SocketAddress send_addr_;
+  const rtc::SocketAddress recv_addr_;
+
+  int next_packet_id_ = 0;
+  std::map<int, FakePacketType> 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<TransportPacketsFeedback> 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<SentPacket> received_packet_handler_;
+  FakePacketRoute<TransportPacketsFeedback> received_feedback_handler_;
+
+  TransportPacketsFeedback builder_;
+  std::vector<TransportPacketsFeedback> 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 0000000..54029d0
--- /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<size_t>(), kPacketSize);
+    }
+  }
+}
+}  // namespace webrtc