[PCLF] Introduce test video source and make it more controllable

Bug: b/272350185
Change-Id: I15572b7e4d0cb0ce41da676a4eedbc1e138510fc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/298047
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39621}
diff --git a/api/test/video/BUILD.gn b/api/test/video/BUILD.gn
index d24ffa5..0eae85a 100644
--- a/api/test/video/BUILD.gn
+++ b/api/test/video/BUILD.gn
@@ -11,7 +11,7 @@
 rtc_library("function_video_factory") {
   visibility = [ "*" ]
   testonly = true
-  public = [
+  sources = [
     "function_video_decoder_factory.h",
     "function_video_encoder_factory.h",
   ]
@@ -25,7 +25,27 @@
 rtc_library("video_frame_writer") {
   visibility = [ "*" ]
   testonly = true
-  public = [ "video_frame_writer.h" ]
+  sources = [ "video_frame_writer.h" ]
 
   deps = [ "../../video:video_frame" ]
 }
+
+rtc_library("test_video_track_source") {
+  visibility = [ "*" ]
+  testonly = true
+  sources = [
+    "test_video_track_source.cc",
+    "test_video_track_source.h",
+  ]
+
+  deps = [
+    "../..:media_stream_interface",
+    "../..:sequence_checker",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:macromagic",
+    "../../../rtc_base/system:no_unique_address",
+    "../../video:recordable_encoded_frame",
+    "../../video:video_frame",
+  ]
+  absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
diff --git a/api/test/video/DEPS b/api/test/video/DEPS
new file mode 100644
index 0000000..2256b34
--- /dev/null
+++ b/api/test/video/DEPS
@@ -0,0 +1,6 @@
+specific_include_rules = {
+  "test_video_track_source\.h": [
+    "+rtc_base/thread_annotations.h",
+    "+rtc_base/system/no_unique_address.h",
+  ],
+}
diff --git a/api/test/video/test_video_track_source.cc b/api/test/video/test_video_track_source.cc
new file mode 100644
index 0000000..c570a7a
--- /dev/null
+++ b/api/test/video/test_video_track_source.cc
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2023 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/video/test_video_track_source.h"
+
+#include "api/media_stream_interface.h"
+#include "api/sequence_checker.h"
+#include "api/video/video_frame.h"
+#include "api/video/video_sink_interface.h"
+#include "api/video/video_source_interface.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace test {
+
+TestVideoTrackSource::TestVideoTrackSource(bool remote)
+    : state_(kInitializing), remote_(remote) {
+  worker_thread_checker_.Detach();
+}
+
+VideoTrackSourceInterface::SourceState TestVideoTrackSource::state() const {
+  RTC_DCHECK_RUN_ON(&signaling_thread_checker_);
+  return state_;
+}
+
+void TestVideoTrackSource::SetState(SourceState new_state) {
+  RTC_DCHECK_RUN_ON(&signaling_thread_checker_);
+  if (state_ != new_state) {
+    state_ = new_state;
+    FireOnChanged();
+  }
+}
+
+void TestVideoTrackSource::AddOrUpdateSink(
+    rtc::VideoSinkInterface<VideoFrame>* sink,
+    const rtc::VideoSinkWants& wants) {
+  RTC_DCHECK(worker_thread_checker_.IsCurrent());
+  source()->AddOrUpdateSink(sink, wants);
+}
+
+void TestVideoTrackSource::RemoveSink(
+    rtc::VideoSinkInterface<VideoFrame>* sink) {
+  RTC_DCHECK(worker_thread_checker_.IsCurrent());
+  source()->RemoveSink(sink);
+}
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/api/test/video/test_video_track_source.h b/api/test/video/test_video_track_source.h
new file mode 100644
index 0000000..4e2d138
--- /dev/null
+++ b/api/test/video/test_video_track_source.h
@@ -0,0 +1,78 @@
+/*
+ *  Copyright (c) 2023 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_VIDEO_TEST_VIDEO_TRACK_SOURCE_H_
+#define API_TEST_VIDEO_TEST_VIDEO_TRACK_SOURCE_H_
+
+#include "absl/types/optional.h"
+#include "api/media_stream_interface.h"
+#include "api/notifier.h"
+#include "api/sequence_checker.h"
+#include "api/video/recordable_encoded_frame.h"
+#include "api/video/video_frame.h"
+#include "api/video/video_sink_interface.h"
+#include "api/video/video_source_interface.h"
+#include "rtc_base/system/no_unique_address.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+namespace test {
+
+// Video source that can be used as input for tests.
+class TestVideoTrackSource : public Notifier<VideoTrackSourceInterface> {
+ public:
+  explicit TestVideoTrackSource(bool remote);
+  ~TestVideoTrackSource() override = default;
+
+  void SetState(SourceState new_state);
+
+  SourceState state() const override;
+  bool remote() const override { return remote_; }
+
+  bool is_screencast() const override { return false; }
+  absl::optional<bool> needs_denoising() const override {
+    return absl::nullopt;
+  }
+
+  bool GetStats(Stats* stats) override { return false; }
+
+  void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
+                       const rtc::VideoSinkWants& wants) override;
+  void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override;
+
+  bool SupportsEncodedOutput() const override { return false; }
+  void GenerateKeyFrame() override {}
+  void AddEncodedSink(
+      rtc::VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
+  void RemoveEncodedSink(
+      rtc::VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
+
+  // Starts producing video.
+  virtual void Start() = 0;
+
+  // Stops producing video.
+  virtual void Stop() = 0;
+
+  virtual void SetScreencast(bool is_screencast) = 0;
+
+ protected:
+  virtual rtc::VideoSourceInterface<VideoFrame>* source() = 0;
+
+ private:
+  RTC_NO_UNIQUE_ADDRESS SequenceChecker worker_thread_checker_;
+  RTC_NO_UNIQUE_ADDRESS SequenceChecker signaling_thread_checker_;
+  SourceState state_ RTC_GUARDED_BY(&signaling_thread_checker_);
+  const bool remote_;
+};
+
+}  // namespace test
+}  // namespace webrtc
+
+#endif  // API_TEST_VIDEO_TEST_VIDEO_TRACK_SOURCE_H_
diff --git a/test/pc/e2e/BUILD.gn b/test/pc/e2e/BUILD.gn
index ae9dd64..635b917 100644
--- a/test/pc/e2e/BUILD.gn
+++ b/test/pc/e2e/BUILD.gn
@@ -136,8 +136,10 @@
         "../../../api:create_frame_generator",
         "../../../api:frame_generator_api",
         "../../../api:media_stream_interface",
+        "../../../api:sequence_checker",
         "../../../api/test/pclf:media_configuration",
         "../../../api/test/pclf:peer_configurer",
+        "../../../api/test/video:test_video_track_source",
         "../../../api/video:video_frame",
         "../../../pc:session_description",
         "../../../pc:video_track_source",
diff --git a/test/pc/e2e/media/test_video_capturer_video_track_source.h b/test/pc/e2e/media/test_video_capturer_video_track_source.h
index c883a2e..350766b 100644
--- a/test/pc/e2e/media/test_video_capturer_video_track_source.h
+++ b/test/pc/e2e/media/test_video_capturer_video_track_source.h
@@ -14,30 +14,54 @@
 #include <memory>
 #include <utility>
 
+#include "api/sequence_checker.h"
+#include "api/test/video/test_video_track_source.h"
 #include "api/video/video_frame.h"
 #include "api/video/video_source_interface.h"
-#include "pc/video_track_source.h"
 #include "test/test_video_capturer.h"
 
 namespace webrtc {
 namespace webrtc_pc_e2e {
 
-class TestVideoCapturerVideoTrackSource : public VideoTrackSource {
+class TestVideoCapturerVideoTrackSource : public test::TestVideoTrackSource {
  public:
   TestVideoCapturerVideoTrackSource(
       std::unique_ptr<test::TestVideoCapturer> video_capturer,
       bool is_screencast)
-      : VideoTrackSource(/*remote=*/false),
+      : TestVideoTrackSource(/*remote=*/false),
         video_capturer_(std::move(video_capturer)),
-        is_screencast_(is_screencast) {}
+        is_screencast_(is_screencast) {
+    sequence_checker_.Detach();
+  }
+
+  TestVideoCapturerVideoTrackSource(const TestVideoCapturerVideoTrackSource&) =
+      delete;
+  TestVideoCapturerVideoTrackSource& operator=(
+      const TestVideoCapturerVideoTrackSource&) = delete;
+  TestVideoCapturerVideoTrackSource(TestVideoCapturerVideoTrackSource&&) =
+      delete;
+  TestVideoCapturerVideoTrackSource& operator=(
+      TestVideoCapturerVideoTrackSource&&) = delete;
 
   ~TestVideoCapturerVideoTrackSource() = default;
 
-  void Start() { SetState(kLive); }
+  void Start() override { SetState(kLive); }
 
-  void Stop() { SetState(kMuted); }
+  void Stop() override { SetState(kMuted); }
 
-  bool is_screencast() const override { return is_screencast_; }
+  bool is_screencast() const override {
+    RTC_DCHECK_RUN_ON(&sequence_checker_);
+    return is_screencast_;
+  }
+
+  void SetDisableAdaptation(bool disable_adaptation) {
+    video_capturer_->SetDisableAdaptation(disable_adaptation);
+  }
+
+  void SetScreencast(bool is_screencast) override {
+    RTC_DCHECK_RUN_ON(&sequence_checker_);
+    is_screencast_ = is_screencast;
+  }
 
  protected:
   rtc::VideoSourceInterface<VideoFrame>* source() override {
@@ -45,8 +69,9 @@
   }
 
  private:
-  std::unique_ptr<test::TestVideoCapturer> video_capturer_;
-  const bool is_screencast_;
+  const std::unique_ptr<test::TestVideoCapturer> video_capturer_;
+  SequenceChecker sequence_checker_;
+  bool is_screencast_ RTC_GUARDED_BY(sequence_checker_);
 };
 
 }  // namespace webrtc_pc_e2e
diff --git a/test/test_video_capturer.cc b/test/test_video_capturer.cc
index 4a4adc6..b55eefc 100644
--- a/test/test_video_capturer.cc
+++ b/test/test_video_capturer.cc
@@ -40,6 +40,15 @@
 
   VideoFrame frame = MaybePreprocess(original_frame);
 
+  bool disable_adaptation;
+  {
+    MutexLock lock(&lock_);
+    disable_adaptation = disable_adaptation_;
+  }
+  if (disable_adaptation) {
+    broadcaster_.OnFrame(frame);
+  }
+
   if (!video_adapter_.AdaptFrameResolution(
           frame.width(), frame.height(), frame.timestamp_us() * 1000,
           &cropped_width, &cropped_height, &out_width, &out_height)) {
diff --git a/test/test_video_capturer.h b/test/test_video_capturer.h
index 6fafd96..3fc03f0 100644
--- a/test/test_video_capturer.h
+++ b/test/test_video_capturer.h
@@ -41,6 +41,10 @@
     MutexLock lock(&lock_);
     preprocessor_ = std::move(preprocessor);
   }
+  void SetDisableAdaptation(bool disable_adaptation) {
+    MutexLock lock(&lock_);
+    disable_adaptation_ = disable_adaptation;
+  }
   void OnOutputFormatRequest(int width,
                              int height,
                              const absl::optional<int>& max_fps);
@@ -55,6 +59,7 @@
 
   Mutex lock_;
   std::unique_ptr<FramePreprocessor> preprocessor_ RTC_GUARDED_BY(lock_);
+  bool disable_adaptation_ RTC_GUARDED_BY(lock_) = false;
   rtc::VideoBroadcaster broadcaster_;
   cricket::VideoAdapter video_adapter_;
 };