summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/test/time_controller
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/libwebrtc/test/time_controller
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/test/time_controller')
-rw-r--r--third_party/libwebrtc/test/time_controller/BUILD.gn70
-rw-r--r--third_party/libwebrtc/test/time_controller/external_time_controller.cc134
-rw-r--r--third_party/libwebrtc/test/time_controller/external_time_controller.h69
-rw-r--r--third_party/libwebrtc/test/time_controller/external_time_controller_unittest.cc179
-rw-r--r--third_party/libwebrtc/test/time_controller/real_time_controller.cc66
-rw-r--r--third_party/libwebrtc/test/time_controller/real_time_controller.h41
-rw-r--r--third_party/libwebrtc/test/time_controller/simulated_task_queue.cc89
-rw-r--r--third_party/libwebrtc/test/time_controller/simulated_task_queue.h65
-rw-r--r--third_party/libwebrtc/test/time_controller/simulated_thread.cc118
-rw-r--r--third_party/libwebrtc/test/time_controller/simulated_thread.h66
-rw-r--r--third_party/libwebrtc/test/time_controller/simulated_time_controller.cc224
-rw-r--r--third_party/libwebrtc/test/time_controller/simulated_time_controller.h162
-rw-r--r--third_party/libwebrtc/test/time_controller/simulated_time_controller_unittest.cc149
-rw-r--r--third_party/libwebrtc/test/time_controller/time_controller_conformance_test.cc181
14 files changed, 1613 insertions, 0 deletions
diff --git a/third_party/libwebrtc/test/time_controller/BUILD.gn b/third_party/libwebrtc/test/time_controller/BUILD.gn
new file mode 100644
index 0000000000..b4b368a42a
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/BUILD.gn
@@ -0,0 +1,70 @@
+# Copyright (c) 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.
+
+import("../../webrtc.gni")
+
+rtc_library("time_controller") {
+ testonly = true
+ sources = [
+ "external_time_controller.cc",
+ "external_time_controller.h",
+ "real_time_controller.cc",
+ "real_time_controller.h",
+ "simulated_task_queue.cc",
+ "simulated_task_queue.h",
+ "simulated_thread.cc",
+ "simulated_thread.h",
+ "simulated_time_controller.cc",
+ "simulated_time_controller.h",
+ ]
+
+ deps = [
+ "../../api:sequence_checker",
+ "../../api:time_controller",
+ "../../api/task_queue",
+ "../../api/task_queue:default_task_queue_factory",
+ "../../api/units:time_delta",
+ "../../api/units:timestamp",
+ "../../rtc_base:checks",
+ "../../rtc_base:null_socket_server",
+ "../../rtc_base:platform_thread_types",
+ "../../rtc_base:rtc_base_tests_utils",
+ "../../rtc_base:rtc_event",
+ "../../rtc_base/synchronization:mutex",
+ "../../rtc_base/synchronization:yield_policy",
+ "../../system_wrappers",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/functional:any_invocable",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("time_controller_unittests") {
+ testonly = true
+ sources = [
+ "external_time_controller_unittest.cc",
+ "simulated_time_controller_unittest.cc",
+ "time_controller_conformance_test.cc",
+ ]
+ deps = [
+ ":time_controller",
+ "../:test_support",
+ "../../api:time_controller",
+ "../../api/units:time_delta",
+ "../../rtc_base:macromagic",
+ "../../rtc_base:rtc_event",
+ "../../rtc_base:rtc_task_queue",
+ "../../rtc_base:task_queue_for_test",
+ "../../rtc_base:threading",
+ "../../rtc_base/synchronization:mutex",
+ "../../rtc_base/task_utils:repeating_task",
+ ]
+ }
+}
diff --git a/third_party/libwebrtc/test/time_controller/external_time_controller.cc b/third_party/libwebrtc/test/time_controller/external_time_controller.cc
new file mode 100644
index 0000000000..f652eb686c
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/external_time_controller.cc
@@ -0,0 +1,134 @@
+/*
+ * 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/time_controller/external_time_controller.h"
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <utility>
+
+#include "absl/functional/any_invocable.h"
+#include "api/task_queue/task_queue_base.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/synchronization/yield_policy.h"
+#include "test/time_controller/simulated_time_controller.h"
+
+namespace webrtc {
+
+// Wraps a TaskQueue so that it can reschedule the time controller whenever
+// an external call schedules a new task.
+class ExternalTimeController::TaskQueueWrapper : public TaskQueueBase {
+ public:
+ TaskQueueWrapper(ExternalTimeController* parent,
+ std::unique_ptr<TaskQueueBase, TaskQueueDeleter> base)
+ : parent_(parent), base_(std::move(base)) {}
+
+ void PostTask(absl::AnyInvocable<void() &&> task) override {
+ parent_->UpdateTime();
+ base_->PostTask(TaskWrapper(std::move(task)));
+ parent_->ScheduleNext();
+ }
+
+ void PostDelayedTask(absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) override {
+ parent_->UpdateTime();
+ base_->PostDelayedTask(TaskWrapper(std::move(task)), delay);
+ parent_->ScheduleNext();
+ }
+
+ void PostDelayedHighPrecisionTask(absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) override {
+ parent_->UpdateTime();
+ base_->PostDelayedHighPrecisionTask(TaskWrapper(std::move(task)), delay);
+ parent_->ScheduleNext();
+ }
+
+ void Delete() override { delete this; }
+
+ private:
+ absl::AnyInvocable<void() &&> TaskWrapper(
+ absl::AnyInvocable<void() &&> task) {
+ return [task = std::move(task), this]() mutable {
+ CurrentTaskQueueSetter current(this);
+ std::move(task)();
+ };
+ }
+
+ ExternalTimeController* const parent_;
+ std::unique_ptr<TaskQueueBase, TaskQueueDeleter> base_;
+};
+
+ExternalTimeController::ExternalTimeController(ControlledAlarmClock* alarm)
+ : alarm_(alarm),
+ impl_(alarm_->GetClock()->CurrentTime()),
+ yield_policy_(&impl_) {
+ global_clock_.SetTime(alarm_->GetClock()->CurrentTime());
+ alarm_->SetCallback([this] { Run(); });
+}
+
+Clock* ExternalTimeController::GetClock() {
+ return alarm_->GetClock();
+}
+
+TaskQueueFactory* ExternalTimeController::GetTaskQueueFactory() {
+ return this;
+}
+
+void ExternalTimeController::AdvanceTime(TimeDelta duration) {
+ alarm_->Sleep(duration);
+}
+
+std::unique_ptr<rtc::Thread> ExternalTimeController::CreateThread(
+ const std::string& name,
+ std::unique_ptr<rtc::SocketServer> socket_server) {
+ RTC_DCHECK_NOTREACHED();
+ return nullptr;
+}
+
+rtc::Thread* ExternalTimeController::GetMainThread() {
+ RTC_DCHECK_NOTREACHED();
+ return nullptr;
+}
+
+std::unique_ptr<TaskQueueBase, TaskQueueDeleter>
+ExternalTimeController::CreateTaskQueue(
+ absl::string_view name,
+ TaskQueueFactory::Priority priority) const {
+ return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>(
+ new TaskQueueWrapper(const_cast<ExternalTimeController*>(this),
+ impl_.CreateTaskQueue(name, priority)));
+}
+
+void ExternalTimeController::Run() {
+ rtc::ScopedYieldPolicy yield_policy(&impl_);
+ UpdateTime();
+ impl_.RunReadyRunners();
+ ScheduleNext();
+}
+
+void ExternalTimeController::UpdateTime() {
+ Timestamp now = alarm_->GetClock()->CurrentTime();
+ impl_.AdvanceTime(now);
+ global_clock_.SetTime(now);
+}
+
+void ExternalTimeController::ScheduleNext() {
+ RTC_DCHECK_EQ(impl_.CurrentTime(), alarm_->GetClock()->CurrentTime());
+ TimeDelta delay =
+ std::max(impl_.NextRunTime() - impl_.CurrentTime(), TimeDelta::Zero());
+ if (delay.IsFinite()) {
+ alarm_->ScheduleAlarmAt(alarm_->GetClock()->CurrentTime() + delay);
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/test/time_controller/external_time_controller.h b/third_party/libwebrtc/test/time_controller/external_time_controller.h
new file mode 100644
index 0000000000..a67f2557b4
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/external_time_controller.h
@@ -0,0 +1,69 @@
+/*
+ * 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_TIME_CONTROLLER_EXTERNAL_TIME_CONTROLLER_H_
+#define TEST_TIME_CONTROLLER_EXTERNAL_TIME_CONTROLLER_H_
+
+#include <functional>
+#include <memory>
+
+#include "absl/strings/string_view.h"
+#include "api/task_queue/task_queue_base.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "api/test/time_controller.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "system_wrappers/include/clock.h"
+#include "test/time_controller/simulated_time_controller.h"
+
+namespace webrtc {
+
+// TimeController implementation built on an external controlled alarm.
+// This implementation is used to delegate scheduling and execution to an
+// external run loop.
+class ExternalTimeController : public TimeController, public TaskQueueFactory {
+ public:
+ explicit ExternalTimeController(ControlledAlarmClock* alarm);
+
+ // Implementation of TimeController.
+ Clock* GetClock() override;
+ TaskQueueFactory* GetTaskQueueFactory() override;
+ void AdvanceTime(TimeDelta duration) override;
+ std::unique_ptr<rtc::Thread> CreateThread(
+ const std::string& name,
+ std::unique_ptr<rtc::SocketServer> socket_server) override;
+ rtc::Thread* GetMainThread() override;
+
+ // Implementation of TaskQueueFactory.
+ std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
+ absl::string_view name,
+ TaskQueueFactory::Priority priority) const override;
+
+ private:
+ class TaskQueueWrapper;
+
+ // Executes any tasks scheduled at or before the current time. May call
+ // `ScheduleNext` to schedule the next call to `Run`.
+ void Run();
+
+ void UpdateTime();
+ void ScheduleNext();
+
+ ControlledAlarmClock* alarm_;
+ sim_time_impl::SimulatedTimeControllerImpl impl_;
+ rtc::ScopedYieldPolicy yield_policy_;
+
+ // Overrides the global rtc::Clock to ensure that it reports the same times as
+ // the time controller.
+ rtc::ScopedBaseFakeClock global_clock_;
+};
+
+} // namespace webrtc
+
+#endif // TEST_TIME_CONTROLLER_EXTERNAL_TIME_CONTROLLER_H_
diff --git a/third_party/libwebrtc/test/time_controller/external_time_controller_unittest.cc b/third_party/libwebrtc/test/time_controller/external_time_controller_unittest.cc
new file mode 100644
index 0000000000..13d63fe8ed
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/external_time_controller_unittest.cc
@@ -0,0 +1,179 @@
+/*
+ * 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/time_controller/external_time_controller.h"
+
+#include <atomic>
+#include <memory>
+#include <utility>
+
+#include "rtc_base/event.h"
+#include "rtc_base/task_queue.h"
+#include "rtc_base/task_utils/repeating_task.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+// NOTE: Since these tests rely on real time behavior, they will be flaky
+// if run on heavily loaded systems.
+namespace webrtc {
+namespace {
+using ::testing::AtLeast;
+using ::testing::Invoke;
+using ::testing::MockFunction;
+using ::testing::NiceMock;
+using ::testing::Return;
+constexpr Timestamp kStartTime = Timestamp::Seconds(1000);
+
+class FakeAlarm : public ControlledAlarmClock {
+ public:
+ explicit FakeAlarm(Timestamp start_time);
+
+ Clock* GetClock() override;
+ bool ScheduleAlarmAt(Timestamp deadline) override;
+ void SetCallback(std::function<void()> callback) override;
+ void Sleep(TimeDelta duration) override;
+
+ private:
+ SimulatedClock clock_;
+ Timestamp deadline_;
+ std::function<void()> callback_;
+};
+
+FakeAlarm::FakeAlarm(Timestamp start_time)
+ : clock_(start_time),
+ deadline_(Timestamp::PlusInfinity()),
+ callback_([] {}) {}
+
+Clock* FakeAlarm::GetClock() {
+ return &clock_;
+}
+
+bool FakeAlarm::ScheduleAlarmAt(Timestamp deadline) {
+ if (deadline < deadline_) {
+ deadline_ = deadline;
+ return true;
+ }
+ return false;
+}
+
+void FakeAlarm::SetCallback(std::function<void()> callback) {
+ callback_ = callback;
+}
+
+void FakeAlarm::Sleep(TimeDelta duration) {
+ Timestamp end_time = clock_.CurrentTime() + duration;
+
+ while (deadline_ <= end_time) {
+ clock_.AdvanceTime(deadline_ - clock_.CurrentTime());
+ deadline_ = Timestamp::PlusInfinity();
+ callback_();
+ }
+
+ clock_.AdvanceTime(end_time - clock_.CurrentTime());
+}
+
+} // namespace
+
+TEST(ExternalTimeControllerTest, TaskIsStoppedOnStop) {
+ const TimeDelta kShortInterval = TimeDelta::Millis(5);
+ const TimeDelta kLongInterval = TimeDelta::Millis(20);
+ const int kShortIntervalCount = 4;
+ const int kMargin = 1;
+ FakeAlarm alarm(kStartTime);
+ ExternalTimeController time_simulation(&alarm);
+ rtc::TaskQueue task_queue(
+ time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
+ "TestQueue", TaskQueueFactory::Priority::NORMAL));
+ std::atomic_int counter(0);
+ auto handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] {
+ if (++counter >= kShortIntervalCount)
+ return kLongInterval;
+ return kShortInterval;
+ });
+ // Sleep long enough to go through the initial phase.
+ time_simulation.AdvanceTime(kShortInterval * (kShortIntervalCount + kMargin));
+ EXPECT_EQ(counter.load(), kShortIntervalCount);
+
+ task_queue.PostTask(
+ [handle = std::move(handle)]() mutable { handle.Stop(); });
+
+ // Sleep long enough that the task would run at least once more if not
+ // stopped.
+ time_simulation.AdvanceTime(kLongInterval * 2);
+ EXPECT_EQ(counter.load(), kShortIntervalCount);
+}
+
+TEST(ExternalTimeControllerTest, TaskCanStopItself) {
+ std::atomic_int counter(0);
+ FakeAlarm alarm(kStartTime);
+ ExternalTimeController time_simulation(&alarm);
+ rtc::TaskQueue task_queue(
+ time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
+ "TestQueue", TaskQueueFactory::Priority::NORMAL));
+
+ RepeatingTaskHandle handle;
+ task_queue.PostTask([&] {
+ handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] {
+ ++counter;
+ handle.Stop();
+ return TimeDelta::Millis(2);
+ });
+ });
+ time_simulation.AdvanceTime(TimeDelta::Millis(10));
+ EXPECT_EQ(counter.load(), 1);
+}
+
+TEST(ExternalTimeControllerTest, YieldForTask) {
+ FakeAlarm alarm(kStartTime);
+ ExternalTimeController time_simulation(&alarm);
+
+ rtc::TaskQueue task_queue(
+ time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
+ "TestQueue", TaskQueueFactory::Priority::NORMAL));
+
+ rtc::Event event;
+ task_queue.PostTask([&] { event.Set(); });
+ EXPECT_TRUE(event.Wait(TimeDelta::Millis(200)));
+}
+
+TEST(ExternalTimeControllerTest, TasksYieldToEachOther) {
+ FakeAlarm alarm(kStartTime);
+ ExternalTimeController time_simulation(&alarm);
+
+ rtc::TaskQueue task_queue(
+ time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
+ "TestQueue", TaskQueueFactory::Priority::NORMAL));
+ rtc::TaskQueue other_queue(
+ time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
+ "OtherQueue", TaskQueueFactory::Priority::NORMAL));
+
+ task_queue.PostTask([&] {
+ rtc::Event event;
+ other_queue.PostTask([&] { event.Set(); });
+ EXPECT_TRUE(event.Wait(TimeDelta::Millis(200)));
+ });
+
+ time_simulation.AdvanceTime(TimeDelta::Millis(300));
+}
+
+TEST(ExternalTimeControllerTest, CurrentTaskQueue) {
+ FakeAlarm alarm(kStartTime);
+ ExternalTimeController time_simulation(&alarm);
+
+ rtc::TaskQueue task_queue(
+ time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
+ "TestQueue", TaskQueueFactory::Priority::NORMAL));
+
+ task_queue.PostTask([&] { EXPECT_TRUE(task_queue.IsCurrent()); });
+
+ time_simulation.AdvanceTime(TimeDelta::Millis(10));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/test/time_controller/real_time_controller.cc b/third_party/libwebrtc/test/time_controller/real_time_controller.cc
new file mode 100644
index 0000000000..7cc750d6d4
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/real_time_controller.cc
@@ -0,0 +1,66 @@
+/*
+ * 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/time_controller/real_time_controller.h"
+
+#include "api/task_queue/default_task_queue_factory.h"
+#include "rtc_base/null_socket_server.h"
+
+namespace webrtc {
+namespace {
+class MainThread : public rtc::Thread {
+ public:
+ MainThread()
+ : Thread(std::make_unique<rtc::NullSocketServer>(), false),
+ current_setter_(this) {
+ DoInit();
+ }
+ ~MainThread() {
+ Stop();
+ DoDestroy();
+ }
+
+ private:
+ CurrentThreadSetter current_setter_;
+};
+} // namespace
+RealTimeController::RealTimeController()
+ : task_queue_factory_(CreateDefaultTaskQueueFactory()),
+ main_thread_(std::make_unique<MainThread>()) {
+ main_thread_->SetName("Main", this);
+}
+
+Clock* RealTimeController::GetClock() {
+ return Clock::GetRealTimeClock();
+}
+
+TaskQueueFactory* RealTimeController::GetTaskQueueFactory() {
+ return task_queue_factory_.get();
+}
+
+std::unique_ptr<rtc::Thread> RealTimeController::CreateThread(
+ const std::string& name,
+ std::unique_ptr<rtc::SocketServer> socket_server) {
+ if (!socket_server)
+ socket_server = std::make_unique<rtc::NullSocketServer>();
+ auto res = std::make_unique<rtc::Thread>(std::move(socket_server));
+ res->SetName(name, nullptr);
+ res->Start();
+ return res;
+}
+
+rtc::Thread* RealTimeController::GetMainThread() {
+ return main_thread_.get();
+}
+
+void RealTimeController::AdvanceTime(TimeDelta duration) {
+ main_thread_->ProcessMessages(duration.ms());
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/test/time_controller/real_time_controller.h b/third_party/libwebrtc/test/time_controller/real_time_controller.h
new file mode 100644
index 0000000000..5f02eaf85f
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/real_time_controller.h
@@ -0,0 +1,41 @@
+/*
+ * 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_TIME_CONTROLLER_REAL_TIME_CONTROLLER_H_
+#define TEST_TIME_CONTROLLER_REAL_TIME_CONTROLLER_H_
+
+#include <functional>
+#include <memory>
+
+#include "api/task_queue/task_queue_factory.h"
+#include "api/test/time_controller.h"
+#include "api/units/time_delta.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+class RealTimeController : public TimeController {
+ public:
+ RealTimeController();
+
+ Clock* GetClock() override;
+ TaskQueueFactory* GetTaskQueueFactory() override;
+ std::unique_ptr<rtc::Thread> CreateThread(
+ const std::string& name,
+ std::unique_ptr<rtc::SocketServer> socket_server) override;
+ rtc::Thread* GetMainThread() override;
+ void AdvanceTime(TimeDelta duration) override;
+
+ private:
+ const std::unique_ptr<TaskQueueFactory> task_queue_factory_;
+ const std::unique_ptr<rtc::Thread> main_thread_;
+};
+
+} // namespace webrtc
+
+#endif // TEST_TIME_CONTROLLER_REAL_TIME_CONTROLLER_H_
diff --git a/third_party/libwebrtc/test/time_controller/simulated_task_queue.cc b/third_party/libwebrtc/test/time_controller/simulated_task_queue.cc
new file mode 100644
index 0000000000..3c26721845
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/simulated_task_queue.cc
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2020 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/time_controller/simulated_task_queue.h"
+
+#include <algorithm>
+#include <utility>
+
+namespace webrtc {
+
+SimulatedTaskQueue::SimulatedTaskQueue(
+ sim_time_impl::SimulatedTimeControllerImpl* handler,
+ absl::string_view name)
+ : handler_(handler), name_(new char[name.size()]) {
+ std::copy_n(name.begin(), name.size(), name_);
+}
+
+SimulatedTaskQueue::~SimulatedTaskQueue() {
+ handler_->Unregister(this);
+ delete[] name_;
+}
+
+void SimulatedTaskQueue::Delete() {
+ // Need to destroy the tasks outside of the lock because task destruction
+ // can lead to re-entry in SimulatedTaskQueue via custom destructors.
+ std::deque<absl::AnyInvocable<void() &&>> ready_tasks;
+ std::map<Timestamp, std::vector<absl::AnyInvocable<void() &&>>> delayed_tasks;
+ {
+ MutexLock lock(&lock_);
+ ready_tasks_.swap(ready_tasks);
+ delayed_tasks_.swap(delayed_tasks);
+ }
+ ready_tasks.clear();
+ delayed_tasks.clear();
+ delete this;
+}
+
+void SimulatedTaskQueue::RunReady(Timestamp at_time) {
+ MutexLock lock(&lock_);
+ for (auto it = delayed_tasks_.begin();
+ it != delayed_tasks_.end() && it->first <= at_time;
+ it = delayed_tasks_.erase(it)) {
+ for (auto& task : it->second) {
+ ready_tasks_.push_back(std::move(task));
+ }
+ }
+ CurrentTaskQueueSetter set_current(this);
+ while (!ready_tasks_.empty()) {
+ absl::AnyInvocable<void()&&> ready = std::move(ready_tasks_.front());
+ ready_tasks_.pop_front();
+ lock_.Unlock();
+ std::move(ready)();
+ ready = nullptr;
+ lock_.Lock();
+ }
+ if (!delayed_tasks_.empty()) {
+ next_run_time_ = delayed_tasks_.begin()->first;
+ } else {
+ next_run_time_ = Timestamp::PlusInfinity();
+ }
+}
+
+void SimulatedTaskQueue::PostTask(absl::AnyInvocable<void() &&> task) {
+ MutexLock lock(&lock_);
+ ready_tasks_.push_back(std::move(task));
+ next_run_time_ = Timestamp::MinusInfinity();
+}
+
+void SimulatedTaskQueue::PostDelayedTask(absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) {
+ PostDelayedHighPrecisionTask(std::move(task), delay);
+}
+
+void SimulatedTaskQueue::PostDelayedHighPrecisionTask(
+ absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) {
+ MutexLock lock(&lock_);
+ Timestamp target_time = handler_->CurrentTime() + delay;
+ delayed_tasks_[target_time].push_back(std::move(task));
+ next_run_time_ = std::min(next_run_time_, target_time);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/test/time_controller/simulated_task_queue.h b/third_party/libwebrtc/test/time_controller/simulated_task_queue.h
new file mode 100644
index 0000000000..3c55f15dde
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/simulated_task_queue.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020 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_TIME_CONTROLLER_SIMULATED_TASK_QUEUE_H_
+#define TEST_TIME_CONTROLLER_SIMULATED_TASK_QUEUE_H_
+
+#include <deque>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "absl/functional/any_invocable.h"
+#include "api/units/time_delta.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "test/time_controller/simulated_time_controller.h"
+
+namespace webrtc {
+
+class SimulatedTaskQueue : public TaskQueueBase,
+ public sim_time_impl::SimulatedSequenceRunner {
+ public:
+ SimulatedTaskQueue(sim_time_impl::SimulatedTimeControllerImpl* handler,
+ absl::string_view name);
+
+ ~SimulatedTaskQueue();
+
+ void RunReady(Timestamp at_time) override;
+
+ Timestamp GetNextRunTime() const override {
+ MutexLock lock(&lock_);
+ return next_run_time_;
+ }
+ TaskQueueBase* GetAsTaskQueue() override { return this; }
+
+ // TaskQueueBase interface
+ void Delete() override;
+ void PostTask(absl::AnyInvocable<void() &&> task) override;
+ void PostDelayedTask(absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) override;
+ void PostDelayedHighPrecisionTask(absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) override;
+
+ private:
+ sim_time_impl::SimulatedTimeControllerImpl* const handler_;
+ // Using char* to be debugger friendly.
+ char* name_;
+
+ mutable Mutex lock_;
+
+ std::deque<absl::AnyInvocable<void() &&>> ready_tasks_ RTC_GUARDED_BY(lock_);
+ std::map<Timestamp, std::vector<absl::AnyInvocable<void() &&>>> delayed_tasks_
+ RTC_GUARDED_BY(lock_);
+
+ Timestamp next_run_time_ RTC_GUARDED_BY(lock_) = Timestamp::PlusInfinity();
+};
+
+} // namespace webrtc
+
+#endif // TEST_TIME_CONTROLLER_SIMULATED_TASK_QUEUE_H_
diff --git a/third_party/libwebrtc/test/time_controller/simulated_thread.cc b/third_party/libwebrtc/test/time_controller/simulated_thread.cc
new file mode 100644
index 0000000000..bdd1096327
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/simulated_thread.cc
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2020 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/time_controller/simulated_thread.h"
+
+#include <algorithm>
+#include <utility>
+
+namespace webrtc {
+namespace {
+
+// A socket server that does nothing. It's different from NullSocketServer in
+// that it does allow sleep/wakeup. This avoids usage of an Event instance which
+// otherwise would cause issues with the simulated Yeild behavior.
+class DummySocketServer : public rtc::SocketServer {
+ public:
+ rtc::Socket* CreateSocket(int family, int type) override {
+ RTC_DCHECK_NOTREACHED();
+ return nullptr;
+ }
+ bool Wait(TimeDelta max_wait_duration, bool process_io) override {
+ RTC_CHECK(max_wait_duration.IsZero());
+ return true;
+ }
+ void WakeUp() override {}
+};
+
+} // namespace
+
+SimulatedThread::SimulatedThread(
+ sim_time_impl::SimulatedTimeControllerImpl* handler,
+ absl::string_view name,
+ std::unique_ptr<rtc::SocketServer> socket_server)
+ : rtc::Thread(socket_server ? std::move(socket_server)
+ : std::make_unique<DummySocketServer>()),
+ handler_(handler),
+ name_(new char[name.size()]) {
+ std::copy_n(name.begin(), name.size(), name_);
+}
+
+SimulatedThread::~SimulatedThread() {
+ handler_->Unregister(this);
+ delete[] name_;
+}
+
+void SimulatedThread::RunReady(Timestamp at_time) {
+ CurrentThreadSetter set_current(this);
+ ProcessMessages(0);
+ int delay_ms = GetDelay();
+ MutexLock lock(&lock_);
+ if (delay_ms == kForever) {
+ next_run_time_ = Timestamp::PlusInfinity();
+ } else {
+ next_run_time_ = at_time + TimeDelta::Millis(delay_ms);
+ }
+}
+
+void SimulatedThread::BlockingCall(rtc::FunctionView<void()> functor) {
+ if (IsQuitting())
+ return;
+
+ if (IsCurrent()) {
+ functor();
+ } else {
+ TaskQueueBase* yielding_from = TaskQueueBase::Current();
+ handler_->StartYield(yielding_from);
+ RunReady(Timestamp::MinusInfinity());
+ CurrentThreadSetter set_current(this);
+ functor();
+ handler_->StopYield(yielding_from);
+ }
+}
+
+void SimulatedThread::PostTask(absl::AnyInvocable<void() &&> task) {
+ rtc::Thread::PostTask(std::move(task));
+ MutexLock lock(&lock_);
+ next_run_time_ = Timestamp::MinusInfinity();
+}
+
+void SimulatedThread::PostDelayedTask(absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) {
+ rtc::Thread::PostDelayedTask(std::move(task), delay);
+ MutexLock lock(&lock_);
+ next_run_time_ =
+ std::min(next_run_time_, Timestamp::Millis(rtc::TimeMillis()) + delay);
+}
+
+void SimulatedThread::PostDelayedHighPrecisionTask(
+ absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) {
+ rtc::Thread::PostDelayedHighPrecisionTask(std::move(task), delay);
+ MutexLock lock(&lock_);
+ next_run_time_ =
+ std::min(next_run_time_, Timestamp::Millis(rtc::TimeMillis()) + delay);
+}
+
+void SimulatedThread::Stop() {
+ Thread::Quit();
+}
+
+SimulatedMainThread::SimulatedMainThread(
+ sim_time_impl::SimulatedTimeControllerImpl* handler)
+ : SimulatedThread(handler, "main", nullptr), current_setter_(this) {}
+
+SimulatedMainThread::~SimulatedMainThread() {
+ // Removes pending tasks in case they keep shared pointer references to
+ // objects whose destructor expects to run before the Thread destructor.
+ Stop();
+ DoDestroy();
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/test/time_controller/simulated_thread.h b/third_party/libwebrtc/test/time_controller/simulated_thread.h
new file mode 100644
index 0000000000..e8e08c5000
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/simulated_thread.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 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_TIME_CONTROLLER_SIMULATED_THREAD_H_
+#define TEST_TIME_CONTROLLER_SIMULATED_THREAD_H_
+
+#include <memory>
+
+#include "rtc_base/synchronization/mutex.h"
+#include "test/time_controller/simulated_time_controller.h"
+
+namespace webrtc {
+
+class SimulatedThread : public rtc::Thread,
+ public sim_time_impl::SimulatedSequenceRunner {
+ public:
+ using CurrentThreadSetter = CurrentThreadSetter;
+ SimulatedThread(sim_time_impl::SimulatedTimeControllerImpl* handler,
+ absl::string_view name,
+ std::unique_ptr<rtc::SocketServer> socket_server);
+ ~SimulatedThread() override;
+
+ void RunReady(Timestamp at_time) override;
+
+ Timestamp GetNextRunTime() const override {
+ MutexLock lock(&lock_);
+ return next_run_time_;
+ }
+
+ TaskQueueBase* GetAsTaskQueue() override { return this; }
+
+ // Thread interface
+ void BlockingCall(rtc::FunctionView<void()> functor) override;
+ void PostTask(absl::AnyInvocable<void() &&> task) override;
+ void PostDelayedTask(absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) override;
+ void PostDelayedHighPrecisionTask(absl::AnyInvocable<void() &&> task,
+ TimeDelta delay) override;
+
+ void Stop() override;
+
+ private:
+ sim_time_impl::SimulatedTimeControllerImpl* const handler_;
+ // Using char* to be debugger friendly.
+ char* name_;
+ mutable Mutex lock_;
+ Timestamp next_run_time_ RTC_GUARDED_BY(lock_) = Timestamp::PlusInfinity();
+};
+
+class SimulatedMainThread : public SimulatedThread {
+ public:
+ explicit SimulatedMainThread(
+ sim_time_impl::SimulatedTimeControllerImpl* handler);
+ ~SimulatedMainThread();
+
+ private:
+ CurrentThreadSetter current_setter_;
+};
+} // namespace webrtc
+#endif // TEST_TIME_CONTROLLER_SIMULATED_THREAD_H_
diff --git a/third_party/libwebrtc/test/time_controller/simulated_time_controller.cc b/third_party/libwebrtc/test/time_controller/simulated_time_controller.cc
new file mode 100644
index 0000000000..1ed2b30dc8
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/simulated_time_controller.cc
@@ -0,0 +1,224 @@
+/*
+ * 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/time_controller/simulated_time_controller.h"
+
+#include <algorithm>
+#include <deque>
+#include <list>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "test/time_controller/simulated_task_queue.h"
+#include "test/time_controller/simulated_thread.h"
+
+namespace webrtc {
+namespace {
+// Helper function to remove from a std container by value.
+template <class C>
+bool RemoveByValue(C* vec, typename C::value_type val) {
+ auto it = std::find(vec->begin(), vec->end(), val);
+ if (it == vec->end())
+ return false;
+ vec->erase(it);
+ return true;
+}
+} // namespace
+
+namespace sim_time_impl {
+
+SimulatedTimeControllerImpl::SimulatedTimeControllerImpl(Timestamp start_time)
+ : thread_id_(rtc::CurrentThreadId()), current_time_(start_time) {}
+
+SimulatedTimeControllerImpl::~SimulatedTimeControllerImpl() = default;
+
+std::unique_ptr<TaskQueueBase, TaskQueueDeleter>
+SimulatedTimeControllerImpl::CreateTaskQueue(
+ absl::string_view name,
+ TaskQueueFactory::Priority priority) const {
+ // TODO(srte): Remove the const cast when the interface is made mutable.
+ auto mutable_this = const_cast<SimulatedTimeControllerImpl*>(this);
+ auto task_queue = std::unique_ptr<SimulatedTaskQueue, TaskQueueDeleter>(
+ new SimulatedTaskQueue(mutable_this, name));
+ mutable_this->Register(task_queue.get());
+ return task_queue;
+}
+
+std::unique_ptr<rtc::Thread> SimulatedTimeControllerImpl::CreateThread(
+ const std::string& name,
+ std::unique_ptr<rtc::SocketServer> socket_server) {
+ auto thread =
+ std::make_unique<SimulatedThread>(this, name, std::move(socket_server));
+ Register(thread.get());
+ return thread;
+}
+
+void SimulatedTimeControllerImpl::YieldExecution() {
+ if (rtc::CurrentThreadId() == thread_id_) {
+ TaskQueueBase* yielding_from = TaskQueueBase::Current();
+ // Since we might continue execution on a process thread, we should reset
+ // the thread local task queue reference. This ensures that thread checkers
+ // won't think we are executing on the yielding task queue. It also ensure
+ // that TaskQueueBase::Current() won't return the yielding task queue.
+ TokenTaskQueue::CurrentTaskQueueSetter reset_queue(nullptr);
+ // When we yield, we don't want to risk executing further tasks on the
+ // currently executing task queue. If there's a ready task that also yields,
+ // it's added to this set as well and only tasks on the remaining task
+ // queues are executed.
+ auto inserted = yielded_.insert(yielding_from);
+ RTC_DCHECK(inserted.second);
+ RunReadyRunners();
+ yielded_.erase(inserted.first);
+ }
+}
+
+void SimulatedTimeControllerImpl::RunReadyRunners() {
+ // Using a dummy thread rather than nullptr to avoid implicit thread creation
+ // by Thread::Current().
+ SimulatedThread::CurrentThreadSetter set_current(dummy_thread_.get());
+ MutexLock lock(&lock_);
+ RTC_DCHECK_EQ(rtc::CurrentThreadId(), thread_id_);
+ Timestamp current_time = CurrentTime();
+ // Clearing `ready_runners_` in case this is a recursive call:
+ // RunReadyRunners -> Run -> Event::Wait -> Yield ->RunReadyRunners
+ ready_runners_.clear();
+
+ // We repeat until we have no ready left to handle tasks posted by ready
+ // runners.
+ while (true) {
+ for (auto* runner : runners_) {
+ if (yielded_.find(runner->GetAsTaskQueue()) == yielded_.end() &&
+ runner->GetNextRunTime() <= current_time) {
+ ready_runners_.push_back(runner);
+ }
+ }
+ if (ready_runners_.empty())
+ break;
+ while (!ready_runners_.empty()) {
+ auto* runner = ready_runners_.front();
+ ready_runners_.pop_front();
+ lock_.Unlock();
+ // Note that the RunReady function might indirectly cause a call to
+ // Unregister() which will grab `lock_` again to remove items from
+ // `ready_runners_`.
+ runner->RunReady(current_time);
+ lock_.Lock();
+ }
+ }
+}
+
+Timestamp SimulatedTimeControllerImpl::CurrentTime() const {
+ MutexLock lock(&time_lock_);
+ return current_time_;
+}
+
+Timestamp SimulatedTimeControllerImpl::NextRunTime() const {
+ Timestamp current_time = CurrentTime();
+ Timestamp next_time = Timestamp::PlusInfinity();
+ MutexLock lock(&lock_);
+ for (auto* runner : runners_) {
+ Timestamp next_run_time = runner->GetNextRunTime();
+ if (next_run_time <= current_time)
+ return current_time;
+ next_time = std::min(next_time, next_run_time);
+ }
+ return next_time;
+}
+
+void SimulatedTimeControllerImpl::AdvanceTime(Timestamp target_time) {
+ MutexLock time_lock(&time_lock_);
+ RTC_DCHECK_GE(target_time, current_time_);
+ current_time_ = target_time;
+}
+
+void SimulatedTimeControllerImpl::Register(SimulatedSequenceRunner* runner) {
+ MutexLock lock(&lock_);
+ runners_.push_back(runner);
+}
+
+void SimulatedTimeControllerImpl::Unregister(SimulatedSequenceRunner* runner) {
+ MutexLock lock(&lock_);
+ bool removed = RemoveByValue(&runners_, runner);
+ RTC_CHECK(removed);
+ RemoveByValue(&ready_runners_, runner);
+}
+
+void SimulatedTimeControllerImpl::StartYield(TaskQueueBase* yielding_from) {
+ auto inserted = yielded_.insert(yielding_from);
+ RTC_DCHECK(inserted.second);
+}
+
+void SimulatedTimeControllerImpl::StopYield(TaskQueueBase* yielding_from) {
+ yielded_.erase(yielding_from);
+}
+
+} // namespace sim_time_impl
+
+GlobalSimulatedTimeController::GlobalSimulatedTimeController(
+ Timestamp start_time)
+ : sim_clock_(start_time.us()), impl_(start_time), yield_policy_(&impl_) {
+ global_clock_.SetTime(start_time);
+ auto main_thread = std::make_unique<SimulatedMainThread>(&impl_);
+ impl_.Register(main_thread.get());
+ main_thread_ = std::move(main_thread);
+}
+
+GlobalSimulatedTimeController::~GlobalSimulatedTimeController() = default;
+
+Clock* GlobalSimulatedTimeController::GetClock() {
+ return &sim_clock_;
+}
+
+TaskQueueFactory* GlobalSimulatedTimeController::GetTaskQueueFactory() {
+ return &impl_;
+}
+
+std::unique_ptr<rtc::Thread> GlobalSimulatedTimeController::CreateThread(
+ const std::string& name,
+ std::unique_ptr<rtc::SocketServer> socket_server) {
+ return impl_.CreateThread(name, std::move(socket_server));
+}
+
+rtc::Thread* GlobalSimulatedTimeController::GetMainThread() {
+ return main_thread_.get();
+}
+
+void GlobalSimulatedTimeController::AdvanceTime(TimeDelta duration) {
+ rtc::ScopedYieldPolicy yield_policy(&impl_);
+ Timestamp current_time = impl_.CurrentTime();
+ Timestamp target_time = current_time + duration;
+ RTC_DCHECK_EQ(current_time.us(), rtc::TimeMicros());
+ while (current_time < target_time) {
+ impl_.RunReadyRunners();
+ Timestamp next_time = std::min(impl_.NextRunTime(), target_time);
+ impl_.AdvanceTime(next_time);
+ auto delta = next_time - current_time;
+ current_time = next_time;
+ sim_clock_.AdvanceTimeMicroseconds(delta.us());
+ global_clock_.AdvanceTime(delta);
+ }
+ // After time has been simulated up until `target_time` we also need to run
+ // tasks meant to be executed at `target_time`.
+ impl_.RunReadyRunners();
+}
+
+void GlobalSimulatedTimeController::Register(
+ sim_time_impl::SimulatedSequenceRunner* runner) {
+ impl_.Register(runner);
+}
+
+void GlobalSimulatedTimeController::Unregister(
+ sim_time_impl::SimulatedSequenceRunner* runner) {
+ impl_.Unregister(runner);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/test/time_controller/simulated_time_controller.h b/third_party/libwebrtc/test/time_controller/simulated_time_controller.h
new file mode 100644
index 0000000000..121b9171e8
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/simulated_time_controller.h
@@ -0,0 +1,162 @@
+/*
+ * 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_TIME_CONTROLLER_SIMULATED_TIME_CONTROLLER_H_
+#define TEST_TIME_CONTROLLER_SIMULATED_TIME_CONTROLLER_H_
+
+#include <list>
+#include <memory>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/sequence_checker.h"
+#include "api/test/time_controller.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/fake_clock.h"
+#include "rtc_base/platform_thread_types.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/synchronization/yield_policy.h"
+
+namespace webrtc {
+namespace sim_time_impl {
+class SimulatedSequenceRunner {
+ public:
+ virtual ~SimulatedSequenceRunner() = default;
+ // Provides next run time.
+ virtual Timestamp GetNextRunTime() const = 0;
+ // Runs all ready tasks and modules and updates next run time.
+ virtual void RunReady(Timestamp at_time) = 0;
+
+ // All implementations also implements TaskQueueBase in some form, but if we'd
+ // inherit from it in this interface we'd run into issues with double
+ // inheritance. Therefore we simply allow the implementations to provide a
+ // casted pointer to themself.
+ virtual TaskQueueBase* GetAsTaskQueue() = 0;
+};
+
+class SimulatedTimeControllerImpl : public TaskQueueFactory,
+ public rtc::YieldInterface {
+ public:
+ explicit SimulatedTimeControllerImpl(Timestamp start_time);
+ ~SimulatedTimeControllerImpl() override;
+
+ std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
+ absl::string_view name,
+ Priority priority) const RTC_LOCKS_EXCLUDED(time_lock_) override;
+
+ // Implements the YieldInterface by running ready tasks on all task queues,
+ // except that if this method is called from a task, the task queue running
+ // that task is skipped.
+ void YieldExecution() RTC_LOCKS_EXCLUDED(time_lock_, lock_) override;
+
+ // Create thread using provided `socket_server`.
+ std::unique_ptr<rtc::Thread> CreateThread(
+ const std::string& name,
+ std::unique_ptr<rtc::SocketServer> socket_server)
+ RTC_LOCKS_EXCLUDED(time_lock_, lock_);
+
+ // Runs all runners in `runners_` that has tasks or modules ready for
+ // execution.
+ void RunReadyRunners() RTC_LOCKS_EXCLUDED(time_lock_, lock_);
+ // Return `current_time_`.
+ Timestamp CurrentTime() const RTC_LOCKS_EXCLUDED(time_lock_);
+ // Return min of runner->GetNextRunTime() for runner in `runners_`.
+ Timestamp NextRunTime() const RTC_LOCKS_EXCLUDED(lock_);
+ // Set `current_time_` to `target_time`.
+ void AdvanceTime(Timestamp target_time) RTC_LOCKS_EXCLUDED(time_lock_);
+ // Adds `runner` to `runners_`.
+ void Register(SimulatedSequenceRunner* runner) RTC_LOCKS_EXCLUDED(lock_);
+ // Removes `runner` from `runners_`.
+ void Unregister(SimulatedSequenceRunner* runner) RTC_LOCKS_EXCLUDED(lock_);
+
+ // Indicates that `yielding_from` is not ready to run.
+ void StartYield(TaskQueueBase* yielding_from);
+ // Indicates that processing can be continued on `yielding_from`.
+ void StopYield(TaskQueueBase* yielding_from);
+
+ private:
+ const rtc::PlatformThreadId thread_id_;
+ const std::unique_ptr<rtc::Thread> dummy_thread_ = rtc::Thread::Create();
+ mutable Mutex time_lock_;
+ Timestamp current_time_ RTC_GUARDED_BY(time_lock_);
+ mutable Mutex lock_;
+ std::vector<SimulatedSequenceRunner*> runners_ RTC_GUARDED_BY(lock_);
+ // Used in RunReadyRunners() to keep track of ready runners that are to be
+ // processed in a round robin fashion. the reason it's a member is so that
+ // runners can removed from here by Unregister().
+ std::list<SimulatedSequenceRunner*> ready_runners_ RTC_GUARDED_BY(lock_);
+
+ // Runners on which YieldExecution has been called.
+ std::unordered_set<TaskQueueBase*> yielded_;
+};
+} // namespace sim_time_impl
+
+// Used to satisfy sequence checkers for non task queue sequences.
+class TokenTaskQueue : public TaskQueueBase {
+ public:
+ // Promoted to public
+ using CurrentTaskQueueSetter = TaskQueueBase::CurrentTaskQueueSetter;
+
+ void Delete() override { RTC_DCHECK_NOTREACHED(); }
+ void PostTask(absl::AnyInvocable<void() &&> /*task*/) override {
+ RTC_DCHECK_NOTREACHED();
+ }
+ void PostDelayedTask(absl::AnyInvocable<void() &&> /*task*/,
+ TimeDelta /*delay*/) override {
+ RTC_DCHECK_NOTREACHED();
+ }
+ void PostDelayedHighPrecisionTask(absl::AnyInvocable<void() &&> /*task*/,
+ TimeDelta /*delay*/) override {
+ RTC_DCHECK_NOTREACHED();
+ }
+};
+
+// TimeController implementation using completely simulated time. Task queues
+// and process threads created by this controller will run delayed activities
+// when AdvanceTime() is called. Overrides the global clock backing
+// rtc::TimeMillis() and rtc::TimeMicros(). Note that this is not thread safe
+// since it modifies global state.
+class GlobalSimulatedTimeController : public TimeController {
+ public:
+ explicit GlobalSimulatedTimeController(Timestamp start_time);
+ ~GlobalSimulatedTimeController() override;
+
+ Clock* GetClock() override;
+ TaskQueueFactory* GetTaskQueueFactory() override;
+ std::unique_ptr<rtc::Thread> CreateThread(
+ const std::string& name,
+ std::unique_ptr<rtc::SocketServer> socket_server) override;
+ rtc::Thread* GetMainThread() override;
+
+ void AdvanceTime(TimeDelta duration) override;
+
+ // Makes the simulated time controller aware of a custom
+ // SimulatedSequenceRunner.
+ // TODO(bugs.webrtc.org/11581): remove method once the ModuleRtpRtcpImpl2 unit
+ // test stops using it.
+ void Register(sim_time_impl::SimulatedSequenceRunner* runner);
+ // Removes a previously installed custom SimulatedSequenceRunner from the
+ // simulated time controller.
+ // TODO(bugs.webrtc.org/11581): remove method once the ModuleRtpRtcpImpl2 unit
+ // test stops using it.
+ void Unregister(sim_time_impl::SimulatedSequenceRunner* runner);
+
+ private:
+ rtc::ScopedBaseFakeClock global_clock_;
+ // Provides simulated CurrentNtpInMilliseconds()
+ SimulatedClock sim_clock_;
+ sim_time_impl::SimulatedTimeControllerImpl impl_;
+ rtc::ScopedYieldPolicy yield_policy_;
+ std::unique_ptr<rtc::Thread> main_thread_;
+};
+} // namespace webrtc
+
+#endif // TEST_TIME_CONTROLLER_SIMULATED_TIME_CONTROLLER_H_
diff --git a/third_party/libwebrtc/test/time_controller/simulated_time_controller_unittest.cc b/third_party/libwebrtc/test/time_controller/simulated_time_controller_unittest.cc
new file mode 100644
index 0000000000..1ee592cc7c
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/simulated_time_controller_unittest.cc
@@ -0,0 +1,149 @@
+/*
+ * 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/time_controller/simulated_time_controller.h"
+
+#include <atomic>
+#include <memory>
+
+#include "rtc_base/event.h"
+#include "rtc_base/task_queue.h"
+#include "rtc_base/task_queue_for_test.h"
+#include "rtc_base/task_utils/repeating_task.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+// NOTE: Since these tests rely on real time behavior, they will be flaky
+// if run on heavily loaded systems.
+namespace webrtc {
+namespace {
+using ::testing::AtLeast;
+using ::testing::Invoke;
+using ::testing::MockFunction;
+using ::testing::NiceMock;
+using ::testing::Return;
+constexpr Timestamp kStartTime = Timestamp::Seconds(1000);
+} // namespace
+
+TEST(SimulatedTimeControllerTest, TaskIsStoppedOnStop) {
+ const TimeDelta kShortInterval = TimeDelta::Millis(5);
+ const TimeDelta kLongInterval = TimeDelta::Millis(20);
+ const int kShortIntervalCount = 4;
+ const int kMargin = 1;
+ GlobalSimulatedTimeController time_simulation(kStartTime);
+ rtc::TaskQueue task_queue(
+ time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
+ "TestQueue", TaskQueueFactory::Priority::NORMAL));
+ std::atomic_int counter(0);
+ auto handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] {
+ if (++counter >= kShortIntervalCount)
+ return kLongInterval;
+ return kShortInterval;
+ });
+ // Sleep long enough to go through the initial phase.
+ time_simulation.AdvanceTime(kShortInterval * (kShortIntervalCount + kMargin));
+ EXPECT_EQ(counter.load(), kShortIntervalCount);
+
+ task_queue.PostTask(
+ [handle = std::move(handle)]() mutable { handle.Stop(); });
+
+ // Sleep long enough that the task would run at least once more if not
+ // stopped.
+ time_simulation.AdvanceTime(kLongInterval * 2);
+ EXPECT_EQ(counter.load(), kShortIntervalCount);
+}
+
+TEST(SimulatedTimeControllerTest, TaskCanStopItself) {
+ std::atomic_int counter(0);
+ GlobalSimulatedTimeController time_simulation(kStartTime);
+ rtc::TaskQueue task_queue(
+ time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
+ "TestQueue", TaskQueueFactory::Priority::NORMAL));
+
+ RepeatingTaskHandle handle;
+ task_queue.PostTask([&] {
+ handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] {
+ ++counter;
+ handle.Stop();
+ return TimeDelta::Millis(2);
+ });
+ });
+ time_simulation.AdvanceTime(TimeDelta::Millis(10));
+ EXPECT_EQ(counter.load(), 1);
+}
+
+TEST(SimulatedTimeControllerTest, Example) {
+ class ObjectOnTaskQueue {
+ public:
+ void DoPeriodicTask() {}
+ TimeDelta TimeUntilNextRun() { return TimeDelta::Millis(100); }
+ void StartPeriodicTask(RepeatingTaskHandle* handle,
+ rtc::TaskQueue* task_queue) {
+ *handle = RepeatingTaskHandle::Start(task_queue->Get(), [this] {
+ DoPeriodicTask();
+ return TimeUntilNextRun();
+ });
+ }
+ };
+ GlobalSimulatedTimeController time_simulation(kStartTime);
+ rtc::TaskQueue task_queue(
+ time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
+ "TestQueue", TaskQueueFactory::Priority::NORMAL));
+ auto object = std::make_unique<ObjectOnTaskQueue>();
+ // Create and start the periodic task.
+ RepeatingTaskHandle handle;
+ object->StartPeriodicTask(&handle, &task_queue);
+ // Restart the task
+ task_queue.PostTask(
+ [handle = std::move(handle)]() mutable { handle.Stop(); });
+ object->StartPeriodicTask(&handle, &task_queue);
+ task_queue.PostTask(
+ [handle = std::move(handle)]() mutable { handle.Stop(); });
+
+ task_queue.PostTask([object = std::move(object)] {});
+}
+
+TEST(SimulatedTimeControllerTest, DelayTaskRunOnTime) {
+ GlobalSimulatedTimeController time_simulation(kStartTime);
+ std::unique_ptr<TaskQueueBase, TaskQueueDeleter> task_queue =
+ time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
+ "TestQueue", TaskQueueFactory::Priority::NORMAL);
+
+ bool delay_task_executed = false;
+ task_queue->PostDelayedTask([&] { delay_task_executed = true; },
+ TimeDelta::Millis(10));
+
+ time_simulation.AdvanceTime(TimeDelta::Millis(10));
+ EXPECT_TRUE(delay_task_executed);
+}
+
+TEST(SimulatedTimeControllerTest, ThreadYeildsOnSynchronousCall) {
+ GlobalSimulatedTimeController sim(kStartTime);
+ auto main_thread = sim.GetMainThread();
+ auto t2 = sim.CreateThread("thread", nullptr);
+ bool task_has_run = false;
+ // Posting a task to the main thread, this should not run until AdvanceTime is
+ // called.
+ main_thread->PostTask([&] { task_has_run = true; });
+ SendTask(t2.get(), [] {
+ rtc::Event yield_event;
+ // Wait() triggers YieldExecution() which will runs message processing on
+ // all threads that are not in the yielded set.
+
+ yield_event.Wait(TimeDelta::Zero());
+ });
+ // Since we are doing an invoke from the main thread, we don't expect the main
+ // thread message loop to be processed.
+ EXPECT_FALSE(task_has_run);
+ sim.AdvanceTime(TimeDelta::Seconds(1));
+ ASSERT_TRUE(task_has_run);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/test/time_controller/time_controller_conformance_test.cc b/third_party/libwebrtc/test/time_controller/time_controller_conformance_test.cc
new file mode 100644
index 0000000000..300dd9175c
--- /dev/null
+++ b/third_party/libwebrtc/test/time_controller/time_controller_conformance_test.cc
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2020 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 <memory>
+#include <vector>
+
+#include "api/test/time_controller.h"
+#include "api/units/time_delta.h"
+#include "rtc_base/event.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/thread.h"
+#include "rtc_base/thread_annotations.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/time_controller/real_time_controller.h"
+#include "test/time_controller/simulated_time_controller.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::ElementsAreArray;
+using ::testing::TestParamInfo;
+using ::testing::TestWithParam;
+using ::testing::Values;
+
+enum class TimeMode { kRealTime, kSimulated };
+
+std::unique_ptr<TimeController> CreateTimeController(TimeMode mode) {
+ switch (mode) {
+ case TimeMode::kRealTime:
+ return std::make_unique<RealTimeController>();
+ case TimeMode::kSimulated:
+ // Using an offset of 100000 to get nice fixed width and readable
+ // timestamps in typical test scenarios.
+ constexpr Timestamp kSimulatedStartTime = Timestamp::Seconds(100000);
+ return std::make_unique<GlobalSimulatedTimeController>(
+ kSimulatedStartTime);
+ }
+}
+
+std::string ParamsToString(const TestParamInfo<webrtc::TimeMode>& param) {
+ switch (param.param) {
+ case webrtc::TimeMode::kRealTime:
+ return "RealTime";
+ case webrtc::TimeMode::kSimulated:
+ return "SimulatedTime";
+ default:
+ RTC_DCHECK_NOTREACHED() << "Time mode not supported";
+ }
+}
+
+// Keeps order of executions. May be called from different threads.
+class ExecutionOrderKeeper {
+ public:
+ void Executed(int execution_id) {
+ MutexLock lock(&mutex_);
+ order_.push_back(execution_id);
+ }
+
+ std::vector<int> order() const {
+ MutexLock lock(&mutex_);
+ return order_;
+ }
+
+ private:
+ mutable Mutex mutex_;
+ std::vector<int> order_ RTC_GUARDED_BY(mutex_);
+};
+
+// Tests conformance between real time and simulated time time controller.
+class SimulatedRealTimeControllerConformanceTest
+ : public TestWithParam<webrtc::TimeMode> {};
+
+TEST_P(SimulatedRealTimeControllerConformanceTest, ThreadPostOrderTest) {
+ std::unique_ptr<TimeController> time_controller =
+ CreateTimeController(GetParam());
+ std::unique_ptr<rtc::Thread> thread = time_controller->CreateThread("thread");
+
+ // Tasks on thread have to be executed in order in which they were
+ // posted.
+ ExecutionOrderKeeper execution_order;
+ thread->PostTask([&]() { execution_order.Executed(1); });
+ thread->PostTask([&]() { execution_order.Executed(2); });
+ time_controller->AdvanceTime(TimeDelta::Millis(100));
+ EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2}));
+ // Destroy `thread` before `execution_order` to be sure `execution_order`
+ // is not accessed on the posted task after it is destroyed.
+ thread = nullptr;
+}
+
+TEST_P(SimulatedRealTimeControllerConformanceTest, ThreadPostDelayedOrderTest) {
+ std::unique_ptr<TimeController> time_controller =
+ CreateTimeController(GetParam());
+ std::unique_ptr<rtc::Thread> thread = time_controller->CreateThread("thread");
+
+ ExecutionOrderKeeper execution_order;
+ thread->PostDelayedTask([&]() { execution_order.Executed(2); },
+ TimeDelta::Millis(500));
+ thread->PostTask([&]() { execution_order.Executed(1); });
+ time_controller->AdvanceTime(TimeDelta::Millis(600));
+ EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2}));
+ // Destroy `thread` before `execution_order` to be sure `execution_order`
+ // is not accessed on the posted task after it is destroyed.
+ thread = nullptr;
+}
+
+TEST_P(SimulatedRealTimeControllerConformanceTest, ThreadPostInvokeOrderTest) {
+ std::unique_ptr<TimeController> time_controller =
+ CreateTimeController(GetParam());
+ std::unique_ptr<rtc::Thread> thread = time_controller->CreateThread("thread");
+
+ // Tasks on thread have to be executed in order in which they were
+ // posted/invoked.
+ ExecutionOrderKeeper execution_order;
+ thread->PostTask([&]() { execution_order.Executed(1); });
+ thread->BlockingCall([&]() { execution_order.Executed(2); });
+ time_controller->AdvanceTime(TimeDelta::Millis(100));
+ EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2}));
+ // Destroy `thread` before `execution_order` to be sure `execution_order`
+ // is not accessed on the posted task after it is destroyed.
+ thread = nullptr;
+}
+
+TEST_P(SimulatedRealTimeControllerConformanceTest,
+ ThreadPostInvokeFromThreadOrderTest) {
+ std::unique_ptr<TimeController> time_controller =
+ CreateTimeController(GetParam());
+ std::unique_ptr<rtc::Thread> thread = time_controller->CreateThread("thread");
+
+ // If task is invoked from thread X on thread X it has to be executed
+ // immediately.
+ ExecutionOrderKeeper execution_order;
+ thread->PostTask([&]() {
+ thread->PostTask([&]() { execution_order.Executed(2); });
+ thread->BlockingCall([&]() { execution_order.Executed(1); });
+ });
+ time_controller->AdvanceTime(TimeDelta::Millis(100));
+ EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2}));
+ // Destroy `thread` before `execution_order` to be sure `execution_order`
+ // is not accessed on the posted task after it is destroyed.
+ thread = nullptr;
+}
+
+TEST_P(SimulatedRealTimeControllerConformanceTest,
+ TaskQueuePostEventWaitOrderTest) {
+ std::unique_ptr<TimeController> time_controller =
+ CreateTimeController(GetParam());
+ auto task_queue = time_controller->GetTaskQueueFactory()->CreateTaskQueue(
+ "task_queue", webrtc::TaskQueueFactory::Priority::NORMAL);
+
+ // Tasks on thread have to be executed in order in which they were
+ // posted/invoked.
+ ExecutionOrderKeeper execution_order;
+ rtc::Event event;
+ task_queue->PostTask([&]() { execution_order.Executed(1); });
+ task_queue->PostTask([&]() {
+ execution_order.Executed(2);
+ event.Set();
+ });
+ EXPECT_TRUE(event.Wait(/*give_up_after=*/TimeDelta::Millis(100)));
+ time_controller->AdvanceTime(TimeDelta::Millis(100));
+ EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2}));
+ // Destroy `task_queue` before `execution_order` to be sure `execution_order`
+ // is not accessed on the posted task after it is destroyed.
+ task_queue = nullptr;
+}
+
+INSTANTIATE_TEST_SUITE_P(ConformanceTest,
+ SimulatedRealTimeControllerConformanceTest,
+ Values(TimeMode::kRealTime, TimeMode::kSimulated),
+ ParamsToString);
+
+} // namespace
+} // namespace webrtc