webrtc_m130/webrtc/video/send_statistics_proxy_unittest.cc
stefan@webrtc.org 58e2d262fc Return an aggregated report from ViERtpRtcp::GetSentRTCPStatistics().
Fixes issues where statistics only was reported for the first stream if
configured with simulcast, and in case of RTX the reported statistics was
depending on the order of the report blocks.

Also fixes issues with multiple report blocks in the SendStatisticsProxy and the
RtcpStatisticsCallback. SendStatisticsProxy is now aware of RTX ssrcs, and the
RTCPReceiver is calling the RtcpStatisticsCallback with the correct SSRCs, and
not only the primary stream SSRC.

R=mflodman@webrtc.org, sprang@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6903 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-08-14 15:10:49 +00:00

308 lines
12 KiB
C++

/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This file includes unit tests for SendStatisticsProxy.
#include "webrtc/video/send_statistics_proxy.h"
#include <map>
#include <string>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
namespace webrtc {
class SendStatisticsProxyTest : public ::testing::Test {
public:
SendStatisticsProxyTest() : avg_delay_ms_(0), max_delay_ms_(0) {}
virtual ~SendStatisticsProxyTest() {}
protected:
virtual void SetUp() {
statistics_proxy_.reset(
new SendStatisticsProxy(GetTestConfig()));
config_ = GetTestConfig();
expected_ = VideoSendStream::Stats();
}
VideoSendStream::Config GetTestConfig() {
VideoSendStream::Config config;
config.rtp.ssrcs.push_back(17);
config.rtp.ssrcs.push_back(42);
config.rtp.rtx.ssrcs.push_back(18);
config.rtp.rtx.ssrcs.push_back(43);
return config;
}
void ExpectEqual(VideoSendStream::Stats one, VideoSendStream::Stats other) {
EXPECT_EQ(one.input_frame_rate, other.input_frame_rate);
EXPECT_EQ(one.encode_frame_rate, other.encode_frame_rate);
EXPECT_EQ(one.suspended, other.suspended);
EXPECT_EQ(one.substreams.size(), other.substreams.size());
for (std::map<uint32_t, StreamStats>::const_iterator it =
one.substreams.begin();
it != one.substreams.end();
++it) {
std::map<uint32_t, StreamStats>::const_iterator corresponding_it =
other.substreams.find(it->first);
ASSERT_TRUE(corresponding_it != other.substreams.end());
const StreamStats& a = it->second;
const StreamStats& b = corresponding_it->second;
EXPECT_EQ(a.key_frames, b.key_frames);
EXPECT_EQ(a.delta_frames, b.delta_frames);
EXPECT_EQ(a.bitrate_bps, b.bitrate_bps);
EXPECT_EQ(a.avg_delay_ms, b.avg_delay_ms);
EXPECT_EQ(a.max_delay_ms, b.max_delay_ms);
EXPECT_EQ(a.rtp_stats.bytes, b.rtp_stats.bytes);
EXPECT_EQ(a.rtp_stats.header_bytes, b.rtp_stats.header_bytes);
EXPECT_EQ(a.rtp_stats.padding_bytes, b.rtp_stats.padding_bytes);
EXPECT_EQ(a.rtp_stats.packets, b.rtp_stats.packets);
EXPECT_EQ(a.rtp_stats.retransmitted_packets,
b.rtp_stats.retransmitted_packets);
EXPECT_EQ(a.rtp_stats.fec_packets, b.rtp_stats.fec_packets);
EXPECT_EQ(a.rtcp_stats.fraction_lost, b.rtcp_stats.fraction_lost);
EXPECT_EQ(a.rtcp_stats.cumulative_lost, b.rtcp_stats.cumulative_lost);
EXPECT_EQ(a.rtcp_stats.extended_max_sequence_number,
b.rtcp_stats.extended_max_sequence_number);
EXPECT_EQ(a.rtcp_stats.jitter, b.rtcp_stats.jitter);
}
}
scoped_ptr<SendStatisticsProxy> statistics_proxy_;
VideoSendStream::Config config_;
int avg_delay_ms_;
int max_delay_ms_;
VideoSendStream::Stats expected_;
typedef std::map<uint32_t, StreamStats>::const_iterator StreamIterator;
};
TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
RtcpStatisticsCallback* callback = statistics_proxy_.get();
for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
it != config_.rtp.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
StreamStats& ssrc_stats = expected_.substreams[ssrc];
// Add statistics with some arbitrary, but unique, numbers.
uint32_t offset = ssrc * sizeof(RtcpStatistics);
ssrc_stats.rtcp_stats.cumulative_lost = offset;
ssrc_stats.rtcp_stats.extended_max_sequence_number = offset + 1;
ssrc_stats.rtcp_stats.fraction_lost = offset + 2;
ssrc_stats.rtcp_stats.jitter = offset + 3;
callback->StatisticsUpdated(ssrc_stats.rtcp_stats, ssrc);
}
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
it != config_.rtp.rtx.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
StreamStats& ssrc_stats = expected_.substreams[ssrc];
// Add statistics with some arbitrary, but unique, numbers.
uint32_t offset = ssrc * sizeof(RtcpStatistics);
ssrc_stats.rtcp_stats.cumulative_lost = offset;
ssrc_stats.rtcp_stats.extended_max_sequence_number = offset + 1;
ssrc_stats.rtcp_stats.fraction_lost = offset + 2;
ssrc_stats.rtcp_stats.jitter = offset + 3;
callback->StatisticsUpdated(ssrc_stats.rtcp_stats, ssrc);
}
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
ExpectEqual(expected_, stats);
}
TEST_F(SendStatisticsProxyTest, FrameRates) {
const int capture_fps = 31;
const int encode_fps = 29;
ViECaptureObserver* capture_observer = statistics_proxy_.get();
capture_observer->CapturedFrameRate(0, capture_fps);
ViEEncoderObserver* encoder_observer = statistics_proxy_.get();
encoder_observer->OutgoingRate(0, encode_fps, 0);
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
EXPECT_EQ(capture_fps, stats.input_frame_rate);
EXPECT_EQ(encode_fps, stats.encode_frame_rate);
}
TEST_F(SendStatisticsProxyTest, Suspended) {
// Verify that the value is false by default.
EXPECT_FALSE(statistics_proxy_->GetStats().suspended);
// Verify that we can set it to true.
ViEEncoderObserver* encoder_observer = statistics_proxy_.get();
encoder_observer->SuspendChange(0, true);
EXPECT_TRUE(statistics_proxy_->GetStats().suspended);
// Verify that we can set it back to false again.
encoder_observer->SuspendChange(0, false);
EXPECT_FALSE(statistics_proxy_->GetStats().suspended);
}
TEST_F(SendStatisticsProxyTest, FrameCounts) {
FrameCountObserver* observer = statistics_proxy_.get();
for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
it != config_.rtp.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
// Add statistics with some arbitrary, but unique, numbers.
StreamStats& stats = expected_.substreams[ssrc];
uint32_t offset = ssrc * sizeof(StreamStats);
stats.key_frames = offset;
stats.delta_frames = offset + 1;
observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc);
observer->FrameCountUpdated(kVideoFrameDelta, stats.delta_frames, ssrc);
}
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
it != config_.rtp.rtx.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
// Add statistics with some arbitrary, but unique, numbers.
StreamStats& stats = expected_.substreams[ssrc];
uint32_t offset = ssrc * sizeof(StreamStats);
stats.key_frames = offset;
stats.delta_frames = offset + 1;
observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc);
observer->FrameCountUpdated(kVideoFrameDelta, stats.delta_frames, ssrc);
}
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
ExpectEqual(expected_, stats);
}
TEST_F(SendStatisticsProxyTest, DataCounters) {
StreamDataCountersCallback* callback = statistics_proxy_.get();
for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
it != config_.rtp.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats;
// Add statistics with some arbitrary, but unique, numbers.
uint32_t offset = ssrc * sizeof(StreamDataCounters);
counters.bytes = offset;
counters.header_bytes = offset + 1;
counters.fec_packets = offset + 2;
counters.padding_bytes = offset + 3;
counters.retransmitted_packets = offset + 4;
counters.packets = offset + 5;
callback->DataCountersUpdated(counters, ssrc);
}
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
it != config_.rtp.rtx.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats;
// Add statistics with some arbitrary, but unique, numbers.
uint32_t offset = ssrc * sizeof(StreamDataCounters);
counters.bytes = offset;
counters.header_bytes = offset + 1;
counters.fec_packets = offset + 2;
counters.padding_bytes = offset + 3;
counters.retransmitted_packets = offset + 4;
counters.packets = offset + 5;
callback->DataCountersUpdated(counters, ssrc);
}
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
ExpectEqual(expected_, stats);
}
TEST_F(SendStatisticsProxyTest, Bitrate) {
BitrateStatisticsObserver* observer = statistics_proxy_.get();
for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
it != config_.rtp.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
BitrateStatistics bitrate;
// Use ssrc as bitrate_bps to get a unique value for each stream.
bitrate.bitrate_bps = ssrc;
observer->Notify(bitrate, ssrc);
expected_.substreams[ssrc].bitrate_bps = ssrc;
}
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
it != config_.rtp.rtx.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
BitrateStatistics bitrate;
// Use ssrc as bitrate_bps to get a unique value for each stream.
bitrate.bitrate_bps = ssrc;
observer->Notify(bitrate, ssrc);
expected_.substreams[ssrc].bitrate_bps = ssrc;
}
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
ExpectEqual(expected_, stats);
}
TEST_F(SendStatisticsProxyTest, SendSideDelay) {
SendSideDelayObserver* observer = statistics_proxy_.get();
for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
it != config_.rtp.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
// Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each
// stream.
int avg_delay_ms = ssrc;
int max_delay_ms = ssrc + 1;
observer->SendSideDelayUpdated(avg_delay_ms, max_delay_ms, ssrc);
expected_.substreams[ssrc].avg_delay_ms = avg_delay_ms;
expected_.substreams[ssrc].max_delay_ms = max_delay_ms;
}
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
it != config_.rtp.rtx.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
// Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each
// stream.
int avg_delay_ms = ssrc;
int max_delay_ms = ssrc + 1;
observer->SendSideDelayUpdated(avg_delay_ms, max_delay_ms, ssrc);
expected_.substreams[ssrc].avg_delay_ms = avg_delay_ms;
expected_.substreams[ssrc].max_delay_ms = max_delay_ms;
}
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
ExpectEqual(expected_, stats);
}
TEST_F(SendStatisticsProxyTest, NoSubstreams) {
uint32_t exluded_ssrc =
std::max(
*std::max_element(config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end()),
*std::max_element(config_.rtp.rtx.ssrcs.begin(),
config_.rtp.rtx.ssrcs.end())) +
1;
// From RtcpStatisticsCallback.
RtcpStatistics rtcp_stats;
RtcpStatisticsCallback* rtcp_callback = statistics_proxy_.get();
rtcp_callback->StatisticsUpdated(rtcp_stats, exluded_ssrc);
// From StreamDataCountersCallback.
StreamDataCounters rtp_stats;
StreamDataCountersCallback* rtp_callback = statistics_proxy_.get();
rtp_callback->DataCountersUpdated(rtp_stats, exluded_ssrc);
// From BitrateStatisticsObserver.
BitrateStatistics bitrate;
BitrateStatisticsObserver* bitrate_observer = statistics_proxy_.get();
bitrate_observer->Notify(bitrate, exluded_ssrc);
// From FrameCountObserver.
FrameCountObserver* fps_observer = statistics_proxy_.get();
fps_observer->FrameCountUpdated(kVideoFrameKey, 1, exluded_ssrc);
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
EXPECT_TRUE(stats.substreams.empty());
}
} // namespace webrtc