From bdc5ed2e7d081de6597f0f993d54489eb3abd496 Mon Sep 17 00:00:00 2001 From: "asapersson@webrtc.org" Date: Fri, 31 Jan 2014 10:05:07 +0000 Subject: [PATCH] Add configuration for cpu overuse detection to video send stream. BUG=2422 R=mflodman@webrtc.org, pbos@webrtc.org Review URL: https://webrtc-codereview.appspot.com/7129004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5468 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/call.h | 22 +++++++++-- webrtc/video/call.cc | 44 ++++++++++++++++++--- webrtc/video/call_perf_tests.cc | 65 +++++++++++++++++++++++++++---- webrtc/video/loopback.cc | 1 - webrtc/video/video_send_stream.cc | 59 ++-------------------------- webrtc/video/video_send_stream.h | 6 +-- 6 files changed, 121 insertions(+), 76 deletions(-) diff --git a/webrtc/call.h b/webrtc/call.h index efc65f0cd..1b95c2988 100644 --- a/webrtc/call.h +++ b/webrtc/call.h @@ -31,6 +31,19 @@ class PacketReceiver { virtual ~PacketReceiver() {} }; +// Callback interface for reporting when a system overuse is detected. +// The detection is based on the jitter of incoming captured frames. +class OveruseCallback { + 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; + + protected: + virtual ~OveruseCallback() {} +}; + // A Call instance can contain several send and/or receive streams. All streams // are assumed to have the same remote endpoint and will share bitrate estimates // etc. @@ -40,21 +53,24 @@ class Call { explicit Config(newapi::Transport* send_transport) : webrtc_config(NULL), send_transport(send_transport), - overuse_detection(false), voice_engine(NULL), trace_callback(NULL), - trace_filter(kTraceDefault) {} + trace_filter(kTraceDefault), + overuse_callback(NULL) {} webrtc::Config* webrtc_config; newapi::Transport* send_transport; - bool overuse_detection; // VoiceEngine used for audio/video synchronization for this Call. VoiceEngine* voice_engine; TraceCallback* trace_callback; uint32_t trace_filter; + + // Callback for overuse and normal usage based on the jitter of incoming + // captured frames. 'NULL' disables the callback. + OveruseCallback* overuse_callback; }; static Call* Create(const Call::Config& config); diff --git a/webrtc/video/call.cc b/webrtc/video/call.cc index 10dcf14b8..7c4699e44 100644 --- a/webrtc/video/call.cc +++ b/webrtc/video/call.cc @@ -33,6 +33,32 @@ const char* RtpExtension::kTOffset = "urn:ietf:params:rtp-hdrext:toffset"; const char* RtpExtension::kAbsSendTime = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; namespace internal { + +class CpuOveruseObserverProxy : public webrtc::CpuOveruseObserver { + public: + CpuOveruseObserverProxy(OveruseCallback* overuse_callback) + : crit_(CriticalSectionWrapper::CreateCriticalSection()), + overuse_callback_(overuse_callback) { + assert(overuse_callback != NULL); + } + + virtual ~CpuOveruseObserverProxy() {} + + virtual void OveruseDetected() OVERRIDE { + CriticalSectionScoped cs(crit_.get()); + overuse_callback_->OnOveruse(); + } + + virtual void NormalUsage() OVERRIDE { + CriticalSectionScoped cs(crit_.get()); + overuse_callback_->OnNormalUse(); + } + + private: + scoped_ptr crit_; + OveruseCallback* overuse_callback_; +}; + class Call : public webrtc::Call, public PacketReceiver { public: Call(webrtc::VideoEngine* video_engine, const Call::Config& config); @@ -78,6 +104,8 @@ class Call : public webrtc::Call, public PacketReceiver { scoped_ptr rtp_header_parser_; + scoped_ptr overuse_observer_proxy_; + VideoEngine* video_engine_; ViERTP_RTCP* rtp_rtcp_; ViECodec* codec_; @@ -185,6 +213,11 @@ Call::Call(webrtc::VideoEngine* video_engine, const Call::Config& config) assert(video_engine != NULL); assert(config.send_transport != NULL); + if (config.overuse_callback) { + overuse_observer_proxy_.reset( + new CpuOveruseObserverProxy(config.overuse_callback)); + } + global_trace_dispatcher->RegisterCallback(this, &config_); rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine_); @@ -236,11 +269,12 @@ VideoSendStream* Call::CreateVideoSendStream( assert(config.rtp.ssrcs.size() > 0); assert(config.rtp.ssrcs.size() >= config.codec.numberOfSimulcastStreams); - VideoSendStream* send_stream = new VideoSendStream(config_.send_transport, - config_.overuse_detection, - video_engine_, - config, - base_channel_id_); + VideoSendStream* send_stream = new VideoSendStream( + config_.send_transport, + overuse_observer_proxy_.get(), + video_engine_, + config, + base_channel_id_); WriteLockScoped write_lock(*send_lock_); for (size_t i = 0; i < config.rtp.ssrcs.size(); ++i) { diff --git a/webrtc/video/call_perf_tests.cc b/webrtc/video/call_perf_tests.cc index 8234bf53f..4766ff81a 100644 --- a/webrtc/video/call_perf_tests.cc +++ b/webrtc/video/call_perf_tests.cc @@ -45,6 +45,39 @@ static const uint32_t kReceiverLocalSsrc = 0x123456; static const uint8_t kSendPayloadType = 125; class CallPerfTest : public ::testing::Test { + public: + CallPerfTest() + : send_stream_(NULL), fake_encoder_(Clock::GetRealTimeClock()) {} + protected: + VideoSendStream::Config GetSendTestConfig(Call* call) { + VideoSendStream::Config config = call->GetDefaultSendConfig(); + config.encoder = &fake_encoder_; + config.internal_source = false; + config.rtp.ssrcs.push_back(kSendSsrc); + test::FakeEncoder::SetCodecSettings(&config.codec, 1); + config.codec.plType = kSendPayloadType; + return config; + } + void RunVideoSendTest(Call* call, + const VideoSendStream::Config& config, + test::RtpRtcpObserver* observer) { + send_stream_ = call->CreateVideoSendStream(config); + scoped_ptr frame_generator_capturer( + test::FrameGeneratorCapturer::Create( + send_stream_->Input(), 320, 240, 30, Clock::GetRealTimeClock())); + send_stream_->StartSending(); + frame_generator_capturer->Start(); + + EXPECT_EQ(kEventSignaled, observer->Wait()); + + observer->StopSending(); + frame_generator_capturer->Stop(); + send_stream_->StopSending(); + call->DestroyVideoSendStream(send_stream_); + } + + VideoSendStream* send_stream_; + test::FakeEncoder fake_encoder_; }; class SyncRtcpObserver : public test::RtpRtcpObserver { @@ -236,15 +269,9 @@ TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSync) { observer.SetReceivers(receiver_call->Receiver(), sender_call->Receiver()); - test::FakeEncoder fake_encoder(Clock::GetRealTimeClock()); test::FakeDecoder fake_decoder; - VideoSendStream::Config send_config = sender_call->GetDefaultSendConfig(); - send_config.rtp.ssrcs.push_back(kSendSsrc); - send_config.encoder = &fake_encoder; - send_config.internal_source = false; - test::FakeEncoder::SetCodecSettings(&send_config.codec, 1); - send_config.codec.plType = kSendPayloadType; + VideoSendStream::Config send_config = GetSendTestConfig(sender_call.get()); VideoReceiveStream::Config receive_config = receiver_call->GetDefaultReceiveConfig(); @@ -301,4 +328,28 @@ TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSync) { receiver_call->DestroyVideoReceiveStream(receive_stream); VoiceEngine::Delete(voice_engine); } + +TEST_F(CallPerfTest, RegisterCpuOveruseObserver) { + // Verifies that either a normal or overuse callback is triggered. + class OveruseCallbackObserver : public test::RtpRtcpObserver, + public webrtc::OveruseCallback { + public: + OveruseCallbackObserver() : RtpRtcpObserver(kLongTimeoutMs) {} + + virtual void OnOveruse() OVERRIDE { + observation_complete_->Set(); + } + virtual void OnNormalUse() OVERRIDE { + observation_complete_->Set(); + } + }; + + OveruseCallbackObserver observer; + Call::Config call_config(observer.SendTransport()); + call_config.overuse_callback = &observer; + scoped_ptr call(Call::Create(call_config)); + + VideoSendStream::Config send_config = GetSendTestConfig(call.get()); + RunVideoSendTest(call.get(), send_config, &observer); +} } // namespace webrtc diff --git a/webrtc/video/loopback.cc b/webrtc/video/loopback.cc index e9b08931f..48de326ef 100644 --- a/webrtc/video/loopback.cc +++ b/webrtc/video/loopback.cc @@ -43,7 +43,6 @@ TEST_F(LoopbackTest, Test) { test::DirectTransport transport; Call::Config call_config(&transport); - call_config.overuse_detection = true; scoped_ptr call(Call::Create(call_config)); // Loopback, call sends to itself. diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc index 3b592f818..13839152a 100644 --- a/webrtc/video/video_send_stream.cc +++ b/webrtc/video/video_send_stream.cc @@ -26,58 +26,8 @@ namespace webrtc { namespace internal { -// Super simple and temporary overuse logic. This will move to the application -// as soon as the new API allows changing send codec on the fly. -class ResolutionAdaptor : public webrtc::CpuOveruseObserver { - public: - ResolutionAdaptor(ViECodec* codec, int channel, size_t width, size_t height) - : codec_(codec), - channel_(channel), - max_width_(width), - max_height_(height) {} - - virtual ~ResolutionAdaptor() {} - - virtual void OveruseDetected() OVERRIDE { - VideoCodec codec; - if (codec_->GetSendCodec(channel_, codec) != 0) - return; - - if (codec.width / 2 < min_width || codec.height / 2 < min_height) - return; - - codec.width /= 2; - codec.height /= 2; - codec_->SetSendCodec(channel_, codec); - } - - virtual void NormalUsage() OVERRIDE { - VideoCodec codec; - if (codec_->GetSendCodec(channel_, codec) != 0) - return; - - if (codec.width * 2u > max_width_ || codec.height * 2u > max_height_) - return; - - codec.width *= 2; - codec.height *= 2; - codec_->SetSendCodec(channel_, codec); - } - - private: - // Temporary and arbitrary chosen minimum resolution. - static const size_t min_width = 160; - static const size_t min_height = 120; - - ViECodec* codec_; - const int channel_; - - const size_t max_width_; - const size_t max_height_; -}; - VideoSendStream::VideoSendStream(newapi::Transport* transport, - bool overuse_detection, + CpuOveruseObserver* overuse_observer, webrtc::VideoEngine* video_engine, const VideoSendStream::Config& config, int base_channel) @@ -169,11 +119,8 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport, if (!SetCodec(config_.codec)) abort(); - if (overuse_detection) { - overuse_observer_.reset(new ResolutionAdaptor( - codec_, channel_, config_.codec.width, config_.codec.height)); - video_engine_base_->RegisterCpuOveruseObserver(channel_, - overuse_observer_.get()); + if (overuse_observer) { + video_engine_base_->RegisterCpuOveruseObserver(channel_, overuse_observer); } image_process_ = ViEImageProcess::GetInterface(video_engine); diff --git a/webrtc/video/video_send_stream.h b/webrtc/video/video_send_stream.h index 05c481f3f..2a84b8c3b 100644 --- a/webrtc/video/video_send_stream.h +++ b/webrtc/video/video_send_stream.h @@ -21,6 +21,7 @@ namespace webrtc { +class CpuOveruseObserver; class VideoEngine; class ViEBase; class ViECapture; @@ -33,14 +34,12 @@ class ViERTP_RTCP; namespace internal { -class ResolutionAdaptor; - class VideoSendStream : public webrtc::VideoSendStream, public VideoSendStreamInput, public SendStatisticsProxy::StreamStatsProvider { public: VideoSendStream(newapi::Transport* transport, - bool overuse_detection, + CpuOveruseObserver* overuse_observer, webrtc::VideoEngine* video_engine, const VideoSendStream::Config& config, int base_channel); @@ -88,7 +87,6 @@ class VideoSendStream : public webrtc::VideoSendStream, int channel_; int capture_id_; - scoped_ptr overuse_observer_; scoped_ptr stats_proxy_; };