[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:
committed by
WebRTC LUCI CQ
parent
d959f3a665
commit
0d510529e7
@ -433,9 +433,13 @@ rtc_source_set("peer_network_dependencies") {
|
|||||||
rtc_source_set("peer_connection_quality_test_fixture_api") {
|
rtc_source_set("peer_connection_quality_test_fixture_api") {
|
||||||
visibility = [ "*" ]
|
visibility = [ "*" ]
|
||||||
testonly = true
|
testonly = true
|
||||||
sources = [ "test/peerconnection_quality_test_fixture.h" ]
|
sources = [
|
||||||
|
"test/peerconnection_quality_test_fixture.cc",
|
||||||
|
"test/peerconnection_quality_test_fixture.h",
|
||||||
|
]
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
|
":array_view",
|
||||||
":audio_quality_analyzer_api",
|
":audio_quality_analyzer_api",
|
||||||
":callfactory_api",
|
":callfactory_api",
|
||||||
":fec_controller_api",
|
":fec_controller_api",
|
||||||
@ -1176,6 +1180,7 @@ if (rtc_include_tests) {
|
|||||||
"scoped_refptr_unittest.cc",
|
"scoped_refptr_unittest.cc",
|
||||||
"sequence_checker_unittest.cc",
|
"sequence_checker_unittest.cc",
|
||||||
"test/create_time_controller_unittest.cc",
|
"test/create_time_controller_unittest.cc",
|
||||||
|
"test/peerconnection_quality_test_fixture_unittest.cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
@ -1185,6 +1190,7 @@ if (rtc_include_tests) {
|
|||||||
":field_trials_view",
|
":field_trials_view",
|
||||||
":function_view",
|
":function_view",
|
||||||
":libjingle_peerconnection_api",
|
":libjingle_peerconnection_api",
|
||||||
|
":peer_connection_quality_test_fixture_api",
|
||||||
":rtc_error",
|
":rtc_error",
|
||||||
":rtc_event_log_output_file",
|
":rtc_event_log_output_file",
|
||||||
":rtp_packet_info",
|
":rtp_packet_info",
|
||||||
@ -1212,6 +1218,7 @@ if (rtc_include_tests) {
|
|||||||
"video:rtp_video_frame_assembler_unittests",
|
"video:rtp_video_frame_assembler_unittests",
|
||||||
"video:video_unittests",
|
"video:video_unittests",
|
||||||
]
|
]
|
||||||
|
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_library("compile_all_headers") {
|
rtc_library("compile_all_headers") {
|
||||||
|
|||||||
73
api/test/peerconnection_quality_test_fixture.cc
Normal file
73
api/test/peerconnection_quality_test_fixture.cc
Normal 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
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
|
#include "api/array_view.h"
|
||||||
#include "api/async_resolver_factory.h"
|
#include "api/async_resolver_factory.h"
|
||||||
#include "api/audio/audio_mixer.h"
|
#include "api/audio/audio_mixer.h"
|
||||||
#include "api/call/call_factory_interface.h"
|
#include "api/call/call_factory_interface.h"
|
||||||
@ -327,6 +328,99 @@ class PeerConnectionE2EQualityTestFixture {
|
|||||||
std::map<std::string, std::string> required_params;
|
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.
|
// This class is used to fully configure one peer inside the call.
|
||||||
class PeerConfigurer {
|
class PeerConfigurer {
|
||||||
public:
|
public:
|
||||||
@ -396,6 +490,11 @@ class PeerConnectionE2EQualityTestFixture {
|
|||||||
virtual PeerConfigurer* AddVideoConfig(
|
virtual PeerConfigurer* AddVideoConfig(
|
||||||
VideoConfig config,
|
VideoConfig config,
|
||||||
CapturingDeviceIndex capturing_device_index) = 0;
|
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
|
// 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
|
// 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`.
|
// of these codecs during negotiation will be the same as in `video_codecs`.
|
||||||
|
|||||||
82
api/test/peerconnection_quality_test_fixture_unittest.cc
Normal file
82
api/test/peerconnection_quality_test_fixture_unittest.cc
Normal 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
|
||||||
@ -145,6 +145,12 @@ class PeerConfigurerImpl final
|
|||||||
video_sources_.push_back(index);
|
video_sources_.push_back(index);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
PeerConfigurer* SetVideoSubscription(
|
||||||
|
PeerConnectionE2EQualityTestFixture::VideoSubscription subscription)
|
||||||
|
override {
|
||||||
|
params_->video_subscription = std::move(subscription);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
PeerConfigurer* SetAudioConfig(
|
PeerConfigurer* SetAudioConfig(
|
||||||
PeerConnectionE2EQualityTestFixture::AudioConfig config) override {
|
PeerConnectionE2EQualityTestFixture::AudioConfig config) override {
|
||||||
params_->audio_config = std::move(config);
|
params_->audio_config = std::move(config);
|
||||||
|
|||||||
@ -143,6 +143,9 @@ struct Params {
|
|||||||
BitrateSettings bitrate_settings;
|
BitrateSettings bitrate_settings;
|
||||||
std::vector<PeerConnectionE2EQualityTestFixture::VideoCodecConfig>
|
std::vector<PeerConnectionE2EQualityTestFixture::VideoCodecConfig>
|
||||||
video_codecs;
|
video_codecs;
|
||||||
|
PeerConnectionE2EQualityTestFixture::VideoSubscription video_subscription =
|
||||||
|
PeerConnectionE2EQualityTestFixture::VideoSubscription()
|
||||||
|
.SubscribeToAllPeers();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webrtc_pc_e2e
|
} // namespace webrtc_pc_e2e
|
||||||
|
|||||||
Reference in New Issue
Block a user