Refactor some receive-side stats.

Removes polling of CName as well as receive codec statistics in favor of
internal callbacks keeping a statistics struct up to date.

R=mflodman@webrtc.org, stefan@webrtc.org
BUG=1667

Review URL: https://webrtc-codereview.appspot.com/28259005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@7950 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pbos@webrtc.org 2014-12-18 13:50:16 +00:00
parent 98c04b38a8
commit ce4e9a3562
38 changed files with 235 additions and 178 deletions

View File

@ -727,6 +727,9 @@ class FakeWebRtcVideoEngine
WEBRTC_VOID_STUB(RegisterSendStatisticsProxy,
(int, webrtc::SendStatisticsProxy*));
WEBRTC_VOID_STUB(RegisterReceiveStatisticsProxy,
(int, webrtc::ReceiveStatisticsProxy*));
// webrtc::ViECodec
WEBRTC_FUNC_CONST(NumberOfCodecs, ()) {
return num_codecs_;

View File

@ -188,13 +188,13 @@ struct RtcpStatistics {
uint32_t jitter;
};
// Callback, called whenever a new rtcp report block is transmitted.
class RtcpStatisticsCallback {
public:
virtual ~RtcpStatisticsCallback() {}
virtual void StatisticsUpdated(const RtcpStatistics& statistics,
uint32_t ssrc) = 0;
virtual void CNameChanged(const char* cname, uint32_t ssrc) = 0;
};
// Statistics for RTCP packet types.
@ -331,13 +331,18 @@ class BitrateStatisticsObserver {
uint32_t ssrc) = 0;
};
struct FrameCounts {
FrameCounts() : key_frames(0), delta_frames(0) {}
int key_frames;
int delta_frames;
};
// Callback, used to notify an observer whenever frame counts have been updated.
class FrameCountObserver {
public:
virtual ~FrameCountObserver() {}
virtual void FrameCountUpdated(FrameType frame_type,
uint32_t frame_count,
const unsigned int ssrc) = 0;
virtual void FrameCountUpdated(const FrameCounts& frame_counts,
uint32_t ssrc) = 0;
};
// Callback, used to notify an observer whenever the send-side delay is updated.

View File

@ -23,16 +23,13 @@ namespace webrtc {
struct SsrcStats {
SsrcStats()
: key_frames(0),
delta_frames(0),
sent_width(0),
: sent_width(0),
sent_height(0),
total_bitrate_bps(0),
retransmit_bitrate_bps(0),
avg_delay_ms(0),
max_delay_ms(0) {}
uint32_t key_frames;
uint32_t delta_frames;
FrameCounts frame_counts;
int sent_width;
int sent_height;
// TODO(holmer): Move bitrate_bps out to the webrtc::Call layer.

View File

@ -586,10 +586,10 @@ class RtpRtcp : public Module {
virtual bool StorePackets() const = 0;
// Called on receipt of RTCP report block from remote side.
virtual void RegisterSendChannelRtcpStatisticsCallback(
virtual void RegisterRtcpStatisticsCallback(
RtcpStatisticsCallback* callback) = 0;
virtual RtcpStatisticsCallback*
GetSendChannelRtcpStatisticsCallback() = 0;
GetRtcpStatisticsCallback() = 0;
/**************************************************************************
*

View File

@ -221,10 +221,8 @@ class MockRtpRtcp : public RtpRtcp {
MOCK_METHOD2(SetStorePacketsStatus,
int32_t(const bool enable, const uint16_t numberToStore));
MOCK_CONST_METHOD0(StorePackets, bool());
MOCK_METHOD1(RegisterSendChannelRtcpStatisticsCallback,
void(RtcpStatisticsCallback*));
MOCK_METHOD0(GetSendChannelRtcpStatisticsCallback,
RtcpStatisticsCallback*());
MOCK_METHOD1(RegisterRtcpStatisticsCallback, void(RtcpStatisticsCallback*));
MOCK_METHOD0(GetRtcpStatisticsCallback, RtcpStatisticsCallback*());
MOCK_METHOD1(RegisterAudioCallback,
int32_t(RtpAudioFeedback* messagesCallback));
MOCK_METHOD1(SetAudioPacketSize,

View File

@ -511,9 +511,14 @@ void ReceiveStatisticsImpl::RegisterRtcpStatisticsCallback(
void ReceiveStatisticsImpl::StatisticsUpdated(const RtcpStatistics& statistics,
uint32_t ssrc) {
CriticalSectionScoped cs(receive_statistics_lock_.get());
if (rtcp_stats_callback_) {
if (rtcp_stats_callback_)
rtcp_stats_callback_->StatisticsUpdated(statistics, ssrc);
}
}
void ReceiveStatisticsImpl::CNameChanged(const char* cname, uint32_t ssrc) {
CriticalSectionScoped cs(receive_statistics_lock_.get());
if (rtcp_stats_callback_)
rtcp_stats_callback_->CNameChanged(cname, ssrc);
}
void ReceiveStatisticsImpl::RegisterRtpStatisticsCallback(

View File

@ -128,6 +128,7 @@ class ReceiveStatisticsImpl : public ReceiveStatistics,
private:
virtual void StatisticsUpdated(const RtcpStatistics& statistics,
uint32_t ssrc) OVERRIDE;
virtual void CNameChanged(const char* cname, uint32_t ssrc) OVERRIDE;
virtual void DataCountersUpdated(const StreamDataCounters& counters,
uint32_t ssrc) OVERRIDE;

View File

@ -169,6 +169,8 @@ TEST_F(ReceiveStatisticsTest, RtcpCallbacks) {
++num_calls_;
}
virtual void CNameChanged(const char* cname, uint32_t ssrc) OVERRIDE {}
uint32_t num_calls_;
uint32_t ssrc_;
RtcpStatistics stats_;

View File

@ -809,6 +809,10 @@ void RTCPReceiver::HandleSDESChunk(RTCPUtility::RTCPParserV2& rtcpParser) {
cnameInfo->name[RTCP_CNAME_SIZE - 1] = 0;
strncpy(cnameInfo->name, rtcpPacket.CName.CName, RTCP_CNAME_SIZE - 1);
if (stats_callback_ != NULL) {
stats_callback_->CNameChanged(rtcpPacket.CName.CName,
rtcpPacket.CName.SenderSSRC);
}
}
// no need for critsect we have _criticalSectionRTCPReceiver

View File

@ -820,6 +820,8 @@ TEST_F(RtcpReceiverTest, Callbacks) {
ssrc_ = ssrc;
}
virtual void CNameChanged(const char* cname, uint32_t ssrc) OVERRIDE {}
bool Matches(uint32_t ssrc, uint32_t extended_max, uint8_t fraction_loss,
uint32_t cumulative_loss, uint32_t jitter) {
return ssrc_ == ssrc &&

View File

@ -988,13 +988,13 @@ bool ModuleRtpRtcpImpl::StorePackets() const {
return rtp_sender_.StorePackets();
}
void ModuleRtpRtcpImpl::RegisterSendChannelRtcpStatisticsCallback(
void ModuleRtpRtcpImpl::RegisterRtcpStatisticsCallback(
RtcpStatisticsCallback* callback) {
rtcp_receiver_.RegisterRtcpStatisticsCallback(callback);
}
RtcpStatisticsCallback* ModuleRtpRtcpImpl::
GetSendChannelRtcpStatisticsCallback() {
RtcpStatisticsCallback*
ModuleRtpRtcpImpl::GetRtcpStatisticsCallback() {
return rtcp_receiver_.GetRtcpStatisticsCallback();
}

View File

@ -247,10 +247,9 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
virtual bool StorePackets() const OVERRIDE;
// Called on receipt of RTCP report block from remote side.
virtual void RegisterSendChannelRtcpStatisticsCallback(
virtual void RegisterRtcpStatisticsCallback(
RtcpStatisticsCallback* callback) OVERRIDE;
virtual RtcpStatisticsCallback*
GetSendChannelRtcpStatisticsCallback() OVERRIDE;
virtual RtcpStatisticsCallback* GetRtcpStatisticsCallback() OVERRIDE;
// (APP) Application specific data.
virtual int32_t SetRTCPApplicationSpecificData(

View File

@ -502,9 +502,14 @@ int32_t RTPSender::SendOutgoingData(
}
CriticalSectionScoped cs(statistics_crit_.get());
uint32_t frame_count = ++frame_counts_[frame_type];
// Note: This is currently only counting for video.
if (frame_type == kVideoFrameKey) {
++frame_counts_.key_frames;
} else if (frame_type == kVideoFrameDelta) {
++frame_counts_.delta_frames;
}
if (frame_count_observer_) {
frame_count_observer_->FrameCountUpdated(frame_type, frame_count, ssrc);
frame_count_observer_->FrameCountUpdated(frame_counts_, ssrc);
}
return ret_val;

View File

@ -371,7 +371,7 @@ class RTPSender : public RTPSenderInterface {
// Statistics
scoped_ptr<CriticalSectionWrapper> statistics_crit_;
SendDelayMap send_delays_ GUARDED_BY(statistics_crit_);
std::map<FrameType, uint32_t> frame_counts_ GUARDED_BY(statistics_crit_);
FrameCounts frame_counts_ GUARDED_BY(statistics_crit_);
StreamDataCounters rtp_stats_ GUARDED_BY(statistics_crit_);
StreamDataCounters rtx_rtp_stats_ GUARDED_BY(statistics_crit_);
StreamDataCountersCallback* rtp_stats_callback_ GUARDED_BY(statistics_crit_);

View File

@ -768,32 +768,19 @@ TEST_F(RtpSenderTest, SendGenericVideo) {
TEST_F(RtpSenderTest, FrameCountCallbacks) {
class TestCallback : public FrameCountObserver {
public:
TestCallback()
: FrameCountObserver(), num_calls_(0), ssrc_(0),
key_frames_(0), delta_frames_(0) {}
TestCallback() : FrameCountObserver(), num_calls_(0), ssrc_(0) {}
virtual ~TestCallback() {}
virtual void FrameCountUpdated(FrameType frame_type,
uint32_t frame_count,
const unsigned int ssrc) OVERRIDE {
virtual void FrameCountUpdated(const FrameCounts& frame_counts,
uint32_t ssrc) OVERRIDE {
++num_calls_;
ssrc_ = ssrc;
switch (frame_type) {
case kVideoFrameDelta:
delta_frames_ = frame_count;
break;
case kVideoFrameKey:
key_frames_ = frame_count;
break;
default:
break;
}
frame_counts_ = frame_counts;
}
uint32_t num_calls_;
uint32_t ssrc_;
uint32_t key_frames_;
uint32_t delta_frames_;
FrameCounts frame_counts_;
} callback;
rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_, NULL,
@ -813,8 +800,8 @@ TEST_F(RtpSenderTest, FrameCountCallbacks) {
EXPECT_EQ(1U, callback.num_calls_);
EXPECT_EQ(ssrc, callback.ssrc_);
EXPECT_EQ(1U, callback.key_frames_);
EXPECT_EQ(0U, callback.delta_frames_);
EXPECT_EQ(1, callback.frame_counts_.key_frames);
EXPECT_EQ(0, callback.frame_counts_.delta_frames);
ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kVideoFrameDelta,
payload_type, 1234, 4321, payload,
@ -822,8 +809,8 @@ TEST_F(RtpSenderTest, FrameCountCallbacks) {
EXPECT_EQ(2U, callback.num_calls_);
EXPECT_EQ(ssrc, callback.ssrc_);
EXPECT_EQ(1U, callback.key_frames_);
EXPECT_EQ(1U, callback.delta_frames_);
EXPECT_EQ(1, callback.frame_counts_.key_frames);
EXPECT_EQ(1, callback.frame_counts_.delta_frames);
rtp_sender_.reset();
}

View File

@ -485,16 +485,6 @@ public:
// < 0, on error.
virtual int32_t Delay() const = 0;
// Get the received frame counters. Keeps track of the number of each frame type
// received since the start of the call.
//
// Output:
// - frameCount : Struct to be filled with the number of frames received.
//
// Return value : VCM_OK, on success.
// <0, on error.
virtual int32_t ReceivedFrameCount(VCMFrameCount& frameCount) const = 0;
// Returns the number of packets discarded by the jitter buffer due to being
// too late. This can include duplicated packets which arrived after the
// frame was sent to the decoder. Therefore packets which were prematurely
@ -592,6 +582,8 @@ public:
EncodedImageCallback* observer) = 0;
virtual void RegisterPostEncodeImageCallback(
EncodedImageCallback* post_encode_callback) = 0;
virtual void RegisterReceiveFrameCountObserver(
FrameCountObserver* frame_count_observer) = 0;
};
} // namespace webrtc

View File

@ -124,6 +124,7 @@ VCMJitterBuffer::VCMJitterBuffer(Clock* clock, EventFactory* event_factory)
incomplete_frames_(),
last_decoded_state_(),
first_packet_since_reset_(true),
frame_count_observer_(NULL),
incoming_frame_rate_(0),
incoming_frame_count_(0),
time_last_incoming_frame_count_(0),
@ -184,14 +185,15 @@ void VCMJitterBuffer::UpdateHistograms() {
RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.DuplicatedPacketsInPercent",
num_duplicated_packets_ * 100 / num_packets_);
uint32_t total_frames = receive_statistics_[kVideoFrameKey] +
receive_statistics_[kVideoFrameDelta];
int total_frames =
receive_statistics_.key_frames + receive_statistics_.delta_frames;
if (total_frames > 0) {
RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.CompleteFramesReceivedPerSecond",
static_cast<int>((total_frames / elapsed_sec) + 0.5f));
RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.KeyFramesReceivedInPermille",
static_cast<int>((receive_statistics_[kVideoFrameKey] * 1000.0f /
total_frames) + 0.5f));
RTC_HISTOGRAM_COUNTS_1000(
"WebRTC.Video.KeyFramesReceivedInPermille",
static_cast<int>(
(receive_statistics_.key_frames * 1000.0f / total_frames) + 0.5f));
}
}
@ -203,7 +205,7 @@ void VCMJitterBuffer::Start() {
incoming_bit_count_ = 0;
incoming_bit_rate_ = 0;
time_last_incoming_frame_count_ = clock_->TimeInMilliseconds();
receive_statistics_.clear();
receive_statistics_ = FrameCounts();
num_consecutive_old_packets_ = 0;
num_packets_ = 0;
@ -269,7 +271,7 @@ void VCMJitterBuffer::Flush() {
}
// Get received key and delta frames
std::map<FrameType, uint32_t> VCMJitterBuffer::FrameStatistics() const {
FrameCounts VCMJitterBuffer::FrameStatistics() const {
CriticalSectionScoped cs(crit_sect_);
return receive_statistics_;
}
@ -1038,6 +1040,12 @@ void VCMJitterBuffer::RenderBufferSize(uint32_t* timestamp_start,
*timestamp_end = decodable_frames_.Back()->TimeStamp();
}
void VCMJitterBuffer::RegisterFrameCountObserver(
FrameCountObserver* frame_count_observer) {
CriticalSectionScoped cs(crit_sect_);
frame_count_observer_ = frame_count_observer;
}
VCMFrameBuffer* VCMJitterBuffer::GetEmptyFrame() {
if (free_frames_.empty()) {
if (!TryToIncreaseJitterBufferSize()) {
@ -1105,7 +1113,13 @@ void VCMJitterBuffer::CountFrame(const VCMFrameBuffer& frame) {
// Update receive statistics. We count all layers, thus when you use layers
// adding all key and delta frames might differ from frame count.
if (frame.IsSessionComplete()) {
++receive_statistics_[frame.FrameType()];
if (frame.FrameType() == kVideoFrameKey) {
++receive_statistics_.key_frames;
} else {
++receive_statistics_.delta_frames;
}
if (frame_count_observer_ != NULL)
frame_count_observer_->FrameCountUpdated(receive_statistics_, 0);
}
}

View File

@ -94,7 +94,7 @@ class VCMJitterBuffer {
// Get the number of received frames, by type, since the jitter buffer
// was started.
std::map<FrameType, uint32_t> FrameStatistics() const;
FrameCounts FrameStatistics() const;
// The number of packets discarded by the jitter buffer because the decoder
// won't be able to decode them.
@ -184,6 +184,8 @@ class VCMJitterBuffer {
// corresponding to the start and end of the continuous complete buffer.
void RenderBufferSize(uint32_t* timestamp_start, uint32_t* timestamp_end);
void RegisterFrameCountObserver(FrameCountObserver* observer);
private:
class SequenceNumberLessThan {
public:
@ -254,7 +256,8 @@ class VCMJitterBuffer {
// Updates the frame statistics.
// Counts only complete frames, so decodable incomplete frames will not be
// counted.
void CountFrame(const VCMFrameBuffer& frame);
void CountFrame(const VCMFrameBuffer& frame)
EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
// Update rolling average of packets per frame.
void UpdateAveragePacketsPerFrame(int current_number_packets_);
@ -301,7 +304,8 @@ class VCMJitterBuffer {
// Statistics.
// Frame counts for each type (key, delta, ...)
std::map<FrameType, uint32_t> receive_statistics_;
FrameCountObserver* frame_count_observer_ GUARDED_BY(crit_sect_);
FrameCounts receive_statistics_;
// Latest calculated frame rates of incoming stream.
unsigned int incoming_frame_rate_;
unsigned int incoming_frame_count_;

View File

@ -1693,9 +1693,9 @@ TEST_F(TestRunningJitterBuffer, EmptyPackets) {
}
TEST_F(TestRunningJitterBuffer, StatisticsTest) {
std::map<FrameType, uint32_t> frame_stats(jitter_buffer_->FrameStatistics());
EXPECT_EQ(0u, frame_stats[kVideoFrameDelta]);
EXPECT_EQ(0u, frame_stats[kVideoFrameKey]);
FrameCounts frame_stats(jitter_buffer_->FrameStatistics());
EXPECT_EQ(0, frame_stats.delta_frames);
EXPECT_EQ(0, frame_stats.key_frames);
uint32_t framerate = 0;
uint32_t bitrate = 0;
@ -1714,8 +1714,8 @@ TEST_F(TestRunningJitterBuffer, StatisticsTest) {
EXPECT_TRUE(DecodeCompleteFrame());
EXPECT_TRUE(DecodeCompleteFrame());
frame_stats = jitter_buffer_->FrameStatistics();
EXPECT_EQ(3u, frame_stats[kVideoFrameDelta]);
EXPECT_EQ(2u, frame_stats[kVideoFrameKey]);
EXPECT_EQ(3, frame_stats.delta_frames);
EXPECT_EQ(2, frame_stats.key_frames);
// Insert 20 more frames to get estimates of bitrate and framerate over
// 1 second.

View File

@ -186,13 +186,6 @@ void VCMReceiver::ReceiveStatistics(uint32_t* bitrate,
jitter_buffer_.IncomingRateStatistics(framerate, bitrate);
}
void VCMReceiver::ReceivedFrameCount(VCMFrameCount* frame_count) const {
assert(frame_count);
std::map<FrameType, uint32_t> counts(jitter_buffer_.FrameStatistics());
frame_count->numDeltaFrames = counts[kVideoFrameDelta];
frame_count->numKeyFrames = counts[kVideoFrameKey];
}
uint32_t VCMReceiver::DiscardedPackets() const {
return jitter_buffer_.num_discarded_packets();
}
@ -276,4 +269,10 @@ int VCMReceiver::RenderBufferSizeMs() {
uint32_t render_end = timing_->RenderTimeMs(timestamp_end, now_ms);
return render_end - render_start;
}
void VCMReceiver::RegisterFrameCountObserver(
FrameCountObserver* frame_count_observer) {
jitter_buffer_.RegisterFrameCountObserver(frame_count_observer);
}
} // namespace webrtc

View File

@ -53,7 +53,6 @@ class VCMReceiver {
bool render_timing = true);
void ReleaseFrame(VCMEncodedFrame* frame);
void ReceiveStatistics(uint32_t* bitrate, uint32_t* framerate);
void ReceivedFrameCount(VCMFrameCount* frame_count) const;
uint32_t DiscardedPackets() const;
// NACK.
@ -80,6 +79,8 @@ class VCMReceiver {
// the time this function is called.
int RenderBufferSizeMs();
void RegisterFrameCountObserver(FrameCountObserver* frame_count_observer);
private:
static int32_t GenerateReceiverId();

View File

@ -278,6 +278,11 @@ class VideoCodingModuleImpl : public VideoCodingModule {
return receiver_->RegisterRenderBufferSizeCallback(callback);
}
virtual void RegisterReceiveFrameCountObserver(
FrameCountObserver* frame_count_observer) OVERRIDE {
receiver_->RegisterFrameCountObserver(frame_count_observer);
}
virtual int32_t Decode(uint16_t maxWaitTimeMs) OVERRIDE {
return receiver_->Decode(maxWaitTimeMs);
}
@ -308,10 +313,6 @@ class VideoCodingModuleImpl : public VideoCodingModule {
virtual int32_t Delay() const OVERRIDE { return receiver_->Delay(); }
virtual int32_t ReceivedFrameCount(VCMFrameCount& frameCount) const OVERRIDE {
return receiver_->ReceivedFrameCount(&frameCount);
}
virtual uint32_t DiscardedPackets() const OVERRIDE {
return receiver_->DiscardedPackets();
}

View File

@ -164,7 +164,6 @@ class VideoReceiver {
int32_t SetMinimumPlayoutDelay(uint32_t minPlayoutDelayMs);
int32_t SetRenderDelay(uint32_t timeMS);
int32_t Delay() const;
int32_t ReceivedFrameCount(VCMFrameCount* frameCount) const;
uint32_t DiscardedPackets() const;
int SetReceiverRobustnessMode(ReceiverRobustness robustnessMode,
@ -183,6 +182,7 @@ class VideoReceiver {
int32_t Process();
void RegisterPreDecodeImageCallback(EncodedImageCallback* observer);
void RegisterFrameCountObserver(FrameCountObserver* frame_count_observer);
protected:
int32_t Decode(const webrtc::VCMEncodedFrame& frame)

View File

@ -592,11 +592,6 @@ int32_t VideoReceiver::NackList(uint16_t* nackList, uint16_t* size) {
return VCM_OK;
}
int32_t VideoReceiver::ReceivedFrameCount(VCMFrameCount* frameCount) const {
_receiver.ReceivedFrameCount(frameCount);
return VCM_OK;
}
uint32_t VideoReceiver::DiscardedPackets() const {
return _receiver.DiscardedPackets();
}
@ -671,6 +666,10 @@ void VideoReceiver::RegisterPreDecodeImageCallback(
CriticalSectionScoped cs(_receiveCritSect);
pre_decode_image_callback_ = observer;
}
void VideoReceiver::RegisterFrameCountObserver(
FrameCountObserver* frame_count_observer) {
_receiver.RegisterFrameCountObserver(frame_count_observer);
}
} // namespace vcm
} // namespace webrtc

View File

@ -1496,8 +1496,13 @@ TEST_F(EndToEndTest, GetStats) {
stats.rtp_stats.retransmitted_packets != 0;
receive_stats_filled_["CodecStats"] |=
stats.avg_delay_ms != 0 || stats.discarded_packets != 0 ||
stats.key_frames != 0 || stats.delta_frames != 0;
stats.avg_delay_ms != 0 || stats.discarded_packets != 0;
receive_stats_filled_["FrameCounts"] |=
stats.frame_counts.key_frames != 0 ||
stats.frame_counts.delta_frames != 0;
receive_stats_filled_["CName"] |= stats.c_name != "";
return AllStatsFilled(receive_stats_filled_);
}
@ -1537,7 +1542,8 @@ TEST_F(EndToEndTest, GetStats) {
stream_stats.total_bitrate_bps != 0;
send_stats_filled_[CompoundKey("FrameCountObserver", it->first)] |=
stream_stats.delta_frames != 0 || stream_stats.key_frames != 0;
stream_stats.frame_counts.delta_frames != 0 ||
stream_stats.frame_counts.key_frames != 0;
send_stats_filled_[CompoundKey("OutgoingRate", it->first)] |=
stats.encode_frame_rate != 0;

View File

@ -14,17 +14,14 @@
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
namespace webrtc {
namespace internal {
ReceiveStatisticsProxy::ReceiveStatisticsProxy(uint32_t ssrc,
Clock* clock,
ViERTP_RTCP* rtp_rtcp,
ViECodec* codec,
int channel)
: channel_(channel),
clock_(clock),
codec_(codec),
rtp_rtcp_(rtp_rtcp),
crit_(CriticalSectionWrapper::CreateCriticalSection()),
// 1000ms window, scale 1000 for ms to s.
decode_fps_estimator_(1000, 1000),
@ -40,24 +37,11 @@ VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const {
CriticalSectionScoped lock(crit_.get());
stats = stats_;
}
stats.c_name = GetCName();
stats.discarded_packets = codec_->GetNumDiscardedPackets(channel_);
codec_->GetReceiveCodecStastistics(
channel_, stats.key_frames, stats.delta_frames);
codec_->GetReceiveCodecStastistics(channel_, stats.key_frames,
stats.delta_frames);
return stats;
}
std::string ReceiveStatisticsProxy::GetCName() const {
char rtcp_cname[ViERTP_RTCP::KMaxRTCPCNameLength];
if (rtp_rtcp_->GetRemoteRTCPCName(channel_, rtcp_cname) != 0)
rtcp_cname[0] = '\0';
return rtcp_cname;
}
void ReceiveStatisticsProxy::IncomingRate(const int video_channel,
const unsigned int framerate,
const unsigned int bitrate_bps) {
@ -85,6 +69,11 @@ void ReceiveStatisticsProxy::StatisticsUpdated(
stats_.rtcp_stats = statistics;
}
void ReceiveStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {
CriticalSectionScoped lock(crit_.get());
stats_.c_name = cname;
}
void ReceiveStatisticsProxy::DataCountersUpdated(
const webrtc::StreamDataCounters& counters,
uint32_t ssrc) {
@ -109,5 +98,10 @@ void ReceiveStatisticsProxy::OnRenderedFrame() {
stats_.render_frame_rate = renders_fps_estimator_.Rate(now);
}
} // namespace internal
void ReceiveStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
uint32_t ssrc) {
CriticalSectionScoped lock(crit_.get());
stats_.frame_counts = frame_counts;
}
} // namespace webrtc

View File

@ -29,15 +29,13 @@ class CriticalSectionWrapper;
class ViECodec;
class ViEDecoderObserver;
namespace internal {
class ReceiveStatisticsProxy : public ViEDecoderObserver,
public RtcpStatisticsCallback,
public StreamDataCountersCallback {
public StreamDataCountersCallback,
public FrameCountObserver {
public:
ReceiveStatisticsProxy(uint32_t ssrc,
Clock* clock,
ViERTP_RTCP* rtp_rtcp,
ViECodec* codec,
int channel);
virtual ~ReceiveStatisticsProxy();
@ -62,21 +60,23 @@ class ReceiveStatisticsProxy : public ViEDecoderObserver,
int render_delay_ms) OVERRIDE;
virtual void RequestNewKeyFrame(const int video_channel) OVERRIDE {}
// Overrides RtcpStatisticsBallback.
// Overrides RtcpStatisticsCallback.
virtual void StatisticsUpdated(const webrtc::RtcpStatistics& statistics,
uint32_t ssrc) OVERRIDE;
virtual void CNameChanged(const char* cname, uint32_t ssrc) OVERRIDE;
// Overrides StreamDataCountersCallback.
virtual void DataCountersUpdated(const webrtc::StreamDataCounters& counters,
uint32_t ssrc) OVERRIDE;
private:
std::string GetCName() const;
// Overrides FrameCountObserver.
virtual void FrameCountUpdated(const FrameCounts& frame_counts,
uint32_t ssrc) OVERRIDE;
private:
const int channel_;
Clock* const clock_;
ViECodec* const codec_;
ViERTP_RTCP* const rtp_rtcp_;
scoped_ptr<CriticalSectionWrapper> crit_;
VideoReceiveStream::Stats stats_ GUARDED_BY(crit_);
@ -84,6 +84,5 @@ class ReceiveStatisticsProxy : public ViEDecoderObserver,
RateStatistics renders_fps_estimator_ GUARDED_BY(crit_);
};
} // namespace internal
} // namespace webrtc
#endif // WEBRTC_VIDEO_RECEIVE_STATISTICS_PROXY_H_

View File

@ -115,6 +115,9 @@ void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
stats->rtcp_stats = statistics;
}
void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {
}
void SendStatisticsProxy::DataCountersUpdated(
const StreamDataCounters& counters,
uint32_t ssrc) {
@ -138,26 +141,14 @@ void SendStatisticsProxy::Notify(const BitrateStatistics& total_stats,
stats->retransmit_bitrate_bps = retransmit_stats.bitrate_bps;
}
void SendStatisticsProxy::FrameCountUpdated(FrameType frame_type,
uint32_t frame_count,
const unsigned int ssrc) {
void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
uint32_t ssrc) {
CriticalSectionScoped lock(crit_.get());
SsrcStats* stats = GetStatsEntry(ssrc);
if (stats == NULL)
return;
switch (frame_type) {
case kVideoFrameDelta:
stats->delta_frames = frame_count;
break;
case kVideoFrameKey:
stats->key_frames = frame_count;
break;
case kFrameEmpty:
case kAudioFrameSpeech:
case kAudioFrameCN:
break;
}
stats->frame_counts = frame_counts;
}
void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,

View File

@ -48,6 +48,7 @@ class SendStatisticsProxy : public RtcpStatisticsCallback,
// From RtcpStatisticsCallback.
virtual void StatisticsUpdated(const RtcpStatistics& statistics,
uint32_t ssrc) OVERRIDE;
virtual void CNameChanged(const char *cname, uint32_t ssrc) OVERRIDE;
// From StreamDataCountersCallback.
virtual void DataCountersUpdated(const StreamDataCounters& counters,
uint32_t ssrc) OVERRIDE;
@ -58,9 +59,8 @@ class SendStatisticsProxy : public RtcpStatisticsCallback,
uint32_t ssrc) OVERRIDE;
// From FrameCountObserver.
virtual void FrameCountUpdated(FrameType frame_type,
uint32_t frame_count,
const unsigned int ssrc) OVERRIDE;
virtual void FrameCountUpdated(const FrameCounts& frame_counts,
uint32_t ssrc) OVERRIDE;
// From ViEEncoderObserver.
virtual void OutgoingRate(const int video_channel,

View File

@ -59,8 +59,8 @@ class SendStatisticsProxyTest : public ::testing::Test {
const SsrcStats& a = it->second;
const SsrcStats& b = corresponding_it->second;
EXPECT_EQ(a.key_frames, b.key_frames);
EXPECT_EQ(a.delta_frames, b.delta_frames);
EXPECT_EQ(a.frame_counts.key_frames, b.frame_counts.key_frames);
EXPECT_EQ(a.frame_counts.delta_frames, b.frame_counts.delta_frames);
EXPECT_EQ(a.total_bitrate_bps, b.total_bitrate_bps);
EXPECT_EQ(a.avg_delay_ms, b.avg_delay_ms);
EXPECT_EQ(a.max_delay_ms, b.max_delay_ms);
@ -169,10 +169,11 @@ TEST_F(SendStatisticsProxyTest, FrameCounts) {
// Add statistics with some arbitrary, but unique, numbers.
SsrcStats& stats = expected_.substreams[ssrc];
uint32_t offset = ssrc * sizeof(SsrcStats);
stats.key_frames = offset;
stats.delta_frames = offset + 1;
observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc);
observer->FrameCountUpdated(kVideoFrameDelta, stats.delta_frames, ssrc);
FrameCounts frame_counts;
frame_counts.key_frames = offset;
frame_counts.delta_frames = offset + 1;
stats.frame_counts = frame_counts;
observer->FrameCountUpdated(frame_counts, ssrc);
}
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
it != config_.rtp.rtx.ssrcs.end();
@ -181,10 +182,11 @@ TEST_F(SendStatisticsProxyTest, FrameCounts) {
// Add statistics with some arbitrary, but unique, numbers.
SsrcStats& stats = expected_.substreams[ssrc];
uint32_t offset = ssrc * sizeof(SsrcStats);
stats.key_frames = offset;
stats.delta_frames = offset + 1;
observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc);
observer->FrameCountUpdated(kVideoFrameDelta, stats.delta_frames, ssrc);
FrameCounts frame_counts;
frame_counts.key_frames = offset;
frame_counts.delta_frames = offset + 1;
stats.frame_counts = frame_counts;
observer->FrameCountUpdated(frame_counts, ssrc);
}
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
@ -318,7 +320,9 @@ TEST_F(SendStatisticsProxyTest, NoSubstreams) {
// From FrameCountObserver.
FrameCountObserver* fps_observer = statistics_proxy_.get();
fps_observer->FrameCountUpdated(kVideoFrameKey, 1, exluded_ssrc);
FrameCounts frame_counts;
frame_counts.key_frames = 1;
fps_observer->FrameCountUpdated(frame_counts, exluded_ssrc);
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
EXPECT_TRUE(stats.substreams.empty());

View File

@ -148,19 +148,25 @@ VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine,
}
}
stats_proxy_.reset(new ReceiveStatisticsProxy(
config_.rtp.local_ssrc, clock_, rtp_rtcp_, codec_, channel_));
stats_proxy_.reset(new ReceiveStatisticsProxy(config_.rtp.local_ssrc, clock_,
codec_, channel_));
if (rtp_rtcp_->RegisterReceiveChannelRtcpStatisticsCallback(
channel_, stats_proxy_.get()) != 0)
channel_, stats_proxy_.get()) != 0) {
abort();
}
if (rtp_rtcp_->RegisterReceiveChannelRtpStatisticsCallback(
channel_, stats_proxy_.get()) != 0)
channel_, stats_proxy_.get()) != 0) {
abort();
}
if (codec_->RegisterDecoderObserver(channel_, *stats_proxy_) != 0)
if (codec_->RegisterDecoderObserver(channel_, *stats_proxy_) != 0) {
abort();
}
video_engine_base_->RegisterReceiveStatisticsProxy(channel_,
stats_proxy_.get());
external_codec_ = ViEExternalCodec::GetInterface(video_engine);
assert(!config_.decoders.empty());

View File

@ -958,9 +958,10 @@ TEST_F(VideoSendStreamTest, ProducesStats) {
// Check for data populated by various sources. RTCP excluded as this
// data is received from remote side. Tested in call tests instead.
const SsrcStats& entry = stats.substreams[ssrc];
if (entry.key_frames > 0u && entry.total_bitrate_bps > 0 &&
entry.rtp_stats.packets > 0u && entry.avg_delay_ms > 0 &&
entry.max_delay_ms > 0) {
if (entry.frame_counts.key_frames > 0 &&
entry.frame_counts.delta_frames > 0 &&
entry.total_bitrate_bps > 0 && entry.rtp_stats.packets > 0u &&
entry.avg_delay_ms > 0 && entry.max_delay_ms > 0) {
return true;
}
}

View File

@ -25,6 +25,7 @@ namespace webrtc {
class Config;
class VoiceEngine;
class ReceiveStatisticsProxy;
class SendStatisticsProxy;
// CpuOveruseObserver is called when a system overuse is detected and
@ -243,6 +244,10 @@ class WEBRTC_DLLEXPORT ViEBase {
int channel,
SendStatisticsProxy* send_statistics_proxy) = 0;
virtual void RegisterReceiveStatisticsProxy(
int channel,
ReceiveStatisticsProxy* receive_statistics_proxy) = 0;
protected:
ViEBase() {}
virtual ~ViEBase() {}

View File

@ -373,4 +373,17 @@ void ViEBaseImpl::RegisterSendStatisticsProxy(
vie_encoder->RegisterSendStatisticsProxy(send_statistics_proxy);
}
void ViEBaseImpl::RegisterReceiveStatisticsProxy(
int channel,
ReceiveStatisticsProxy* receive_statistics_proxy) {
LOG_F(LS_VERBOSE) << "RegisterReceiveStatisticsProxy on channel " << channel;
ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
ViEChannel* vie_channel = cs.Channel(channel);
if (!vie_channel) {
shared_data_.SetLastError(kViEBaseInvalidChannelId);
return;
}
vie_channel->RegisterReceiveStatisticsProxy(receive_statistics_proxy);
}
} // namespace webrtc

View File

@ -70,6 +70,9 @@ class ViEBaseImpl
virtual void RegisterSendStatisticsProxy(
int channel,
SendStatisticsProxy* send_statistics_proxy) OVERRIDE;
virtual void RegisterReceiveStatisticsProxy(
int channel,
ReceiveStatisticsProxy* receive_statistics_proxy) OVERRIDE;
// ViEBaseImpl owns ViESharedData used by all interface implementations.
ViESharedData shared_data_;
};

View File

@ -16,6 +16,7 @@
#include "webrtc/common.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/experiments.h"
#include "webrtc/frame_callback.h"
#include "webrtc/modules/pacing/include/paced_sender.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
@ -27,12 +28,12 @@
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/metrics.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/video/receive_statistics_proxy.h"
#include "webrtc/video_engine/call_stats.h"
#include "webrtc/video_engine/include/vie_codec.h"
#include "webrtc/video_engine/include/vie_errors.h"
#include "webrtc/video_engine/include/vie_image_process.h"
#include "webrtc/video_engine/include/vie_rtp_rtcp.h"
#include "webrtc/frame_callback.h"
#include "webrtc/video_engine/vie_defines.h"
namespace webrtc {
@ -156,6 +157,7 @@ ViEChannel::ViEChannel(int32_t channel_id,
rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(configuration));
vie_receiver_.SetRtpRtcpModule(rtp_rtcp_.get());
vcm_->SetNackSettings(kMaxNackListSize, max_nack_reordering_threshold_, 0);
vcm_->RegisterReceiveFrameCountObserver(&receive_frame_count_observer_);
}
int32_t ViEChannel::Init() {
@ -424,7 +426,7 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
module_process_thread_.DeRegisterModule(rtp_rtcp);
rtp_rtcp->SetSendingStatus(false);
rtp_rtcp->SetSendingMediaStatus(false);
rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(NULL);
rtp_rtcp->RegisterRtcpStatisticsCallback(NULL);
rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(NULL);
simulcast_rtp_rtcp_.pop_back();
removed_rtp_rtcp_.push_front(rtp_rtcp);
@ -471,8 +473,8 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
rtp_rtcp->DeregisterSendRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime);
}
rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(
rtp_rtcp_->GetSendChannelRtcpStatisticsCallback());
rtp_rtcp->RegisterRtcpStatisticsCallback(
rtp_rtcp_->GetRtcpStatisticsCallback());
rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(
rtp_rtcp_->GetSendChannelRtpStatisticsCallback());
}
@ -485,7 +487,7 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
module_process_thread_.DeRegisterModule(rtp_rtcp);
rtp_rtcp->SetSendingStatus(false);
rtp_rtcp->SetSendingMediaStatus(false);
rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(NULL);
rtp_rtcp->RegisterRtcpStatisticsCallback(NULL);
rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(NULL);
simulcast_rtp_rtcp_.pop_back();
removed_rtp_rtcp_.push_front(rtp_rtcp);
@ -577,12 +579,7 @@ int32_t ViEChannel::DeRegisterExternalDecoder(const uint8_t pl_type) {
int32_t ViEChannel::ReceiveCodecStatistics(uint32_t* num_key_frames,
uint32_t* num_delta_frames) {
VCMFrameCount received_frames;
if (vcm_->ReceivedFrameCount(received_frames) != VCM_OK) {
return -1;
}
*num_key_frames = received_frames.numKeyFrames;
*num_delta_frames = received_frames.numDeltaFrames;
receive_frame_count_observer_.GetFrameCount(num_key_frames, num_delta_frames);
return 0;
}
@ -1127,12 +1124,12 @@ int32_t ViEChannel::GetSendRtcpStatistics(uint16_t* fraction_lost,
void ViEChannel::RegisterSendChannelRtcpStatisticsCallback(
RtcpStatisticsCallback* callback) {
rtp_rtcp_->RegisterSendChannelRtcpStatisticsCallback(callback);
rtp_rtcp_->RegisterRtcpStatisticsCallback(callback);
CriticalSectionScoped cs(rtp_rtcp_cs_.get());
for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
it != simulcast_rtp_rtcp_.end();
++it) {
(*it)->RegisterSendChannelRtcpStatisticsCallback(callback);
(*it)->RegisterRtcpStatisticsCallback(callback);
}
}
@ -1168,6 +1165,7 @@ void ViEChannel::RegisterReceiveChannelRtcpStatisticsCallback(
RtcpStatisticsCallback* callback) {
vie_receiver_.GetReceiveStatistics()->RegisterRtcpStatisticsCallback(
callback);
rtp_rtcp_->RegisterRtcpStatisticsCallback(callback);
}
int32_t ViEChannel::GetRtpStatistics(size_t* bytes_sent,
@ -1667,7 +1665,7 @@ void ViEChannel::ReserveRtpRtcpModules(size_t num_modules) {
RtpRtcp* rtp_rtcp = CreateRtpRtcpModule();
rtp_rtcp->SetSendingStatus(false);
rtp_rtcp->SetSendingMediaStatus(false);
rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(NULL);
rtp_rtcp->RegisterRtcpStatisticsCallback(NULL);
rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(NULL);
removed_rtp_rtcp_.push_back(rtp_rtcp);
}
@ -1848,6 +1846,11 @@ void ViEChannel::RegisterSendFrameCountObserver(
send_frame_count_observer_.Set(observer);
}
void ViEChannel::RegisterReceiveStatisticsProxy(
ReceiveStatisticsProxy* receive_statistics_proxy) {
receive_frame_count_observer_.Set(receive_statistics_proxy);
}
void ViEChannel::ReceivedBWEPacket(int64_t arrival_time_ms,
size_t payload_size,
const RTPHeader& header) {

View File

@ -39,6 +39,7 @@ class EncodedImageCallback;
class I420FrameCallback;
class PacedSender;
class ProcessThread;
class ReceiveStatisticsProxy;
class RtcpRttStats;
class ThreadWrapper;
class ViEDecoderObserver;
@ -353,7 +354,8 @@ class ViEChannel
EncodedImageCallback* pre_decode_callback);
void RegisterSendFrameCountObserver(FrameCountObserver* observer);
void RegisterReceiveStatisticsProxy(
ReceiveStatisticsProxy* receive_statistics_proxy);
void ReceivedBWEPacket(int64_t arrival_time_ms, size_t payload_size,
const RTPHeader& header);
@ -427,14 +429,24 @@ class ViEChannel
class RegisterableFrameCountObserver
: public RegisterableCallback<FrameCountObserver> {
virtual void FrameCountUpdated(FrameType frame_type,
uint32_t frame_count,
const unsigned int ssrc) {
public:
virtual void FrameCountUpdated(const FrameCounts& frame_counts,
uint32_t ssrc) {
CriticalSectionScoped cs(critsect_.get());
frame_counts_ = frame_counts;
if (callback_)
callback_->FrameCountUpdated(frame_type, frame_count, ssrc);
callback_->FrameCountUpdated(frame_counts, ssrc);
}
} send_frame_count_observer_;
void GetFrameCount(uint32_t* num_key_frames, uint32_t* num_delta_frames) {
CriticalSectionScoped cs(critsect_.get());
*num_key_frames = frame_counts_.key_frames;
*num_delta_frames = frame_counts_.delta_frames;
}
private:
FrameCounts frame_counts_ GUARDED_BY(critsect_);
} send_frame_count_observer_, receive_frame_count_observer_;
class RegisterableSendSideDelayObserver :
public RegisterableCallback<SendSideDelayObserver> {

View File

@ -71,6 +71,8 @@ class StatisticsProxy : public RtcpStatisticsCallback {
}
}
virtual void CNameChanged(const char* cname, uint32_t ssrc) OVERRIDE {}
void ResetStatistics() {
CriticalSectionScoped cs(stats_lock_.get());
stats_ = ChannelStatistics();