Add support of fast media sending in peer connection e2e test

Start sending media from the peer when it's ICE connection state is
connected.

Bug: webrtc:10138
Change-Id: I9f5a1cd917317a3ebadd7c156563035b0bbecf2a
Reviewed-on: https://webrtc-review.googlesource.com/c/121956
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Peter Slatala <psla@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26698}
diff --git a/test/DEPS b/test/DEPS
index 712dc6b..d69c889 100644
--- a/test/DEPS
+++ b/test/DEPS
@@ -54,7 +54,7 @@
     "+pc/test/mock_peer_connection_observers.h",
     "+p2p/client/basic_port_allocator.h",
   ],
-  ".*peer_connection_quality_test\.h": [
+  ".*peer_connection_quality_test\.(h|cc)": [
     "+pc",
   ]
 }
diff --git a/test/pc/e2e/peer_connection_quality_test.cc b/test/pc/e2e/peer_connection_quality_test.cc
index 44170c4..4f293fa 100644
--- a/test/pc/e2e/peer_connection_quality_test.cc
+++ b/test/pc/e2e/peer_connection_quality_test.cc
@@ -1,3 +1,5 @@
+#include <utility>
+
 /*
  *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
  *
@@ -13,9 +15,11 @@
 #include <utility>
 
 #include "absl/memory/memory.h"
+#include "api/media_stream_interface.h"
 #include "api/peer_connection_interface.h"
 #include "api/scoped_refptr.h"
 #include "api/units/time_delta.h"
+#include "pc/test/mock_peer_connection_observers.h"
 #include "rtc_base/bind.h"
 #include "rtc_base/gunit.h"
 #include "system_wrappers/include/cpu_info.h"
@@ -49,6 +53,41 @@
   return builder.str();
 }
 
+class FixturePeerConnectionObserver : public MockPeerConnectionObserver {
+ public:
+  // |on_track_callback| will be called when any new track will be added to peer
+  // connection.
+  // |on_connected_callback| will be called when peer connection will come to
+  // either connected or completed state. Client should notice that in the case
+  // of reconnect this callback can be called again, so it should be tolerant
+  // to such behavior.
+  FixturePeerConnectionObserver(
+      std::function<void(rtc::scoped_refptr<RtpTransceiverInterface>)>
+          on_track_callback,
+      std::function<void()> on_connected_callback)
+      : on_track_callback_(std::move(on_track_callback)),
+        on_connected_callback_(std::move(on_connected_callback)) {}
+
+  void OnTrack(
+      rtc::scoped_refptr<RtpTransceiverInterface> transceiver) override {
+    MockPeerConnectionObserver::OnTrack(transceiver);
+    on_track_callback_(transceiver);
+  }
+
+  void OnIceConnectionChange(
+      PeerConnectionInterface::IceConnectionState new_state) override {
+    MockPeerConnectionObserver::OnIceConnectionChange(new_state);
+    if (ice_connected_) {
+      on_connected_callback_();
+    }
+  }
+
+ private:
+  std::function<void(rtc::scoped_refptr<RtpTransceiverInterface>)>
+      on_track_callback_;
+  std::function<void()> on_connected_callback_;
+};
+
 }  // namespace
 
 PeerConnectionE2EQualityTest::PeerConnectionE2EQualityTest(
@@ -110,12 +149,28 @@
       alice_params->audio_config
           ? alice_params->audio_config->output_dump_file_name
           : absl::nullopt;
+  // Copy Alice and Bob video configs to correctly pass them into lambdas.
+  std::vector<VideoConfig> alice_video_configs = alice_params->video_configs;
+  std::vector<VideoConfig> bob_video_configs = bob_params->video_configs;
+
   alice_ = TestPeer::CreateTestPeer(
       std::move(alice_components), std::move(alice_params),
+      absl::make_unique<FixturePeerConnectionObserver>(
+          [this, bob_video_configs](
+              rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {
+            SetupVideoSink(transceiver, bob_video_configs);
+          },
+          [this]() { StartVideo(alice_video_sources_); }),
       video_quality_analyzer_injection_helper_.get(), signaling_thread.get(),
       alice_audio_output_dump_file_name);
   bob_ = TestPeer::CreateTestPeer(
       std::move(bob_components), std::move(bob_params),
+      absl::make_unique<FixturePeerConnectionObserver>(
+          [this, alice_video_configs](
+              rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {
+            SetupVideoSink(transceiver, alice_video_configs);
+          },
+          [this]() { StartVideo(bob_video_sources_); }),
       video_quality_analyzer_injection_helper_.get(), signaling_thread.get(),
       bob_audio_output_dump_file_name);
 
@@ -144,7 +199,8 @@
   RTC_CHECK(!bob_);
   // Ensuring that FrameGeneratorCapturerVideoTrackSource and VideoFrameWriter
   // are destroyed on the right thread.
-  RTC_CHECK(video_sources_.empty());
+  RTC_CHECK(alice_video_sources_.empty());
+  RTC_CHECK(bob_video_sources_.empty());
   RTC_CHECK(video_writers_.empty());
 }
 
@@ -211,35 +267,60 @@
   RTC_CHECK_GT(media_streams_count, 0) << "No media in the call.";
 }
 
+void PeerConnectionE2EQualityTest::SetupVideoSink(
+    rtc::scoped_refptr<RtpTransceiverInterface> transceiver,
+    std::vector<VideoConfig> remote_video_configs) {
+  const rtc::scoped_refptr<MediaStreamTrackInterface>& track =
+      transceiver->receiver()->track();
+  if (track->kind() != MediaStreamTrackInterface::kVideoKind) {
+    return;
+  }
+
+  VideoConfig* video_config = nullptr;
+  for (auto& config : remote_video_configs) {
+    if (config.stream_label == track->id()) {
+      video_config = &config;
+      break;
+    }
+  }
+  RTC_CHECK(video_config);
+
+  VideoFrameWriter* writer = MaybeCreateVideoWriter(
+      video_config->output_dump_file_name, *video_config);
+  // It is safe to cast here, because it is checked above that
+  // track->kind() is kVideoKind.
+  auto* video_track = static_cast<VideoTrackInterface*>(track.get());
+  std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> video_sink =
+      video_quality_analyzer_injection_helper_->CreateVideoSink(writer);
+  video_track->AddOrUpdateSink(video_sink.get(), rtc::VideoSinkWants());
+  output_video_sinks_.push_back(std::move(video_sink));
+}
+
 void PeerConnectionE2EQualityTest::RunOnSignalingThread(RunParams run_params) {
-  AddMedia(alice_.get());
-  AddMedia(bob_.get());
+  alice_video_sources_ = AddMedia(alice_.get());
+  bob_video_sources_ = AddMedia(bob_.get());
 
   SetupCall();
 
-  WaitForTransceiversSetup(alice_->params(), bob_.get());
-  WaitForTransceiversSetup(bob_->params(), alice_.get());
-  SetupVideoSink(alice_->params(), bob_.get());
-  SetupVideoSink(bob_->params(), alice_.get());
-
-  StartVideo();
-
   rtc::Event done;
   done.Wait(static_cast<int>(run_params.run_duration.ms()));
 
   TearDownCall();
 }
 
-void PeerConnectionE2EQualityTest::AddMedia(TestPeer* peer) {
-  AddVideo(peer);
+std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>
+PeerConnectionE2EQualityTest::AddMedia(TestPeer* peer) {
   if (peer->params()->audio_config) {
     AddAudio(peer);
   }
+  return AddVideo(peer);
 }
 
-void PeerConnectionE2EQualityTest::AddVideo(TestPeer* peer) {
+std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>
+PeerConnectionE2EQualityTest::AddVideo(TestPeer* peer) {
   // Params here valid because of pre-run validation.
   Params* params = peer->params();
+  std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>> out;
   for (auto video_config : params->video_configs) {
     // Create video generator.
     std::unique_ptr<FrameGenerator> frame_generator =
@@ -261,7 +342,7 @@
     rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource> source =
         new rtc::RefCountedObject<FrameGeneratorCapturerVideoTrackSource>(
             move(capturer));
-    video_sources_.push_back(source);
+    out.push_back(source);
     RTC_LOG(INFO) << "Adding video with video_config.stream_label="
                   << video_config.stream_label.value();
     rtc::scoped_refptr<VideoTrackInterface> track =
@@ -269,6 +350,7 @@
                                              source);
     peer->AddTransceiver(track);
   }
+  return out;
 }
 
 std::unique_ptr<FrameGenerator>
@@ -332,58 +414,21 @@
   ASSERT_TRUE_WAIT(alice_->IsIceConnected(), kDefaultTimeoutMs);
 }
 
-void PeerConnectionE2EQualityTest::WaitForTransceiversSetup(
-    Params* params,
-    TestPeer* remote_peer) {
-  uint64_t expected_remote_transceivers =
-      params->video_configs.size() + (params->audio_config ? 1 : 0);
-  ASSERT_EQ_WAIT(remote_peer->observer()->on_track_transceivers_.size(),
-                 expected_remote_transceivers, kDefaultTimeoutMs);
-}
-
-void PeerConnectionE2EQualityTest::SetupVideoSink(Params* params,
-                                                  TestPeer* remote_peer) {
-  if (params->video_configs.empty()) {
-    return;
-  }
-  std::map<std::string, VideoConfig*> video_configs_by_label;
-  for (auto& video_config : params->video_configs) {
-    video_configs_by_label.insert(std::pair<std::string, VideoConfig*>(
-        video_config.stream_label.value(), &video_config));
-  }
-
-  for (const auto& transceiver :
-       remote_peer->observer()->on_track_transceivers_) {
-    const rtc::scoped_refptr<MediaStreamTrackInterface>& track =
-        transceiver->receiver()->track();
-    if (track->kind() != MediaStreamTrackInterface::kVideoKind) {
-      continue;
+void PeerConnectionE2EQualityTest::StartVideo(
+    const std::vector<
+        rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>& sources) {
+  for (auto& source : sources) {
+    if (source->state() != MediaSourceInterface::SourceState::kLive) {
+      source->Start();
     }
-
-    auto it = video_configs_by_label.find(track->id());
-    RTC_CHECK(it != video_configs_by_label.end());
-    VideoConfig* video_config = it->second;
-
-    VideoFrameWriter* writer = MaybeCreateVideoWriter(
-        video_config->output_dump_file_name, *video_config);
-    // It is safe to cast here, because it is checked above that track->kind()
-    // is kVideoKind.
-    auto* video_track = static_cast<VideoTrackInterface*>(track.get());
-    std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> video_sink =
-        video_quality_analyzer_injection_helper_->CreateVideoSink(writer);
-    video_track->AddOrUpdateSink(video_sink.get(), rtc::VideoSinkWants());
-    output_video_sinks_.push_back(std::move(video_sink));
-  }
-}
-
-void PeerConnectionE2EQualityTest::StartVideo() {
-  for (const auto& video_source : video_sources_) {
-    video_source->Start();
   }
 }
 
 void PeerConnectionE2EQualityTest::TearDownCall() {
-  for (const auto& video_source : video_sources_) {
+  for (const auto& video_source : alice_video_sources_) {
+    video_source->Stop();
+  }
+  for (const auto& video_source : bob_video_sources_) {
     video_source->Stop();
   }
 
@@ -394,7 +439,8 @@
     video_writer->Close();
   }
 
-  video_sources_.clear();
+  alice_video_sources_.clear();
+  bob_video_sources_.clear();
   video_writers_.clear();
   alice_.reset();
   bob_.reset();
diff --git a/test/pc/e2e/peer_connection_quality_test.h b/test/pc/e2e/peer_connection_quality_test.h
index 8cce506..b19a4fe 100644
--- a/test/pc/e2e/peer_connection_quality_test.h
+++ b/test/pc/e2e/peer_connection_quality_test.h
@@ -55,17 +55,21 @@
   // Validate peer's parameters, also ensure uniqueness of all video stream
   // labels.
   void ValidateParams(std::vector<Params*> params);
+  void SetupVideoSink(rtc::scoped_refptr<RtpTransceiverInterface> transceiver,
+                      std::vector<VideoConfig> remote_video_configs);
   // Have to be run on the signaling thread.
   void RunOnSignalingThread(RunParams run_params);
-  void AddMedia(TestPeer* peer);
-  void AddVideo(TestPeer* peer);
+  std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>
+  AddMedia(TestPeer* peer);
+  std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>
+  AddVideo(TestPeer* peer);
   std::unique_ptr<FrameGenerator> CreateFrameGenerator(
       const VideoConfig& video_config);
   void AddAudio(TestPeer* peer);
   void SetupCall();
-  void WaitForTransceiversSetup(Params* params, TestPeer* remote_peer);
-  void SetupVideoSink(Params* params, TestPeer* remote_peer);
-  void StartVideo();
+  void StartVideo(
+      const std::vector<
+          rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>& sources);
   void TearDownCall();
   VideoFrameWriter* MaybeCreateVideoWriter(
       absl::optional<std::string> file_name,
@@ -81,7 +85,9 @@
   std::unique_ptr<TestPeer> bob_;
 
   std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>
-      video_sources_;
+      alice_video_sources_;
+  std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>
+      bob_video_sources_;
   std::vector<std::unique_ptr<VideoFrameWriter>> video_writers_;
   std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>>
       output_video_sinks_;
diff --git a/test/pc/e2e/test_peer.cc b/test/pc/e2e/test_peer.cc
index 8c46206..d0e7e5a 100644
--- a/test/pc/e2e/test_peer.cc
+++ b/test/pc/e2e/test_peer.cc
@@ -245,6 +245,7 @@
 std::unique_ptr<TestPeer> TestPeer::CreateTestPeer(
     std::unique_ptr<InjectableComponents> components,
     std::unique_ptr<Params> params,
+    std::unique_ptr<MockPeerConnectionObserver> observer,
     VideoQualityAnalyzerInjectionHelper* video_analyzer_helper,
     rtc::Thread* signaling_thread,
     absl::optional<std::string> audio_output_file_name) {
@@ -253,9 +254,6 @@
   SetMandatoryEntities(components.get());
   params->rtc_configuration.sdp_semantics = SdpSemantics::kUnifiedPlan;
 
-  std::unique_ptr<MockPeerConnectionObserver> observer =
-      absl::make_unique<MockPeerConnectionObserver>();
-
   // Create peer connection factory.
   PeerConnectionFactoryDependencies pcf_deps = CreatePCFDependencies(
       std::move(components->pcf_dependencies), params->audio_config,
diff --git a/test/pc/e2e/test_peer.h b/test/pc/e2e/test_peer.h
index f6e878d..3ee96c2 100644
--- a/test/pc/e2e/test_peer.h
+++ b/test/pc/e2e/test_peer.h
@@ -53,6 +53,7 @@
   static std::unique_ptr<TestPeer> CreateTestPeer(
       std::unique_ptr<InjectableComponents> components,
       std::unique_ptr<Params> params,
+      std::unique_ptr<MockPeerConnectionObserver> observer,
       VideoQualityAnalyzerInjectionHelper* video_analyzer_helper,
       rtc::Thread* signaling_thread,
       absl::optional<std::string> audio_output_file_name);