diff --git a/test/DEPS b/test/DEPS index 712dc6b043..d69c889c94 100644 --- a/test/DEPS +++ b/test/DEPS @@ -54,7 +54,7 @@ specific_include_rules = { "+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 44170c44e6..4f293fa42c 100644 --- a/test/pc/e2e/peer_connection_quality_test.cc +++ b/test/pc/e2e/peer_connection_quality_test.cc @@ -1,3 +1,5 @@ +#include + /* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * @@ -13,9 +15,11 @@ #include #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 @@ std::string VideoConfigSourcePresenceToString(const VideoConfig& video_config) { 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)> + on_track_callback, + std::function on_connected_callback) + : on_track_callback_(std::move(on_track_callback)), + on_connected_callback_(std::move(on_connected_callback)) {} + + void OnTrack( + rtc::scoped_refptr 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)> + on_track_callback_; + std::function on_connected_callback_; +}; + } // namespace PeerConnectionE2EQualityTest::PeerConnectionE2EQualityTest( @@ -110,12 +149,28 @@ void PeerConnectionE2EQualityTest::Run( 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 alice_video_configs = alice_params->video_configs; + std::vector bob_video_configs = bob_params->video_configs; + alice_ = TestPeer::CreateTestPeer( std::move(alice_components), std::move(alice_params), + absl::make_unique( + [this, bob_video_configs]( + rtc::scoped_refptr 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( + [this, alice_video_configs]( + rtc::scoped_refptr 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 @@ void PeerConnectionE2EQualityTest::Run( 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 @@ void PeerConnectionE2EQualityTest::ValidateParams(std::vector params) { RTC_CHECK_GT(media_streams_count, 0) << "No media in the call."; } +void PeerConnectionE2EQualityTest::SetupVideoSink( + rtc::scoped_refptr transceiver, + std::vector remote_video_configs) { + const rtc::scoped_refptr& 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(track.get()); + std::unique_ptr> 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(run_params.run_duration.ms())); TearDownCall(); } -void PeerConnectionE2EQualityTest::AddMedia(TestPeer* peer) { - AddVideo(peer); +std::vector> +PeerConnectionE2EQualityTest::AddMedia(TestPeer* peer) { if (peer->params()->audio_config) { AddAudio(peer); } + return AddVideo(peer); } -void PeerConnectionE2EQualityTest::AddVideo(TestPeer* peer) { +std::vector> +PeerConnectionE2EQualityTest::AddVideo(TestPeer* peer) { // Params here valid because of pre-run validation. Params* params = peer->params(); + std::vector> out; for (auto video_config : params->video_configs) { // Create video generator. std::unique_ptr frame_generator = @@ -261,7 +342,7 @@ void PeerConnectionE2EQualityTest::AddVideo(TestPeer* peer) { rtc::scoped_refptr source = new rtc::RefCountedObject( 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 track = @@ -269,6 +350,7 @@ void PeerConnectionE2EQualityTest::AddVideo(TestPeer* peer) { source); peer->AddTransceiver(track); } + return out; } std::unique_ptr @@ -332,58 +414,21 @@ void PeerConnectionE2EQualityTest::SetupCall() { 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 video_configs_by_label; - for (auto& video_config : params->video_configs) { - video_configs_by_label.insert(std::pair( - video_config.stream_label.value(), &video_config)); - } - - for (const auto& transceiver : - remote_peer->observer()->on_track_transceivers_) { - const rtc::scoped_refptr& track = - transceiver->receiver()->track(); - if (track->kind() != MediaStreamTrackInterface::kVideoKind) { - continue; +void PeerConnectionE2EQualityTest::StartVideo( + const std::vector< + rtc::scoped_refptr>& 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(track.get()); - std::unique_ptr> 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 @@ void PeerConnectionE2EQualityTest::TearDownCall() { 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 8cce506235..b19a4fe6da 100644 --- a/test/pc/e2e/peer_connection_quality_test.h +++ b/test/pc/e2e/peer_connection_quality_test.h @@ -55,17 +55,21 @@ class PeerConnectionE2EQualityTest // Validate peer's parameters, also ensure uniqueness of all video stream // labels. void ValidateParams(std::vector params); + void SetupVideoSink(rtc::scoped_refptr transceiver, + std::vector 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> + AddMedia(TestPeer* peer); + std::vector> + AddVideo(TestPeer* peer); std::unique_ptr 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>& sources); void TearDownCall(); VideoFrameWriter* MaybeCreateVideoWriter( absl::optional file_name, @@ -81,7 +85,9 @@ class PeerConnectionE2EQualityTest std::unique_ptr bob_; std::vector> - video_sources_; + alice_video_sources_; + std::vector> + bob_video_sources_; std::vector> video_writers_; std::vector>> output_video_sinks_; diff --git a/test/pc/e2e/test_peer.cc b/test/pc/e2e/test_peer.cc index 8c46206eeb..d0e7e5a597 100644 --- a/test/pc/e2e/test_peer.cc +++ b/test/pc/e2e/test_peer.cc @@ -245,6 +245,7 @@ PeerConnectionDependencies CreatePCDependencies( std::unique_ptr TestPeer::CreateTestPeer( std::unique_ptr components, std::unique_ptr params, + std::unique_ptr observer, VideoQualityAnalyzerInjectionHelper* video_analyzer_helper, rtc::Thread* signaling_thread, absl::optional audio_output_file_name) { @@ -253,9 +254,6 @@ std::unique_ptr TestPeer::CreateTestPeer( SetMandatoryEntities(components.get()); params->rtc_configuration.sdp_semantics = SdpSemantics::kUnifiedPlan; - std::unique_ptr observer = - absl::make_unique(); - // 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 f6e878db28..3ee96c22ef 100644 --- a/test/pc/e2e/test_peer.h +++ b/test/pc/e2e/test_peer.h @@ -53,6 +53,7 @@ class TestPeer final : public PeerConnectionWrapper { static std::unique_ptr CreateTestPeer( std::unique_ptr components, std::unique_ptr params, + std::unique_ptr observer, VideoQualityAnalyzerInjectionHelper* video_analyzer_helper, rtc::Thread* signaling_thread, absl::optional audio_output_file_name);