Split VideoReceiveStream2 init into worker / network steps.

This is in preparation for actually doing this initialization
differently in the Call class. This CL takes the registration
steps that are inherently network thread associated and makes
them separate from the ctor/dtor.

Inject Call* instead of worker_thread(), which will simplify upcoming
work that needs to access the network_thread() as well.

This is related to:
https://webrtc-review.googlesource.com/c/src/+/220608
https://webrtc-review.googlesource.com/c/src/+/220609

Bug: webrtc:11993
Change-Id: I72769fd61de84967d9a645750c40d01660a2716b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220764
Reviewed-by: Markus Handell <handellm@webrtc.org>
Commit-Queue: Tommi <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34172}
diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc
index ef69e73..aecc246 100644
--- a/audio/audio_receive_stream.cc
+++ b/audio/audio_receive_stream.cc
@@ -126,7 +126,7 @@
   RTC_DCHECK(audio_state_);
   RTC_DCHECK(channel_receive_);
 
-  network_thread_checker_.Detach();
+  packet_sequence_checker_.Detach();
 
   RTC_DCHECK(packet_router);
   // Configure bandwidth estimation.
@@ -157,14 +157,14 @@
 
 void AudioReceiveStream::RegisterWithTransport(
     RtpStreamReceiverControllerInterface* receiver_controller) {
-  RTC_DCHECK_RUN_ON(&network_thread_checker_);
+  RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
   RTC_DCHECK(!rtp_stream_receiver_);
   rtp_stream_receiver_ = receiver_controller->CreateReceiver(
       config_.rtp.remote_ssrc, channel_receive_.get());
 }
 
 void AudioReceiveStream::UnregisterFromTransport() {
-  RTC_DCHECK_RUN_ON(&network_thread_checker_);
+  RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
   rtp_stream_receiver_.reset();
 }
 
@@ -395,7 +395,7 @@
 }
 
 void AudioReceiveStream::AssociateSendStream(AudioSendStream* send_stream) {
-  RTC_DCHECK_RUN_ON(&network_thread_checker_);
+  RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
   channel_receive_->SetAssociatedSendChannel(
       send_stream ? send_stream->GetChannel() : nullptr);
   associated_send_stream_ = send_stream;
@@ -416,7 +416,7 @@
 
 const AudioSendStream* AudioReceiveStream::GetAssociatedSendStreamForTesting()
     const {
-  RTC_DCHECK_RUN_ON(&network_thread_checker_);
+  RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
   return associated_send_stream_;
 }
 
diff --git a/audio/audio_receive_stream.h b/audio/audio_receive_stream.h
index 40749cc..87c82cc 100644
--- a/audio/audio_receive_stream.h
+++ b/audio/audio_receive_stream.h
@@ -125,18 +125,18 @@
   // thread, but still serves as a mechanism of grouping together concepts
   // that belong to the network thread. Once the packets are fully delivered
   // on the network thread, this comment will be deleted.
-  RTC_NO_UNIQUE_ADDRESS SequenceChecker network_thread_checker_;
+  RTC_NO_UNIQUE_ADDRESS SequenceChecker packet_sequence_checker_;
   webrtc::AudioReceiveStream::Config config_;
   rtc::scoped_refptr<webrtc::AudioState> audio_state_;
   SourceTracker source_tracker_;
   const std::unique_ptr<voe::ChannelReceiveInterface> channel_receive_;
   AudioSendStream* associated_send_stream_
-      RTC_GUARDED_BY(network_thread_checker_) = nullptr;
+      RTC_GUARDED_BY(packet_sequence_checker_) = nullptr;
 
   bool playing_ RTC_GUARDED_BY(worker_thread_checker_) = false;
 
   std::unique_ptr<RtpStreamReceiverInterface> rtp_stream_receiver_
-      RTC_GUARDED_BY(network_thread_checker_);
+      RTC_GUARDED_BY(packet_sequence_checker_);
 };
 }  // namespace internal
 }  // namespace webrtc
diff --git a/call/call.cc b/call/call.cc
index 76ba46f..b8eafdc 100644
--- a/call/call.cc
+++ b/call/call.cc
@@ -1099,10 +1099,13 @@
   // and set it up asynchronously on the network thread (the registration and
   // |video_receiver_controller_| need to live on the network thread).
   VideoReceiveStream2* receive_stream = new VideoReceiveStream2(
-      task_queue_factory_, worker_thread_, &video_receiver_controller_,
-      num_cpu_cores_, transport_send_->packet_router(),
-      std::move(configuration), module_process_thread_->process_thread(),
-      call_stats_.get(), clock_, new VCMTiming(clock_));
+      task_queue_factory_, this, num_cpu_cores_,
+      transport_send_->packet_router(), std::move(configuration),
+      module_process_thread_->process_thread(), call_stats_.get(), clock_,
+      new VCMTiming(clock_));
+  // TODO(bugs.webrtc.org/11993): Set this up asynchronously on the network
+  // thread.
+  receive_stream->RegisterWithTransport(&video_receiver_controller_);
 
   const webrtc::VideoReceiveStream::Config& config = receive_stream->config();
   if (config.rtp.rtx_ssrc) {
@@ -1130,6 +1133,9 @@
   RTC_DCHECK(receive_stream != nullptr);
   VideoReceiveStream2* receive_stream_impl =
       static_cast<VideoReceiveStream2*>(receive_stream);
+  // TODO(bugs.webrtc.org/11993): Unregister on the network thread.
+  receive_stream_impl->UnregisterFromTransport();
+
   const VideoReceiveStream::Config& config = receive_stream_impl->config();
 
   // Remove all ssrcs pointing to a receive stream. As RTX retransmits on a
diff --git a/call/flexfec_receive_stream_impl.cc b/call/flexfec_receive_stream_impl.cc
index c335b03..8a09108 100644
--- a/call/flexfec_receive_stream_impl.cc
+++ b/call/flexfec_receive_stream_impl.cc
@@ -154,7 +154,7 @@
       process_thread_(process_thread) {
   RTC_LOG(LS_INFO) << "FlexfecReceiveStreamImpl: " << config_.ToString();
 
-  network_thread_checker_.Detach();
+  packet_sequence_checker_.Detach();
 
   // RTCP reporting.
   rtp_rtcp_->SetRTCPStatus(config_.rtcp_mode);
@@ -168,7 +168,7 @@
 
 void FlexfecReceiveStreamImpl::RegisterWithTransport(
     RtpStreamReceiverControllerInterface* receiver_controller) {
-  RTC_DCHECK_RUN_ON(&network_thread_checker_);
+  RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
   RTC_DCHECK(!rtp_stream_receiver_);
 
   if (!receiver_)
@@ -183,7 +183,7 @@
 }
 
 void FlexfecReceiveStreamImpl::UnregisterFromTransport() {
-  RTC_DCHECK_RUN_ON(&network_thread_checker_);
+  RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
   rtp_stream_receiver_.reset();
 }
 
diff --git a/call/flexfec_receive_stream_impl.h b/call/flexfec_receive_stream_impl.h
index 1a4aa03..8826aed 100644
--- a/call/flexfec_receive_stream_impl.h
+++ b/call/flexfec_receive_stream_impl.h
@@ -62,7 +62,7 @@
   const Config& GetConfig() const override;
 
  private:
-  RTC_NO_UNIQUE_ADDRESS SequenceChecker network_thread_checker_;
+  RTC_NO_UNIQUE_ADDRESS SequenceChecker packet_sequence_checker_;
 
   // Config.
   const Config config_;
@@ -76,7 +76,7 @@
   ProcessThread* const process_thread_;
 
   std::unique_ptr<RtpStreamReceiverInterface> rtp_stream_receiver_
-      RTC_GUARDED_BY(network_thread_checker_);
+      RTC_GUARDED_BY(packet_sequence_checker_);
 };
 
 }  // namespace webrtc
diff --git a/video/video_receive_stream2.cc b/video/video_receive_stream2.cc
index c9ec9e0..78e436a 100644
--- a/video/video_receive_stream2.cc
+++ b/video/video_receive_stream2.cc
@@ -211,30 +211,28 @@
                      : kMaxWaitForFrameMs;
 }
 
-VideoReceiveStream2::VideoReceiveStream2(
-    TaskQueueFactory* task_queue_factory,
-    TaskQueueBase* current_queue,
-    RtpStreamReceiverControllerInterface* receiver_controller,
-    int num_cpu_cores,
-    PacketRouter* packet_router,
-    VideoReceiveStream::Config config,
-    ProcessThread* process_thread,
-    CallStats* call_stats,
-    Clock* clock,
-    VCMTiming* timing)
+VideoReceiveStream2::VideoReceiveStream2(TaskQueueFactory* task_queue_factory,
+                                         Call* call,
+                                         int num_cpu_cores,
+                                         PacketRouter* packet_router,
+                                         VideoReceiveStream::Config config,
+                                         ProcessThread* process_thread,
+                                         CallStats* call_stats,
+                                         Clock* clock,
+                                         VCMTiming* timing)
     : task_queue_factory_(task_queue_factory),
       transport_adapter_(config.rtcp_send_transport),
       config_(std::move(config)),
       num_cpu_cores_(num_cpu_cores),
-      worker_thread_(current_queue),
+      call_(call),
       clock_(clock),
       call_stats_(call_stats),
       source_tracker_(clock_),
-      stats_proxy_(&config_, clock_, worker_thread_),
+      stats_proxy_(&config_, clock_, call->worker_thread()),
       rtp_receive_statistics_(ReceiveStatistics::Create(clock_)),
       timing_(timing),
       video_receiver_(clock_, timing_.get()),
-      rtp_video_stream_receiver_(worker_thread_,
+      rtp_video_stream_receiver_(call->worker_thread(),
                                  clock_,
                                  &transport_adapter_,
                                  call_stats->AsRtcpRttStats(),
@@ -249,7 +247,7 @@
                                  this,     // OnCompleteFrameCallback
                                  config_.frame_decryptor,
                                  config_.frame_transformer),
-      rtp_stream_sync_(current_queue, this),
+      rtp_stream_sync_(call->worker_thread(), this),
       max_wait_for_keyframe_ms_(DetermineMaxWaitForFrame(config, true)),
       max_wait_for_frame_ms_(DetermineMaxWaitForFrame(config, false)),
       low_latency_renderer_enabled_("enabled", true),
@@ -261,10 +259,11 @@
           TaskQueueFactory::Priority::HIGH)) {
   RTC_LOG(LS_INFO) << "VideoReceiveStream2: " << config_.ToString();
 
-  RTC_DCHECK(worker_thread_);
+  RTC_DCHECK(call_->worker_thread());
   RTC_DCHECK(config_.renderer);
   RTC_DCHECK(call_stats_);
   module_process_sequence_checker_.Detach();
+  packet_sequence_checker_.Detach();
 
   RTC_DCHECK(!config_.decoders.empty());
   RTC_CHECK(config_.decoder_factory);
@@ -282,15 +281,10 @@
   frame_buffer_.reset(
       new video_coding::FrameBuffer(clock_, timing_.get(), &stats_proxy_));
 
-  // Register with RtpStreamReceiverController.
-  media_receiver_ = receiver_controller->CreateReceiver(
-      config_.rtp.remote_ssrc, &rtp_video_stream_receiver_);
   if (config_.rtp.rtx_ssrc) {
     rtx_receive_stream_ = std::make_unique<RtxReceiveStream>(
         &rtp_video_stream_receiver_, config.rtp.rtx_associated_payload_types,
         config_.rtp.remote_ssrc, rtp_receive_statistics_.get());
-    rtx_receiver_ = receiver_controller->CreateReceiver(
-        config_.rtp.rtx_ssrc, rtx_receive_stream_.get());
   } else {
     rtp_receive_statistics_->EnableRetransmitDetection(config.rtp.remote_ssrc,
                                                        true);
@@ -309,20 +303,45 @@
 VideoReceiveStream2::~VideoReceiveStream2() {
   RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
   RTC_LOG(LS_INFO) << "~VideoReceiveStream2: " << config_.ToString();
+  RTC_DCHECK(!media_receiver_);
+  RTC_DCHECK(!rtx_receiver_);
   Stop();
 }
 
+void VideoReceiveStream2::RegisterWithTransport(
+    RtpStreamReceiverControllerInterface* receiver_controller) {
+  RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
+  RTC_DCHECK(!media_receiver_);
+  RTC_DCHECK(!rtx_receiver_);
+
+  // Register with RtpStreamReceiverController.
+  media_receiver_ = receiver_controller->CreateReceiver(
+      config_.rtp.remote_ssrc, &rtp_video_stream_receiver_);
+  if (config_.rtp.rtx_ssrc) {
+    RTC_DCHECK(rtx_receive_stream_);
+    rtx_receiver_ = receiver_controller->CreateReceiver(
+        config_.rtp.rtx_ssrc, rtx_receive_stream_.get());
+  }
+}
+
+void VideoReceiveStream2::UnregisterFromTransport() {
+  RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
+  media_receiver_.reset();
+  rtx_receiver_.reset();
+}
+
 void VideoReceiveStream2::SignalNetworkState(NetworkState state) {
   RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
   rtp_video_stream_receiver_.SignalNetworkState(state);
 }
 
 bool VideoReceiveStream2::DeliverRtcp(const uint8_t* packet, size_t length) {
+  RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
   return rtp_video_stream_receiver_.DeliverRtcp(packet, length);
 }
 
 void VideoReceiveStream2::SetSync(Syncable* audio_syncable) {
-  RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
+  RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
   rtp_stream_sync_.ConfigureSync(audio_syncable);
 }
 
@@ -529,7 +548,7 @@
   // TODO(bugs.webrtc.org/10739): we should set local capture clock offset for
   // |video_frame.packet_infos|. But VideoFrame is const qualified here.
 
-  worker_thread_->PostTask(
+  call_->worker_thread()->PostTask(
       ToQueuedTask(task_safety_, [frame_meta, this]() {
         RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
         int64_t video_playout_ntp_ms;
@@ -685,7 +704,7 @@
           HandleEncodedFrame(std::move(frame));
         } else {
           int64_t now_ms = clock_->TimeInMilliseconds();
-          worker_thread_->PostTask(ToQueuedTask(
+          call_->worker_thread()->PostTask(ToQueuedTask(
               task_safety_, [this, now_ms, wait_ms = GetMaxWaitMs()]() {
                 RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
                 HandleFrameBufferTimeout(now_ms, wait_ms);
@@ -746,7 +765,7 @@
     force_request_key_frame = true;
   }
 
-  worker_thread_->PostTask(ToQueuedTask(
+  call_->worker_thread()->PostTask(ToQueuedTask(
       task_safety_,
       [this, now_ms, received_frame_is_keyframe, force_request_key_frame,
        decoded_frame_picture_id, keyframe_request_is_due]() {
diff --git a/video/video_receive_stream2.h b/video/video_receive_stream2.h
index f952de2..8bf673d 100644
--- a/video/video_receive_stream2.h
+++ b/video/video_receive_stream2.h
@@ -18,6 +18,7 @@
 #include "api/task_queue/task_queue_factory.h"
 #include "api/units/timestamp.h"
 #include "api/video/recordable_encoded_frame.h"
+#include "call/call.h"
 #include "call/rtp_packet_sink_interface.h"
 #include "call/syncable.h"
 #include "call/video_receive_stream.h"
@@ -91,8 +92,7 @@
   static constexpr size_t kBufferedEncodedFramesMaxSize = 60;
 
   VideoReceiveStream2(TaskQueueFactory* task_queue_factory,
-                      TaskQueueBase* current_queue,
-                      RtpStreamReceiverControllerInterface* receiver_controller,
+                      Call* call,
                       int num_cpu_cores,
                       PacketRouter* packet_router,
                       VideoReceiveStream::Config config,
@@ -100,8 +100,22 @@
                       CallStats* call_stats,
                       Clock* clock,
                       VCMTiming* timing);
+  // Destruction happens on the worker thread. Prior to destruction the caller
+  // must ensure that a registration with the transport has been cleared. See
+  // `RegisterWithTransport` for details.
+  // TODO(tommi): As a further improvement to this, performing the full
+  // destruction on the network thread could be made the default.
   ~VideoReceiveStream2() override;
 
+  // Called on `packet_sequence_checker_` to register/unregister with the
+  // network transport.
+  void RegisterWithTransport(
+      RtpStreamReceiverControllerInterface* receiver_controller);
+  // If registration has previously been done (via `RegisterWithTransport`) then
+  // `UnregisterFromTransport` must be called prior to destruction, on the
+  // network thread.
+  void UnregisterFromTransport();
+
   const Config& config() const { return config_; }
 
   void SignalNetworkState(NetworkState state);
@@ -184,13 +198,21 @@
 
   RTC_NO_UNIQUE_ADDRESS SequenceChecker worker_sequence_checker_;
   RTC_NO_UNIQUE_ADDRESS SequenceChecker module_process_sequence_checker_;
+  // TODO(bugs.webrtc.org/11993): This checker conceptually represents
+  // operations that belong to the network thread. The Call class is currently
+  // moving towards handling network packets on the network thread and while
+  // that work is ongoing, this checker may in practice represent the worker
+  // thread, but still serves as a mechanism of grouping together concepts
+  // that belong to the network thread. Once the packets are fully delivered
+  // on the network thread, this comment will be deleted.
+  RTC_NO_UNIQUE_ADDRESS SequenceChecker packet_sequence_checker_;
 
   TaskQueueFactory* const task_queue_factory_;
 
   TransportAdapter transport_adapter_;
   const VideoReceiveStream::Config config_;
   const int num_cpu_cores_;
-  TaskQueueBase* const worker_thread_;
+  Call* const call_;
   Clock* const clock_;
 
   CallStats* const call_stats_;
@@ -218,9 +240,12 @@
   // Members for the new jitter buffer experiment.
   std::unique_ptr<video_coding::FrameBuffer> frame_buffer_;
 
-  std::unique_ptr<RtpStreamReceiverInterface> media_receiver_;
-  std::unique_ptr<RtxReceiveStream> rtx_receive_stream_;
-  std::unique_ptr<RtpStreamReceiverInterface> rtx_receiver_;
+  std::unique_ptr<RtpStreamReceiverInterface> media_receiver_
+      RTC_GUARDED_BY(packet_sequence_checker_);
+  std::unique_ptr<RtxReceiveStream> rtx_receive_stream_
+      RTC_GUARDED_BY(packet_sequence_checker_);
+  std::unique_ptr<RtpStreamReceiverInterface> rtx_receiver_
+      RTC_GUARDED_BY(packet_sequence_checker_);
 
   // Whenever we are in an undecodable state (stream has just started or due to
   // a decoding error) we require a keyframe to restart the stream.
diff --git a/video/video_receive_stream2_unittest.cc b/video/video_receive_stream2_unittest.cc
index 3bbc070..f3372b1 100644
--- a/video/video_receive_stream2_unittest.cc
+++ b/video/video_receive_stream2_unittest.cc
@@ -23,6 +23,7 @@
 #include "call/rtp_stream_receiver_controller.h"
 #include "common_video/test/utilities.h"
 #include "media/base/fake_video_renderer.h"
+#include "media/engine/fake_webrtc_call.h"
 #include "modules/pacing/packet_router.h"
 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
 #include "modules/utility/include/process_thread.h"
@@ -113,8 +114,12 @@
         config_(&mock_transport_),
         call_stats_(Clock::GetRealTimeClock(), loop_.task_queue()),
         h264_decoder_factory_(&mock_h264_video_decoder_) {}
+  ~VideoReceiveStream2Test() override {
+    if (video_receive_stream_)
+      video_receive_stream_->UnregisterFromTransport();
+  }
 
-  void SetUp() {
+  void SetUp() override {
     constexpr int kDefaultNumCpuCores = 2;
     config_.rtp.remote_ssrc = 1111;
     config_.rtp.local_ssrc = 2222;
@@ -133,10 +138,11 @@
 
     video_receive_stream_ =
         std::make_unique<webrtc::internal::VideoReceiveStream2>(
-            task_queue_factory_.get(), loop_.task_queue(),
-            &rtp_stream_receiver_controller_, kDefaultNumCpuCores,
+            task_queue_factory_.get(), &fake_call_, kDefaultNumCpuCores,
             &packet_router_, config_.Copy(), process_thread_.get(),
             &call_stats_, clock_, timing_);
+    video_receive_stream_->RegisterWithTransport(
+        &rtp_stream_receiver_controller_);
   }
 
  protected:
@@ -148,6 +154,7 @@
   MockVideoDecoder mock_h264_video_decoder_;
   test::VideoDecoderProxyFactory h264_decoder_factory_;
   cricket::FakeVideoRenderer fake_renderer_;
+  cricket::FakeCall fake_call_;
   MockTransport mock_transport_;
   PacketRouter packet_router_;
   RtpStreamReceiverController rtp_stream_receiver_controller_;
@@ -288,8 +295,12 @@
         task_queue_factory_(CreateDefaultTaskQueueFactory()),
         config_(&mock_transport_),
         call_stats_(Clock::GetRealTimeClock(), loop_.task_queue()) {}
+  ~VideoReceiveStream2TestWithFakeDecoder() override {
+    if (video_receive_stream_)
+      video_receive_stream_->UnregisterFromTransport();
+  }
 
-  void SetUp() {
+  void SetUp() override {
     config_.rtp.remote_ssrc = 1111;
     config_.rtp.local_ssrc = 2222;
     config_.renderer = &fake_renderer_;
@@ -304,12 +315,17 @@
 
   void ReCreateReceiveStream(VideoReceiveStream::RecordingState state) {
     constexpr int kDefaultNumCpuCores = 2;
-    video_receive_stream_ = nullptr;
+    if (video_receive_stream_) {
+      video_receive_stream_->UnregisterFromTransport();
+      video_receive_stream_ = nullptr;
+    }
     timing_ = new VCMTiming(clock_);
     video_receive_stream_.reset(new webrtc::internal::VideoReceiveStream2(
-        task_queue_factory_.get(), loop_.task_queue(),
-        &rtp_stream_receiver_controller_, kDefaultNumCpuCores, &packet_router_,
-        config_.Copy(), process_thread_.get(), &call_stats_, clock_, timing_));
+        task_queue_factory_.get(), &fake_call_, kDefaultNumCpuCores,
+        &packet_router_, config_.Copy(), process_thread_.get(), &call_stats_,
+        clock_, timing_));
+    video_receive_stream_->RegisterWithTransport(
+        &rtp_stream_receiver_controller_);
     video_receive_stream_->SetAndGetRecordingState(std::move(state), false);
   }
 
@@ -324,6 +340,7 @@
   MockTransport mock_transport_;
   PacketRouter packet_router_;
   RtpStreamReceiverController rtp_stream_receiver_controller_;
+  cricket::FakeCall fake_call_;
   std::unique_ptr<webrtc::internal::VideoReceiveStream2> video_receive_stream_;
   Clock* clock_;
   VCMTiming* timing_;
@@ -568,8 +585,7 @@
                           &fake_renderer_)),
         call_stats_(time_controller_.GetClock(), loop_.task_queue()),
         video_receive_stream_(time_controller_.GetTaskQueueFactory(),
-                              loop_.task_queue(),
-                              &rtp_stream_receiver_controller_,
+                              &fake_call_,
                               /*num_cores=*/2,
                               &packet_router_,
                               config_.Copy(),
@@ -577,9 +593,15 @@
                               &call_stats_,
                               time_controller_.GetClock(),
                               new VCMTiming(time_controller_.GetClock())) {
+    video_receive_stream_.RegisterWithTransport(
+        &rtp_stream_receiver_controller_);
     video_receive_stream_.Start();
   }
 
+  ~VideoReceiveStream2TestWithSimulatedClock() override {
+    video_receive_stream_.UnregisterFromTransport();
+  }
+
   void OnFrameDecoded() { event_->Set(); }
 
   void PassEncodedFrameAndWait(std::unique_ptr<EncodedFrame> frame) {
@@ -597,6 +619,7 @@
   std::unique_ptr<ProcessThread> process_thread_;
   MockTransport mock_transport_;
   FakeRenderer fake_renderer_;
+  cricket::FakeCall fake_call_;
   VideoReceiveStream::Config config_;
   internal::CallStats call_stats_;
   PacketRouter packet_router_;
@@ -714,7 +737,11 @@
         config_(&mock_transport_),
         call_stats_(Clock::GetRealTimeClock(), loop_.task_queue()) {}
 
-  void SetUp() {
+  ~VideoReceiveStream2TestWithLazyDecoderCreation() override {
+    video_receive_stream_->UnregisterFromTransport();
+  }
+
+  void SetUp() override {
     webrtc::test::ScopedFieldTrials field_trials(
         "WebRTC-PreStreamDecoders/max:0/");
     constexpr int kDefaultNumCpuCores = 2;
@@ -735,10 +762,11 @@
 
     video_receive_stream_ =
         std::make_unique<webrtc::internal::VideoReceiveStream2>(
-            task_queue_factory_.get(), loop_.task_queue(),
-            &rtp_stream_receiver_controller_, kDefaultNumCpuCores,
+            task_queue_factory_.get(), &fake_call_, kDefaultNumCpuCores,
             &packet_router_, config_.Copy(), process_thread_.get(),
             &call_stats_, clock_, timing_);
+    video_receive_stream_->RegisterWithTransport(
+        &rtp_stream_receiver_controller_);
   }
 
  protected:
@@ -750,6 +778,7 @@
   MockVideoDecoder mock_h264_video_decoder_;
   MockVideoDecoderFactory mock_h264_decoder_factory_;
   cricket::FakeVideoRenderer fake_renderer_;
+  cricket::FakeCall fake_call_;
   MockTransport mock_transport_;
   PacketRouter packet_router_;
   RtpStreamReceiverController rtp_stream_receiver_controller_;