blob: e2cb2fdbb2d59e4c98373c35bc05e52257e4adc7 [file] [log] [blame]
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000011#include "webrtc/video/send_statistics_proxy.h"
12
13#include <map>
kwiberg27f982b2016-03-01 11:52:33 -080014#include <memory>
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000015#include <string>
16#include <vector>
17
sprang07fb9be2016-02-24 07:55:00 -080018#include "webrtc/system_wrappers/include/metrics.h"
asapersson01d70a32016-05-20 06:29:46 -070019#include "webrtc/system_wrappers/include/metrics_default.h"
kwibergac9f8762016-09-30 22:29:43 -070020#include "webrtc/test/gtest.h"
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000021
22namespace webrtc {
asapersson5265fed2016-04-18 02:58:47 -070023namespace {
24const uint32_t kFirstSsrc = 17;
25const uint32_t kSecondSsrc = 42;
26const uint32_t kFirstRtxSsrc = 18;
27const uint32_t kSecondRtxSsrc = 43;
asaperssona6a699a2016-11-25 03:52:46 -080028const uint32_t kFlexFecSsrc = 55;
asapersson320e45a2016-11-29 01:40:35 -080029const int kFpsPeriodicIntervalMs = 2000;
30const int kWidth = 640;
31const int kHeight = 480;
asapersson5265fed2016-04-18 02:58:47 -070032const int kQpIdx0 = 21;
33const int kQpIdx1 = 39;
kthelgason0cd27ba2016-12-19 06:32:16 -080034const CodecSpecificInfo kDefaultCodecInfo = []() {
35 CodecSpecificInfo codec_info;
36 codec_info.codecType = kVideoCodecVP8;
37 codec_info.codecSpecific.VP8.simulcastIdx = 0;
38 return codec_info;
39}();
asapersson5265fed2016-04-18 02:58:47 -070040} // namespace
sprang07fb9be2016-02-24 07:55:00 -080041
stefan@webrtc.org168f23f2014-07-11 13:44:02 +000042class SendStatisticsProxyTest : public ::testing::Test {
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000043 public:
pbos@webrtc.org273a4142014-12-01 15:23:21 +000044 SendStatisticsProxyTest()
solenberg4fbae2b2015-08-28 04:07:10 -070045 : fake_clock_(1234), config_(GetTestConfig()), avg_delay_ms_(0),
46 max_delay_ms_(0) {}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000047 virtual ~SendStatisticsProxyTest() {}
48
49 protected:
50 virtual void SetUp() {
asapersson01d70a32016-05-20 06:29:46 -070051 metrics::Reset();
sprangb4a1ae52015-12-03 08:10:08 -080052 statistics_proxy_.reset(new SendStatisticsProxy(
53 &fake_clock_, GetTestConfig(),
54 VideoEncoderConfig::ContentType::kRealtimeVideo));
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000055 expected_ = VideoSendStream::Stats();
asapersson2e5cfcd2016-08-11 08:41:18 -070056 for (const auto& ssrc : config_.rtp.ssrcs)
57 expected_.substreams[ssrc].is_rtx = false;
58 for (const auto& ssrc : config_.rtp.rtx.ssrcs)
59 expected_.substreams[ssrc].is_rtx = true;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000060 }
61
62 VideoSendStream::Config GetTestConfig() {
solenberg4fbae2b2015-08-28 04:07:10 -070063 VideoSendStream::Config config(nullptr);
sprang07fb9be2016-02-24 07:55:00 -080064 config.rtp.ssrcs.push_back(kFirstSsrc);
65 config.rtp.ssrcs.push_back(kSecondSsrc);
66 config.rtp.rtx.ssrcs.push_back(kFirstRtxSsrc);
67 config.rtp.rtx.ssrcs.push_back(kSecondRtxSsrc);
brandtrb5f2c3f2016-10-04 23:28:39 -070068 config.rtp.ulpfec.red_payload_type = 17;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000069 return config;
70 }
71
asaperssona6a699a2016-11-25 03:52:46 -080072 VideoSendStream::Config GetTestConfigWithFlexFec() {
73 VideoSendStream::Config config(nullptr);
74 config.rtp.ssrcs.push_back(kFirstSsrc);
75 config.rtp.ssrcs.push_back(kSecondSsrc);
76 config.rtp.rtx.ssrcs.push_back(kFirstRtxSsrc);
77 config.rtp.rtx.ssrcs.push_back(kSecondRtxSsrc);
brandtr3d200bd2017-01-16 06:59:19 -080078 config.rtp.flexfec.payload_type = 50;
79 config.rtp.flexfec.ssrc = kFlexFecSsrc;
asaperssona6a699a2016-11-25 03:52:46 -080080 return config;
81 }
82
83 VideoSendStream::StreamStats GetStreamStats(uint32_t ssrc) {
84 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
85 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
86 stats.substreams.find(ssrc);
87 EXPECT_NE(it, stats.substreams.end());
88 return it->second;
89 }
90
asapersson66d4b372016-12-19 06:50:53 -080091 void UpdateDataCounters(uint32_t ssrc) {
92 StreamDataCountersCallback* proxy =
93 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
94 StreamDataCounters counters;
95 proxy->DataCountersUpdated(counters, ssrc);
96 }
97
sprang@webrtc.org09315702014-02-07 12:06:29 +000098 void ExpectEqual(VideoSendStream::Stats one, VideoSendStream::Stats other) {
sprang@webrtc.org09315702014-02-07 12:06:29 +000099 EXPECT_EQ(one.input_frame_rate, other.input_frame_rate);
100 EXPECT_EQ(one.encode_frame_rate, other.encode_frame_rate);
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000101 EXPECT_EQ(one.media_bitrate_bps, other.media_bitrate_bps);
Pera48ddb72016-09-29 11:48:50 +0200102 EXPECT_EQ(one.preferred_media_bitrate_bps,
103 other.preferred_media_bitrate_bps);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000104 EXPECT_EQ(one.suspended, other.suspended);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000105
106 EXPECT_EQ(one.substreams.size(), other.substreams.size());
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000107 for (std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator it =
sprang@webrtc.org09315702014-02-07 12:06:29 +0000108 one.substreams.begin();
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000109 it != one.substreams.end(); ++it) {
110 std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator
111 corresponding_it = other.substreams.find(it->first);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000112 ASSERT_TRUE(corresponding_it != other.substreams.end());
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000113 const VideoSendStream::StreamStats& a = it->second;
114 const VideoSendStream::StreamStats& b = corresponding_it->second;
sprang@webrtc.org09315702014-02-07 12:06:29 +0000115
asapersson2e5cfcd2016-08-11 08:41:18 -0700116 EXPECT_EQ(a.is_rtx, b.is_rtx);
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000117 EXPECT_EQ(a.frame_counts.key_frames, b.frame_counts.key_frames);
118 EXPECT_EQ(a.frame_counts.delta_frames, b.frame_counts.delta_frames);
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000119 EXPECT_EQ(a.total_bitrate_bps, b.total_bitrate_bps);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000120 EXPECT_EQ(a.avg_delay_ms, b.avg_delay_ms);
121 EXPECT_EQ(a.max_delay_ms, b.max_delay_ms);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000122
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000123 EXPECT_EQ(a.rtp_stats.transmitted.payload_bytes,
124 b.rtp_stats.transmitted.payload_bytes);
125 EXPECT_EQ(a.rtp_stats.transmitted.header_bytes,
126 b.rtp_stats.transmitted.header_bytes);
127 EXPECT_EQ(a.rtp_stats.transmitted.padding_bytes,
128 b.rtp_stats.transmitted.padding_bytes);
129 EXPECT_EQ(a.rtp_stats.transmitted.packets,
130 b.rtp_stats.transmitted.packets);
131 EXPECT_EQ(a.rtp_stats.retransmitted.packets,
132 b.rtp_stats.retransmitted.packets);
133 EXPECT_EQ(a.rtp_stats.fec.packets, b.rtp_stats.fec.packets);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000134
135 EXPECT_EQ(a.rtcp_stats.fraction_lost, b.rtcp_stats.fraction_lost);
136 EXPECT_EQ(a.rtcp_stats.cumulative_lost, b.rtcp_stats.cumulative_lost);
137 EXPECT_EQ(a.rtcp_stats.extended_max_sequence_number,
138 b.rtcp_stats.extended_max_sequence_number);
139 EXPECT_EQ(a.rtcp_stats.jitter, b.rtcp_stats.jitter);
140 }
141 }
142
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000143 SimulatedClock fake_clock_;
kwiberg27f982b2016-03-01 11:52:33 -0800144 std::unique_ptr<SendStatisticsProxy> statistics_proxy_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000145 VideoSendStream::Config config_;
146 int avg_delay_ms_;
147 int max_delay_ms_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000148 VideoSendStream::Stats expected_;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000149 typedef std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator
150 StreamIterator;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000151};
152
153TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
154 RtcpStatisticsCallback* callback = statistics_proxy_.get();
asapersson35151f32016-05-02 23:44:01 -0700155 for (const auto& ssrc : config_.rtp.ssrcs) {
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000156 VideoSendStream::StreamStats& ssrc_stats = expected_.substreams[ssrc];
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000157
158 // Add statistics with some arbitrary, but unique, numbers.
159 uint32_t offset = ssrc * sizeof(RtcpStatistics);
160 ssrc_stats.rtcp_stats.cumulative_lost = offset;
161 ssrc_stats.rtcp_stats.extended_max_sequence_number = offset + 1;
162 ssrc_stats.rtcp_stats.fraction_lost = offset + 2;
163 ssrc_stats.rtcp_stats.jitter = offset + 3;
164 callback->StatisticsUpdated(ssrc_stats.rtcp_stats, ssrc);
165 }
asapersson35151f32016-05-02 23:44:01 -0700166 for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000167 VideoSendStream::StreamStats& ssrc_stats = expected_.substreams[ssrc];
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000168
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000169 // Add statistics with some arbitrary, but unique, numbers.
170 uint32_t offset = ssrc * sizeof(RtcpStatistics);
171 ssrc_stats.rtcp_stats.cumulative_lost = offset;
172 ssrc_stats.rtcp_stats.extended_max_sequence_number = offset + 1;
173 ssrc_stats.rtcp_stats.fraction_lost = offset + 2;
174 ssrc_stats.rtcp_stats.jitter = offset + 3;
175 callback->StatisticsUpdated(ssrc_stats.rtcp_stats, ssrc);
176 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000177 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000178 ExpectEqual(expected_, stats);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000179}
180
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000181TEST_F(SendStatisticsProxyTest, EncodedBitrateAndFramerate) {
Peter Boström7083e112015-09-22 16:28:51 +0200182 int media_bitrate_bps = 500;
183 int encode_fps = 29;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000184
perkj275afc52016-09-01 00:21:16 -0700185 statistics_proxy_->OnEncoderStatsUpdate(encode_fps, media_bitrate_bps);
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000186
187 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
188 EXPECT_EQ(media_bitrate_bps, stats.media_bitrate_bps);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000189 EXPECT_EQ(encode_fps, stats.encode_frame_rate);
190}
191
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000192TEST_F(SendStatisticsProxyTest, Suspended) {
193 // Verify that the value is false by default.
194 EXPECT_FALSE(statistics_proxy_->GetStats().suspended);
195
196 // Verify that we can set it to true.
Peter Boström7083e112015-09-22 16:28:51 +0200197 statistics_proxy_->OnSuspendChange(true);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000198 EXPECT_TRUE(statistics_proxy_->GetStats().suspended);
199
200 // Verify that we can set it back to false again.
Peter Boström7083e112015-09-22 16:28:51 +0200201 statistics_proxy_->OnSuspendChange(false);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000202 EXPECT_FALSE(statistics_proxy_->GetStats().suspended);
203}
204
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000205TEST_F(SendStatisticsProxyTest, FrameCounts) {
206 FrameCountObserver* observer = statistics_proxy_.get();
asapersson35151f32016-05-02 23:44:01 -0700207 for (const auto& ssrc : config_.rtp.ssrcs) {
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000208 // Add statistics with some arbitrary, but unique, numbers.
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000209 VideoSendStream::StreamStats& stats = expected_.substreams[ssrc];
210 uint32_t offset = ssrc * sizeof(VideoSendStream::StreamStats);
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000211 FrameCounts frame_counts;
212 frame_counts.key_frames = offset;
213 frame_counts.delta_frames = offset + 1;
214 stats.frame_counts = frame_counts;
215 observer->FrameCountUpdated(frame_counts, ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000216 }
asapersson35151f32016-05-02 23:44:01 -0700217 for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000218 // Add statistics with some arbitrary, but unique, numbers.
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000219 VideoSendStream::StreamStats& stats = expected_.substreams[ssrc];
220 uint32_t offset = ssrc * sizeof(VideoSendStream::StreamStats);
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000221 FrameCounts frame_counts;
222 frame_counts.key_frames = offset;
223 frame_counts.delta_frames = offset + 1;
224 stats.frame_counts = frame_counts;
225 observer->FrameCountUpdated(frame_counts, ssrc);
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000226 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000227
228 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000229 ExpectEqual(expected_, stats);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000230}
231
232TEST_F(SendStatisticsProxyTest, DataCounters) {
233 StreamDataCountersCallback* callback = statistics_proxy_.get();
asapersson35151f32016-05-02 23:44:01 -0700234 for (const auto& ssrc : config_.rtp.ssrcs) {
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000235 StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats;
236 // Add statistics with some arbitrary, but unique, numbers.
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000237 size_t offset = ssrc * sizeof(StreamDataCounters);
238 uint32_t offset_uint32 = static_cast<uint32_t>(offset);
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000239 counters.transmitted.payload_bytes = offset;
240 counters.transmitted.header_bytes = offset + 1;
241 counters.fec.packets = offset_uint32 + 2;
242 counters.transmitted.padding_bytes = offset + 3;
243 counters.retransmitted.packets = offset_uint32 + 4;
244 counters.transmitted.packets = offset_uint32 + 5;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000245 callback->DataCountersUpdated(counters, ssrc);
246 }
asapersson35151f32016-05-02 23:44:01 -0700247 for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000248 StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats;
249 // Add statistics with some arbitrary, but unique, numbers.
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000250 size_t offset = ssrc * sizeof(StreamDataCounters);
251 uint32_t offset_uint32 = static_cast<uint32_t>(offset);
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000252 counters.transmitted.payload_bytes = offset;
253 counters.transmitted.header_bytes = offset + 1;
254 counters.fec.packets = offset_uint32 + 2;
255 counters.transmitted.padding_bytes = offset + 3;
256 counters.retransmitted.packets = offset_uint32 + 4;
257 counters.transmitted.packets = offset_uint32 + 5;
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000258 callback->DataCountersUpdated(counters, ssrc);
259 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000260
261 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000262 ExpectEqual(expected_, stats);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000263}
264
265TEST_F(SendStatisticsProxyTest, Bitrate) {
266 BitrateStatisticsObserver* observer = statistics_proxy_.get();
asapersson35151f32016-05-02 23:44:01 -0700267 for (const auto& ssrc : config_.rtp.ssrcs) {
sprangcd349d92016-07-13 09:11:28 -0700268 uint32_t total;
269 uint32_t retransmit;
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000270 // Use ssrc as bitrate_bps to get a unique value for each stream.
sprangcd349d92016-07-13 09:11:28 -0700271 total = ssrc;
272 retransmit = ssrc + 1;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000273 observer->Notify(total, retransmit, ssrc);
sprangcd349d92016-07-13 09:11:28 -0700274 expected_.substreams[ssrc].total_bitrate_bps = total;
275 expected_.substreams[ssrc].retransmit_bitrate_bps = retransmit;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000276 }
asapersson35151f32016-05-02 23:44:01 -0700277 for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
sprangcd349d92016-07-13 09:11:28 -0700278 uint32_t total;
279 uint32_t retransmit;
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000280 // Use ssrc as bitrate_bps to get a unique value for each stream.
sprangcd349d92016-07-13 09:11:28 -0700281 total = ssrc;
282 retransmit = ssrc + 1;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000283 observer->Notify(total, retransmit, ssrc);
sprangcd349d92016-07-13 09:11:28 -0700284 expected_.substreams[ssrc].total_bitrate_bps = total;
285 expected_.substreams[ssrc].retransmit_bitrate_bps = retransmit;
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000286 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000287
288 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000289 ExpectEqual(expected_, stats);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000290}
291
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000292TEST_F(SendStatisticsProxyTest, SendSideDelay) {
293 SendSideDelayObserver* observer = statistics_proxy_.get();
asapersson35151f32016-05-02 23:44:01 -0700294 for (const auto& ssrc : config_.rtp.ssrcs) {
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000295 // Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each
296 // stream.
297 int avg_delay_ms = ssrc;
298 int max_delay_ms = ssrc + 1;
299 observer->SendSideDelayUpdated(avg_delay_ms, max_delay_ms, ssrc);
300 expected_.substreams[ssrc].avg_delay_ms = avg_delay_ms;
301 expected_.substreams[ssrc].max_delay_ms = max_delay_ms;
302 }
asapersson35151f32016-05-02 23:44:01 -0700303 for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000304 // Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each
305 // stream.
306 int avg_delay_ms = ssrc;
307 int max_delay_ms = ssrc + 1;
308 observer->SendSideDelayUpdated(avg_delay_ms, max_delay_ms, ssrc);
309 expected_.substreams[ssrc].avg_delay_ms = avg_delay_ms;
310 expected_.substreams[ssrc].max_delay_ms = max_delay_ms;
311 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000312 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000313 ExpectEqual(expected_, stats);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000314}
315
Peter Boströme4499152016-02-05 11:13:28 +0100316TEST_F(SendStatisticsProxyTest, OnEncodedFrameTimeMeasured) {
asapersson1aa420b2015-12-07 03:12:22 -0800317 const int kEncodeTimeMs = 11;
Peter Boströme4499152016-02-05 11:13:28 +0100318 CpuOveruseMetrics metrics;
319 metrics.encode_usage_percent = 80;
320 statistics_proxy_->OnEncodedFrameTimeMeasured(kEncodeTimeMs, metrics);
asapersson1aa420b2015-12-07 03:12:22 -0800321
322 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
323 EXPECT_EQ(kEncodeTimeMs, stats.avg_encode_time_ms);
Peter Boströme4499152016-02-05 11:13:28 +0100324 EXPECT_EQ(metrics.encode_usage_percent, stats.encode_usage_percent);
asapersson1aa420b2015-12-07 03:12:22 -0800325}
326
Pera48ddb72016-09-29 11:48:50 +0200327TEST_F(SendStatisticsProxyTest, OnEncoderReconfiguredChangePreferredBitrate) {
328 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
329 EXPECT_EQ(0, stats.preferred_media_bitrate_bps);
330 const int kPreferredMediaBitrateBps = 50;
331
332 VideoEncoderConfig config;
333 statistics_proxy_->OnEncoderReconfigured(config, kPreferredMediaBitrateBps);
334 stats = statistics_proxy_->GetStats();
335 EXPECT_EQ(kPreferredMediaBitrateBps, stats.preferred_media_bitrate_bps);
336}
337
sakal43536c32016-10-24 01:46:43 -0700338TEST_F(SendStatisticsProxyTest, OnSendEncodedImageIncreasesFramesEncoded) {
339 EncodedImage encoded_image;
340 CodecSpecificInfo codec_info;
341 EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_encoded);
342 for (uint32_t i = 1; i <= 3; ++i) {
343 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
344 EXPECT_EQ(i, statistics_proxy_->GetStats().frames_encoded);
345 }
346}
347
sakal87da4042016-10-31 06:53:47 -0700348TEST_F(SendStatisticsProxyTest, OnSendEncodedImageIncreasesQpSum) {
349 EncodedImage encoded_image;
350 CodecSpecificInfo codec_info;
351 EXPECT_EQ(rtc::Optional<uint64_t>(), statistics_proxy_->GetStats().qp_sum);
352 encoded_image.qp_ = 3;
353 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
354 EXPECT_EQ(rtc::Optional<uint64_t>(3u), statistics_proxy_->GetStats().qp_sum);
355 encoded_image.qp_ = 127;
356 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
357 EXPECT_EQ(rtc::Optional<uint64_t>(130u),
358 statistics_proxy_->GetStats().qp_sum);
359}
360
361TEST_F(SendStatisticsProxyTest, OnSendEncodedImageWithoutQpQpSumWontExist) {
362 EncodedImage encoded_image;
363 CodecSpecificInfo codec_info;
364 encoded_image.qp_ = -1;
365 EXPECT_EQ(rtc::Optional<uint64_t>(), statistics_proxy_->GetStats().qp_sum);
366 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
367 EXPECT_EQ(rtc::Optional<uint64_t>(), statistics_proxy_->GetStats().qp_sum);
368}
369
asapersson36e9eb42017-03-31 05:29:12 -0700370TEST_F(SendStatisticsProxyTest, SetCpuScalingUpdatesStats) {
371 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
asapersson6eca98b2017-04-04 23:40:50 -0700372 statistics_proxy_->SetCpuScalingStats(-1);
asapersson36e9eb42017-03-31 05:29:12 -0700373 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
asapersson6eca98b2017-04-04 23:40:50 -0700374 statistics_proxy_->SetCpuScalingStats(0);
375 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
376 statistics_proxy_->SetCpuScalingStats(1);
377 EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
asapersson36e9eb42017-03-31 05:29:12 -0700378}
379
380TEST_F(SendStatisticsProxyTest, SetQualityScalingUpdatesStats) {
381 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
382 statistics_proxy_->SetQualityScalingStats(-1);
383 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
384 statistics_proxy_->SetQualityScalingStats(0);
385 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
386 statistics_proxy_->SetQualityScalingStats(1);
387 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
388}
389
asaperssonfab67072017-04-04 05:51:49 -0700390TEST_F(SendStatisticsProxyTest, GetStatsReportsCpuResolutionChanges) {
391 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
392 EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
393
394 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
395 EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
396 EXPECT_EQ(1, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
397
398 statistics_proxy_->OnCpuRestrictedResolutionChanged(false);
399 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
400 EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
401}
402
403TEST_F(SendStatisticsProxyTest, GetStatsReportsQualityResolutionChanges) {
404 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
405 EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
406
407 statistics_proxy_->OnQualityRestrictedResolutionChanged(1);
408 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
409 EXPECT_EQ(1, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
410
411 statistics_proxy_->OnQualityRestrictedResolutionChanged(2);
412 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
413 EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
414
415 statistics_proxy_->OnQualityRestrictedResolutionChanged(1);
416 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
417 EXPECT_EQ(3, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
418
419 statistics_proxy_->OnQualityRestrictedResolutionChanged(0);
420 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
421 EXPECT_EQ(4, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
422}
423
asapersson6eca98b2017-04-04 23:40:50 -0700424TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_ScalingNotEnabled) {
asapersson0944a802017-04-07 00:57:58 -0700425 // First RTP packet sent.
426 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700427 // Min runtime has passed.
428 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
429 statistics_proxy_.reset();
430 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
431 EXPECT_EQ(0,
432 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
433}
434
435TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_MinRuntimeNotPassed) {
asapersson0944a802017-04-07 00:57:58 -0700436 // First RTP packet sent.
437 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700438 // Enable scaling.
439 statistics_proxy_->SetQualityScalingStats(0);
440 statistics_proxy_->SetCpuScalingStats(0);
441 // Min runtime has not passed.
442 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000 - 1);
443 statistics_proxy_.reset();
444 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
445 EXPECT_EQ(0,
446 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
447}
448
449TEST_F(SendStatisticsProxyTest, ZeroCpuAdaptChangesReported) {
asapersson0944a802017-04-07 00:57:58 -0700450 // First RTP packet sent.
451 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700452 // Enable scaling.
453 statistics_proxy_->SetCpuScalingStats(0);
454 // Min runtime has passed.
455 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
456 statistics_proxy_.reset();
457 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
458 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 0));
459}
460
461TEST_F(SendStatisticsProxyTest, ZeroQualityAdaptChangesReported) {
asapersson0944a802017-04-07 00:57:58 -0700462 // First RTP packet sent.
463 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700464 // Enable scaling.
465 statistics_proxy_->SetQualityScalingStats(0);
466 // Min runtime has passed.
467 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
468 statistics_proxy_.reset();
469 EXPECT_EQ(1,
470 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
471 EXPECT_EQ(
472 1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 0));
473}
474
475TEST_F(SendStatisticsProxyTest, CpuAdaptChangesReported) {
asapersson0944a802017-04-07 00:57:58 -0700476 // First RTP packet sent.
477 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700478 // Enable scaling.
asapersson0944a802017-04-07 00:57:58 -0700479 // Adapt changes: 1, elapsed time: 10 sec => 6 per minute.
asapersson6eca98b2017-04-04 23:40:50 -0700480 statistics_proxy_->SetCpuScalingStats(0);
481 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
482 fake_clock_.AdvanceTimeMilliseconds(10000);
483 statistics_proxy_.reset();
484 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
485 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 6));
486}
487
488TEST_F(SendStatisticsProxyTest, AdaptChangesStatsExcludesDisabledTime) {
asapersson0944a802017-04-07 00:57:58 -0700489 // First RTP packet sent.
490 UpdateDataCounters(kFirstSsrc);
491
asapersson6eca98b2017-04-04 23:40:50 -0700492 // Disable scaling.
493 statistics_proxy_->SetQualityScalingStats(-1);
494 fake_clock_.AdvanceTimeMilliseconds(10000);
495
496 // Enable scaling.
asapersson0944a802017-04-07 00:57:58 -0700497 // Adapt changes: 2, elapsed time: 20 sec.
asapersson6eca98b2017-04-04 23:40:50 -0700498 statistics_proxy_->SetQualityScalingStats(0);
499 fake_clock_.AdvanceTimeMilliseconds(5000);
500 statistics_proxy_->SetQualityScalingStats(1);
501 fake_clock_.AdvanceTimeMilliseconds(9000);
502 statistics_proxy_->OnQualityRestrictedResolutionChanged(1);
503 fake_clock_.AdvanceTimeMilliseconds(6000);
504 statistics_proxy_->OnQualityRestrictedResolutionChanged(2);
505
506 // Disable scaling.
507 statistics_proxy_->SetQualityScalingStats(-1);
508 fake_clock_.AdvanceTimeMilliseconds(30000);
509
510 // Enable scaling.
asapersson0944a802017-04-07 00:57:58 -0700511 // Adapt changes: 1, elapsed time: 10 sec.
asapersson6eca98b2017-04-04 23:40:50 -0700512 statistics_proxy_->SetQualityScalingStats(0);
513 statistics_proxy_->OnQualityRestrictedResolutionChanged(1);
514 fake_clock_.AdvanceTimeMilliseconds(10000);
515
516 // Disable scaling.
517 statistics_proxy_->SetQualityScalingStats(-1);
518 fake_clock_.AdvanceTimeMilliseconds(5000);
519 statistics_proxy_->SetQualityScalingStats(-1);
520 fake_clock_.AdvanceTimeMilliseconds(20000);
521
asapersson0944a802017-04-07 00:57:58 -0700522 // Adapt changes: 3, elapsed time: 30 sec => 6 per minute.
asapersson6eca98b2017-04-04 23:40:50 -0700523 statistics_proxy_.reset();
524 EXPECT_EQ(1,
525 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
526 EXPECT_EQ(
527 1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
528}
529
asapersson0944a802017-04-07 00:57:58 -0700530TEST_F(SendStatisticsProxyTest,
531 AdaptChangesNotReported_ScalingNotEnabledVideoResumed) {
532 // First RTP packet sent.
533 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700534
asapersson0944a802017-04-07 00:57:58 -0700535 // Suspend and resume video.
536 statistics_proxy_->OnSuspendChange(true);
537 fake_clock_.AdvanceTimeMilliseconds(5000);
538 statistics_proxy_->OnSuspendChange(false);
539
540 // Min runtime has passed but scaling not enabled.
541 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
542 statistics_proxy_.reset();
543 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
544 EXPECT_EQ(0,
545 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
546}
547
548TEST_F(SendStatisticsProxyTest, QualityAdaptChangesStatsExcludesSuspendedTime) {
549 // First RTP packet sent.
550 UpdateDataCounters(kFirstSsrc);
551
552 // Enable scaling.
553 // Adapt changes: 2, elapsed time: 20 sec.
554 statistics_proxy_->SetQualityScalingStats(0);
555 fake_clock_.AdvanceTimeMilliseconds(20000);
556 statistics_proxy_->OnQualityRestrictedResolutionChanged(1);
557 statistics_proxy_->OnQualityRestrictedResolutionChanged(2);
558
559 // Suspend and resume video.
560 statistics_proxy_->OnSuspendChange(true);
561 fake_clock_.AdvanceTimeMilliseconds(30000);
562 statistics_proxy_->OnSuspendChange(false);
563
564 // Adapt changes: 1, elapsed time: 10 sec.
565 statistics_proxy_->OnQualityRestrictedResolutionChanged(3);
566 fake_clock_.AdvanceTimeMilliseconds(10000);
567
568 // Adapt changes: 3, elapsed time: 30 sec => 6 per minute.
569 statistics_proxy_.reset();
570 EXPECT_EQ(1,
571 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
572 EXPECT_EQ(
573 1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
574}
575
576TEST_F(SendStatisticsProxyTest, CpuAdaptChangesStatsExcludesSuspendedTime) {
577 // First RTP packet sent.
578 UpdateDataCounters(kFirstSsrc);
579
580 // Video not suspended.
581 statistics_proxy_->OnSuspendChange(false);
582 fake_clock_.AdvanceTimeMilliseconds(30000);
583
584 // Enable scaling.
585 // Adapt changes: 1, elapsed time: 20 sec.
586 statistics_proxy_->SetCpuScalingStats(0);
587 fake_clock_.AdvanceTimeMilliseconds(10000);
588 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
589
590 // Video not suspended, stats time already started.
591 statistics_proxy_->OnSuspendChange(false);
592 fake_clock_.AdvanceTimeMilliseconds(10000);
593
594 // Disable scaling.
595 statistics_proxy_->SetCpuScalingStats(-1);
596 fake_clock_.AdvanceTimeMilliseconds(30000);
597
598 // Suspend and resume video, stats time not started when scaling not enabled.
599 statistics_proxy_->OnSuspendChange(true);
600 fake_clock_.AdvanceTimeMilliseconds(30000);
601 statistics_proxy_->OnSuspendChange(false);
602 fake_clock_.AdvanceTimeMilliseconds(30000);
603
604 // Enable scaling.
605 // Adapt changes: 1, elapsed time: 10 sec.
606 statistics_proxy_->SetCpuScalingStats(0);
607 fake_clock_.AdvanceTimeMilliseconds(10000);
608 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
609
610 // Adapt changes: 2, elapsed time: 30 sec => 4 per minute.
611 statistics_proxy_.reset();
612 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
613 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 4));
614}
615
616TEST_F(SendStatisticsProxyTest, AdaptChangesStatsNotStartedIfVideoSuspended) {
617 // First RTP packet sent.
618 UpdateDataCounters(kFirstSsrc);
619
620 // Video suspended.
621 statistics_proxy_->OnSuspendChange(true);
622
623 // Enable scaling, stats time not started when suspended.
624 statistics_proxy_->SetCpuScalingStats(0);
625 fake_clock_.AdvanceTimeMilliseconds(10000);
626
627 // Resume video, stats time started.
628 // Adapt changes: 1, elapsed time: 10 sec.
629 statistics_proxy_->OnSuspendChange(false);
630 fake_clock_.AdvanceTimeMilliseconds(10000);
631 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
632
633 // Adapt changes: 1, elapsed time: 10 sec => 6 per minute.
634 statistics_proxy_.reset();
635 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
636 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 6));
637}
638
639TEST_F(SendStatisticsProxyTest, AdaptChangesStatsRestartsOnFirstSentPacket) {
asapersson6eca98b2017-04-04 23:40:50 -0700640 // Send first packet, scaling enabled.
641 // Elapsed time before first packet is sent should be excluded.
642 statistics_proxy_->SetQualityScalingStats(0);
643 fake_clock_.AdvanceTimeMilliseconds(10000);
asapersson0944a802017-04-07 00:57:58 -0700644 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700645
asapersson0944a802017-04-07 00:57:58 -0700646 // Adapt changes: 1, elapsed time: 10 sec.
asapersson6eca98b2017-04-04 23:40:50 -0700647 fake_clock_.AdvanceTimeMilliseconds(10000);
648 statistics_proxy_->OnQualityRestrictedResolutionChanged(1);
asapersson0944a802017-04-07 00:57:58 -0700649 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700650
asapersson0944a802017-04-07 00:57:58 -0700651 // Adapt changes: 1, elapsed time: 10 sec => 6 per minute.
asapersson6eca98b2017-04-04 23:40:50 -0700652 statistics_proxy_.reset();
653 EXPECT_EQ(1,
654 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
655 EXPECT_EQ(
656 1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
657}
658
659TEST_F(SendStatisticsProxyTest, AdaptChangesStatsStartedAfterFirstSentPacket) {
asapersson6eca98b2017-04-04 23:40:50 -0700660 // Enable and disable scaling.
661 statistics_proxy_->SetCpuScalingStats(0);
662 fake_clock_.AdvanceTimeMilliseconds(60000);
663 statistics_proxy_->SetCpuScalingStats(-1);
664
665 // Send first packet, scaling disabled.
666 // Elapsed time before first packet is sent should be excluded.
asapersson0944a802017-04-07 00:57:58 -0700667 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700668 fake_clock_.AdvanceTimeMilliseconds(60000);
669
670 // Enable scaling.
671 statistics_proxy_->SetCpuScalingStats(0);
672 fake_clock_.AdvanceTimeMilliseconds(10000);
asapersson0944a802017-04-07 00:57:58 -0700673 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700674
asapersson0944a802017-04-07 00:57:58 -0700675 // Adapt changes: 1, elapsed time: 20 sec.
asapersson6eca98b2017-04-04 23:40:50 -0700676 fake_clock_.AdvanceTimeMilliseconds(10000);
677 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
678
asapersson0944a802017-04-07 00:57:58 -0700679 // Adapt changes: 1, elapsed time: 20 sec => 3 per minute.
asapersson6eca98b2017-04-04 23:40:50 -0700680 statistics_proxy_.reset();
681 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
682 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 3));
683}
684
685TEST_F(SendStatisticsProxyTest, AdaptChangesReportedAfterContentSwitch) {
asapersson0944a802017-04-07 00:57:58 -0700686 // First RTP packet sent, scaling enabled.
687 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700688 statistics_proxy_->SetCpuScalingStats(0);
689
asapersson0944a802017-04-07 00:57:58 -0700690 // Adapt changes: 2, elapsed time: 15 sec => 8 per minute.
asapersson6eca98b2017-04-04 23:40:50 -0700691 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
692 fake_clock_.AdvanceTimeMilliseconds(6000);
693 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
694 fake_clock_.AdvanceTimeMilliseconds(9000);
695
696 // Switch content type, real-time stats should be updated.
697 VideoEncoderConfig config;
698 config.content_type = VideoEncoderConfig::ContentType::kScreen;
699 statistics_proxy_->OnEncoderReconfigured(config, 50);
700 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
701 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 8));
702 EXPECT_EQ(0,
703 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
704
asapersson0944a802017-04-07 00:57:58 -0700705 // First RTP packet sent, scaling enabled.
706 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700707 statistics_proxy_->SetCpuScalingStats(0);
708
asapersson0944a802017-04-07 00:57:58 -0700709 // Adapt changes: 4, elapsed time: 120 sec => 2 per minute.
asapersson6eca98b2017-04-04 23:40:50 -0700710 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
711 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
712 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
713 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
714 fake_clock_.AdvanceTimeMilliseconds(120000);
715
716 statistics_proxy_.reset();
717 EXPECT_EQ(1, metrics::NumSamples(
718 "WebRTC.Video.Screenshare.AdaptChangesPerMinute.Cpu"));
719 EXPECT_EQ(1, metrics::NumEvents(
720 "WebRTC.Video.Screenshare.AdaptChangesPerMinute.Cpu", 2));
721 EXPECT_EQ(0, metrics::NumSamples(
722 "WebRTC.Video.Screenshare.AdaptChangesPerMinute.Quality"));
723}
724
asapersson59bac1a2016-01-07 23:36:00 -0800725TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) {
perkj803d97f2016-11-01 11:45:46 -0700726 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
asapersson59bac1a2016-01-07 23:36:00 -0800727 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
728
Pera48ddb72016-09-29 11:48:50 +0200729 // No switch, stats should not be updated.
730 VideoEncoderConfig config;
731 config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo;
732 statistics_proxy_->OnEncoderReconfigured(config, 50);
asapersson01d70a32016-05-20 06:29:46 -0700733 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.InputWidthInPixels"));
asapersson59bac1a2016-01-07 23:36:00 -0800734
735 // Switch to screenshare, real-time stats should be updated.
Pera48ddb72016-09-29 11:48:50 +0200736 config.content_type = VideoEncoderConfig::ContentType::kScreen;
737 statistics_proxy_->OnEncoderReconfigured(config, 50);
asapersson01d70a32016-05-20 06:29:46 -0700738 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputWidthInPixels"));
asapersson59bac1a2016-01-07 23:36:00 -0800739}
740
asapersson320e45a2016-11-29 01:40:35 -0800741TEST_F(SendStatisticsProxyTest, InputResolutionHistogramsAreUpdated) {
742 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
743 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
perkj803d97f2016-11-01 11:45:46 -0700744
asapersson320e45a2016-11-29 01:40:35 -0800745 statistics_proxy_.reset();
746 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputWidthInPixels"));
747 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputWidthInPixels", kWidth));
748 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputHeightInPixels"));
749 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputHeightInPixels", kHeight));
750}
751
752TEST_F(SendStatisticsProxyTest, SentResolutionHistogramsAreUpdated) {
753 EncodedImage encoded_image;
754 encoded_image._encodedWidth = kWidth;
755 encoded_image._encodedHeight = kHeight;
756 for (int i = 0; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
757 encoded_image._timeStamp = i + 1;
758 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
759 }
760 statistics_proxy_.reset();
761 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentWidthInPixels"));
762 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentWidthInPixels", kWidth));
763 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentHeightInPixels"));
764 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentHeightInPixels", kHeight));
765}
766
767TEST_F(SendStatisticsProxyTest, InputFpsHistogramIsUpdated) {
768 const int kFps = 20;
769 const int kMinPeriodicSamples = 6;
770 int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000;
771 for (int i = 0; i <= frames; ++i) {
772 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
773 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
774 }
775 statistics_proxy_.reset();
776 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputFramesPerSecond"));
777 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputFramesPerSecond", kFps));
778}
779
780TEST_F(SendStatisticsProxyTest, SentFpsHistogramIsUpdated) {
781 EncodedImage encoded_image;
782 const int kFps = 20;
783 const int kMinPeriodicSamples = 6;
784 int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000 + 1;
785 for (int i = 0; i <= frames; ++i) {
786 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
787 encoded_image._timeStamp = i + 1;
788 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
789 }
790 statistics_proxy_.reset();
791 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentFramesPerSecond"));
792 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentFramesPerSecond", kFps));
793}
794
795TEST_F(SendStatisticsProxyTest, InputFpsHistogramExcludesSuspendedTime) {
796 const int kFps = 20;
797 const int kSuspendTimeMs = 10000;
798 const int kMinPeriodicSamples = 6;
799 int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000;
800 for (int i = 0; i < frames; ++i) {
801 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
802 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
803 }
804 // Suspend.
805 statistics_proxy_->OnSuspendChange(true);
806 fake_clock_.AdvanceTimeMilliseconds(kSuspendTimeMs);
807
808 for (int i = 0; i < frames; ++i) {
809 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
810 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
811 }
812 // Suspended time interval should not affect the framerate.
813 statistics_proxy_.reset();
814 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputFramesPerSecond"));
815 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputFramesPerSecond", kFps));
816}
817
818TEST_F(SendStatisticsProxyTest, SentFpsHistogramExcludesSuspendedTime) {
819 EncodedImage encoded_image;
820 const int kFps = 20;
821 const int kSuspendTimeMs = 10000;
822 const int kMinPeriodicSamples = 6;
823 int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000;
824 for (int i = 0; i <= frames; ++i) {
825 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
826 encoded_image._timeStamp = i + 1;
827 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
828 }
829 // Suspend.
830 statistics_proxy_->OnSuspendChange(true);
831 fake_clock_.AdvanceTimeMilliseconds(kSuspendTimeMs);
832
833 for (int i = 0; i <= frames; ++i) {
834 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
835 encoded_image._timeStamp = i + 1;
836 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
837 }
838 // Suspended time interval should not affect the framerate.
839 statistics_proxy_.reset();
840 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentFramesPerSecond"));
841 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentFramesPerSecond", kFps));
842}
843
844TEST_F(SendStatisticsProxyTest, CpuLimitedResolutionUpdated) {
perkj803d97f2016-11-01 11:45:46 -0700845 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
846 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
847
848 statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
849
850 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
851 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
852
853 statistics_proxy_.reset();
854 EXPECT_EQ(1,
855 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
856 EXPECT_EQ(
857 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
858}
859
asapersson4374a092016-07-27 00:39:09 -0700860TEST_F(SendStatisticsProxyTest, LifetimeHistogramIsUpdated) {
861 const int64_t kTimeSec = 3;
862 fake_clock_.AdvanceTimeMilliseconds(kTimeSec * 1000);
863 statistics_proxy_.reset();
864 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SendStreamLifetimeInSeconds"));
865 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SendStreamLifetimeInSeconds",
866 kTimeSec));
867}
868
869TEST_F(SendStatisticsProxyTest, CodecTypeHistogramIsUpdated) {
870 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
871 statistics_proxy_.reset();
872 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoder.CodecType"));
873}
874
asapersson66d4b372016-12-19 06:50:53 -0800875TEST_F(SendStatisticsProxyTest, PauseEventHistogramIsUpdated) {
876 // First RTP packet sent.
877 UpdateDataCounters(kFirstSsrc);
878
879 // Min runtime has passed.
880 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
881 statistics_proxy_.reset();
882 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
883 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.NumberOfPauseEvents", 0));
884}
885
886TEST_F(SendStatisticsProxyTest,
887 PauseEventHistogramIsNotUpdatedIfMinRuntimeHasNotPassed) {
888 // First RTP packet sent.
889 UpdateDataCounters(kFirstSsrc);
890
891 // Min runtime has not passed.
892 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000 - 1);
893 statistics_proxy_.reset();
894 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
895 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
896}
897
898TEST_F(SendStatisticsProxyTest,
899 PauseEventHistogramIsNotUpdatedIfNoMediaIsSent) {
900 // First RTP packet not sent.
901 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
902 statistics_proxy_.reset();
903 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
904}
905
906TEST_F(SendStatisticsProxyTest, NoPauseEvent) {
907 // First RTP packet sent and min runtime passed.
908 UpdateDataCounters(kFirstSsrc);
909
910 // No change. Video: 10000 ms, paused: 0 ms (0%).
911 statistics_proxy_->OnSetEncoderTargetRate(50000);
912 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
913 statistics_proxy_->OnSetEncoderTargetRate(0); // VideoSendStream::Stop
914
915 statistics_proxy_.reset();
916 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
917 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.NumberOfPauseEvents", 0));
918 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
919 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.PausedTimeInPercent", 0));
920}
921
922TEST_F(SendStatisticsProxyTest, OnePauseEvent) {
923 // First RTP packet sent and min runtime passed.
924 UpdateDataCounters(kFirstSsrc);
925
926 // One change. Video: 7000 ms, paused: 3000 ms (30%).
927 statistics_proxy_->OnSetEncoderTargetRate(50000);
928 fake_clock_.AdvanceTimeMilliseconds(7000);
929 statistics_proxy_->OnSetEncoderTargetRate(0);
930 fake_clock_.AdvanceTimeMilliseconds(3000);
931 statistics_proxy_->OnSetEncoderTargetRate(0); // VideoSendStream::Stop
932
933 statistics_proxy_.reset();
934 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
935 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.NumberOfPauseEvents", 1));
936 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
937 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.PausedTimeInPercent", 30));
938}
939
940TEST_F(SendStatisticsProxyTest, TwoPauseEvents) {
941 // First RTP packet sent.
942 UpdateDataCounters(kFirstSsrc);
943
944 // Two changes. Video: 19000 ms, paused: 1000 ms (5%).
945 statistics_proxy_->OnSetEncoderTargetRate(0);
946 fake_clock_.AdvanceTimeMilliseconds(1000);
947 statistics_proxy_->OnSetEncoderTargetRate(50000); // Starts on bitrate > 0.
948 fake_clock_.AdvanceTimeMilliseconds(7000);
949 statistics_proxy_->OnSetEncoderTargetRate(60000);
950 fake_clock_.AdvanceTimeMilliseconds(3000);
951 statistics_proxy_->OnSetEncoderTargetRate(0);
952 fake_clock_.AdvanceTimeMilliseconds(250);
953 statistics_proxy_->OnSetEncoderTargetRate(0);
954 fake_clock_.AdvanceTimeMilliseconds(750);
955 statistics_proxy_->OnSetEncoderTargetRate(60000);
956 fake_clock_.AdvanceTimeMilliseconds(5000);
957 statistics_proxy_->OnSetEncoderTargetRate(50000);
958 fake_clock_.AdvanceTimeMilliseconds(4000);
959 statistics_proxy_->OnSetEncoderTargetRate(0); // VideoSendStream::Stop
960
961 statistics_proxy_.reset();
962 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
963 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.NumberOfPauseEvents", 2));
964 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
965 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.PausedTimeInPercent", 5));
966}
967
968TEST_F(SendStatisticsProxyTest,
969 PausedTimeHistogramIsNotUpdatedIfMinRuntimeHasNotPassed) {
970 // First RTP packet sent.
971 UpdateDataCounters(kFirstSsrc);
972 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
973
974 // Min runtime has not passed.
975 statistics_proxy_->OnSetEncoderTargetRate(50000);
976 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000 - 1);
977 statistics_proxy_->OnSetEncoderTargetRate(0); // VideoSendStream::Stop
978
979 statistics_proxy_.reset();
980 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
981}
982
asapersson118ef002016-03-31 00:00:19 -0700983TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp8) {
asapersson118ef002016-03-31 00:00:19 -0700984 EncodedImage encoded_image;
kjellander02b3d272016-04-20 05:05:54 -0700985 CodecSpecificInfo codec_info;
986 codec_info.codecType = kVideoCodecVP8;
asapersson118ef002016-03-31 00:00:19 -0700987
perkj803d97f2016-11-01 11:45:46 -0700988 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
kjellander02b3d272016-04-20 05:05:54 -0700989 codec_info.codecSpecific.VP8.simulcastIdx = 0;
asapersson118ef002016-03-31 00:00:19 -0700990 encoded_image.qp_ = kQpIdx0;
kjellander02b3d272016-04-20 05:05:54 -0700991 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
992 codec_info.codecSpecific.VP8.simulcastIdx = 1;
asapersson118ef002016-03-31 00:00:19 -0700993 encoded_image.qp_ = kQpIdx1;
kjellander02b3d272016-04-20 05:05:54 -0700994 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
asapersson118ef002016-03-31 00:00:19 -0700995 }
996 statistics_proxy_.reset();
asapersson01d70a32016-05-20 06:29:46 -0700997 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp8.S0"));
998 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp8.S0", kQpIdx0));
999 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp8.S1"));
1000 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp8.S1", kQpIdx1));
asapersson118ef002016-03-31 00:00:19 -07001001}
1002
1003TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp8OneSsrc) {
1004 VideoSendStream::Config config(nullptr);
1005 config.rtp.ssrcs.push_back(kFirstSsrc);
1006 statistics_proxy_.reset(new SendStatisticsProxy(
1007 &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo));
1008
asapersson118ef002016-03-31 00:00:19 -07001009 EncodedImage encoded_image;
kjellander02b3d272016-04-20 05:05:54 -07001010 CodecSpecificInfo codec_info;
1011 codec_info.codecType = kVideoCodecVP8;
asapersson118ef002016-03-31 00:00:19 -07001012
perkj803d97f2016-11-01 11:45:46 -07001013 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
kjellander02b3d272016-04-20 05:05:54 -07001014 codec_info.codecSpecific.VP8.simulcastIdx = 0;
asapersson118ef002016-03-31 00:00:19 -07001015 encoded_image.qp_ = kQpIdx0;
kjellander02b3d272016-04-20 05:05:54 -07001016 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
asapersson118ef002016-03-31 00:00:19 -07001017 }
1018 statistics_proxy_.reset();
asapersson01d70a32016-05-20 06:29:46 -07001019 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp8"));
1020 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp8", kQpIdx0));
asapersson118ef002016-03-31 00:00:19 -07001021}
1022
asapersson5265fed2016-04-18 02:58:47 -07001023TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp9) {
asapersson5265fed2016-04-18 02:58:47 -07001024 EncodedImage encoded_image;
kjellander02b3d272016-04-20 05:05:54 -07001025 CodecSpecificInfo codec_info;
1026 codec_info.codecType = kVideoCodecVP9;
1027 codec_info.codecSpecific.VP9.num_spatial_layers = 2;
asapersson5265fed2016-04-18 02:58:47 -07001028
perkj803d97f2016-11-01 11:45:46 -07001029 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asapersson5265fed2016-04-18 02:58:47 -07001030 encoded_image.qp_ = kQpIdx0;
kjellander02b3d272016-04-20 05:05:54 -07001031 codec_info.codecSpecific.VP9.spatial_idx = 0;
1032 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
asapersson5265fed2016-04-18 02:58:47 -07001033 encoded_image.qp_ = kQpIdx1;
kjellander02b3d272016-04-20 05:05:54 -07001034 codec_info.codecSpecific.VP9.spatial_idx = 1;
1035 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
asapersson5265fed2016-04-18 02:58:47 -07001036 }
1037 statistics_proxy_.reset();
asapersson01d70a32016-05-20 06:29:46 -07001038 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp9.S0"));
1039 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp9.S0", kQpIdx0));
1040 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp9.S1"));
1041 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp9.S1", kQpIdx1));
asapersson5265fed2016-04-18 02:58:47 -07001042}
1043
1044TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp9OneSpatialLayer) {
1045 VideoSendStream::Config config(nullptr);
1046 config.rtp.ssrcs.push_back(kFirstSsrc);
1047 statistics_proxy_.reset(new SendStatisticsProxy(
1048 &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo));
1049
asapersson5265fed2016-04-18 02:58:47 -07001050 EncodedImage encoded_image;
kjellander02b3d272016-04-20 05:05:54 -07001051 CodecSpecificInfo codec_info;
1052 codec_info.codecType = kVideoCodecVP9;
1053 codec_info.codecSpecific.VP9.num_spatial_layers = 1;
asapersson5265fed2016-04-18 02:58:47 -07001054
perkj803d97f2016-11-01 11:45:46 -07001055 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asapersson5265fed2016-04-18 02:58:47 -07001056 encoded_image.qp_ = kQpIdx0;
kjellander02b3d272016-04-20 05:05:54 -07001057 codec_info.codecSpecific.VP9.spatial_idx = 0;
1058 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
asapersson5265fed2016-04-18 02:58:47 -07001059 }
1060 statistics_proxy_.reset();
asapersson01d70a32016-05-20 06:29:46 -07001061 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp9"));
1062 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp9", kQpIdx0));
asapersson5265fed2016-04-18 02:58:47 -07001063}
1064
asapersson827cab32016-11-02 09:08:47 -07001065TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_H264) {
1066 EncodedImage encoded_image;
1067 CodecSpecificInfo codec_info;
1068 codec_info.codecType = kVideoCodecH264;
1069
1070 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1071 encoded_image.qp_ = kQpIdx0;
1072 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
1073 }
1074 statistics_proxy_.reset();
1075 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.H264"));
1076 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.H264", kQpIdx0));
1077}
1078
asapersson4ee70462016-10-31 04:05:12 -07001079TEST_F(SendStatisticsProxyTest,
1080 BandwidthLimitedHistogramsNotUpdatedWhenDisabled) {
1081 EncodedImage encoded_image;
1082 // encoded_image.adapt_reason_.bw_resolutions_disabled by default: -1
perkj803d97f2016-11-01 11:45:46 -07001083 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
asapersson4ee70462016-10-31 04:05:12 -07001084 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1085
1086 // Histograms are updated when the statistics_proxy_ is deleted.
1087 statistics_proxy_.reset();
1088 EXPECT_EQ(0, metrics::NumSamples(
1089 "WebRTC.Video.BandwidthLimitedResolutionInPercent"));
1090 EXPECT_EQ(0, metrics::NumSamples(
1091 "WebRTC.Video.BandwidthLimitedResolutionsDisabled"));
1092}
1093
1094TEST_F(SendStatisticsProxyTest,
1095 BandwidthLimitedHistogramsUpdatedWhenEnabled_NoResolutionDisabled) {
1096 const int kResolutionsDisabled = 0;
1097 EncodedImage encoded_image;
1098 encoded_image.adapt_reason_.bw_resolutions_disabled = kResolutionsDisabled;
perkj803d97f2016-11-01 11:45:46 -07001099 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
asapersson4ee70462016-10-31 04:05:12 -07001100 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1101
1102 // Histograms are updated when the statistics_proxy_ is deleted.
1103 statistics_proxy_.reset();
1104 EXPECT_EQ(1, metrics::NumSamples(
1105 "WebRTC.Video.BandwidthLimitedResolutionInPercent"));
1106 EXPECT_EQ(1, metrics::NumEvents(
1107 "WebRTC.Video.BandwidthLimitedResolutionInPercent", 0));
1108 // No resolution disabled.
1109 EXPECT_EQ(0, metrics::NumSamples(
1110 "WebRTC.Video.BandwidthLimitedResolutionsDisabled"));
1111}
1112
1113TEST_F(SendStatisticsProxyTest,
1114 BandwidthLimitedHistogramsUpdatedWhenEnabled_OneResolutionDisabled) {
1115 const int kResolutionsDisabled = 1;
1116 EncodedImage encoded_image;
1117 encoded_image.adapt_reason_.bw_resolutions_disabled = kResolutionsDisabled;
perkj803d97f2016-11-01 11:45:46 -07001118 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
asapersson4ee70462016-10-31 04:05:12 -07001119 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1120
1121 // Histograms are updated when the statistics_proxy_ is deleted.
1122 statistics_proxy_.reset();
1123 EXPECT_EQ(1, metrics::NumSamples(
1124 "WebRTC.Video.BandwidthLimitedResolutionInPercent"));
1125 EXPECT_EQ(1, metrics::NumEvents(
1126 "WebRTC.Video.BandwidthLimitedResolutionInPercent", 100));
1127 // Resolutions disabled.
1128 EXPECT_EQ(1, metrics::NumSamples(
1129 "WebRTC.Video.BandwidthLimitedResolutionsDisabled"));
1130 EXPECT_EQ(
1131 1, metrics::NumEvents("WebRTC.Video.BandwidthLimitedResolutionsDisabled",
1132 kResolutionsDisabled));
1133}
1134
1135TEST_F(SendStatisticsProxyTest,
1136 QualityLimitedHistogramsNotUpdatedWhenDisabled) {
asapersson36e9eb42017-03-31 05:29:12 -07001137 const int kNumDownscales = -1;
asapersson4ee70462016-10-31 04:05:12 -07001138 EncodedImage encoded_image;
asapersson36e9eb42017-03-31 05:29:12 -07001139 statistics_proxy_->SetQualityScalingStats(kNumDownscales);
perkj803d97f2016-11-01 11:45:46 -07001140 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
kthelgason0cd27ba2016-12-19 06:32:16 -08001141 statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo);
asapersson4ee70462016-10-31 04:05:12 -07001142
1143 // Histograms are updated when the statistics_proxy_ is deleted.
1144 statistics_proxy_.reset();
1145 EXPECT_EQ(
1146 0, metrics::NumSamples("WebRTC.Video.QualityLimitedResolutionInPercent"));
1147 EXPECT_EQ(0, metrics::NumSamples(
1148 "WebRTC.Video.QualityLimitedResolutionDownscales"));
1149}
1150
1151TEST_F(SendStatisticsProxyTest,
1152 QualityLimitedHistogramsUpdatedWhenEnabled_NoResolutionDownscale) {
asapersson0944a802017-04-07 00:57:58 -07001153 const int kNumDownscales = 0;
asapersson4ee70462016-10-31 04:05:12 -07001154 EncodedImage encoded_image;
asapersson0944a802017-04-07 00:57:58 -07001155 statistics_proxy_->SetQualityScalingStats(kNumDownscales);
perkj803d97f2016-11-01 11:45:46 -07001156 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
kthelgason0cd27ba2016-12-19 06:32:16 -08001157 statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo);
asapersson4ee70462016-10-31 04:05:12 -07001158
1159 // Histograms are updated when the statistics_proxy_ is deleted.
1160 statistics_proxy_.reset();
1161 EXPECT_EQ(
1162 1, metrics::NumSamples("WebRTC.Video.QualityLimitedResolutionInPercent"));
1163 EXPECT_EQ(1, metrics::NumEvents(
1164 "WebRTC.Video.QualityLimitedResolutionInPercent", 0));
1165 // No resolution downscale.
1166 EXPECT_EQ(0, metrics::NumSamples(
1167 "WebRTC.Video.QualityLimitedResolutionDownscales"));
1168}
1169
1170TEST_F(SendStatisticsProxyTest,
1171 QualityLimitedHistogramsUpdatedWhenEnabled_TwoResolutionDownscales) {
1172 const int kDownscales = 2;
1173 EncodedImage encoded_image;
kthelgason0cd27ba2016-12-19 06:32:16 -08001174 statistics_proxy_->OnQualityRestrictedResolutionChanged(kDownscales);
perkj803d97f2016-11-01 11:45:46 -07001175 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
kthelgason0cd27ba2016-12-19 06:32:16 -08001176 statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo);
asapersson4ee70462016-10-31 04:05:12 -07001177 // Histograms are updated when the statistics_proxy_ is deleted.
1178 statistics_proxy_.reset();
1179 EXPECT_EQ(
1180 1, metrics::NumSamples("WebRTC.Video.QualityLimitedResolutionInPercent"));
1181 EXPECT_EQ(1, metrics::NumEvents(
1182 "WebRTC.Video.QualityLimitedResolutionInPercent", 100));
1183 // Resolution downscales.
1184 EXPECT_EQ(1, metrics::NumSamples(
1185 "WebRTC.Video.QualityLimitedResolutionDownscales"));
1186 EXPECT_EQ(
1187 1, metrics::NumEvents("WebRTC.Video.QualityLimitedResolutionDownscales",
1188 kDownscales));
1189}
1190
1191TEST_F(SendStatisticsProxyTest, GetStatsReportsBandwidthLimitedResolution) {
1192 // Initially false.
1193 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
1194 // No resolution scale by default.
1195 EncodedImage encoded_image;
1196 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1197 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
kthelgason0cd27ba2016-12-19 06:32:16 -08001198
1199 // Simulcast disabled resolutions
1200 encoded_image.adapt_reason_.bw_resolutions_disabled = 1;
1201 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1202 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
1203
asapersson4ee70462016-10-31 04:05:12 -07001204 encoded_image.adapt_reason_.bw_resolutions_disabled = 0;
asapersson4ee70462016-10-31 04:05:12 -07001205 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1206 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
kthelgason0cd27ba2016-12-19 06:32:16 -08001207
1208 // Resolution scaled due to quality.
1209 statistics_proxy_->OnQualityRestrictedResolutionChanged(1);
asapersson4ee70462016-10-31 04:05:12 -07001210 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1211 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
1212}
1213
asapersson66d4b372016-12-19 06:50:53 -08001214TEST_F(SendStatisticsProxyTest, GetStatsReportsTargetMediaBitrate) {
1215 // Initially zero.
1216 EXPECT_EQ(0, statistics_proxy_->GetStats().target_media_bitrate_bps);
1217
1218 const int kBitrate = 100000;
1219 statistics_proxy_->OnSetEncoderTargetRate(kBitrate);
1220 EXPECT_EQ(kBitrate, statistics_proxy_->GetStats().target_media_bitrate_bps);
1221
1222 statistics_proxy_->OnSetEncoderTargetRate(0);
1223 EXPECT_EQ(0, statistics_proxy_->GetStats().target_media_bitrate_bps);
1224}
1225
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001226TEST_F(SendStatisticsProxyTest, NoSubstreams) {
pbos@webrtc.org49096de2015-02-24 22:37:52 +00001227 uint32_t excluded_ssrc =
stefan@webrtc.org58e2d262014-08-14 15:10:49 +00001228 std::max(
1229 *std::max_element(config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end()),
1230 *std::max_element(config_.rtp.rtx.ssrcs.begin(),
1231 config_.rtp.rtx.ssrcs.end())) +
1232 1;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001233 // From RtcpStatisticsCallback.
1234 RtcpStatistics rtcp_stats;
1235 RtcpStatisticsCallback* rtcp_callback = statistics_proxy_.get();
pbos@webrtc.org49096de2015-02-24 22:37:52 +00001236 rtcp_callback->StatisticsUpdated(rtcp_stats, excluded_ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001237
1238 // From BitrateStatisticsObserver.
sprangcd349d92016-07-13 09:11:28 -07001239 uint32_t total = 0;
1240 uint32_t retransmit = 0;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001241 BitrateStatisticsObserver* bitrate_observer = statistics_proxy_.get();
pbos@webrtc.org49096de2015-02-24 22:37:52 +00001242 bitrate_observer->Notify(total, retransmit, excluded_ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001243
1244 // From FrameCountObserver.
1245 FrameCountObserver* fps_observer = statistics_proxy_.get();
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +00001246 FrameCounts frame_counts;
1247 frame_counts.key_frames = 1;
pbos@webrtc.org49096de2015-02-24 22:37:52 +00001248 fps_observer->FrameCountUpdated(frame_counts, excluded_ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001249
1250 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
1251 EXPECT_TRUE(stats.substreams.empty());
1252}
1253
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001254TEST_F(SendStatisticsProxyTest, EncodedResolutionTimesOut) {
1255 static const int kEncodedWidth = 123;
1256 static const int kEncodedHeight = 81;
1257 EncodedImage encoded_image;
1258 encoded_image._encodedWidth = kEncodedWidth;
1259 encoded_image._encodedHeight = kEncodedHeight;
1260
kjellander02b3d272016-04-20 05:05:54 -07001261 CodecSpecificInfo codec_info;
1262 codec_info.codecType = kVideoCodecVP8;
1263 codec_info.codecSpecific.VP8.simulcastIdx = 0;
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001264
kjellander02b3d272016-04-20 05:05:54 -07001265 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
1266 codec_info.codecSpecific.VP8.simulcastIdx = 1;
1267 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001268
1269 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001270 EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
1271 EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
1272 EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[1]].width);
1273 EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[1]].height);
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001274
1275 // Forward almost to timeout, this should not have removed stats.
1276 fake_clock_.AdvanceTimeMilliseconds(SendStatisticsProxy::kStatsTimeoutMs - 1);
1277 stats = statistics_proxy_->GetStats();
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001278 EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
1279 EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001280
1281 // Update the first SSRC with bogus RTCP stats to make sure that encoded
1282 // resolution still times out (no global timeout for all stats).
1283 RtcpStatistics rtcp_statistics;
1284 RtcpStatisticsCallback* rtcp_stats = statistics_proxy_.get();
1285 rtcp_stats->StatisticsUpdated(rtcp_statistics, config_.rtp.ssrcs[0]);
1286
1287 // Report stats for second SSRC to make sure it's not outdated along with the
1288 // first SSRC.
kjellander02b3d272016-04-20 05:05:54 -07001289 codec_info.codecSpecific.VP8.simulcastIdx = 1;
1290 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001291
1292 // Forward 1 ms, reach timeout, substream 0 should have no resolution
1293 // reported, but substream 1 should.
1294 fake_clock_.AdvanceTimeMilliseconds(1);
1295 stats = statistics_proxy_->GetStats();
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001296 EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[0]].width);
1297 EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[0]].height);
1298 EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[1]].width);
1299 EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[1]].height);
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001300}
1301
Peter Boström20f3f942015-05-15 11:33:39 +02001302TEST_F(SendStatisticsProxyTest, ClearsResolutionFromInactiveSsrcs) {
1303 static const int kEncodedWidth = 123;
1304 static const int kEncodedHeight = 81;
1305 EncodedImage encoded_image;
1306 encoded_image._encodedWidth = kEncodedWidth;
1307 encoded_image._encodedHeight = kEncodedHeight;
1308
kjellander02b3d272016-04-20 05:05:54 -07001309 CodecSpecificInfo codec_info;
1310 codec_info.codecType = kVideoCodecVP8;
1311 codec_info.codecSpecific.VP8.simulcastIdx = 0;
Peter Boström20f3f942015-05-15 11:33:39 +02001312
kjellander02b3d272016-04-20 05:05:54 -07001313 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
1314 codec_info.codecSpecific.VP8.simulcastIdx = 1;
1315 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
Peter Boström20f3f942015-05-15 11:33:39 +02001316
1317 statistics_proxy_->OnInactiveSsrc(config_.rtp.ssrcs[1]);
1318 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
1319 EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
1320 EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
1321 EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[1]].width);
1322 EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[1]].height);
1323}
1324
1325TEST_F(SendStatisticsProxyTest, ClearsBitratesFromInactiveSsrcs) {
sprangcd349d92016-07-13 09:11:28 -07001326 uint32_t bitrate = 42;
Peter Boström20f3f942015-05-15 11:33:39 +02001327 BitrateStatisticsObserver* observer = statistics_proxy_.get();
1328 observer->Notify(bitrate, bitrate, config_.rtp.ssrcs[0]);
1329 observer->Notify(bitrate, bitrate, config_.rtp.ssrcs[1]);
1330
1331 statistics_proxy_->OnInactiveSsrc(config_.rtp.ssrcs[1]);
1332
1333 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
sprangcd349d92016-07-13 09:11:28 -07001334 EXPECT_EQ(static_cast<int>(bitrate),
Peter Boström20f3f942015-05-15 11:33:39 +02001335 stats.substreams[config_.rtp.ssrcs[0]].total_bitrate_bps);
sprangcd349d92016-07-13 09:11:28 -07001336 EXPECT_EQ(static_cast<int>(bitrate),
Peter Boström20f3f942015-05-15 11:33:39 +02001337 stats.substreams[config_.rtp.ssrcs[0]].retransmit_bitrate_bps);
1338 EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[1]].total_bitrate_bps);
1339 EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[1]].retransmit_bitrate_bps);
1340}
1341
sprang07fb9be2016-02-24 07:55:00 -08001342TEST_F(SendStatisticsProxyTest, ResetsRtcpCountersOnContentChange) {
1343 RtcpPacketTypeCounterObserver* proxy =
1344 static_cast<RtcpPacketTypeCounterObserver*>(statistics_proxy_.get());
1345 RtcpPacketTypeCounter counters;
1346 counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
1347 proxy->RtcpPacketTypesCounterUpdated(kFirstSsrc, counters);
1348 proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters);
1349
1350 fake_clock_.AdvanceTimeMilliseconds(1000 * metrics::kMinRunTimeInSeconds);
1351
1352 counters.nack_packets += 1 * metrics::kMinRunTimeInSeconds;
1353 counters.fir_packets += 2 * metrics::kMinRunTimeInSeconds;
1354 counters.pli_packets += 3 * metrics::kMinRunTimeInSeconds;
1355 counters.unique_nack_requests += 4 * metrics::kMinRunTimeInSeconds;
1356 counters.nack_requests += 5 * metrics::kMinRunTimeInSeconds;
1357
1358 proxy->RtcpPacketTypesCounterUpdated(kFirstSsrc, counters);
1359 proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters);
1360
1361 // Changing content type causes histograms to be reported.
Pera48ddb72016-09-29 11:48:50 +02001362 VideoEncoderConfig config;
1363 config.content_type = VideoEncoderConfig::ContentType::kScreen;
1364 statistics_proxy_->OnEncoderReconfigured(config, 50);
sprang07fb9be2016-02-24 07:55:00 -08001365
asapersson01d70a32016-05-20 06:29:46 -07001366 EXPECT_EQ(1,
1367 metrics::NumSamples("WebRTC.Video.NackPacketsReceivedPerMinute"));
1368 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.FirPacketsReceivedPerMinute"));
1369 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PliPacketsReceivedPerMinute"));
1370 EXPECT_EQ(1, metrics::NumSamples(
sprang07fb9be2016-02-24 07:55:00 -08001371 "WebRTC.Video.UniqueNackRequestsReceivedInPercent"));
1372
1373 const int kRate = 60 * 2; // Packets per minute with two streams.
1374
asapersson01d70a32016-05-20 06:29:46 -07001375 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.NackPacketsReceivedPerMinute",
1376 1 * kRate));
1377 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.FirPacketsReceivedPerMinute",
1378 2 * kRate));
1379 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.PliPacketsReceivedPerMinute",
1380 3 * kRate));
1381 EXPECT_EQ(
1382 1, metrics::NumEvents("WebRTC.Video.UniqueNackRequestsReceivedInPercent",
1383 4 * 100 / 5));
sprang07fb9be2016-02-24 07:55:00 -08001384
1385 // New start time but same counter values.
1386 proxy->RtcpPacketTypesCounterUpdated(kFirstSsrc, counters);
1387 proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters);
1388
1389 fake_clock_.AdvanceTimeMilliseconds(1000 * metrics::kMinRunTimeInSeconds);
1390
1391 counters.nack_packets += 1 * metrics::kMinRunTimeInSeconds;
1392 counters.fir_packets += 2 * metrics::kMinRunTimeInSeconds;
1393 counters.pli_packets += 3 * metrics::kMinRunTimeInSeconds;
1394 counters.unique_nack_requests += 4 * metrics::kMinRunTimeInSeconds;
1395 counters.nack_requests += 5 * metrics::kMinRunTimeInSeconds;
1396
1397 proxy->RtcpPacketTypesCounterUpdated(kFirstSsrc, counters);
1398 proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters);
1399
1400 SetUp(); // Reset stats proxy also causes histograms to be reported.
1401
asapersson01d70a32016-05-20 06:29:46 -07001402 EXPECT_EQ(1, metrics::NumSamples(
sprang07fb9be2016-02-24 07:55:00 -08001403 "WebRTC.Video.Screenshare.NackPacketsReceivedPerMinute"));
asapersson01d70a32016-05-20 06:29:46 -07001404 EXPECT_EQ(1, metrics::NumSamples(
sprang07fb9be2016-02-24 07:55:00 -08001405 "WebRTC.Video.Screenshare.FirPacketsReceivedPerMinute"));
asapersson01d70a32016-05-20 06:29:46 -07001406 EXPECT_EQ(1, metrics::NumSamples(
sprang07fb9be2016-02-24 07:55:00 -08001407 "WebRTC.Video.Screenshare.PliPacketsReceivedPerMinute"));
1408 EXPECT_EQ(
asapersson01d70a32016-05-20 06:29:46 -07001409 1, metrics::NumSamples(
sprang07fb9be2016-02-24 07:55:00 -08001410 "WebRTC.Video.Screenshare.UniqueNackRequestsReceivedInPercent"));
1411
asapersson01d70a32016-05-20 06:29:46 -07001412 EXPECT_EQ(1, metrics::NumEvents(
1413 "WebRTC.Video.Screenshare.NackPacketsReceivedPerMinute",
1414 1 * kRate));
1415 EXPECT_EQ(1, metrics::NumEvents(
1416 "WebRTC.Video.Screenshare.FirPacketsReceivedPerMinute",
1417 2 * kRate));
1418 EXPECT_EQ(1, metrics::NumEvents(
1419 "WebRTC.Video.Screenshare.PliPacketsReceivedPerMinute",
1420 3 * kRate));
1421 EXPECT_EQ(1,
1422 metrics::NumEvents(
1423 "WebRTC.Video.Screenshare.UniqueNackRequestsReceivedInPercent",
1424 4 * 100 / 5));
sprang07fb9be2016-02-24 07:55:00 -08001425}
1426
asaperssona6a699a2016-11-25 03:52:46 -08001427TEST_F(SendStatisticsProxyTest, GetStatsReportsIsFlexFec) {
1428 statistics_proxy_.reset(
1429 new SendStatisticsProxy(&fake_clock_, GetTestConfigWithFlexFec(),
1430 VideoEncoderConfig::ContentType::kRealtimeVideo));
1431
1432 StreamDataCountersCallback* proxy =
1433 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
1434 StreamDataCounters counters;
1435 proxy->DataCountersUpdated(counters, kFirstSsrc);
1436 proxy->DataCountersUpdated(counters, kFlexFecSsrc);
1437
1438 EXPECT_FALSE(GetStreamStats(kFirstSsrc).is_flexfec);
1439 EXPECT_TRUE(GetStreamStats(kFlexFecSsrc).is_flexfec);
1440}
1441
1442TEST_F(SendStatisticsProxyTest, SendBitratesAreReportedWithFlexFecEnabled) {
1443 statistics_proxy_.reset(
1444 new SendStatisticsProxy(&fake_clock_, GetTestConfigWithFlexFec(),
1445 VideoEncoderConfig::ContentType::kRealtimeVideo));
1446
1447 StreamDataCountersCallback* proxy =
1448 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
asaperssona6a699a2016-11-25 03:52:46 -08001449 StreamDataCounters counters;
1450 StreamDataCounters rtx_counters;
asaperssona6a699a2016-11-25 03:52:46 -08001451
asapersson93e1e232017-02-06 05:18:35 -08001452 const int kMinRequiredPeriodSamples = 8;
1453 const int kPeriodIntervalMs = 2000;
1454 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
1455 counters.transmitted.packets += 20;
1456 counters.transmitted.header_bytes += 500;
1457 counters.transmitted.padding_bytes += 1000;
1458 counters.transmitted.payload_bytes += 2000;
1459 counters.retransmitted.packets += 2;
1460 counters.retransmitted.header_bytes += 25;
1461 counters.retransmitted.padding_bytes += 100;
1462 counters.retransmitted.payload_bytes += 250;
1463 counters.fec = counters.retransmitted;
1464 rtx_counters.transmitted = counters.transmitted;
1465 // Advance one interval and update counters.
1466 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
1467 proxy->DataCountersUpdated(counters, kFirstSsrc);
1468 proxy->DataCountersUpdated(counters, kSecondSsrc);
1469 proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
1470 proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
1471 proxy->DataCountersUpdated(counters, kFlexFecSsrc);
1472 }
asaperssona6a699a2016-11-25 03:52:46 -08001473
asaperssona6a699a2016-11-25 03:52:46 -08001474 statistics_proxy_.reset();
asapersson93e1e232017-02-06 05:18:35 -08001475 // Interval: 3500 bytes * 4 / 2 sec = 7000 bytes / sec = 56 kbps
asaperssona6a699a2016-11-25 03:52:46 -08001476 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.BitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08001477 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.BitrateSentInKbps", 56));
1478 // Interval: 3500 bytes * 2 / 2 sec = 3500 bytes / sec = 28 kbps
1479 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
1480 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.RtxBitrateSentInKbps", 28));
1481 // Interval: (2000 - 2 * 250) bytes / 2 sec = 1500 bytes / sec = 12 kbps
asaperssona6a699a2016-11-25 03:52:46 -08001482 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.MediaBitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08001483 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.MediaBitrateSentInKbps", 12));
1484 // Interval: 1000 bytes * 4 / 2 sec = 2000 bytes / sec = 16 kbps
asaperssona6a699a2016-11-25 03:52:46 -08001485 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PaddingBitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08001486 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.PaddingBitrateSentInKbps", 16));
1487 // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
1488 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
1489 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.FecBitrateSentInKbps", 3));
1490 // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
asaperssona6a699a2016-11-25 03:52:46 -08001491 EXPECT_EQ(1,
1492 metrics::NumSamples("WebRTC.Video.RetransmittedBitrateSentInKbps"));
asaperssona6a699a2016-11-25 03:52:46 -08001493 EXPECT_EQ(
asapersson93e1e232017-02-06 05:18:35 -08001494 1, metrics::NumEvents("WebRTC.Video.RetransmittedBitrateSentInKbps", 3));
asaperssona6a699a2016-11-25 03:52:46 -08001495}
1496
Erik Språng22c2b482016-03-01 09:40:42 +01001497TEST_F(SendStatisticsProxyTest, ResetsRtpCountersOnContentChange) {
1498 StreamDataCountersCallback* proxy =
1499 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
1500 StreamDataCounters counters;
1501 StreamDataCounters rtx_counters;
1502 counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
Erik Språng22c2b482016-03-01 09:40:42 +01001503
asapersson93e1e232017-02-06 05:18:35 -08001504 const int kMinRequiredPeriodSamples = 8;
1505 const int kPeriodIntervalMs = 2000;
1506 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
1507 counters.transmitted.packets += 20;
1508 counters.transmitted.header_bytes += 500;
1509 counters.transmitted.padding_bytes += 1000;
1510 counters.transmitted.payload_bytes += 2000;
1511 counters.retransmitted.packets += 2;
1512 counters.retransmitted.header_bytes += 25;
1513 counters.retransmitted.padding_bytes += 100;
1514 counters.retransmitted.payload_bytes += 250;
1515 counters.fec = counters.retransmitted;
1516 rtx_counters.transmitted = counters.transmitted;
1517 // Advance one interval and update counters.
1518 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
1519 proxy->DataCountersUpdated(counters, kFirstSsrc);
1520 proxy->DataCountersUpdated(counters, kSecondSsrc);
1521 proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
1522 proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
1523 }
Erik Språng22c2b482016-03-01 09:40:42 +01001524
1525 // Changing content type causes histograms to be reported.
Pera48ddb72016-09-29 11:48:50 +02001526 VideoEncoderConfig config;
1527 config.content_type = VideoEncoderConfig::ContentType::kScreen;
asapersson93e1e232017-02-06 05:18:35 -08001528 statistics_proxy_->OnEncoderReconfigured(config, 50000);
Erik Språng22c2b482016-03-01 09:40:42 +01001529
asapersson93e1e232017-02-06 05:18:35 -08001530 // Interval: 3500 bytes * 4 / 2 sec = 7000 bytes / sec = 56 kbps
asapersson01d70a32016-05-20 06:29:46 -07001531 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.BitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08001532 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.BitrateSentInKbps", 56));
1533 // Interval: 3500 bytes * 2 / 2 sec = 3500 bytes / sec = 28 kbps
1534 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
1535 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.RtxBitrateSentInKbps", 28));
1536 // Interval: (2000 - 2 * 250) bytes / 2 sec = 1500 bytes / sec = 12 kbps
asapersson01d70a32016-05-20 06:29:46 -07001537 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.MediaBitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08001538 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.MediaBitrateSentInKbps", 12));
1539 // Interval: 1000 bytes * 4 / 2 sec = 2000 bytes / sec = 16 kbps
asapersson01d70a32016-05-20 06:29:46 -07001540 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PaddingBitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08001541 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.PaddingBitrateSentInKbps", 16));
1542 // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
1543 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
1544 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.FecBitrateSentInKbps", 3));
1545 // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
Erik Språng22c2b482016-03-01 09:40:42 +01001546 EXPECT_EQ(1,
asapersson01d70a32016-05-20 06:29:46 -07001547 metrics::NumSamples("WebRTC.Video.RetransmittedBitrateSentInKbps"));
Erik Språng22c2b482016-03-01 09:40:42 +01001548 EXPECT_EQ(
asapersson93e1e232017-02-06 05:18:35 -08001549 1, metrics::NumEvents("WebRTC.Video.RetransmittedBitrateSentInKbps", 3));
Erik Språng22c2b482016-03-01 09:40:42 +01001550
asapersson93e1e232017-02-06 05:18:35 -08001551 // New metric counters but same data counters.
Erik Språng22c2b482016-03-01 09:40:42 +01001552 // Double counter values, this should result in the same counts as before but
1553 // with new histogram names.
asapersson93e1e232017-02-06 05:18:35 -08001554 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
1555 counters.transmitted.packets += 20;
1556 counters.transmitted.header_bytes += 500;
1557 counters.transmitted.padding_bytes += 1000;
1558 counters.transmitted.payload_bytes += 2000;
1559 counters.retransmitted.packets += 2;
1560 counters.retransmitted.header_bytes += 25;
1561 counters.retransmitted.padding_bytes += 100;
1562 counters.retransmitted.payload_bytes += 250;
1563 counters.fec = counters.retransmitted;
1564 rtx_counters.transmitted = counters.transmitted;
1565 // Advance one interval and update counters.
1566 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
1567 proxy->DataCountersUpdated(counters, kFirstSsrc);
1568 proxy->DataCountersUpdated(counters, kSecondSsrc);
1569 proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
1570 proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
1571 }
Erik Språng22c2b482016-03-01 09:40:42 +01001572
asapersson93e1e232017-02-06 05:18:35 -08001573 // Reset stats proxy also causes histograms to be reported.
1574 statistics_proxy_.reset();
Erik Språng22c2b482016-03-01 09:40:42 +01001575
asapersson93e1e232017-02-06 05:18:35 -08001576 // Interval: 3500 bytes * 4 / 2 sec = 7000 bytes / sec = 56 kbps
asapersson01d70a32016-05-20 06:29:46 -07001577 EXPECT_EQ(1,
1578 metrics::NumSamples("WebRTC.Video.Screenshare.BitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08001579 EXPECT_EQ(
1580 1, metrics::NumEvents("WebRTC.Video.Screenshare.BitrateSentInKbps", 56));
1581 // Interval: 3500 bytes * 2 / 2 sec = 3500 bytes / sec = 28 kbps
1582 EXPECT_EQ(
1583 1, metrics::NumSamples("WebRTC.Video.Screenshare.RtxBitrateSentInKbps"));
1584 EXPECT_EQ(1, metrics::NumEvents(
1585 "WebRTC.Video.Screenshare.RtxBitrateSentInKbps", 28));
1586 // Interval: (2000 - 2 * 250) bytes / 2 sec = 1500 bytes / sec = 12 kbps
asapersson01d70a32016-05-20 06:29:46 -07001587 EXPECT_EQ(1, metrics::NumSamples(
Erik Språng22c2b482016-03-01 09:40:42 +01001588 "WebRTC.Video.Screenshare.MediaBitrateSentInKbps"));
asapersson01d70a32016-05-20 06:29:46 -07001589 EXPECT_EQ(1, metrics::NumEvents(
asapersson93e1e232017-02-06 05:18:35 -08001590 "WebRTC.Video.Screenshare.MediaBitrateSentInKbps", 12));
1591 // Interval: 1000 bytes * 4 / 2 sec = 2000 bytes / sec = 16 kbps
asapersson01d70a32016-05-20 06:29:46 -07001592 EXPECT_EQ(1, metrics::NumSamples(
Erik Språng22c2b482016-03-01 09:40:42 +01001593 "WebRTC.Video.Screenshare.PaddingBitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08001594 EXPECT_EQ(1, metrics::NumEvents(
1595 "WebRTC.Video.Screenshare.PaddingBitrateSentInKbps", 16));
1596 // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
1597 EXPECT_EQ(
1598 1, metrics::NumSamples("WebRTC.Video.Screenshare.FecBitrateSentInKbps"));
1599 EXPECT_EQ(1, metrics::NumEvents(
1600 "WebRTC.Video.Screenshare.FecBitrateSentInKbps", 3));
1601 // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
asapersson01d70a32016-05-20 06:29:46 -07001602 EXPECT_EQ(1, metrics::NumSamples(
Erik Språng22c2b482016-03-01 09:40:42 +01001603 "WebRTC.Video.Screenshare.RetransmittedBitrateSentInKbps"));
asapersson01d70a32016-05-20 06:29:46 -07001604 EXPECT_EQ(1,
1605 metrics::NumEvents(
asapersson93e1e232017-02-06 05:18:35 -08001606 "WebRTC.Video.Screenshare.RetransmittedBitrateSentInKbps", 3));
1607}
Erik Språng22c2b482016-03-01 09:40:42 +01001608
asapersson93e1e232017-02-06 05:18:35 -08001609TEST_F(SendStatisticsProxyTest, RtxBitrateIsZeroWhenEnabledAndNoRtxDataIsSent) {
1610 StreamDataCountersCallback* proxy =
1611 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
1612 StreamDataCounters counters;
1613 StreamDataCounters rtx_counters;
Erik Språng22c2b482016-03-01 09:40:42 +01001614
asapersson93e1e232017-02-06 05:18:35 -08001615 const int kMinRequiredPeriodSamples = 8;
1616 const int kPeriodIntervalMs = 2000;
1617 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
1618 counters.transmitted.packets += 20;
1619 counters.transmitted.header_bytes += 500;
1620 counters.transmitted.payload_bytes += 2000;
1621 counters.fec = counters.retransmitted;
1622 // Advance one interval and update counters.
1623 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
1624 proxy->DataCountersUpdated(counters, kFirstSsrc);
1625 }
1626
1627 // RTX enabled. No data sent over RTX.
1628 statistics_proxy_.reset();
1629 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
1630 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.RtxBitrateSentInKbps", 0));
1631}
1632
1633TEST_F(SendStatisticsProxyTest, RtxBitrateNotReportedWhenNotEnabled) {
1634 VideoSendStream::Config config(nullptr);
1635 config.rtp.ssrcs.push_back(kFirstSsrc); // RTX not configured.
1636 statistics_proxy_.reset(new SendStatisticsProxy(
1637 &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo));
1638
1639 StreamDataCountersCallback* proxy =
1640 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
1641 StreamDataCounters counters;
1642
1643 const int kMinRequiredPeriodSamples = 8;
1644 const int kPeriodIntervalMs = 2000;
1645 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
1646 counters.transmitted.packets += 20;
1647 counters.transmitted.header_bytes += 500;
1648 counters.transmitted.payload_bytes += 2000;
1649 counters.fec = counters.retransmitted;
1650 // Advance one interval and update counters.
1651 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
1652 proxy->DataCountersUpdated(counters, kFirstSsrc);
1653 }
1654
1655 // RTX not enabled.
1656 statistics_proxy_.reset();
1657 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
1658}
1659
1660TEST_F(SendStatisticsProxyTest, FecBitrateIsZeroWhenEnabledAndNoFecDataIsSent) {
1661 StreamDataCountersCallback* proxy =
1662 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
1663 StreamDataCounters counters;
1664 StreamDataCounters rtx_counters;
1665
1666 const int kMinRequiredPeriodSamples = 8;
1667 const int kPeriodIntervalMs = 2000;
1668 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
1669 counters.transmitted.packets += 20;
1670 counters.transmitted.header_bytes += 500;
1671 counters.transmitted.payload_bytes += 2000;
1672 // Advance one interval and update counters.
1673 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
1674 proxy->DataCountersUpdated(counters, kFirstSsrc);
1675 }
1676
1677 // FEC enabled. No FEC data sent.
1678 statistics_proxy_.reset();
1679 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
1680 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.FecBitrateSentInKbps", 0));
1681}
1682
1683TEST_F(SendStatisticsProxyTest, FecBitrateNotReportedWhenNotEnabled) {
1684 VideoSendStream::Config config(nullptr);
1685 config.rtp.ssrcs.push_back(kFirstSsrc); // FEC not configured.
1686 statistics_proxy_.reset(new SendStatisticsProxy(
1687 &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo));
1688
1689 StreamDataCountersCallback* proxy =
1690 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
1691 StreamDataCounters counters;
1692
1693 const int kMinRequiredPeriodSamples = 8;
1694 const int kPeriodIntervalMs = 2000;
1695 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
1696 counters.transmitted.packets += 20;
1697 counters.transmitted.header_bytes += 500;
1698 counters.transmitted.payload_bytes += 2000;
1699 counters.fec = counters.retransmitted;
1700 // Advance one interval and update counters.
1701 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
1702 proxy->DataCountersUpdated(counters, kFirstSsrc);
1703 }
1704
1705 // FEC not enabled.
1706 statistics_proxy_.reset();
1707 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
Erik Språng22c2b482016-03-01 09:40:42 +01001708}
1709
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001710} // namespace webrtc