Add screen share support to PC level test framework
Bug: webrtc:10138 Change-Id: I1a8ac683e91f8061387f407610d7db2a6d0d4fe9 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/136805 Commit-Queue: Artem Titov <titovartem@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Reviewed-by: Bjorn Mellem <mellem@webrtc.org> Cr-Commit-Position: refs/heads/master@{#27950}
This commit is contained in:
@ -13,6 +13,7 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
@ -40,19 +41,72 @@
|
||||
namespace webrtc {
|
||||
namespace webrtc_pc_e2e {
|
||||
|
||||
constexpr size_t kDefaultSlidesWidth = 1850;
|
||||
constexpr size_t kDefaultSlidesHeight = 1110;
|
||||
|
||||
// API is in development. Can be changed/removed without notice.
|
||||
class PeerConnectionE2EQualityTestFixture {
|
||||
public:
|
||||
// Contains parameters for screen share scrolling.
|
||||
//
|
||||
// If scrolling is enabled, then it will be done by putting sliding window
|
||||
// on source video and moving this window from top left corner to the
|
||||
// bottom right corner of the picture.
|
||||
//
|
||||
// In such case source dimensions must be greater or equal to the sliding
|
||||
// window dimensions. So |source_width| and |source_height| are the dimensions
|
||||
// of the source frame, while |VideoConfig::width| and |VideoConfig::height|
|
||||
// are the dimensions of the sliding window.
|
||||
//
|
||||
// Because |source_width| and |source_height| are dimensions of the source
|
||||
// frame, they have to be width and height of videos from
|
||||
// |ScreenShareConfig::slides_yuv_file_names|.
|
||||
//
|
||||
// Because scrolling have to be done on single slide it also requires, that
|
||||
// |duration| must be less or equal to
|
||||
// |ScreenShareConfig::slide_change_interval|.
|
||||
struct ScrollingParams {
|
||||
ScrollingParams(TimeDelta duration,
|
||||
size_t source_width,
|
||||
size_t source_height)
|
||||
: duration(duration),
|
||||
source_width(source_width),
|
||||
source_height(source_height) {
|
||||
RTC_CHECK_GT(duration.ms(), 0);
|
||||
}
|
||||
|
||||
// Duration of scrolling.
|
||||
TimeDelta duration;
|
||||
// Width of source slides video.
|
||||
size_t source_width;
|
||||
// Height of source slides video.
|
||||
size_t source_height;
|
||||
};
|
||||
|
||||
// Contains screen share video stream properties.
|
||||
struct ScreenShareConfig {
|
||||
// If true, slides will be generated programmatically.
|
||||
bool generate_slides;
|
||||
explicit ScreenShareConfig(TimeDelta slide_change_interval)
|
||||
: slide_change_interval(slide_change_interval) {
|
||||
RTC_CHECK_GT(slide_change_interval.ms(), 0);
|
||||
}
|
||||
|
||||
// Shows how long one slide should be presented on the screen during
|
||||
// slide generation.
|
||||
TimeDelta slide_change_interval;
|
||||
// If equal to 0, no scrolling will be applied.
|
||||
TimeDelta scroll_duration;
|
||||
// If empty, default set of slides will be used.
|
||||
// If true, slides will be generated programmatically. No scrolling params
|
||||
// will be applied in such case.
|
||||
bool generate_slides = false;
|
||||
// If present scrolling will be applied. Please read extra requirement on
|
||||
// |slides_yuv_file_names| for scrolling.
|
||||
absl::optional<ScrollingParams> scrolling_params;
|
||||
// Contains list of yuv files with slides.
|
||||
//
|
||||
// If empty, default set of slides will be used. In such case
|
||||
// |VideoConfig::width| must be equal to |kDefaultSlidesWidth| and
|
||||
// |VideoConfig::height| must be equal to |kDefaultSlidesHeight| or if
|
||||
// |scrolling_params| are specified, then |ScrollingParams::source_width|
|
||||
// must be equal to |kDefaultSlidesWidth| and
|
||||
// |ScrollingParams::source_height| must be equal to |kDefaultSlidesHeight|.
|
||||
std::vector<std::string> slides_yuv_file_names;
|
||||
};
|
||||
|
||||
@ -63,7 +117,9 @@ class PeerConnectionE2EQualityTestFixture {
|
||||
VideoConfig(size_t width, size_t height, int32_t fps)
|
||||
: width(width), height(height), fps(fps) {}
|
||||
|
||||
// Video stream width.
|
||||
const size_t width;
|
||||
// Video stream height.
|
||||
const size_t height;
|
||||
const int32_t fps;
|
||||
// Have to be unique among all specified configs for all peers in the call.
|
||||
|
@ -37,6 +37,9 @@ TEST(PeerConnectionE2EQualityTestSmokeTest, MAYBE_RunWithEmulatedNetwork) {
|
||||
using RunParams = PeerConnectionE2EQualityTestFixture::RunParams;
|
||||
using VideoConfig = PeerConnectionE2EQualityTestFixture::VideoConfig;
|
||||
using AudioConfig = PeerConnectionE2EQualityTestFixture::AudioConfig;
|
||||
using ScreenShareConfig =
|
||||
PeerConnectionE2EQualityTestFixture::ScreenShareConfig;
|
||||
using ScrollingParams = PeerConnectionE2EQualityTestFixture::ScrollingParams;
|
||||
|
||||
// Setup emulated network
|
||||
std::unique_ptr<NetworkEmulationManager> network_emulation_manager =
|
||||
@ -87,31 +90,42 @@ TEST(PeerConnectionE2EQualityTestSmokeTest, MAYBE_RunWithEmulatedNetwork) {
|
||||
{alice_endpoint});
|
||||
fixture->AddPeer(alice_network->network_thread(),
|
||||
alice_network->network_manager(), [](PeerConfigurer* alice) {
|
||||
VideoConfig video_config(640, 360, 30);
|
||||
video_config.stream_label = "alice-video";
|
||||
alice->AddVideoConfig(std::move(video_config));
|
||||
AudioConfig audio_config;
|
||||
audio_config.stream_label = "alice-audio";
|
||||
audio_config.mode = AudioConfig::Mode::kFile;
|
||||
audio_config.input_file_name = test::ResourcePath(
|
||||
VideoConfig video(640, 360, 30);
|
||||
video.stream_label = "alice-video";
|
||||
alice->AddVideoConfig(std::move(video));
|
||||
|
||||
AudioConfig audio;
|
||||
audio.stream_label = "alice-audio";
|
||||
audio.mode = AudioConfig::Mode::kFile;
|
||||
audio.input_file_name = test::ResourcePath(
|
||||
"pc_quality_smoke_test_alice_source", "wav");
|
||||
alice->SetAudioConfig(std::move(audio_config));
|
||||
alice->SetAudioConfig(std::move(audio));
|
||||
});
|
||||
|
||||
EmulatedNetworkManagerInterface* bob_network =
|
||||
network_emulation_manager->CreateEmulatedNetworkManagerInterface(
|
||||
{bob_endpoint});
|
||||
fixture->AddPeer(bob_network->network_thread(),
|
||||
bob_network->network_manager(), [](PeerConfigurer* bob) {
|
||||
VideoConfig video_config(640, 360, 30);
|
||||
video_config.stream_label = "bob-video";
|
||||
bob->AddVideoConfig(std::move(video_config));
|
||||
AudioConfig audio_config;
|
||||
audio_config.stream_label = "bob-audio";
|
||||
audio_config.mode = AudioConfig::Mode::kFile;
|
||||
audio_config.input_file_name = test::ResourcePath(
|
||||
"pc_quality_smoke_test_bob_source", "wav");
|
||||
bob->SetAudioConfig(std::move(audio_config));
|
||||
fixture->AddPeer(
|
||||
bob_network->network_thread(), bob_network->network_manager(),
|
||||
[](PeerConfigurer* bob) {
|
||||
VideoConfig video(640, 360, 30);
|
||||
video.stream_label = "bob-video";
|
||||
bob->AddVideoConfig(std::move(video));
|
||||
|
||||
VideoConfig screenshare(640, 360, 30);
|
||||
screenshare.stream_label = "bob-screenshare";
|
||||
screenshare.screen_share_config =
|
||||
ScreenShareConfig(TimeDelta::seconds(2));
|
||||
screenshare.screen_share_config->scrolling_params = ScrollingParams(
|
||||
TimeDelta::ms(1800), kDefaultSlidesWidth, kDefaultSlidesHeight);
|
||||
bob->AddVideoConfig(screenshare);
|
||||
|
||||
AudioConfig audio;
|
||||
audio.stream_label = "bob-audio";
|
||||
audio.mode = AudioConfig::Mode::kFile;
|
||||
audio.input_file_name =
|
||||
test::ResourcePath("pc_quality_smoke_test_bob_source", "wav");
|
||||
bob->SetAudioConfig(std::move(audio));
|
||||
});
|
||||
|
||||
fixture->AddQualityMetricsReporter(
|
||||
|
@ -461,6 +461,37 @@ void PeerConnectionE2EQualityTest::ValidateParams(const RunParams& run_params,
|
||||
<< VideoConfigSourcePresenceToString(video_config);
|
||||
RTC_CHECK(!(video_config.screen_share_config && video_config.generator))
|
||||
<< VideoConfigSourcePresenceToString(video_config);
|
||||
|
||||
if (video_config.screen_share_config) {
|
||||
if (video_config.screen_share_config->slides_yuv_file_names.empty()) {
|
||||
if (video_config.screen_share_config->scrolling_params) {
|
||||
// If we have scrolling params, then its |source_width| and
|
||||
// |source_heigh| will be used as width and height of video input,
|
||||
// so we have to validate it against width and height of default
|
||||
// input.
|
||||
RTC_CHECK_EQ(video_config.screen_share_config->scrolling_params
|
||||
->source_width,
|
||||
kDefaultSlidesWidth);
|
||||
RTC_CHECK_EQ(video_config.screen_share_config->scrolling_params
|
||||
->source_height,
|
||||
kDefaultSlidesHeight);
|
||||
} else {
|
||||
RTC_CHECK_EQ(video_config.width, kDefaultSlidesWidth);
|
||||
RTC_CHECK_EQ(video_config.height, kDefaultSlidesHeight);
|
||||
}
|
||||
}
|
||||
if (video_config.screen_share_config->scrolling_params) {
|
||||
RTC_CHECK_LE(
|
||||
video_config.screen_share_config->scrolling_params->duration,
|
||||
video_config.screen_share_config->slide_change_interval);
|
||||
RTC_CHECK_GE(
|
||||
video_config.screen_share_config->scrolling_params->source_width,
|
||||
video_config.width);
|
||||
RTC_CHECK_GE(
|
||||
video_config.screen_share_config->scrolling_params->source_height,
|
||||
video_config.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p->audio_config) {
|
||||
bool inserted =
|
||||
@ -616,15 +647,55 @@ PeerConnectionE2EQualityTest::CreateFrameGenerator(
|
||||
video_config.width, video_config.height, /*frame_repeat_count=*/1);
|
||||
}
|
||||
if (video_config.screen_share_config) {
|
||||
// TODO(titovartem) implement screen share support
|
||||
// (http://bugs.webrtc.org/10138)
|
||||
RTC_NOTREACHED() << "Screen share is not implemented";
|
||||
return nullptr;
|
||||
return CreateScreenShareFrameGenerator(video_config);
|
||||
}
|
||||
RTC_NOTREACHED() << "Unsupported video_config input source";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<test::FrameGenerator>
|
||||
PeerConnectionE2EQualityTest::CreateScreenShareFrameGenerator(
|
||||
const VideoConfig& video_config) {
|
||||
RTC_CHECK(video_config.screen_share_config);
|
||||
if (video_config.screen_share_config->generate_slides) {
|
||||
return test::FrameGenerator::CreateSlideGenerator(
|
||||
video_config.width, video_config.height,
|
||||
video_config.screen_share_config->slide_change_interval.seconds() *
|
||||
video_config.fps);
|
||||
}
|
||||
std::vector<std::string> slides =
|
||||
video_config.screen_share_config->slides_yuv_file_names;
|
||||
if (slides.empty()) {
|
||||
// If slides is empty we need to add default slides as source. In such case
|
||||
// video width and height is validated to be equal to kDefaultSlidesWidth
|
||||
// and kDefaultSlidesHeight.
|
||||
slides.push_back(test::ResourcePath("web_screenshot_1850_1110", "yuv"));
|
||||
slides.push_back(test::ResourcePath("presentation_1850_1110", "yuv"));
|
||||
slides.push_back(test::ResourcePath("photo_1850_1110", "yuv"));
|
||||
slides.push_back(test::ResourcePath("difficult_photo_1850_1110", "yuv"));
|
||||
}
|
||||
if (!video_config.screen_share_config->scrolling_params) {
|
||||
// Cycle image every slide_change_interval seconds.
|
||||
return test::FrameGenerator::CreateFromYuvFile(
|
||||
slides, video_config.width, video_config.height,
|
||||
video_config.screen_share_config->slide_change_interval.seconds() *
|
||||
video_config.fps);
|
||||
}
|
||||
|
||||
// |pause_duration| is nonnegative. It is validated in ValidateParams(...).
|
||||
TimeDelta pause_duration =
|
||||
video_config.screen_share_config->slide_change_interval -
|
||||
video_config.screen_share_config->scrolling_params->duration;
|
||||
|
||||
return test::FrameGenerator::CreateScrollingInputFromYuvFiles(
|
||||
clock_, slides,
|
||||
video_config.screen_share_config->scrolling_params->source_width,
|
||||
video_config.screen_share_config->scrolling_params->source_height,
|
||||
video_config.width, video_config.height,
|
||||
video_config.screen_share_config->scrolling_params->duration.ms(),
|
||||
pause_duration.ms());
|
||||
}
|
||||
|
||||
void PeerConnectionE2EQualityTest::MaybeAddAudio(TestPeer* peer) {
|
||||
if (!peer->params()->audio_config) {
|
||||
return;
|
||||
|
@ -219,6 +219,8 @@ class PeerConnectionE2EQualityTest
|
||||
MaybeAddVideo(TestPeer* peer);
|
||||
std::unique_ptr<test::FrameGenerator> CreateFrameGenerator(
|
||||
const VideoConfig& video_config);
|
||||
std::unique_ptr<test::FrameGenerator> CreateScreenShareFrameGenerator(
|
||||
const VideoConfig& video_config);
|
||||
void MaybeAddAudio(TestPeer* peer);
|
||||
void SetPeerCodecPreferences(TestPeer* peer, const RunParams& run_params);
|
||||
void SetupCall();
|
||||
|
Reference in New Issue
Block a user