Consolidate FakeAudioStream and FakeVideoStream classes for tests.

Bug: webrtc:42233500
Change-Id: I31fc6151e38087436227ed21f4a219d784b9f651
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/455241
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Fredrik Solenberg <solenberg@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#47108}
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 20e7f5d..9863aa6 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -2903,12 +2903,14 @@
     sources = [
       "test/fake_audio_capture_module.cc",
       "test/fake_audio_capture_module.h",
+      "test/fake_audio_track.h",
       "test/fake_data_channel_controller.h",
       "test/fake_peer_connection_base.h",
       "test/fake_peer_connection_for_stats.h",
       "test/fake_periodic_video_source.h",
       "test/fake_periodic_video_track_source.h",
       "test/fake_rtc_certificate_generator.h",
+      "test/fake_video_track.h",
       "test/fake_video_track_renderer.h",
       "test/fake_video_track_source.h",
       "test/frame_generator_capturer_video_track_source.h",
diff --git a/pc/legacy_stats_collector_unittest.cc b/pc/legacy_stats_collector_unittest.cc
index 676b2ee..63c33ec 100644
--- a/pc/legacy_stats_collector_unittest.cc
+++ b/pc/legacy_stats_collector_unittest.cc
@@ -28,7 +28,6 @@
 #include "api/legacy_stats_types.h"
 #include "api/make_ref_counted.h"
 #include "api/media_stream_interface.h"
-#include "api/media_stream_track.h"
 #include "api/media_types.h"
 #include "api/peer_connection_interface.h"
 #include "api/rtp_sender_interface.h"
@@ -42,6 +41,7 @@
 #include "pc/media_stream.h"
 #include "pc/peer_connection_internal.h"
 #include "pc/sctp_data_channel.h"
+#include "pc/test/fake_audio_track.h"
 #include "pc/test/fake_peer_connection_for_stats.h"
 #include "pc/test/fake_video_track_source.h"
 #include "pc/test/mock_rtp_receiver_internal.h"
@@ -85,82 +85,20 @@
 constexpr char kRemoteTrackId[] = "remote_track_id";
 constexpr uint32_t kSsrcOfTrack = 1234;
 
-class FakeAudioProcessor : public AudioProcessorInterface {
- public:
-  FakeAudioProcessor() {}
-  ~FakeAudioProcessor() override {}
-
- private:
-  AudioProcessorInterface::AudioProcessorStatistics GetStats(
-      bool has_recv_streams) override {
-    AudioProcessorStatistics stats;
-    if (has_recv_streams) {
-      stats.apm_statistics.echo_return_loss = 2.0;
-      stats.apm_statistics.echo_return_loss_enhancement = 3.0;
-      stats.apm_statistics.delay_median_ms = 4;
-      stats.apm_statistics.delay_standard_deviation_ms = 5;
-    }
-    return stats;
+// Returns a FakeAudioTrack with the given ID and configuration.
+scoped_refptr<AudioTrackInterface> CreateFakeAudioTrack(const std::string& id,
+                                                        bool return_stats) {
+  auto processor = make_ref_counted<FakeAudioProcessor>();
+  processor->return_stats = return_stats;
+  if (return_stats) {
+    processor->stats.apm_statistics.echo_return_loss = 2.0;
+    processor->stats.apm_statistics.echo_return_loss_enhancement = 3.0;
+    processor->stats.apm_statistics.delay_median_ms = 4;
+    processor->stats.apm_statistics.delay_standard_deviation_ms = 5;
   }
-};
-
-class FakeAudioTrack : public MediaStreamTrack<AudioTrackInterface> {
- public:
-  explicit FakeAudioTrack(const std::string& id)
-      : MediaStreamTrack<AudioTrackInterface>(id),
-        processor_(make_ref_counted<FakeAudioProcessor>()) {}
-  std::string kind() const override { return "audio"; }
-  AudioSourceInterface* GetSource() const override { return nullptr; }
-  void AddSink(AudioTrackSinkInterface* sink) override {}
-  void RemoveSink(AudioTrackSinkInterface* sink) override {}
-  bool GetSignalLevel(int* level) override {
-    *level = 1;
-    return true;
-  }
-  scoped_refptr<AudioProcessorInterface> GetAudioProcessor() override {
-    return processor_;
-  }
-
- private:
-  scoped_refptr<FakeAudioProcessor> processor_;
-};
-
-// This fake audio processor is used to verify that the undesired initial values
-// (-1) will be filtered out.
-class FakeAudioProcessorWithInitValue : public AudioProcessorInterface {
- public:
-  FakeAudioProcessorWithInitValue() {}
-  ~FakeAudioProcessorWithInitValue() override {}
-
- private:
-  AudioProcessorInterface::AudioProcessorStatistics GetStats(
-      bool /*has_recv_streams*/) override {
-    AudioProcessorStatistics stats;
-    return stats;
-  }
-};
-
-class FakeAudioTrackWithInitValue
-    : public MediaStreamTrack<AudioTrackInterface> {
- public:
-  explicit FakeAudioTrackWithInitValue(const std::string& id)
-      : MediaStreamTrack<AudioTrackInterface>(id),
-        processor_(make_ref_counted<FakeAudioProcessorWithInitValue>()) {}
-  std::string kind() const override { return "audio"; }
-  AudioSourceInterface* GetSource() const override { return nullptr; }
-  void AddSink(AudioTrackSinkInterface* sink) override {}
-  void RemoveSink(AudioTrackSinkInterface* sink) override {}
-  bool GetSignalLevel(int* level) override {
-    *level = 1;
-    return true;
-  }
-  scoped_refptr<AudioProcessorInterface> GetAudioProcessor() override {
-    return processor_;
-  }
-
- private:
-  scoped_refptr<FakeAudioProcessorWithInitValue> processor_;
-};
+  return FakeAudioTrack::Create(id, MediaStreamTrackInterface::kLive,
+                                processor);
+}
 
 bool GetValue(const StatsReport* report,
               StatsReport::StatsValueName name,
@@ -600,7 +538,7 @@
         pc, clock_, [this]() { return GetUtcTimeNowMs(); });
   }
 
-  void VerifyAudioTrackStats(FakeAudioTrack* audio_track,
+  void VerifyAudioTrackStats(AudioTrackInterface* audio_track,
                              LegacyStatsCollector* stats,
                              const VoiceMediaInfo& voice_info,
                              StatsReports* reports) {
@@ -841,7 +779,7 @@
   scoped_refptr<RtpSenderInterface> AddOutgoingAudioTrack(
       FakePeerConnectionForStats* pc,
       LegacyStatsCollector* stats) {
-    audio_track_ = make_ref_counted<FakeAudioTrack>(kLocalTrackId);
+    audio_track_ = CreateFakeAudioTrack(kLocalTrackId, true);
     if (GetParam()) {
       if (!stream_)
         stream_ = MediaStream::Create("streamid");
@@ -859,7 +797,7 @@
   // Adds a incoming audio track with a given SSRC into the stats.
   void AddIncomingAudioTrack(FakePeerConnectionForStats* pc,
                              LegacyStatsCollector* stats) {
-    audio_track_ = make_ref_counted<FakeAudioTrack>(kRemoteTrackId);
+    audio_track_ = CreateFakeAudioTrack(kRemoteTrackId, true);
     if (GetParam()) {
       if (stream_ == nullptr)
         stream_ = MediaStream::Create("streamid");
@@ -878,7 +816,7 @@
 
   scoped_refptr<MediaStream> stream_;
   scoped_refptr<VideoTrack> video_track_;
-  scoped_refptr<FakeAudioTrack> audio_track_;
+  scoped_refptr<AudioTrackInterface> audio_track_;
 };
 
 TEST(StatsCollectionTest, DetachAndMerge) {
@@ -1593,8 +1531,7 @@
 
   // Create a local stream with a local audio track and adds it to the stats.
   stream_ = MediaStream::Create("streamid");
-  auto local_track =
-      make_ref_counted<FakeAudioTrackWithInitValue>(kLocalTrackId);
+  auto local_track = CreateFakeAudioTrack(kLocalTrackId, false);
   stream_->AddTrack(scoped_refptr<AudioTrackInterface>(local_track.get()));
   RTC_ALLOW_PLAN_B_DEPRECATION_BEGIN();
   pc->AddSender(CreateMockSender(local_track, kSsrcOfTrack));
@@ -1608,7 +1545,7 @@
   scoped_refptr<MediaStream> remote_stream(
       MediaStream::Create("remotestreamid"));
   scoped_refptr<AudioTrackInterface> remote_track =
-      make_ref_counted<FakeAudioTrackWithInitValue>(kRemoteTrackId);
+      CreateFakeAudioTrack(kRemoteTrackId, false);
   remote_stream->AddTrack(remote_track);
   RTC_ALLOW_PLAN_B_DEPRECATION_BEGIN();
   pc->AddReceiver(CreateMockReceiver(remote_track, kSsrcOfTrack));
@@ -1793,7 +1730,7 @@
   scoped_refptr<MediaStream> remote_stream(
       MediaStream::Create("remotestreamid"));
   scoped_refptr<AudioTrackInterface> remote_track =
-      make_ref_counted<FakeAudioTrack>(kRemoteTrackId);
+      CreateFakeAudioTrack(kRemoteTrackId, true);
   RTC_ALLOW_PLAN_B_DEPRECATION_BEGIN();
   pc->AddReceiver(CreateMockReceiver(remote_track, kSsrcOfTrack));
   RTC_ALLOW_PLAN_B_DEPRECATION_END();
@@ -1893,7 +1830,7 @@
 
   // Create a new audio track and adds it to the stream and stats.
   static const std::string kNewTrackId = "new_track_id";
-  auto new_audio_track = make_ref_counted<FakeAudioTrack>(kNewTrackId);
+  auto new_audio_track = CreateFakeAudioTrack(kNewTrackId, true);
   RTC_ALLOW_PLAN_B_DEPRECATION_BEGIN();
   pc->AddSender(CreateMockSender(new_audio_track, kSsrcOfTrack));
   RTC_ALLOW_PLAN_B_DEPRECATION_END();
@@ -1926,8 +1863,7 @@
   auto pc = CreatePeerConnection();
   auto stats = CreateStatsCollector(pc.get());
 
-  auto local_track =
-      make_ref_counted<FakeAudioTrackWithInitValue>(kLocalTrackId);
+  auto local_track = CreateFakeAudioTrack(kLocalTrackId, false);
   RTC_ALLOW_PLAN_B_DEPRECATION_BEGIN();
   pc->AddSender(CreateMockSender(local_track, kFirstSsrc));
   stats->AddLocalAudioTrack(local_track.get(), kFirstSsrc);
diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc
index 4c69afd..55f1976 100644
--- a/pc/rtc_stats_collector_unittest.cc
+++ b/pc/rtc_stats_collector_unittest.cc
@@ -32,7 +32,6 @@
 #include "api/environment/environment.h"
 #include "api/make_ref_counted.h"
 #include "api/media_stream_interface.h"
-#include "api/media_stream_track.h"
 #include "api/media_types.h"
 #include "api/peer_connection_interface.h"
 #include "api/rtp_parameters.h"
@@ -48,11 +47,7 @@
 #include "api/units/data_rate.h"
 #include "api/units/time_delta.h"
 #include "api/units/timestamp.h"
-#include "api/video/recordable_encoded_frame.h"
 #include "api/video/video_content_type.h"
-#include "api/video/video_frame.h"
-#include "api/video/video_sink_interface.h"
-#include "api/video/video_source_interface.h"
 #include "api/video/video_timing.h"
 #include "api/video_codecs/scalability_mode.h"
 #include "call/call.h"
@@ -72,8 +67,11 @@
 #include "pc/peer_connection_internal.h"
 #include "pc/sctp_data_channel.h"
 #include "pc/stream_collection.h"
+#include "pc/test/fake_audio_track.h"
 #include "pc/test/fake_data_channel_controller.h"
 #include "pc/test/fake_peer_connection_for_stats.h"
+#include "pc/test/fake_video_track.h"
+#include "pc/test/fake_video_track_source.h"
 #include "pc/test/mock_data_channel.h"
 #include "pc/test/mock_rtp_receiver_internal.h"
 #include "pc/test/mock_rtp_sender_internal.h"
@@ -199,129 +197,26 @@
               (override));
 };
 
-class FakeAudioProcessor : public AudioProcessorInterface {
- public:
-  FakeAudioProcessor() {}
-  ~FakeAudioProcessor() override {}
-
- private:
-  AudioProcessorInterface::AudioProcessorStatistics GetStats(
-      bool has_recv_streams) override {
-    AudioProcessorStatistics stats;
-    stats.apm_statistics.echo_return_loss = 2.0;
-    stats.apm_statistics.echo_return_loss_enhancement = 3.0;
-    return stats;
+// Helper functions to create fake tracks for stats tests.
+scoped_refptr<AudioTrackInterface> CreateFakeAudioTrackForStats(
+    const std::string& id,
+    MediaStreamTrackInterface::TrackState state,
+    bool create_fake_audio_processor) {
+  scoped_refptr<FakeAudioProcessor> processor = nullptr;
+  if (create_fake_audio_processor) {
+    processor = make_ref_counted<FakeAudioProcessor>();
+    processor->stats.apm_statistics.echo_return_loss = 2.0;
+    processor->stats.apm_statistics.echo_return_loss_enhancement = 3.0;
   }
-};
+  return FakeAudioTrack::Create(id, state, processor);
+}
 
-class FakeAudioTrackForStats : public MediaStreamTrack<AudioTrackInterface> {
- public:
-  static scoped_refptr<FakeAudioTrackForStats> Create(
-      const std::string& id,
-      MediaStreamTrackInterface::TrackState state,
-      bool create_fake_audio_processor) {
-    auto audio_track_stats = make_ref_counted<FakeAudioTrackForStats>(id);
-    audio_track_stats->set_state(state);
-    if (create_fake_audio_processor) {
-      audio_track_stats->processor_ = make_ref_counted<FakeAudioProcessor>();
-    }
-    return audio_track_stats;
-  }
-
-  explicit FakeAudioTrackForStats(const std::string& id)
-      : MediaStreamTrack<AudioTrackInterface>(id) {}
-
-  std::string kind() const override {
-    return MediaStreamTrackInterface::kAudioKind;
-  }
-  AudioSourceInterface* GetSource() const override { return nullptr; }
-  void AddSink(AudioTrackSinkInterface* sink) override {}
-  void RemoveSink(AudioTrackSinkInterface* sink) override {}
-  bool GetSignalLevel(int* level) override { return false; }
-  scoped_refptr<AudioProcessorInterface> GetAudioProcessor() override {
-    return processor_;
-  }
-
- private:
-  scoped_refptr<FakeAudioProcessor> processor_;
-};
-
-class FakeVideoTrackSourceForStats : public VideoTrackSourceInterface {
- public:
-  static scoped_refptr<FakeVideoTrackSourceForStats> Create(int input_width,
-                                                            int input_height) {
-    return make_ref_counted<FakeVideoTrackSourceForStats>(input_width,
-                                                          input_height);
-  }
-
-  FakeVideoTrackSourceForStats(int input_width, int input_height)
-      : input_width_(input_width), input_height_(input_height) {}
-  ~FakeVideoTrackSourceForStats() override {}
-
-  // VideoTrackSourceInterface
-  bool is_screencast() const override { return false; }
-  std::optional<bool> needs_denoising() const override { return false; }
-  bool GetStats(VideoTrackSourceInterface::Stats* stats) override {
-    stats->input_width = input_width_;
-    stats->input_height = input_height_;
-    return true;
-  }
-  // MediaSourceInterface (part of VideoTrackSourceInterface)
-  MediaSourceInterface::SourceState state() const override {
-    return MediaSourceInterface::SourceState::kLive;
-  }
-  bool remote() const override { return false; }
-  // NotifierInterface (part of MediaSourceInterface)
-  void RegisterObserver(ObserverInterface* observer) override {}
-  void UnregisterObserver(ObserverInterface* observer) override {}
-  // webrtc::VideoSourceInterface<VideoFrame> (part of
-  // VideoTrackSourceInterface)
-  void AddOrUpdateSink(VideoSinkInterface<VideoFrame>* sink,
-                       const VideoSinkWants& wants) override {}
-  void RemoveSink(VideoSinkInterface<VideoFrame>* sink) override {}
-  bool SupportsEncodedOutput() const override { return false; }
-  void GenerateKeyFrame() override {}
-  void AddEncodedSink(
-      VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
-  void RemoveEncodedSink(
-      VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
-
- private:
-  int input_width_;
-  int input_height_;
-};
-
-class FakeVideoTrackForStats : public MediaStreamTrack<VideoTrackInterface> {
- public:
-  static scoped_refptr<FakeVideoTrackForStats> Create(
-      const std::string& id,
-      MediaStreamTrackInterface::TrackState state,
-      scoped_refptr<VideoTrackSourceInterface> source) {
-    auto video_track =
-        make_ref_counted<FakeVideoTrackForStats>(id, std::move(source));
-    video_track->set_state(state);
-    return video_track;
-  }
-
-  FakeVideoTrackForStats(const std::string& id,
-                         scoped_refptr<VideoTrackSourceInterface> source)
-      : MediaStreamTrack<VideoTrackInterface>(id), source_(source) {}
-
-  std::string kind() const override {
-    return MediaStreamTrackInterface::kVideoKind;
-  }
-
-  void AddOrUpdateSink(VideoSinkInterface<VideoFrame>* sink,
-                       const VideoSinkWants& wants) override {}
-  void RemoveSink(VideoSinkInterface<VideoFrame>* sink) override {}
-
-  VideoTrackSourceInterface* GetSource() const override {
-    return source_.get();
-  }
-
- private:
-  scoped_refptr<VideoTrackSourceInterface> source_;
-};
+scoped_refptr<VideoTrackInterface> CreateFakeVideoTrackForStats(
+    const std::string& id,
+    MediaStreamTrackInterface::TrackState state,
+    scoped_refptr<VideoTrackSourceInterface> source) {
+  return FakeVideoTrack::Create(id, state, source);
+}
 
 scoped_refptr<MediaStreamTrackInterface> CreateFakeTrack(
     MediaType media_type,
@@ -329,11 +224,11 @@
     MediaStreamTrackInterface::TrackState track_state,
     bool create_fake_audio_processor = false) {
   if (media_type == MediaType::AUDIO) {
-    return FakeAudioTrackForStats::Create(track_id, track_state,
-                                          create_fake_audio_processor);
+    return CreateFakeAudioTrackForStats(track_id, track_state,
+                                        create_fake_audio_processor);
   } else {
     RTC_DCHECK_EQ(media_type, MediaType::VIDEO);
-    return FakeVideoTrackForStats::Create(track_id, track_state, nullptr);
+    return CreateFakeVideoTrackForStats(track_id, track_state, nullptr);
   }
 }
 
@@ -3261,9 +3156,9 @@
   pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
   RTC_ALLOW_PLAN_B_DEPRECATION_END();
 
-  auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
-                                                           kVideoSourceHeight);
-  auto video_track = FakeVideoTrackForStats::Create(
+  auto video_source = FakeVideoTrackSource::Create(false);
+  video_source->SetSize(kVideoSourceWidth, kVideoSourceHeight);
+  auto video_track = CreateFakeVideoTrackForStats(
       "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
   scoped_refptr<MockRtpSenderInternal> sender =
       CreateMockSender(MediaType::VIDEO, video_track, kSsrc, kAttachmentId, {});
@@ -3313,9 +3208,9 @@
   pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
   RTC_ALLOW_PLAN_B_DEPRECATION_END();
 
-  auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
-                                                           kVideoSourceHeight);
-  auto video_track = FakeVideoTrackForStats::Create(
+  auto video_source = FakeVideoTrackSource::Create(false);
+  video_source->SetSize(kVideoSourceWidth, kVideoSourceHeight);
+  auto video_track = CreateFakeVideoTrackForStats(
       "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
   scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
       MediaType::VIDEO, video_track, kNoSsrc, kAttachmentId, {});
@@ -3352,7 +3247,7 @@
   pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
   RTC_ALLOW_PLAN_B_DEPRECATION_END();
 
-  auto video_track = FakeVideoTrackForStats::Create(
+  auto video_track = CreateFakeVideoTrackForStats(
       "LocalVideoTrackID", MediaStreamTrackInterface::kLive,
       /*source=*/nullptr);
   scoped_refptr<MockRtpSenderInternal> sender =
diff --git a/pc/test/fake_audio_track.h b/pc/test/fake_audio_track.h
new file mode 100644
index 0000000..42b0016
--- /dev/null
+++ b/pc/test/fake_audio_track.h
@@ -0,0 +1,79 @@
+/*
+ *  Copyright 2026 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 PC_TEST_FAKE_AUDIO_TRACK_H_
+#define PC_TEST_FAKE_AUDIO_TRACK_H_
+
+#include <string>
+
+#include "api/make_ref_counted.h"
+#include "api/media_stream_interface.h"
+#include "api/media_stream_track.h"
+#include "api/scoped_refptr.h"
+
+namespace webrtc {
+
+class FakeAudioProcessor : public AudioProcessorInterface {
+ public:
+  FakeAudioProcessor() = default;
+  ~FakeAudioProcessor() override = default;
+
+  AudioProcessorInterface::AudioProcessorStatistics GetStats(
+      bool /*has_recv_streams*/) override {
+    return return_stats ? stats
+                        : AudioProcessorInterface::AudioProcessorStatistics();
+  }
+
+  AudioProcessorInterface::AudioProcessorStatistics stats;
+  bool return_stats = true;
+};
+
+class FakeAudioTrack : public MediaStreamTrack<AudioTrackInterface> {
+ public:
+  static scoped_refptr<FakeAudioTrack> Create(
+      const std::string& id,
+      MediaStreamTrackInterface::TrackState state,
+      scoped_refptr<FakeAudioProcessor> processor = nullptr) {
+    auto audio_track = make_ref_counted<FakeAudioTrack>(id, processor);
+    audio_track->set_state(state);
+    return audio_track;
+  }
+
+  explicit FakeAudioTrack(const std::string& id,
+                          scoped_refptr<FakeAudioProcessor> processor = nullptr)
+      : MediaStreamTrack<AudioTrackInterface>(id),
+        processor_(processor ? processor
+                             : make_ref_counted<FakeAudioProcessor>()) {}
+
+  std::string kind() const override {
+    return MediaStreamTrackInterface::kAudioKind;
+  }
+  AudioSourceInterface* GetSource() const override { return nullptr; }
+  void AddSink(AudioTrackSinkInterface* sink) override {}
+  void RemoveSink(AudioTrackSinkInterface* sink) override {}
+  bool GetSignalLevel(int* level) override {
+    *level = 1;
+    return true;
+  }
+  scoped_refptr<AudioProcessorInterface> GetAudioProcessor() override {
+    return processor_;
+  }
+
+  void set_processor(scoped_refptr<AudioProcessorInterface> processor) {
+    processor_ = processor;
+  }
+
+ private:
+  scoped_refptr<AudioProcessorInterface> processor_;
+};
+
+}  // namespace webrtc
+
+#endif  // PC_TEST_FAKE_AUDIO_TRACK_H_
diff --git a/pc/test/fake_video_track.h b/pc/test/fake_video_track.h
new file mode 100644
index 0000000..ce11982
--- /dev/null
+++ b/pc/test/fake_video_track.h
@@ -0,0 +1,60 @@
+/*
+ *  Copyright 2026 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 PC_TEST_FAKE_VIDEO_TRACK_H_
+#define PC_TEST_FAKE_VIDEO_TRACK_H_
+
+#include <string>
+#include <utility>
+
+#include "api/make_ref_counted.h"
+#include "api/media_stream_interface.h"
+#include "api/media_stream_track.h"
+#include "api/scoped_refptr.h"
+#include "api/video/video_frame.h"
+#include "api/video/video_sink_interface.h"
+#include "api/video/video_source_interface.h"
+
+namespace webrtc {
+
+class FakeVideoTrack : public MediaStreamTrack<VideoTrackInterface> {
+ public:
+  static scoped_refptr<FakeVideoTrack> Create(
+      const std::string& id,
+      MediaStreamTrackInterface::TrackState state,
+      scoped_refptr<VideoTrackSourceInterface> source) {
+    auto video_track = make_ref_counted<FakeVideoTrack>(id, std::move(source));
+    video_track->set_state(state);
+    return video_track;
+  }
+
+  FakeVideoTrack(const std::string& id,
+                 scoped_refptr<VideoTrackSourceInterface> source)
+      : MediaStreamTrack<VideoTrackInterface>(id), source_(source) {}
+
+  std::string kind() const override {
+    return MediaStreamTrackInterface::kVideoKind;
+  }
+
+  void AddOrUpdateSink(VideoSinkInterface<VideoFrame>* sink,
+                       const VideoSinkWants& wants) override {}
+  void RemoveSink(VideoSinkInterface<VideoFrame>* sink) override {}
+
+  VideoTrackSourceInterface* GetSource() const override {
+    return source_.get();
+  }
+
+ private:
+  scoped_refptr<VideoTrackSourceInterface> source_;
+};
+
+}  // namespace webrtc
+
+#endif  // PC_TEST_FAKE_VIDEO_TRACK_H_
diff --git a/pc/test/fake_video_track_source.h b/pc/test/fake_video_track_source.h
index df56f62..241f73a 100644
--- a/pc/test/fake_video_track_source.h
+++ b/pc/test/fake_video_track_source.h
@@ -12,6 +12,7 @@
 #define PC_TEST_FAKE_VIDEO_TRACK_SOURCE_H_
 
 #include "api/make_ref_counted.h"
+#include "api/media_stream_interface.h"
 #include "api/scoped_refptr.h"
 #include "api/video/video_frame.h"
 #include "api/video/video_source_interface.h"
@@ -31,6 +32,18 @@
   static scoped_refptr<FakeVideoTrackSource> Create() { return Create(false); }
 
   bool is_screencast() const override { return is_screencast_; }
+  bool GetStats(VideoTrackSourceInterface::Stats* stats) override {
+    if (!stats)
+      return false;
+    stats->input_width = width_;
+    stats->input_height = height_;
+    return true;
+  }
+
+  void SetSize(int width, int height) {
+    width_ = width;
+    height_ = height;
+  }
 
   void InjectFrame(const VideoFrame& frame) {
     video_broadcaster_.OnFrame(frame);
@@ -47,6 +60,8 @@
 
  private:
   const bool is_screencast_;
+  int width_ = 0;
+  int height_ = 0;
   VideoBroadcaster video_broadcaster_;
 };