[PCLF] Introduce API to subscribe to particular streams

Bug: b/213863770
Change-Id: If858686cd265ad48b4ea8be246651eff65fad4f3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/258981
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36570}
This commit is contained in:
Artem Titov
2022-04-19 13:01:03 +02:00
committed by WebRTC LUCI CQ
parent d959f3a665
commit 0d510529e7
6 changed files with 271 additions and 1 deletions

View File

@ -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") {

View File

@ -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<VideoSubscription::Resolution>
PeerConnectionE2EQualityTestFixture::VideoSubscription::GetMaxResolution(
rtc::ArrayView<const VideoConfig> 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

View File

@ -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<std::string, std::string> 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<VideoSubscription::Resolution> GetMaxResolution(
rtc::ArrayView<const VideoConfig> 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<Resolution> 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<std::string> GetSubscribedPeers() const {
std::vector<std::string> subscribed_streams;
for (const auto& entry : peers_resolution_) {
subscribed_streams.push_back(entry.first);
}
return subscribed_streams;
}
private:
absl::optional<Resolution> default_resolution_ = absl::nullopt;
std::map<std::string, Resolution> 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`.

View File

@ -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 <vector>
#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<VideoSubscription::Resolution> 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<VideoSubscription::Resolution> resolution =
VideoSubscription::GetMaxResolution(
std::vector<VideoConfig>{max_width, max_height, max_fps});
ASSERT_TRUE(resolution.has_value());
EXPECT_EQ(resolution->width(), static_cast<size_t>(1000));
EXPECT_EQ(resolution->height(), static_cast<size_t>(100));
EXPECT_EQ(resolution->fps(), 10);
}
} // namespace
} // namespace webrtc_pc_e2e
} // namespace webrtc

View File

@ -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);

View File

@ -143,6 +143,9 @@ struct Params {
BitrateSettings bitrate_settings;
std::vector<PeerConnectionE2EQualityTestFixture::VideoCodecConfig>
video_codecs;
PeerConnectionE2EQualityTestFixture::VideoSubscription video_subscription =
PeerConnectionE2EQualityTestFixture::VideoSubscription()
.SubscribeToAllPeers();
};
} // namespace webrtc_pc_e2e