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
This commit is contained in:
asapersson@webrtc.org
2014-01-31 10:05:07 +00:00
parent 7d7f08957c
commit bdc5ed2e7d
6 changed files with 121 additions and 76 deletions

View File

@ -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);

View File

@ -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<CriticalSectionWrapper> 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<RtpHeaderParser> rtp_header_parser_;
scoped_ptr<CpuOveruseObserverProxy> 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,8 +269,9 @@ 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,
VideoSendStream* send_stream = new VideoSendStream(
config_.send_transport,
overuse_observer_proxy_.get(),
video_engine_,
config,
base_channel_id_);

View File

@ -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<test::FrameGeneratorCapturer> 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(Call::Create(call_config));
VideoSendStream::Config send_config = GetSendTestConfig(call.get());
RunVideoSendTest(call.get(), send_config, &observer);
}
} // namespace webrtc

View File

@ -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(Call::Create(call_config));
// Loopback, call sends to itself.

View File

@ -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);

View File

@ -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<ResolutionAdaptor> overuse_observer_;
scoped_ptr<SendStatisticsProxy> stats_proxy_;
};