From 42684be21b255e2b07eb154e6a2807fa2226167e Mon Sep 17 00:00:00 2001 From: "pbos@webrtc.org" Date: Fri, 3 Oct 2014 11:25:45 +0000 Subject: [PATCH] Wire up CPU adaptation in WebRtcVideoEngine2. Includes clean-up work to be able to use the webrtc::Call::Config that's set up. This introduced a CallFactory to spawn a FakeCall with the config used and allowed removal of FakeWebRtcVideoChannel2. BUG=1788 R=mflodman@webrtc.org, pthatcher@webrtc.org Review URL: https://webrtc-codereview.appspot.com/24779004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7370 4adac7df-926f-26a2-2b94-8c16560cd09d --- talk/media/webrtc/webrtcvideoengine2.cc | 74 +++-- talk/media/webrtc/webrtcvideoengine2.h | 40 ++- .../webrtc/webrtcvideoengine2_unittest.cc | 305 ++++++++++-------- .../webrtc/webrtcvideoengine2_unittest.h | 42 +-- webrtc/call.h | 16 +- webrtc/video/call.cc | 8 +- webrtc/video/call_perf_tests.cc | 11 +- 7 files changed, 259 insertions(+), 237 deletions(-) diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc index 26e3079787..1d7c006c20 100644 --- a/talk/media/webrtc/webrtcvideoengine2.cc +++ b/talk/media/webrtc/webrtcvideoengine2.cc @@ -261,6 +261,13 @@ UnsignalledSsrcHandler::Action DefaultUnsignalledSsrcHandler::OnUnsignalledSsrc( return kDeliverPacket; } +WebRtcCallFactory::~WebRtcCallFactory() { +} +webrtc::Call* WebRtcCallFactory::CreateCall( + const webrtc::Call::Config& config) { + return webrtc::Call::Create(config); +} + VideoRenderer* DefaultUnsignalledSsrcHandler::GetDefaultRenderer() const { return default_renderer_; } @@ -284,7 +291,7 @@ WebRtcVideoEngine2::WebRtcVideoEngine2() FOURCC_ANY), initialized_(false), cpu_monitor_(new rtc::CpuMonitor(NULL)), - channel_factory_(NULL), + call_factory_(&default_call_factory_), external_decoder_factory_(NULL), external_encoder_factory_(NULL) { LOG(LS_INFO) << "WebRtcVideoEngine2::WebRtcVideoEngine2()"; @@ -296,11 +303,6 @@ WebRtcVideoEngine2::WebRtcVideoEngine2() kRtpAbsoluteSenderTimeHeaderExtensionDefaultId)); } -void WebRtcVideoEngine2::SetChannelFactory( - WebRtcVideoChannelFactory* channel_factory) { - channel_factory_ = channel_factory; -} - WebRtcVideoEngine2::~WebRtcVideoEngine2() { LOG(LS_INFO) << "WebRtcVideoEngine2::~WebRtcVideoEngine2"; @@ -309,6 +311,10 @@ WebRtcVideoEngine2::~WebRtcVideoEngine2() { } } +void WebRtcVideoEngine2::SetCallFactory(WebRtcCallFactory* call_factory) { + call_factory_ = call_factory; +} + bool WebRtcVideoEngine2::Init(rtc::Thread* worker_thread) { LOG(LS_INFO) << "WebRtcVideoEngine2::Init"; worker_thread_ = worker_thread; @@ -363,11 +369,8 @@ WebRtcVideoChannel2* WebRtcVideoEngine2::CreateChannel( LOG(LS_INFO) << "CreateChannel: " << (voice_channel != NULL ? "With" : "Without") << " voice channel."; - WebRtcVideoChannel2* channel = - channel_factory_ != NULL - ? channel_factory_->Create(this, voice_channel) - : new WebRtcVideoChannel2( - this, voice_channel, GetVideoEncoderFactory()); + WebRtcVideoChannel2* channel = new WebRtcVideoChannel2( + call_factory_, voice_channel, GetVideoEncoderFactory()); if (!channel->Init()) { delete channel; return NULL; @@ -668,39 +671,28 @@ class WebRtcVideoRenderFrame : public VideoFrame { }; WebRtcVideoChannel2::WebRtcVideoChannel2( - WebRtcVideoEngine2* engine, + WebRtcCallFactory* call_factory, VoiceMediaChannel* voice_channel, WebRtcVideoEncoderFactory2* encoder_factory) : unsignalled_ssrc_handler_(&default_unsignalled_ssrc_handler_), encoder_factory_(encoder_factory) { // TODO(pbos): Connect the video and audio with |voice_channel|. webrtc::Call::Config config(this); - Construct(webrtc::Call::Create(config), engine); -} + config.overuse_callback = this; + call_.reset(call_factory->CreateCall(config)); -WebRtcVideoChannel2::WebRtcVideoChannel2( - webrtc::Call* call, - WebRtcVideoEngine2* engine, - WebRtcVideoEncoderFactory2* encoder_factory) - : unsignalled_ssrc_handler_(&default_unsignalled_ssrc_handler_), - encoder_factory_(encoder_factory) { - Construct(call, engine); -} - -void WebRtcVideoChannel2::Construct(webrtc::Call* call, - WebRtcVideoEngine2* engine) { rtcp_receiver_report_ssrc_ = kDefaultRtcpReceiverReportSsrc; sending_ = false; - call_.reset(call); default_send_ssrc_ = 0; SetDefaultOptions(); } void WebRtcVideoChannel2::SetDefaultOptions() { - options_.video_noise_reduction.Set(true); - options_.use_payload_padding.Set(false); + options_.cpu_overuse_detection.Set(false); options_.suspend_below_min_bitrate.Set(false); + options_.use_payload_padding.Set(false); + options_.video_noise_reduction.Set(true); } WebRtcVideoChannel2::~WebRtcVideoChannel2() { @@ -1265,6 +1257,17 @@ void WebRtcVideoChannel2::OnMessage(rtc::Message* msg) { // Ignored. } +void WebRtcVideoChannel2::OnLoadUpdate(Load load) { + for (std::map::iterator it = + send_streams_.begin(); + it != send_streams_.end(); + ++it) { + it->second->OnCpuResolutionRequest(load == kOveruse + ? CoordinatedVideoAdapter::DOWNGRADE + : CoordinatedVideoAdapter::UPGRADE); + } +} + bool WebRtcVideoChannel2::SendRtp(const uint8_t* data, size_t len) { rtc::Buffer packet(data, len, kMaxRtpPacketLen); return MediaChannel::SendPacket(&packet); @@ -1678,6 +1681,21 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo() { return info; } +void WebRtcVideoChannel2::WebRtcVideoSendStream::OnCpuResolutionRequest( + CoordinatedVideoAdapter::AdaptRequest adapt_request) { + rtc::CritScope cs(&lock_); + bool adapt_cpu; + parameters_.options.cpu_overuse_detection.Get(&adapt_cpu); + if (!adapt_cpu) { + return; + } + if (capturer_ == NULL || capturer_->video_adapter() == NULL) { + return; + } + + capturer_->video_adapter()->OnCpuResolutionRequest(adapt_request); +} + void WebRtcVideoChannel2::WebRtcVideoSendStream::RecreateWebRtcStream() { if (stream_ != NULL) { call_->DestroyVideoSendStream(stream_); diff --git a/talk/media/webrtc/webrtcvideoengine2.h b/talk/media/webrtc/webrtcvideoengine2.h index 18a80d7ad7..1c50fbf541 100644 --- a/talk/media/webrtc/webrtcvideoengine2.h +++ b/talk/media/webrtc/webrtcvideoengine2.h @@ -39,6 +39,7 @@ #include "webrtc/base/cpumonitor.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/thread_annotations.h" +#include "webrtc/call.h" #include "webrtc/common_video/interface/i420_video_frame.h" #include "webrtc/transport.h" #include "webrtc/video_receive_stream.h" @@ -46,7 +47,6 @@ #include "webrtc/video_send_stream.h" namespace webrtc { -class Call; class VideoCaptureModule; class VideoDecoder; class VideoEncoder; @@ -79,7 +79,6 @@ class WebRtcVoiceEngine; struct CapturedFrame; struct Device; -class WebRtcVideoEngine2; class WebRtcVideoChannel2; class WebRtcVideoRenderer; @@ -129,6 +128,14 @@ class WebRtcVideoEncoderFactory2 { virtual bool SupportsCodec(const cricket::VideoCodec& codec); }; +// CallFactory, overridden for testing to verify that webrtc::Call is configured +// properly. +class WebRtcCallFactory { + public: + virtual ~WebRtcCallFactory(); + virtual webrtc::Call* CreateCall(const webrtc::Call::Config& config); +}; + // WebRtcVideoEngine2 is used for the new native WebRTC Video API (webrtc:1667). class WebRtcVideoEngine2 : public sigslot::has_slots<>, public WebRtcVideoEncoderFactory::Observer { @@ -137,8 +144,8 @@ class WebRtcVideoEngine2 : public sigslot::has_slots<>, WebRtcVideoEngine2(); virtual ~WebRtcVideoEngine2(); - // Use a custom WebRtcVideoChannelFactory (for testing purposes). - void SetChannelFactory(WebRtcVideoChannelFactory* channel_factory); + // Used for testing to be able to check and use the webrtc::Call config. + void SetCallFactory(WebRtcCallFactory* call_factory); // Basic video engine implementation. bool Init(rtc::Thread* worker_thread); @@ -195,30 +202,24 @@ class WebRtcVideoEngine2 : public sigslot::has_slots<>, bool initialized_; - // Critical section to protect the media processor register/unregister - // while processing a frame - rtc::CriticalSection signal_media_critical_; - rtc::scoped_ptr cpu_monitor_; - WebRtcVideoChannelFactory* channel_factory_; WebRtcVideoEncoderFactory2 default_video_encoder_factory_; + WebRtcCallFactory default_call_factory_; + WebRtcCallFactory* call_factory_; + WebRtcVideoDecoderFactory* external_decoder_factory_; WebRtcVideoEncoderFactory* external_encoder_factory_; }; class WebRtcVideoChannel2 : public rtc::MessageHandler, public VideoMediaChannel, - public webrtc::newapi::Transport { + public webrtc::newapi::Transport, + public webrtc::LoadObserver { public: - WebRtcVideoChannel2(WebRtcVideoEngine2* engine, + WebRtcVideoChannel2(WebRtcCallFactory* call_factory, VoiceMediaChannel* voice_channel, WebRtcVideoEncoderFactory2* encoder_factory); - // For testing purposes insert a pre-constructed call to verify that - // WebRtcVideoChannel2 calls the correct corresponding methods. - WebRtcVideoChannel2(webrtc::Call* call, - WebRtcVideoEngine2* engine, - WebRtcVideoEncoderFactory2* encoder_factory); ~WebRtcVideoChannel2(); bool Init(); @@ -269,6 +270,8 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler, virtual void OnMessage(rtc::Message* msg) OVERRIDE; + virtual void OnLoadUpdate(Load load) OVERRIDE; + // Implemented for VideoMediaChannelTest. bool sending() const { return sending_; } uint32 GetDefaultSendChannelSsrc() { return default_send_ssrc_; } @@ -315,6 +318,9 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler, VideoSenderInfo GetVideoSenderInfo(); + void OnCpuResolutionRequest( + CoordinatedVideoAdapter::AdaptRequest adapt_request); + private: // Parameters needed to reconstruct the underlying stream. // webrtc::VideoSendStream doesn't support setting a lot of options on the @@ -416,6 +422,8 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler, uint32_t rtcp_receiver_report_ssrc_; bool sending_; rtc::scoped_ptr call_; + WebRtcCallFactory* call_factory_; + uint32_t default_send_ssrc_; DefaultUnsignalledSsrcHandler default_unsignalled_ssrc_handler_; diff --git a/talk/media/webrtc/webrtcvideoengine2_unittest.cc b/talk/media/webrtc/webrtcvideoengine2_unittest.cc index 6112c50ec8..b718992f1e 100644 --- a/talk/media/webrtc/webrtcvideoengine2_unittest.cc +++ b/talk/media/webrtc/webrtcvideoengine2_unittest.cc @@ -35,6 +35,7 @@ #include "talk/media/webrtc/webrtcvideoengine2_unittest.h" #include "webrtc/base/gunit.h" #include "webrtc/base/stringutils.h" +#include "webrtc/video_encoder.h" namespace { static const cricket::VideoCodec kVp8Codec720p(100, "VP8", 1280, 720, 30, 0); @@ -69,7 +70,10 @@ namespace cricket { FakeVideoSendStream::FakeVideoSendStream( const webrtc::VideoSendStream::Config& config, const webrtc::VideoEncoderConfig& encoder_config) - : sending_(false), config_(config), codec_settings_set_(false) { + : sending_(false), + config_(config), + codec_settings_set_(false), + num_swapped_frames_(0) { assert(config.encoder_settings.encoder != NULL); ReconfigureVideoEncoder(encoder_config); } @@ -96,6 +100,22 @@ bool FakeVideoSendStream::GetVp8Settings( return true; } +int FakeVideoSendStream::GetNumberOfSwappedFrames() const { + return num_swapped_frames_; +} + +int FakeVideoSendStream::GetLastWidth() const { + return last_frame_.width(); +} + +int FakeVideoSendStream::GetLastHeight() const { + return last_frame_.height(); +} + +void FakeVideoSendStream::SwapFrame(webrtc::I420VideoFrame* frame) { + ++num_swapped_frames_; + last_frame_.SwapFrame(frame); +} webrtc::VideoSendStream::Stats FakeVideoSendStream::GetStats() const { return webrtc::VideoSendStream::Stats(); } @@ -113,8 +133,7 @@ bool FakeVideoSendStream::ReconfigureVideoEncoder( } webrtc::VideoSendStreamInput* FakeVideoSendStream::Input() { - // TODO(pbos): Fix. - return NULL; + return this; } void FakeVideoSendStream::Start() { @@ -153,7 +172,8 @@ void FakeVideoReceiveStream::Stop() { void FakeVideoReceiveStream::GetCurrentReceiveCodec(webrtc::VideoCodec* codec) { } -FakeCall::FakeCall() : network_state_(kNetworkUp) { +FakeCall::FakeCall(const webrtc::Call::Config& config) + : config_(config), network_state_(kNetworkUp) { SetVideoCodecs(GetDefaultVideoCodecs()); } @@ -166,6 +186,10 @@ void FakeCall::SetVideoCodecs(const std::vector codecs) { codecs_ = codecs; } +webrtc::Call::Config FakeCall::GetConfig() const { + return config_; +} + std::vector FakeCall::GetVideoSendStreams() { return video_send_streams_; } @@ -190,8 +214,8 @@ webrtc::VideoCodec FakeCall::GetEmptyVideoCodec() { webrtc::VideoCodec FakeCall::GetVideoCodecVp8() { webrtc::VideoCodec vp8_codec = GetEmptyVideoCodec(); vp8_codec.codecType = webrtc::kVideoCodecVP8; - rtc::strcpyn(vp8_codec.plName, ARRAY_SIZE(vp8_codec.plName), - kVp8Codec.name.c_str()); + rtc::strcpyn( + vp8_codec.plName, ARRAY_SIZE(vp8_codec.plName), kVp8Codec.name.c_str()); vp8_codec.plType = kVp8Codec.id; return vp8_codec; @@ -201,8 +225,8 @@ webrtc::VideoCodec FakeCall::GetVideoCodecVp9() { webrtc::VideoCodec vp9_codec = GetEmptyVideoCodec(); // TODO(pbos): Add a correct codecType when webrtc has one. vp9_codec.codecType = webrtc::kVideoCodecVP8; - rtc::strcpyn(vp9_codec.plName, ARRAY_SIZE(vp9_codec.plName), - kVp9Codec.name.c_str()); + rtc::strcpyn( + vp9_codec.plName, ARRAY_SIZE(vp9_codec.plName), kVp9Codec.name.c_str()); vp9_codec.plType = kVp9Codec.id; return vp9_codec; @@ -279,44 +303,9 @@ void FakeCall::SignalNetworkState(webrtc::Call::NetworkState state) { network_state_ = state; } -FakeWebRtcVideoChannel2::FakeWebRtcVideoChannel2( - FakeCall* call, - WebRtcVideoEngine2* engine, - VoiceMediaChannel* voice_channel) - : WebRtcVideoChannel2(call, engine, engine->GetVideoEncoderFactory()), - fake_call_(call), - voice_channel_(voice_channel) { -} - -FakeWebRtcVideoChannel2::~FakeWebRtcVideoChannel2() { -} - -VoiceMediaChannel* FakeWebRtcVideoChannel2::GetVoiceChannel() { - return voice_channel_; -} - -FakeCall* FakeWebRtcVideoChannel2::GetFakeCall() { - return fake_call_; -} - -FakeWebRtcVideoChannel2* FakeWebRtcVideoMediaChannelFactory::GetFakeChannel( - VideoMediaChannel* channel) { - return channel_map_[channel]; -} - -WebRtcVideoChannel2* FakeWebRtcVideoMediaChannelFactory::Create( - WebRtcVideoEngine2* engine, - VoiceMediaChannel* voice_channel) { - FakeWebRtcVideoChannel2* channel = - new FakeWebRtcVideoChannel2(new FakeCall(), engine, voice_channel); - channel_map_[channel] = channel; - return channel; -} - class WebRtcVideoEngine2Test : public testing::Test { public: WebRtcVideoEngine2Test() { - engine_.SetChannelFactory(&factory_); std::vector engine_codecs = engine_.codecs(); assert(!engine_codecs.empty()); bool codec_set = false; @@ -337,7 +326,6 @@ class WebRtcVideoEngine2Test : public testing::Test { } protected: - FakeWebRtcVideoMediaChannelFactory factory_; WebRtcVideoEngine2 engine_; VideoCodec default_codec_; VideoCodec default_red_codec_; @@ -345,27 +333,9 @@ class WebRtcVideoEngine2Test : public testing::Test { VideoCodec default_rtx_codec_; }; -TEST_F(WebRtcVideoEngine2Test, CreateChannel) { - rtc::scoped_ptr channel(engine_.CreateChannel(NULL)); - ASSERT_TRUE(channel.get() != NULL) << "Could not create channel."; - EXPECT_TRUE(factory_.GetFakeChannel(channel.get()) != NULL) - << "Channel not created through factory."; -} - -TEST_F(WebRtcVideoEngine2Test, CreateChannelWithVoiceEngine) { - VoiceMediaChannel* voice_channel = reinterpret_cast(0x42); - rtc::scoped_ptr channel( - engine_.CreateChannel(voice_channel)); - ASSERT_TRUE(channel.get() != NULL) << "Could not create channel."; - - FakeWebRtcVideoChannel2* fake_channel = - factory_.GetFakeChannel(channel.get()); - ASSERT_TRUE(fake_channel != NULL) << "Channel not created through factory."; - - EXPECT_TRUE(fake_channel->GetVoiceChannel() != NULL) - << "VoiceChannel not set."; - EXPECT_EQ(voice_channel, fake_channel->GetVoiceChannel()) - << "Different VoiceChannel set than the provided one."; +// TODO(pbos): Add test that verifies that sync is configured properly. +TEST_F(WebRtcVideoEngine2Test, DISABLED_CreateChannelWithVoiceEngine) { + FAIL() << "Not implemented."; // TODO(pbos): Implement. } TEST_F(WebRtcVideoEngine2Test, FindCodec) { @@ -419,7 +389,7 @@ TEST_F(WebRtcVideoEngine2Test, DefaultRtxCodecHasAssociatedPayloadTypeSet) { continue; int associated_payload_type; EXPECT_TRUE(engine_codecs[i].GetParam(kCodecParamAssociatedPayloadType, - &associated_payload_type)); + &associated_payload_type)); EXPECT_EQ(default_codec_.id, associated_payload_type); return; } @@ -483,15 +453,16 @@ WEBRTC_ENGINE_BASE_TEST(ConstrainNewCodec2); class WebRtcVideoChannel2BaseTest : public VideoMediaChannelTest { protected: - virtual cricket::VideoCodec DefaultCodec() OVERRIDE { return kVp8Codec; } typedef VideoMediaChannelTest Base; + + virtual cricket::VideoCodec DefaultCodec() OVERRIDE { return kVp8Codec; } }; #define WEBRTC_BASE_TEST(test) \ TEST_F(WebRtcVideoChannel2BaseTest, test) { Base::test(); } #define WEBRTC_DISABLED_BASE_TEST(test) \ - TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_ ## test) { Base::test(); } + TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_##test) { Base::test(); } // TODO(pbos): Fix WebRtcVideoEngine2BaseTest, where we want CheckCoInitialize. #if 0 @@ -604,46 +575,52 @@ TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_SendVp8HdAndReceiveAdaptedVp8Vga) { EXPECT_FRAME_WAIT(1, codec.width, codec.height, kTimeout); } -class WebRtcVideoChannel2Test : public WebRtcVideoEngine2Test { +class WebRtcVideoChannel2Test : public WebRtcVideoEngine2Test, + public WebRtcCallFactory { public: + WebRtcVideoChannel2Test() : fake_call_(NULL) {} virtual void SetUp() OVERRIDE { + engine_.SetCallFactory(this); channel_.reset(engine_.CreateChannel(NULL)); - fake_channel_ = factory_.GetFakeChannel(channel_.get()); + ASSERT_TRUE(fake_call_ != NULL) << "Call not created through factory."; last_ssrc_ = 123; - ASSERT_TRUE(fake_channel_ != NULL) - << "Channel not created through factory."; - EXPECT_TRUE(fake_channel_->SetSendCodecs(engine_.codecs())); + ASSERT_TRUE(channel_->SetSendCodecs(engine_.codecs())); } protected: + virtual webrtc::Call* CreateCall( + const webrtc::Call::Config& config) OVERRIDE { + assert(fake_call_ == NULL); + fake_call_ = new FakeCall(config); + return fake_call_; + } + FakeVideoSendStream* AddSendStream() { - return AddSendStream(StreamParams::CreateLegacy(last_ssrc_++)); + return AddSendStream(StreamParams::CreateLegacy(++last_ssrc_)); } FakeVideoSendStream* AddSendStream(const StreamParams& sp) { - size_t num_streams = - fake_channel_->GetFakeCall()->GetVideoSendStreams().size(); + size_t num_streams = fake_call_->GetVideoSendStreams().size(); EXPECT_TRUE(channel_->AddSendStream(sp)); std::vector streams = - fake_channel_->GetFakeCall()->GetVideoSendStreams(); + fake_call_->GetVideoSendStreams(); EXPECT_EQ(num_streams + 1, streams.size()); return streams[streams.size() - 1]; } std::vector GetFakeSendStreams() { - return fake_channel_->GetFakeCall()->GetVideoSendStreams(); + return fake_call_->GetVideoSendStreams(); } FakeVideoReceiveStream* AddRecvStream() { - return AddRecvStream(StreamParams::CreateLegacy(last_ssrc_++)); + return AddRecvStream(StreamParams::CreateLegacy(++last_ssrc_)); } FakeVideoReceiveStream* AddRecvStream(const StreamParams& sp) { - size_t num_streams = - fake_channel_->GetFakeCall()->GetVideoReceiveStreams().size(); + size_t num_streams = fake_call_->GetVideoReceiveStreams().size(); EXPECT_TRUE(channel_->AddRecvStream(sp)); std::vector streams = - fake_channel_->GetFakeCall()->GetVideoReceiveStreams(); + fake_call_->GetVideoReceiveStreams(); EXPECT_EQ(num_streams + 1, streams.size()); return streams[streams.size() - 1]; } @@ -671,7 +648,7 @@ class WebRtcVideoChannel2Test : public WebRtcVideoEngine2Test { void TestSetSendRtpHeaderExtensions(const std::string& cricket_ext, const std::string& webrtc_ext) { - FakeCall* call = fake_channel_->GetFakeCall(); + FakeCall* call = fake_call_; // Enable extension. const int id = 1; std::vector extensions; @@ -711,7 +688,7 @@ class WebRtcVideoChannel2Test : public WebRtcVideoEngine2Test { void TestSetRecvRtpHeaderExtensions(const std::string& cricket_ext, const std::string& webrtc_ext) { - FakeCall* call = fake_channel_->GetFakeCall(); + FakeCall* call = fake_call_; // Enable extension. const int id = 1; std::vector extensions; @@ -750,8 +727,10 @@ class WebRtcVideoChannel2Test : public WebRtcVideoEngine2Test { EXPECT_EQ(webrtc_ext, recv_stream->GetConfig().rtp.extensions[0].name); } + void TestCpuAdaptation(bool enable_overuse); + + FakeCall* fake_call_; rtc::scoped_ptr channel_; - FakeWebRtcVideoChannel2* fake_channel_; uint32 last_ssrc_; }; @@ -888,15 +867,15 @@ TEST_F(WebRtcVideoChannel2Test, RecvAbsoluteSendTimeHeaderExtensions) { } TEST_F(WebRtcVideoChannel2Test, - SetSendRtpHeaderExtensionsExcludeUnsupportedExtensions) { + SetSendRtpHeaderExtensionsExcludeUnsupportedExtensions) { const int kUnsupportedId = 1; const int kTOffsetId = 2; std::vector extensions; - extensions.push_back(cricket::RtpHeaderExtension( - kUnsupportedExtensionName, kUnsupportedId)); - extensions.push_back(cricket::RtpHeaderExtension( - webrtc::RtpExtension::kTOffset, kTOffsetId)); + extensions.push_back( + cricket::RtpHeaderExtension(kUnsupportedExtensionName, kUnsupportedId)); + extensions.push_back( + cricket::RtpHeaderExtension(webrtc::RtpExtension::kTOffset, kTOffsetId)); EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions)); FakeVideoSendStream* send_stream = AddSendStream(cricket::StreamParams::CreateLegacy(123)); @@ -905,19 +884,19 @@ TEST_F(WebRtcVideoChannel2Test, // unsupported rtp extension is ignored. ASSERT_EQ(1u, send_stream->GetConfig().rtp.extensions.size()); EXPECT_STREQ(webrtc::RtpExtension::kTOffset, - send_stream->GetConfig().rtp.extensions[0].name.c_str()); + send_stream->GetConfig().rtp.extensions[0].name.c_str()); } TEST_F(WebRtcVideoChannel2Test, - SetRecvRtpHeaderExtensionsExcludeUnsupportedExtensions) { + SetRecvRtpHeaderExtensionsExcludeUnsupportedExtensions) { const int kUnsupportedId = 1; const int kTOffsetId = 2; std::vector extensions; - extensions.push_back(cricket::RtpHeaderExtension( - kUnsupportedExtensionName, kUnsupportedId)); - extensions.push_back(cricket::RtpHeaderExtension( - webrtc::RtpExtension::kTOffset, kTOffsetId)); + extensions.push_back( + cricket::RtpHeaderExtension(kUnsupportedExtensionName, kUnsupportedId)); + extensions.push_back( + cricket::RtpHeaderExtension(webrtc::RtpExtension::kTOffset, kTOffsetId)); EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions)); FakeVideoReceiveStream* recv_stream = AddRecvStream(cricket::StreamParams::CreateLegacy(123)); @@ -926,11 +905,10 @@ TEST_F(WebRtcVideoChannel2Test, // unsupported rtp extension is ignored. ASSERT_EQ(1u, recv_stream->GetConfig().rtp.extensions.size()); EXPECT_STREQ(webrtc::RtpExtension::kTOffset, - recv_stream->GetConfig().rtp.extensions[0].name.c_str()); + recv_stream->GetConfig().rtp.extensions[0].name.c_str()); } -TEST_F(WebRtcVideoChannel2Test, - SetSendRtpHeaderExtensionsRejectsIncorrectIds) { +TEST_F(WebRtcVideoChannel2Test, SetSendRtpHeaderExtensionsRejectsIncorrectIds) { const size_t kNumIncorrectIds = 4; const int kIncorrectIds[kNumIncorrectIds] = {-2, -1, 15, 16}; for (size_t i = 0; i < kNumIncorrectIds; ++i) { @@ -942,8 +920,7 @@ TEST_F(WebRtcVideoChannel2Test, } } -TEST_F(WebRtcVideoChannel2Test, - SetRecvRtpHeaderExtensionsRejectsIncorrectIds) { +TEST_F(WebRtcVideoChannel2Test, SetRecvRtpHeaderExtensionsRejectsIncorrectIds) { const size_t kNumIncorrectIds = 4; const int kIncorrectIds[kNumIncorrectIds] = {-2, -1, 15, 16}; for (size_t i = 0; i < kNumIncorrectIds; ++i) { @@ -955,38 +932,36 @@ TEST_F(WebRtcVideoChannel2Test, } } -TEST_F(WebRtcVideoChannel2Test, - SetSendRtpHeaderExtensionsRejectsDuplicateIds) { +TEST_F(WebRtcVideoChannel2Test, SetSendRtpHeaderExtensionsRejectsDuplicateIds) { const int id = 1; std::vector extensions; - extensions.push_back(cricket::RtpHeaderExtension( - webrtc::RtpExtension::kTOffset, id)); - extensions.push_back(cricket::RtpHeaderExtension( - kRtpAbsoluteSenderTimeHeaderExtension, id)); + extensions.push_back( + cricket::RtpHeaderExtension(webrtc::RtpExtension::kTOffset, id)); + extensions.push_back( + cricket::RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, id)); EXPECT_FALSE(channel_->SetSendRtpHeaderExtensions(extensions)); // Duplicate entries are also not supported. extensions.clear(); - extensions.push_back(cricket::RtpHeaderExtension( - webrtc::RtpExtension::kTOffset, id)); + extensions.push_back( + cricket::RtpHeaderExtension(webrtc::RtpExtension::kTOffset, id)); extensions.push_back(extensions.back()); EXPECT_FALSE(channel_->SetSendRtpHeaderExtensions(extensions)); } -TEST_F(WebRtcVideoChannel2Test, - SetRecvRtpHeaderExtensionsRejectsDuplicateIds) { +TEST_F(WebRtcVideoChannel2Test, SetRecvRtpHeaderExtensionsRejectsDuplicateIds) { const int id = 1; std::vector extensions; - extensions.push_back(cricket::RtpHeaderExtension( - webrtc::RtpExtension::kTOffset, id)); - extensions.push_back(cricket::RtpHeaderExtension( - kRtpAbsoluteSenderTimeHeaderExtension, id)); + extensions.push_back( + cricket::RtpHeaderExtension(webrtc::RtpExtension::kTOffset, id)); + extensions.push_back( + cricket::RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, id)); EXPECT_FALSE(channel_->SetRecvRtpHeaderExtensions(extensions)); // Duplicate entries are also not supported. extensions.clear(); - extensions.push_back(cricket::RtpHeaderExtension( - webrtc::RtpExtension::kTOffset, id)); + extensions.push_back( + cricket::RtpHeaderExtension(webrtc::RtpExtension::kTOffset, id)); extensions.push_back(extensions.back()); EXPECT_FALSE(channel_->SetRecvRtpHeaderExtensions(extensions)); } @@ -1005,7 +980,7 @@ TEST_F(WebRtcVideoChannel2Test, DISABLED_AdditiveVideoOptions) { TEST_F(WebRtcVideoChannel2Test, AddRecvStreamOnlyUsesOneReceiveStream) { EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1))); - EXPECT_EQ(1u, fake_channel_->GetFakeCall()->GetVideoReceiveStreams().size()); + EXPECT_EQ(1u, fake_call_->GetVideoReceiveStreams().size()); } TEST_F(WebRtcVideoChannel2Test, RembIsEnabledByDefault) { @@ -1022,13 +997,13 @@ TEST_F(WebRtcVideoChannel2Test, RembCanBeEnabledAndDisabled) { codecs.push_back(kVp8Codec); EXPECT_TRUE(codecs[0].feedback_params.params().empty()); EXPECT_TRUE(channel_->SetRecvCodecs(codecs)); - stream = fake_channel_->GetFakeCall()->GetVideoReceiveStreams()[0]; + stream = fake_call_->GetVideoReceiveStreams()[0]; EXPECT_FALSE(stream->GetConfig().rtp.remb); // Verify that REMB is turned on when setting default codecs since the // default codecs have REMB enabled. EXPECT_TRUE(channel_->SetRecvCodecs(engine_.codecs())); - stream = fake_channel_->GetFakeCall()->GetVideoReceiveStreams()[0]; + stream = fake_call_->GetVideoReceiveStreams()[0]; EXPECT_TRUE(stream->GetConfig().rtp.remb); } @@ -1135,7 +1110,7 @@ TEST_F(WebRtcVideoChannel2Test, SetOptionsWithSuspendBelowMinBitrate) { options.suspend_below_min_bitrate.Set(false); channel_->SetOptions(options); - stream = fake_channel_->GetFakeCall()->GetVideoSendStreams()[0]; + stream = fake_call_->GetVideoSendStreams()[0]; EXPECT_FALSE(stream->GetConfig().suspend_below_min_bitrate); } @@ -1161,7 +1136,7 @@ TEST_F(WebRtcVideoChannel2Test, SetOptionsWithPayloadPadding) { options.use_payload_padding.Set(false); channel_->SetOptions(options); - stream = fake_channel_->GetFakeCall()->GetVideoSendStreams()[0]; + stream = fake_call_->GetVideoSendStreams()[0]; EXPECT_FALSE(stream->GetConfig().rtp.rtx.pad_with_redundant_payloads); } @@ -1185,7 +1160,7 @@ TEST_F(WebRtcVideoChannel2Test, SetOptionsWithDenoising) { options.video_noise_reduction.Set(true); channel_->SetOptions(options); - stream = fake_channel_->GetFakeCall()->GetVideoSendStreams()[0]; + stream = fake_call_->GetVideoSendStreams()[0]; ASSERT_TRUE(stream->GetVp8Settings(&vp8_settings)) << "No VP8 config set."; EXPECT_TRUE(vp8_settings.denoisingOn); } @@ -1198,16 +1173,65 @@ TEST_F(WebRtcVideoChannel2Test, DISABLED_SendReceiveBitratesStats) { FAIL() << "Not implemented."; // TODO(pbos): Implement. } -TEST_F(WebRtcVideoChannel2Test, DISABLED_TestSetAdaptInputToCpuUsage) { - FAIL() << "Not implemented."; // TODO(pbos): Implement. +TEST_F(WebRtcVideoChannel2Test, AdaptsOnOveruse) { + TestCpuAdaptation(true); } -TEST_F(WebRtcVideoChannel2Test, DISABLED_TestSetCpuThreshold) { - FAIL() << "Not implemented."; // TODO(pbos): Implement. +TEST_F(WebRtcVideoChannel2Test, DoesNotAdaptOnOveruseWhenDisabled) { + TestCpuAdaptation(false); } -TEST_F(WebRtcVideoChannel2Test, DISABLED_TestSetInvalidCpuThreshold) { - FAIL() << "Not implemented."; // TODO(pbos): Implement. +void WebRtcVideoChannel2Test::TestCpuAdaptation(bool enable_overuse) { + cricket::VideoCodec codec(100, "VP8", 1280, 720, 30, 0); + std::vector codecs; + codecs.push_back(codec); + EXPECT_TRUE(channel_->SetSendCodecs(codecs)); + + if (enable_overuse) { + VideoOptions options; + options.cpu_overuse_detection.Set(true); + channel_->SetOptions(options); + } + + AddSendStream(); + + cricket::FakeVideoCapturer capturer; + EXPECT_TRUE(channel_->SetCapturer(last_ssrc_, &capturer)); + EXPECT_EQ(cricket::CS_RUNNING, + capturer.Start(capturer.GetSupportedFormats()->front())); + + EXPECT_TRUE(channel_->SetSend(true)); + + // Trigger overuse. + webrtc::LoadObserver* overuse_callback = + fake_call_->GetConfig().overuse_callback; + ASSERT_TRUE(overuse_callback != NULL); + overuse_callback->OnLoadUpdate(webrtc::LoadObserver::kOveruse); + + EXPECT_TRUE(capturer.CaptureFrame()); + ASSERT_EQ(1u, fake_call_->GetVideoSendStreams().size()); + FakeVideoSendStream* send_stream = fake_call_->GetVideoSendStreams().front(); + + EXPECT_EQ(1, send_stream->GetNumberOfSwappedFrames()); + + if (enable_overuse) { + EXPECT_LT(send_stream->GetLastWidth(), codec.width); + EXPECT_LT(send_stream->GetLastHeight(), codec.height); + } else { + EXPECT_EQ(codec.width, send_stream->GetLastWidth()); + EXPECT_EQ(codec.height, send_stream->GetLastHeight()); + } + + // Trigger underuse which should go back to normal resolution. + overuse_callback->OnLoadUpdate(webrtc::LoadObserver::kUnderuse); + EXPECT_TRUE(capturer.CaptureFrame()); + + EXPECT_EQ(2, send_stream->GetNumberOfSwappedFrames()); + + EXPECT_EQ(codec.width, send_stream->GetLastWidth()); + EXPECT_EQ(codec.height, send_stream->GetLastHeight()); + + EXPECT_TRUE(channel_->SetCapturer(last_ssrc_, NULL)); } TEST_F(WebRtcVideoChannel2Test, DISABLED_WebRtcShouldLog) { @@ -1295,7 +1319,7 @@ TEST_F(WebRtcVideoChannel2Test, SetSendCodecsWithoutFecDisablesFec) { codecs.pop_back(); ASSERT_TRUE(channel_->SetSendCodecs(codecs)); - stream = fake_channel_->GetFakeCall()->GetVideoSendStreams()[0]; + stream = fake_call_->GetVideoSendStreams()[0]; ASSERT_TRUE(stream != NULL); config = stream->GetConfig(); EXPECT_EQ(-1, config.rtp.fec.ulpfec_payload_type) @@ -1307,16 +1331,14 @@ TEST_F(WebRtcVideoChannel2Test, SetSendCodecsChangesExistingStreams) { codecs.push_back(kVp8Codec720p); ASSERT_TRUE(channel_->SetSendCodecs(codecs)); - std::vector streams = - AddSendStream()->GetVideoStreams(); + std::vector streams = AddSendStream()->GetVideoStreams(); EXPECT_EQ(kVp8Codec720p.width, streams[0].width); EXPECT_EQ(kVp8Codec720p.height, streams[0].height); codecs.clear(); codecs.push_back(kVp8Codec360p); ASSERT_TRUE(channel_->SetSendCodecs(codecs)); - streams = fake_channel_->GetFakeCall()->GetVideoSendStreams()[0] - ->GetVideoStreams(); + streams = fake_call_->GetVideoSendStreams()[0]->GetVideoStreams(); EXPECT_EQ(kVp8Codec360p.width, streams[0].width); EXPECT_EQ(kVp8Codec360p.height, streams[0].height); } @@ -1367,8 +1389,8 @@ TEST_F(WebRtcVideoChannel2Test, SetSendCodecsRejectBadDimensions) { TEST_F(WebRtcVideoChannel2Test, SetSendCodecsRejectBadPayloadTypes) { // TODO(pbos): Should we only allow the dynamic range? static const size_t kNumIncorrectPayloads = 4; - static const int kIncorrectPayloads[kNumIncorrectPayloads] = {-2, -1, 128, - 129}; + static const int kIncorrectPayloads[kNumIncorrectPayloads] = { + -2, -1, 128, 129}; std::vector codecs; codecs.push_back(kVp8Codec); for (size_t i = 0; i < kNumIncorrectPayloads; ++i) { @@ -1478,7 +1500,7 @@ TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsWithoutFecDisablesFec) { codecs.pop_back(); ASSERT_TRUE(channel_->SetRecvCodecs(codecs)); - stream = fake_channel_->GetFakeCall()->GetVideoReceiveStreams()[0]; + stream = fake_call_->GetVideoReceiveStreams()[0]; ASSERT_TRUE(stream != NULL); config = stream->GetConfig(); EXPECT_EQ(-1, config.rtp.fec.ulpfec_payload_type) @@ -1621,16 +1643,13 @@ TEST_F(WebRtcVideoChannel2Test, DISABLED_UpdateEncoderCodecsAfterSetFactory) { } TEST_F(WebRtcVideoChannel2Test, OnReadyToSendSignalsNetworkState) { - EXPECT_EQ(webrtc::Call::kNetworkUp, - fake_channel_->GetFakeCall()->GetNetworkState()); + EXPECT_EQ(webrtc::Call::kNetworkUp, fake_call_->GetNetworkState()); channel_->OnReadyToSend(false); - EXPECT_EQ(webrtc::Call::kNetworkDown, - fake_channel_->GetFakeCall()->GetNetworkState()); + EXPECT_EQ(webrtc::Call::kNetworkDown, fake_call_->GetNetworkState()); channel_->OnReadyToSend(true); - EXPECT_EQ(webrtc::Call::kNetworkUp, - fake_channel_->GetFakeCall()->GetNetworkState()); + EXPECT_EQ(webrtc::Call::kNetworkUp, fake_call_->GetNetworkState()); } TEST_F(WebRtcVideoChannel2Test, DISABLED_CaptureFrameTimestampToNtpTimestamp) { diff --git a/talk/media/webrtc/webrtcvideoengine2_unittest.h b/talk/media/webrtc/webrtcvideoengine2_unittest.h index 30f1efb85b..b3014ad869 100644 --- a/talk/media/webrtc/webrtcvideoengine2_unittest.h +++ b/talk/media/webrtc/webrtcvideoengine2_unittest.h @@ -36,7 +36,8 @@ #include "webrtc/video_send_stream.h" namespace cricket { -class FakeVideoSendStream : public webrtc::VideoSendStream { +class FakeVideoSendStream : public webrtc::VideoSendStream, + public webrtc::VideoSendStreamInput { public: FakeVideoSendStream(const webrtc::VideoSendStream::Config& config, const webrtc::VideoEncoderConfig& encoder_config); @@ -46,7 +47,12 @@ class FakeVideoSendStream : public webrtc::VideoSendStream { bool IsSending() const; bool GetVp8Settings(webrtc::VideoCodecVP8* settings) const; + int GetNumberOfSwappedFrames() const; + int GetLastWidth() const; + int GetLastHeight() const; + private: + virtual void SwapFrame(webrtc::I420VideoFrame* frame) OVERRIDE; virtual webrtc::VideoSendStream::Stats GetStats() const OVERRIDE; virtual bool ReconfigureVideoEncoder( @@ -62,6 +68,8 @@ class FakeVideoSendStream : public webrtc::VideoSendStream { webrtc::VideoEncoderConfig encoder_config_; bool codec_settings_set_; webrtc::VideoCodecVP8 vp8_settings_; + int num_swapped_frames_; + webrtc::I420VideoFrame last_frame_; }; class FakeVideoReceiveStream : public webrtc::VideoReceiveStream { @@ -86,11 +94,12 @@ class FakeVideoReceiveStream : public webrtc::VideoReceiveStream { class FakeCall : public webrtc::Call { public: - FakeCall(); + FakeCall(const webrtc::Call::Config& config); ~FakeCall(); void SetVideoCodecs(const std::vector codecs); + webrtc::Call::Config GetConfig() const; std::vector GetVideoSendStreams(); std::vector GetVideoReceiveStreams(); @@ -123,39 +132,12 @@ class FakeCall : public webrtc::Call { virtual void SignalNetworkState(webrtc::Call::NetworkState state) OVERRIDE; + const webrtc::Call::Config config_; webrtc::Call::NetworkState network_state_; std::vector codecs_; std::vector video_send_streams_; std::vector video_receive_streams_; }; -class FakeWebRtcVideoChannel2 : public WebRtcVideoChannel2 { - public: - FakeWebRtcVideoChannel2(FakeCall* call, - WebRtcVideoEngine2* engine, - VoiceMediaChannel* voice_channel); - virtual ~FakeWebRtcVideoChannel2(); - - VoiceMediaChannel* GetVoiceChannel(); - FakeCall* GetFakeCall(); - - private: - FakeCall* fake_call_; - VoiceMediaChannel* voice_channel_; -}; - -class FakeWebRtcVideoMediaChannelFactory : public WebRtcVideoChannelFactory { - public: - FakeWebRtcVideoChannel2* GetFakeChannel(VideoMediaChannel* channel); - - private: - virtual WebRtcVideoChannel2* Create( - WebRtcVideoEngine2* engine, - VoiceMediaChannel* voice_channel) OVERRIDE; - - std::map channel_map_; -}; - - } // namespace cricket #endif // TALK_MEDIA_WEBRTC_WEBRTCVIDEOENGINE2_UNITTEST_H_ diff --git a/webrtc/call.h b/webrtc/call.h index bb1dca1446..43ce4c182e 100644 --- a/webrtc/call.h +++ b/webrtc/call.h @@ -39,16 +39,16 @@ class PacketReceiver { }; // Callback interface for reporting when a system overuse is detected. -// The detection is based on the jitter of incoming captured frames. -class OveruseCallback { +class LoadObserver { public: - // Called as soon as an overuse is detected. - virtual void OnOveruse() = 0; - // Called periodically when the system is not overused any longer. - virtual void OnNormalUse() = 0; + enum Load { kOveruse, kUnderuse }; + + // Triggered when overuse is detected or when we believe the system can take + // more load. + virtual void OnLoadUpdate(Load load) = 0; protected: - virtual ~OveruseCallback() {} + virtual ~LoadObserver() {} }; // A Call instance can contain several send and/or receive streams. All streams @@ -77,7 +77,7 @@ class Call { // Callback for overuse and normal usage based on the jitter of incoming // captured frames. 'NULL' disables the callback. - OveruseCallback* overuse_callback; + LoadObserver* overuse_callback; // Start bitrate used before a valid bitrate estimate is calculated. '-1' // lets the call decide start bitrate. diff --git a/webrtc/video/call.cc b/webrtc/video/call.cc index 25853f8b3b..7573bea46e 100644 --- a/webrtc/video/call.cc +++ b/webrtc/video/call.cc @@ -55,7 +55,7 @@ namespace internal { class CpuOveruseObserverProxy : public webrtc::CpuOveruseObserver { public: - explicit CpuOveruseObserverProxy(OveruseCallback* overuse_callback) + explicit CpuOveruseObserverProxy(LoadObserver* overuse_callback) : crit_(CriticalSectionWrapper::CreateCriticalSection()), overuse_callback_(overuse_callback) { assert(overuse_callback != NULL); @@ -65,17 +65,17 @@ class CpuOveruseObserverProxy : public webrtc::CpuOveruseObserver { virtual void OveruseDetected() OVERRIDE { CriticalSectionScoped lock(crit_.get()); - overuse_callback_->OnOveruse(); + overuse_callback_->OnLoadUpdate(LoadObserver::kOveruse); } virtual void NormalUsage() OVERRIDE { CriticalSectionScoped lock(crit_.get()); - overuse_callback_->OnNormalUse(); + overuse_callback_->OnLoadUpdate(LoadObserver::kUnderuse); } private: const scoped_ptr crit_; - OveruseCallback* overuse_callback_ GUARDED_BY(crit_); + LoadObserver* overuse_callback_ GUARDED_BY(crit_); }; class Call : public webrtc::Call, public PacketReceiver { diff --git a/webrtc/video/call_perf_tests.cc b/webrtc/video/call_perf_tests.cc index cd83698fd5..f42e5dd0ba 100644 --- a/webrtc/video/call_perf_tests.cc +++ b/webrtc/video/call_perf_tests.cc @@ -451,16 +451,11 @@ TEST_F(CallPerfTest, CaptureNtpTimeWithNetworkJitter) { TEST_F(CallPerfTest, RegisterCpuOveruseObserver) { // Verifies that either a normal or overuse callback is triggered. - class OveruseCallbackObserver : public test::SendTest, - public webrtc::OveruseCallback { + class LoadObserver : public test::SendTest, public webrtc::LoadObserver { public: - OveruseCallbackObserver() : SendTest(kLongTimeoutMs) {} + LoadObserver() : SendTest(kLongTimeoutMs) {} - virtual void OnOveruse() OVERRIDE { - observation_complete_->Set(); - } - - virtual void OnNormalUse() OVERRIDE { + virtual void OnLoadUpdate(Load load) OVERRIDE { observation_complete_->Set(); }