From 4425b055f92c3bbbf242ed9ae62676e498229977 Mon Sep 17 00:00:00 2001 From: Ilya Nikolaevskiy Date: Thu, 15 Mar 2018 11:42:00 +0100 Subject: [PATCH] Add video send stream test to check switch to and from screenshare MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: webrtc:9005 Change-Id: I07b0a0f68115d5043ef6349e17b3a6bf56a51040 Reviewed-on: https://webrtc-review.googlesource.com/61820 Commit-Queue: Ilya Nikolaevskiy Reviewed-by: Erik Språng Cr-Commit-Position: refs/heads/master@{#22459} --- video/video_send_stream_tests.cc | 151 +++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc index cabc0a4ee0..e6f9244fcf 100644 --- a/video/video_send_stream_tests.cc +++ b/video/video_send_stream_tests.cc @@ -3745,4 +3745,155 @@ TEST_F(VideoSendStreamTest, AlrNotConfiguredWhenSendSideOff) { RunBaseTest(&test_without_send_side); } +// Test class takes as argument a function pointer to reset the send +// stream and call OnVideoStreamsCreated. This is necessary since you cannot +// change the content type of a VideoSendStream, you need to recreate it. +// Stopping and recreating the stream can only be done on the main thread and in +// the context of VideoSendStreamTest (not BaseTest). The test switches from +// realtime to screenshare and back. +template +class ContentSwitchTest : public test::SendTest { + public: + enum class StreamState { + kBeforeSwitch = 0, + kInScreenshare = 1, + kAfterSwitchBack = 2, + }; + static const uint32_t kMinPacketsToSend = 50; + + explicit ContentSwitchTest(T* stream_reset_fun) + : SendTest(test::CallTest::kDefaultTimeoutMs), + content_switch_event_(false, false), + call_(nullptr), + state_(StreamState::kBeforeSwitch), + send_stream_(nullptr), + send_stream_config_(nullptr), + packets_sent_(0), + stream_resetter_(stream_reset_fun) { + RTC_DCHECK(stream_resetter_); + } + + void OnVideoStreamsCreated( + VideoSendStream* send_stream, + const std::vector& receive_streams) override { + rtc::CritScope lock(&crit_); + send_stream_ = send_stream; + } + + void ModifyVideoConfigs( + VideoSendStream::Config* send_config, + std::vector* receive_configs, + VideoEncoderConfig* encoder_config) override { + RTC_DCHECK_EQ(1, encoder_config->number_of_streams); + encoder_config->min_transmit_bitrate_bps = 0; + encoder_config->content_type = + VideoEncoderConfig::ContentType::kRealtimeVideo; + send_stream_config_ = send_config->Copy(); + encoder_config_ = encoder_config->Copy(); + } + + void OnCallsCreated(Call* sender_call, Call* receiver_call) override { + call_ = sender_call; + } + + Action OnSendRtp(const uint8_t* packet, size_t length) override { + rtc::CritScope lock(&crit_); + + auto internal_send_peer = test::VideoSendStreamPeer(send_stream_); + float pacing_factor = + internal_send_peer.GetPacingFactorOverride().value_or(0.0f); + float expected_pacing_factor = PacedSender::kDefaultPaceMultiplier; + if (send_stream_->GetStats().content_type == + webrtc::VideoContentType::SCREENSHARE) { + expected_pacing_factor = 1.0f; // Currently used pacing factor in ALR. + } + + EXPECT_NEAR(expected_pacing_factor, pacing_factor, 1e-6); + + // Wait until at least kMinPacketsToSend packets to be sent, so that + // some frames would be encoded. + if (++packets_sent_ < kMinPacketsToSend) + return SEND_PACKET; + + if (state_ != StreamState::kAfterSwitchBack) { + // We've sent kMinPacketsToSend packets, switch the content type and move + // move to the next state. + // Note that we need to recreate the stream if changing content type. + packets_sent_ = 0; + if (encoder_config_.content_type == + VideoEncoderConfig::ContentType::kRealtimeVideo) { + encoder_config_.content_type = VideoEncoderConfig::ContentType::kScreen; + } else { + encoder_config_.content_type = + VideoEncoderConfig::ContentType::kRealtimeVideo; + } + switch (state_) { + case StreamState::kBeforeSwitch: + state_ = StreamState::kInScreenshare; + break; + case StreamState::kInScreenshare: + state_ = StreamState::kAfterSwitchBack; + break; + case StreamState::kAfterSwitchBack: + RTC_NOTREACHED(); + break; + } + content_switch_event_.Set(); + return SEND_PACKET; + } + + observation_complete_.Set(); + return SEND_PACKET; + } + + void PerformTest() override { + while (GetStreamState() != StreamState::kAfterSwitchBack) { + ASSERT_TRUE( + content_switch_event_.Wait(test::CallTest::kDefaultTimeoutMs)); + (*stream_resetter_)(send_stream_config_, encoder_config_, this); + } + + ASSERT_TRUE(Wait()) + << "Timed out waiting for a frame sent after switch back"; + } + + private: + StreamState GetStreamState() { + rtc::CritScope lock(&crit_); + return state_; + } + + rtc::CriticalSection crit_; + rtc::Event content_switch_event_; + Call* call_; + StreamState state_ RTC_GUARDED_BY(crit_); + VideoSendStream* send_stream_ RTC_GUARDED_BY(crit_); + VideoSendStream::Config send_stream_config_; + VideoEncoderConfig encoder_config_; + uint32_t packets_sent_ RTC_GUARDED_BY(crit_); + T* stream_resetter_; +}; + +TEST_F(VideoSendStreamTest, SwitchesToScreenshareAndBack) { + auto reset_fun = [this](const VideoSendStream::Config& send_stream_config, + const VideoEncoderConfig& encoder_config, + test::BaseTest* test) { + task_queue_.SendTask([this, &send_stream_config, &encoder_config, &test]() { + Stop(); + sender_call_->DestroyVideoSendStream(video_send_stream_); + video_send_config_ = send_stream_config.Copy(); + video_encoder_config_ = encoder_config.Copy(); + video_send_stream_ = sender_call_->CreateVideoSendStream( + video_send_config_.Copy(), video_encoder_config_.Copy()); + video_send_stream_->SetSource( + frame_generator_capturer_.get(), + VideoSendStream::DegradationPreference::kMaintainResolution); + test->OnVideoStreamsCreated(video_send_stream_, video_receive_streams_); + Start(); + }); + }; + ContentSwitchTest test(&reset_fun); + RunBaseTest(&test); +} + } // namespace webrtc