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:
Artem Titov
2019-05-15 15:45:33 +02:00
committed by Commit Bot
parent a768345596
commit 7581ff7375
4 changed files with 172 additions and 29 deletions

View File

@ -13,6 +13,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
@ -40,19 +41,72 @@
namespace webrtc { namespace webrtc {
namespace webrtc_pc_e2e { namespace webrtc_pc_e2e {
constexpr size_t kDefaultSlidesWidth = 1850;
constexpr size_t kDefaultSlidesHeight = 1110;
// API is in development. Can be changed/removed without notice. // API is in development. Can be changed/removed without notice.
class PeerConnectionE2EQualityTestFixture { class PeerConnectionE2EQualityTestFixture {
public: 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. // Contains screen share video stream properties.
struct ScreenShareConfig { struct ScreenShareConfig {
// If true, slides will be generated programmatically. explicit ScreenShareConfig(TimeDelta slide_change_interval)
bool generate_slides; : 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 // Shows how long one slide should be presented on the screen during
// slide generation. // slide generation.
TimeDelta slide_change_interval; TimeDelta slide_change_interval;
// If equal to 0, no scrolling will be applied. // If true, slides will be generated programmatically. No scrolling params
TimeDelta scroll_duration; // will be applied in such case.
// If empty, default set of slides will be used. 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; std::vector<std::string> slides_yuv_file_names;
}; };
@ -63,7 +117,9 @@ class PeerConnectionE2EQualityTestFixture {
VideoConfig(size_t width, size_t height, int32_t fps) VideoConfig(size_t width, size_t height, int32_t fps)
: width(width), height(height), fps(fps) {} : width(width), height(height), fps(fps) {}
// Video stream width.
const size_t width; const size_t width;
// Video stream height.
const size_t height; const size_t height;
const int32_t fps; const int32_t fps;
// Have to be unique among all specified configs for all peers in the call. // Have to be unique among all specified configs for all peers in the call.

View File

@ -37,6 +37,9 @@ TEST(PeerConnectionE2EQualityTestSmokeTest, MAYBE_RunWithEmulatedNetwork) {
using RunParams = PeerConnectionE2EQualityTestFixture::RunParams; using RunParams = PeerConnectionE2EQualityTestFixture::RunParams;
using VideoConfig = PeerConnectionE2EQualityTestFixture::VideoConfig; using VideoConfig = PeerConnectionE2EQualityTestFixture::VideoConfig;
using AudioConfig = PeerConnectionE2EQualityTestFixture::AudioConfig; using AudioConfig = PeerConnectionE2EQualityTestFixture::AudioConfig;
using ScreenShareConfig =
PeerConnectionE2EQualityTestFixture::ScreenShareConfig;
using ScrollingParams = PeerConnectionE2EQualityTestFixture::ScrollingParams;
// Setup emulated network // Setup emulated network
std::unique_ptr<NetworkEmulationManager> network_emulation_manager = std::unique_ptr<NetworkEmulationManager> network_emulation_manager =
@ -87,31 +90,42 @@ TEST(PeerConnectionE2EQualityTestSmokeTest, MAYBE_RunWithEmulatedNetwork) {
{alice_endpoint}); {alice_endpoint});
fixture->AddPeer(alice_network->network_thread(), fixture->AddPeer(alice_network->network_thread(),
alice_network->network_manager(), [](PeerConfigurer* alice) { alice_network->network_manager(), [](PeerConfigurer* alice) {
VideoConfig video_config(640, 360, 30); VideoConfig video(640, 360, 30);
video_config.stream_label = "alice-video"; video.stream_label = "alice-video";
alice->AddVideoConfig(std::move(video_config)); alice->AddVideoConfig(std::move(video));
AudioConfig audio_config;
audio_config.stream_label = "alice-audio"; AudioConfig audio;
audio_config.mode = AudioConfig::Mode::kFile; audio.stream_label = "alice-audio";
audio_config.input_file_name = test::ResourcePath( audio.mode = AudioConfig::Mode::kFile;
audio.input_file_name = test::ResourcePath(
"pc_quality_smoke_test_alice_source", "wav"); "pc_quality_smoke_test_alice_source", "wav");
alice->SetAudioConfig(std::move(audio_config)); alice->SetAudioConfig(std::move(audio));
}); });
EmulatedNetworkManagerInterface* bob_network = EmulatedNetworkManagerInterface* bob_network =
network_emulation_manager->CreateEmulatedNetworkManagerInterface( network_emulation_manager->CreateEmulatedNetworkManagerInterface(
{bob_endpoint}); {bob_endpoint});
fixture->AddPeer(bob_network->network_thread(), fixture->AddPeer(
bob_network->network_manager(), [](PeerConfigurer* bob) { bob_network->network_thread(), bob_network->network_manager(),
VideoConfig video_config(640, 360, 30); [](PeerConfigurer* bob) {
video_config.stream_label = "bob-video"; VideoConfig video(640, 360, 30);
bob->AddVideoConfig(std::move(video_config)); video.stream_label = "bob-video";
AudioConfig audio_config; bob->AddVideoConfig(std::move(video));
audio_config.stream_label = "bob-audio";
audio_config.mode = AudioConfig::Mode::kFile; VideoConfig screenshare(640, 360, 30);
audio_config.input_file_name = test::ResourcePath( screenshare.stream_label = "bob-screenshare";
"pc_quality_smoke_test_bob_source", "wav"); screenshare.screen_share_config =
bob->SetAudioConfig(std::move(audio_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( fixture->AddQualityMetricsReporter(

View File

@ -461,6 +461,37 @@ void PeerConnectionE2EQualityTest::ValidateParams(const RunParams& run_params,
<< VideoConfigSourcePresenceToString(video_config); << VideoConfigSourcePresenceToString(video_config);
RTC_CHECK(!(video_config.screen_share_config && video_config.generator)) RTC_CHECK(!(video_config.screen_share_config && video_config.generator))
<< VideoConfigSourcePresenceToString(video_config); << 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) { if (p->audio_config) {
bool inserted = bool inserted =
@ -616,15 +647,55 @@ PeerConnectionE2EQualityTest::CreateFrameGenerator(
video_config.width, video_config.height, /*frame_repeat_count=*/1); video_config.width, video_config.height, /*frame_repeat_count=*/1);
} }
if (video_config.screen_share_config) { if (video_config.screen_share_config) {
// TODO(titovartem) implement screen share support return CreateScreenShareFrameGenerator(video_config);
// (http://bugs.webrtc.org/10138)
RTC_NOTREACHED() << "Screen share is not implemented";
return nullptr;
} }
RTC_NOTREACHED() << "Unsupported video_config input source"; RTC_NOTREACHED() << "Unsupported video_config input source";
return nullptr; 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) { void PeerConnectionE2EQualityTest::MaybeAddAudio(TestPeer* peer) {
if (!peer->params()->audio_config) { if (!peer->params()->audio_config) {
return; return;

View File

@ -219,6 +219,8 @@ class PeerConnectionE2EQualityTest
MaybeAddVideo(TestPeer* peer); MaybeAddVideo(TestPeer* peer);
std::unique_ptr<test::FrameGenerator> CreateFrameGenerator( std::unique_ptr<test::FrameGenerator> CreateFrameGenerator(
const VideoConfig& video_config); const VideoConfig& video_config);
std::unique_ptr<test::FrameGenerator> CreateScreenShareFrameGenerator(
const VideoConfig& video_config);
void MaybeAddAudio(TestPeer* peer); void MaybeAddAudio(TestPeer* peer);
void SetPeerCodecPreferences(TestPeer* peer, const RunParams& run_params); void SetPeerCodecPreferences(TestPeer* peer, const RunParams& run_params);
void SetupCall(); void SetupCall();