diff --git a/api/BUILD.gn b/api/BUILD.gn index 6abaa70271..651b8fe65f 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn @@ -433,9 +433,13 @@ rtc_source_set("peer_network_dependencies") { rtc_source_set("peer_connection_quality_test_fixture_api") { visibility = [ "*" ] testonly = true - sources = [ "test/peerconnection_quality_test_fixture.h" ] + sources = [ + "test/peerconnection_quality_test_fixture.cc", + "test/peerconnection_quality_test_fixture.h", + ] deps = [ + ":array_view", ":audio_quality_analyzer_api", ":callfactory_api", ":fec_controller_api", @@ -1176,6 +1180,7 @@ if (rtc_include_tests) { "scoped_refptr_unittest.cc", "sequence_checker_unittest.cc", "test/create_time_controller_unittest.cc", + "test/peerconnection_quality_test_fixture_unittest.cc", ] deps = [ @@ -1185,6 +1190,7 @@ if (rtc_include_tests) { ":field_trials_view", ":function_view", ":libjingle_peerconnection_api", + ":peer_connection_quality_test_fixture_api", ":rtc_error", ":rtc_event_log_output_file", ":rtp_packet_info", @@ -1212,6 +1218,7 @@ if (rtc_include_tests) { "video:rtp_video_frame_assembler_unittests", "video:video_unittests", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } rtc_library("compile_all_headers") { diff --git a/api/test/peerconnection_quality_test_fixture.cc b/api/test/peerconnection_quality_test_fixture.cc new file mode 100644 index 0000000000..707c52e0f3 --- /dev/null +++ b/api/test/peerconnection_quality_test_fixture.cc @@ -0,0 +1,73 @@ +/* + * Copyright 2022 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/peerconnection_quality_test_fixture.h" + +#include "absl/types/optional.h" +#include "api/array_view.h" + +namespace webrtc { +namespace webrtc_pc_e2e { + +using VideoCodecConfig = ::webrtc::webrtc_pc_e2e:: + PeerConnectionE2EQualityTestFixture::VideoCodecConfig; +using VideoSubscription = ::webrtc::webrtc_pc_e2e:: + PeerConnectionE2EQualityTestFixture::VideoSubscription; + +PeerConnectionE2EQualityTestFixture::VideoSubscription::Resolution::Resolution( + size_t width, + size_t height, + int32_t fps) + : width_(width), height_(height), fps_(fps), spec_(Spec::kNone) {} +PeerConnectionE2EQualityTestFixture::VideoSubscription::Resolution::Resolution( + const VideoConfig& video_config) + : width_(video_config.width), + height_(video_config.height), + fps_(video_config.fps), + spec_(Spec::kNone) {} +PeerConnectionE2EQualityTestFixture::VideoSubscription::Resolution::Resolution( + Spec spec) + : width_(0), height_(0), fps_(0), spec_(spec) {} + +bool PeerConnectionE2EQualityTestFixture::VideoSubscription::Resolution:: +operator==(const Resolution& other) const { + if (spec_ != Spec::kNone && spec_ == other.spec_) { + // If there is some particular spec set, then it doesn't matter what + // values we have in other fields. + return true; + } + return width_ == other.width_ && height_ == other.height_ && + fps_ == other.fps_ && spec_ == other.spec_; +} + +absl::optional +PeerConnectionE2EQualityTestFixture::VideoSubscription::GetMaxResolution( + rtc::ArrayView video_configs) { + if (video_configs.empty()) { + return absl::nullopt; + } + + VideoSubscription::Resolution max_resolution; + for (const VideoConfig& config : video_configs) { + if (max_resolution.width() < config.width) { + max_resolution.set_width(config.width); + } + if (max_resolution.height() < config.height) { + max_resolution.set_height(config.height); + } + if (max_resolution.fps() < config.fps) { + max_resolution.set_fps(config.fps); + } + } + return max_resolution; +} + +} // namespace webrtc_pc_e2e +} // namespace webrtc diff --git a/api/test/peerconnection_quality_test_fixture.h b/api/test/peerconnection_quality_test_fixture.h index 35a42ba8f1..240cf31993 100644 --- a/api/test/peerconnection_quality_test_fixture.h +++ b/api/test/peerconnection_quality_test_fixture.h @@ -19,6 +19,7 @@ #include "absl/memory/memory.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" +#include "api/array_view.h" #include "api/async_resolver_factory.h" #include "api/audio/audio_mixer.h" #include "api/call/call_factory_interface.h" @@ -327,6 +328,99 @@ class PeerConnectionE2EQualityTestFixture { std::map required_params; }; + // Subscription to the remote video streams. It declares which remote stream + // peer should receive and in which resolution (width x height x fps). + class VideoSubscription { + public: + class Resolution { + public: + // Determines special resolutions, which can't be expressed in terms of + // width, height and fps. + enum class Spec { + // No extra spec set. It describes a regular resolution described by + // width, height and fps. + kNone, + // Describes resolution which contains max value among all sender's + // video streams in each dimension (width, height, fps). + kMaxFromSender + }; + + Resolution(size_t width, size_t height, int32_t fps); + explicit Resolution(const VideoConfig& video_config); + explicit Resolution(Spec spec = Spec::kNone); + + bool operator==(const Resolution& other) const; + bool operator!=(const Resolution& other) const { + return !(*this == other); + } + + size_t width() const { return width_; } + void set_width(size_t width) { width_ = width; } + size_t height() const { return height_; } + void set_height(size_t height) { height_ = height; } + int32_t fps() const { return fps_; } + void set_fps(int32_t fps) { fps_ = fps; } + + private: + size_t width_ = 0; + size_t height_ = 0; + int32_t fps_ = 0; + Spec spec_ = Spec::kNone; + }; + + // Returns the resolution constructed as maximum from all resolution + // dimensions: width, height and fps. + static absl::optional GetMaxResolution( + rtc::ArrayView video_configs); + + // Subscribes receiver to all streams sent by the specified peer with + // specified resolution. It will override any resolution that was used in + // `SubscribeToAll` independently from methods call order. + VideoSubscription& SubscribeToPeer( + absl::string_view peer_name, + Resolution resolution = Resolution(Resolution::Spec::kMaxFromSender)) { + peers_resolution_[std::string(peer_name)] = resolution; + return *this; + } + + // Subscribes receiver to the all sent streams with specified resolution. + // If any stream was subscribed to with `SubscribeTo` method that will + // override resolution passed to this function independently from methods + // call order. + VideoSubscription& SubscribeToAllPeers( + Resolution resolution = Resolution(Resolution::Spec::kMaxFromSender)) { + default_resolution_ = resolution; + return *this; + } + + // Returns resolution for specific sender. If no specific resolution was + // set for this sender, then will return resolution used for all streams. + // If subscription doesn't subscribe to all streams, `absl::nullopt` will be + // returned. + absl::optional GetResolutionForPeer( + absl::string_view peer_name) const { + auto it = peers_resolution_.find(std::string(peer_name)); + if (it == peers_resolution_.end()) { + return default_resolution_; + } + return it->second; + } + + // Returns a maybe empty list of senders for which peer explicitly + // subscribed to with specific resolution. + std::vector GetSubscribedPeers() const { + std::vector subscribed_streams; + for (const auto& entry : peers_resolution_) { + subscribed_streams.push_back(entry.first); + } + return subscribed_streams; + } + + private: + absl::optional default_resolution_ = absl::nullopt; + std::map peers_resolution_; + }; + // This class is used to fully configure one peer inside the call. class PeerConfigurer { public: @@ -396,6 +490,11 @@ class PeerConnectionE2EQualityTestFixture { virtual PeerConfigurer* AddVideoConfig( VideoConfig config, CapturingDeviceIndex capturing_device_index) = 0; + // Sets video subscription for the peer. By default subscription will + // include all streams with `VideoSubscription::kSameAsSendStream` + // resolution. To override this behavior use this method. + virtual PeerConfigurer* SetVideoSubscription( + VideoSubscription subscription) = 0; // Set the list of video codecs used by the peer during the test. These // codecs will be negotiated in SDP during offer/answer exchange. The order // of these codecs during negotiation will be the same as in `video_codecs`. diff --git a/api/test/peerconnection_quality_test_fixture_unittest.cc b/api/test/peerconnection_quality_test_fixture_unittest.cc new file mode 100644 index 0000000000..8bde0aa7c3 --- /dev/null +++ b/api/test/peerconnection_quality_test_fixture_unittest.cc @@ -0,0 +1,82 @@ +/* + * Copyright 2022 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/peerconnection_quality_test_fixture.h" + +#include + +#include "absl/types/optional.h" +#include "rtc_base/gunit.h" +#include "test/gmock.h" + +namespace webrtc { +namespace webrtc_pc_e2e { +namespace { + +using VideoSubscription = ::webrtc::webrtc_pc_e2e:: + PeerConnectionE2EQualityTestFixture::VideoSubscription; +using VideoConfig = + ::webrtc::webrtc_pc_e2e::PeerConnectionE2EQualityTestFixture::VideoConfig; + +TEST(PclfVideoSubscription, MaxFromSenderSpecEqualIndependentOfOtherFields) { + VideoSubscription::Resolution r1( + VideoSubscription::Resolution::Spec::kMaxFromSender); + r1.set_width(1); + r1.set_height(2); + r1.set_fps(3); + VideoSubscription::Resolution r2( + VideoSubscription::Resolution::Spec::kMaxFromSender); + r1.set_width(4); + r1.set_height(5); + r1.set_fps(6); + EXPECT_EQ(r1, r2); +} + +TEST(PclfVideoSubscription, WhenSpecIsNotSetFieldsAreCompared) { + VideoSubscription::Resolution test_resolution(/*width=*/1, /*height=*/2, + /*fps=*/3); + VideoSubscription::Resolution equal_resolution(/*width=*/1, /*height=*/2, + /*fps=*/3); + VideoSubscription::Resolution different_width(/*width=*/10, /*height=*/2, + /*fps=*/3); + VideoSubscription::Resolution different_height(/*width=*/1, /*height=*/20, + /*fps=*/3); + VideoSubscription::Resolution different_fps(/*width=*/1, /*height=*/20, + /*fps=*/30); + + EXPECT_EQ(test_resolution, equal_resolution); + EXPECT_NE(test_resolution, different_width); + EXPECT_NE(test_resolution, different_height); + EXPECT_NE(test_resolution, different_fps); +} + +TEST(PclfVideoSubscription, GetMaxResolutionForEmptyReturnsNullopt) { + absl::optional resolution = + VideoSubscription::GetMaxResolution({}); + ASSERT_FALSE(resolution.has_value()); +} + +TEST(PclfVideoSubscription, GetMaxResolutionSelectMaxForEachDimention) { + VideoConfig max_width(/*width=*/1000, /*height=*/1, /*fps=*/1); + VideoConfig max_height(/*width=*/1, /*height=*/100, /*fps=*/1); + VideoConfig max_fps(/*width=*/1, /*height=*/1, /*fps=*/10); + + absl::optional resolution = + VideoSubscription::GetMaxResolution( + std::vector{max_width, max_height, max_fps}); + ASSERT_TRUE(resolution.has_value()); + EXPECT_EQ(resolution->width(), static_cast(1000)); + EXPECT_EQ(resolution->height(), static_cast(100)); + EXPECT_EQ(resolution->fps(), 10); +} + +} // namespace +} // namespace webrtc_pc_e2e +} // namespace webrtc diff --git a/test/pc/e2e/peer_configurer.h b/test/pc/e2e/peer_configurer.h index 711e09d18d..ee3c992b42 100644 --- a/test/pc/e2e/peer_configurer.h +++ b/test/pc/e2e/peer_configurer.h @@ -145,6 +145,12 @@ class PeerConfigurerImpl final video_sources_.push_back(index); return this; } + PeerConfigurer* SetVideoSubscription( + PeerConnectionE2EQualityTestFixture::VideoSubscription subscription) + override { + params_->video_subscription = std::move(subscription); + return this; + } PeerConfigurer* SetAudioConfig( PeerConnectionE2EQualityTestFixture::AudioConfig config) override { params_->audio_config = std::move(config); diff --git a/test/pc/e2e/peer_connection_quality_test_params.h b/test/pc/e2e/peer_connection_quality_test_params.h index 8062d20707..5a2431ab88 100644 --- a/test/pc/e2e/peer_connection_quality_test_params.h +++ b/test/pc/e2e/peer_connection_quality_test_params.h @@ -143,6 +143,9 @@ struct Params { BitrateSettings bitrate_settings; std::vector video_codecs; + PeerConnectionE2EQualityTestFixture::VideoSubscription video_subscription = + PeerConnectionE2EQualityTestFixture::VideoSubscription() + .SubscribeToAllPeers(); }; } // namespace webrtc_pc_e2e