blob: 72b4e3c3a92c5e25fe87d0b9500eda8abbe3eb53 [file] [log] [blame]
Tommi74fc5742020-04-27 10:43:06 +02001/*
Tommi553c8692020-05-05 15:35:45 +02002 * Copyright 2020 The WebRTC project authors. All Rights Reserved.
Tommi74fc5742020-04-27 10:43:06 +02003 *
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
11#include "video/receive_statistics_proxy2.h"
12
13#include <limits>
14#include <memory>
15#include <string>
16#include <tuple>
17#include <utility>
18
19#include "absl/types/optional.h"
20#include "api/scoped_refptr.h"
21#include "api/video/i420_buffer.h"
22#include "api/video/video_frame.h"
23#include "api/video/video_frame_buffer.h"
24#include "api/video/video_rotation.h"
Tommi553c8692020-05-05 15:35:45 +020025#include "rtc_base/task_utils/to_queued_task.h"
26#include "rtc_base/thread.h"
Tommi74fc5742020-04-27 10:43:06 +020027#include "system_wrappers/include/metrics.h"
28#include "test/field_trial.h"
29#include "test/gtest.h"
Tommi553c8692020-05-05 15:35:45 +020030#include "test/run_loop.h"
Tommid7e08c82020-05-10 11:24:43 +020031#include "video/video_receive_stream2.h"
Tommi74fc5742020-04-27 10:43:06 +020032
33namespace webrtc {
34namespace internal {
35namespace {
36const int64_t kFreqOffsetProcessIntervalInMs = 40000;
Tommi74fc5742020-04-27 10:43:06 +020037const uint32_t kRemoteSsrc = 456;
38const int kMinRequiredSamples = 200;
39const int kWidth = 1280;
40const int kHeight = 720;
41} // namespace
42
43// TODO(sakal): ReceiveStatisticsProxy is lacking unittesting.
44class ReceiveStatisticsProxy2Test : public ::testing::Test {
45 public:
Tommib2db9892021-08-23 22:44:49 +020046 ReceiveStatisticsProxy2Test() : fake_clock_(1234) {
Tommi74fc5742020-04-27 10:43:06 +020047 metrics::Reset();
Tommib2db9892021-08-23 22:44:49 +020048 statistics_proxy_.reset(new ReceiveStatisticsProxy(
49 kRemoteSsrc, &fake_clock_, loop_.task_queue()));
Tommi74fc5742020-04-27 10:43:06 +020050 }
51
Tommi553c8692020-05-05 15:35:45 +020052 ~ReceiveStatisticsProxy2Test() override { statistics_proxy_.reset(); }
53
54 protected:
Tommid93bf122020-05-10 20:24:59 +020055 // Convenience method to avoid too many explict flushes.
56 VideoReceiveStream::Stats FlushAndGetStats() {
57 loop_.Flush();
58 return statistics_proxy_->GetStats();
59 }
60
61 void FlushAndUpdateHistograms(absl::optional<int> fraction_lost,
62 const StreamDataCounters& rtp_stats,
63 const StreamDataCounters* rtx_stats) {
64 loop_.Flush();
65 statistics_proxy_->UpdateHistograms(fraction_lost, rtp_stats, rtx_stats);
66 }
67
Tommi74fc5742020-04-27 10:43:06 +020068 VideoFrame CreateFrame(int width, int height) {
69 return CreateVideoFrame(width, height, 0);
70 }
71
Tommid7e08c82020-05-10 11:24:43 +020072 VideoFrame CreateFrameWithRenderTime(Timestamp render_time) {
73 return CreateFrameWithRenderTimeMs(render_time.ms());
74 }
75
Tommi74fc5742020-04-27 10:43:06 +020076 VideoFrame CreateFrameWithRenderTimeMs(int64_t render_time_ms) {
77 return CreateVideoFrame(kWidth, kHeight, render_time_ms);
78 }
79
80 VideoFrame CreateVideoFrame(int width, int height, int64_t render_time_ms) {
81 VideoFrame frame =
82 VideoFrame::Builder()
83 .set_video_frame_buffer(I420Buffer::Create(width, height))
84 .set_timestamp_rtp(0)
85 .set_timestamp_ms(render_time_ms)
86 .set_rotation(kVideoRotation_0)
87 .build();
88 frame.set_ntp_time_ms(fake_clock_.CurrentNtpInMilliseconds());
89 return frame;
90 }
91
Tommid7e08c82020-05-10 11:24:43 +020092 // Return the current fake time as a Timestamp.
93 Timestamp Now() { return fake_clock_.CurrentTime(); }
94
95 // Creates a VideoFrameMetaData instance with a timestamp.
96 VideoFrameMetaData MetaData(const VideoFrame& frame, Timestamp ts) {
97 return VideoFrameMetaData(frame, ts);
98 }
99
100 // Creates a VideoFrameMetaData instance with the current fake time.
101 VideoFrameMetaData MetaData(const VideoFrame& frame) {
102 return VideoFrameMetaData(frame, Now());
103 }
104
Tommi74fc5742020-04-27 10:43:06 +0200105 SimulatedClock fake_clock_;
Tommi74fc5742020-04-27 10:43:06 +0200106 std::unique_ptr<ReceiveStatisticsProxy> statistics_proxy_;
Tommi553c8692020-05-05 15:35:45 +0200107 test::RunLoop loop_;
Tommi74fc5742020-04-27 10:43:06 +0200108};
109
110TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesFramesDecoded) {
111 EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded);
112 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
113 for (uint32_t i = 1; i <= 3; ++i) {
114 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
115 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200116 EXPECT_EQ(i, FlushAndGetStats().frames_decoded);
Tommi74fc5742020-04-27 10:43:06 +0200117 }
118}
119
120TEST_F(ReceiveStatisticsProxy2Test, DecodedFpsIsReported) {
121 const int kFps = 20;
122 const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps;
123 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
124 for (int i = 0; i < kRequiredSamples; ++i) {
125 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
126 VideoContentType::UNSPECIFIED);
127 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
128 }
Tommid93bf122020-05-10 20:24:59 +0200129 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200130 EXPECT_METRIC_EQ(1,
131 metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond"));
132 EXPECT_METRIC_EQ(
133 1, metrics::NumEvents("WebRTC.Video.DecodedFramesPerSecond", kFps));
134}
135
136TEST_F(ReceiveStatisticsProxy2Test, DecodedFpsIsNotReportedForTooFewSamples) {
137 const int kFps = 20;
138 const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps;
139 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
140 for (int i = 0; i < kRequiredSamples - 1; ++i) {
141 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
142 VideoContentType::UNSPECIFIED);
143 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
144 }
Tommid93bf122020-05-10 20:24:59 +0200145 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200146 EXPECT_METRIC_EQ(0,
147 metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond"));
148}
149
150TEST_F(ReceiveStatisticsProxy2Test,
151 OnDecodedFrameWithQpDoesNotResetFramesDecodedOrTotalDecodeTime) {
152 EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded);
153 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
154 unsigned int expected_total_decode_time_ms = 0;
155 unsigned int expected_frames_decoded = 0;
156 for (uint32_t i = 1; i <= 3; ++i) {
157 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 1,
158 VideoContentType::UNSPECIFIED);
159 expected_total_decode_time_ms += 1;
160 ++expected_frames_decoded;
Tommid93bf122020-05-10 20:24:59 +0200161 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200162 EXPECT_EQ(expected_frames_decoded,
163 statistics_proxy_->GetStats().frames_decoded);
164 EXPECT_EQ(expected_total_decode_time_ms,
165 statistics_proxy_->GetStats().total_decode_time_ms);
166 }
167 statistics_proxy_->OnDecodedFrame(frame, 1u, 3,
168 VideoContentType::UNSPECIFIED);
169 ++expected_frames_decoded;
170 expected_total_decode_time_ms += 3;
Tommid93bf122020-05-10 20:24:59 +0200171 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200172 EXPECT_EQ(expected_frames_decoded,
173 statistics_proxy_->GetStats().frames_decoded);
174 EXPECT_EQ(expected_total_decode_time_ms,
175 statistics_proxy_->GetStats().total_decode_time_ms);
176}
177
178TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesQpSum) {
179 EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
180 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
181 statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
182 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200183 EXPECT_EQ(3u, FlushAndGetStats().qp_sum);
Tommi74fc5742020-04-27 10:43:06 +0200184 statistics_proxy_->OnDecodedFrame(frame, 127u, 0,
185 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200186 EXPECT_EQ(130u, FlushAndGetStats().qp_sum);
Tommi74fc5742020-04-27 10:43:06 +0200187}
188
189TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesTotalDecodeTime) {
190 EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
191 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
192 statistics_proxy_->OnDecodedFrame(frame, 3u, 4,
193 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200194 EXPECT_EQ(4u, FlushAndGetStats().total_decode_time_ms);
Tommi74fc5742020-04-27 10:43:06 +0200195 statistics_proxy_->OnDecodedFrame(frame, 127u, 7,
196 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200197 EXPECT_EQ(11u, FlushAndGetStats().total_decode_time_ms);
Tommi74fc5742020-04-27 10:43:06 +0200198}
199
200TEST_F(ReceiveStatisticsProxy2Test, ReportsContentType) {
201 const std::string kRealtimeString("realtime");
202 const std::string kScreenshareString("screen");
203 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
204 EXPECT_EQ(kRealtimeString, videocontenttypehelpers::ToString(
205 statistics_proxy_->GetStats().content_type));
206 statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
207 VideoContentType::SCREENSHARE);
208 EXPECT_EQ(kScreenshareString,
Tommid93bf122020-05-10 20:24:59 +0200209 videocontenttypehelpers::ToString(FlushAndGetStats().content_type));
Tommi74fc5742020-04-27 10:43:06 +0200210 statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
211 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200212 EXPECT_EQ(kRealtimeString,
213 videocontenttypehelpers::ToString(FlushAndGetStats().content_type));
Tommi74fc5742020-04-27 10:43:06 +0200214}
215
216TEST_F(ReceiveStatisticsProxy2Test, ReportsMaxTotalInterFrameDelay) {
217 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
218 const TimeDelta kInterFrameDelay1 = TimeDelta::Millis(100);
219 const TimeDelta kInterFrameDelay2 = TimeDelta::Millis(200);
220 const TimeDelta kInterFrameDelay3 = TimeDelta::Millis(300);
221 double expected_total_inter_frame_delay = 0;
222 double expected_total_squared_inter_frame_delay = 0;
223 EXPECT_EQ(expected_total_inter_frame_delay,
224 statistics_proxy_->GetStats().total_inter_frame_delay);
225 EXPECT_EQ(expected_total_squared_inter_frame_delay,
226 statistics_proxy_->GetStats().total_squared_inter_frame_delay);
227
228 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
229 VideoContentType::UNSPECIFIED);
230 EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
Tommid93bf122020-05-10 20:24:59 +0200231 FlushAndGetStats().total_inter_frame_delay);
232 EXPECT_DOUBLE_EQ(expected_total_squared_inter_frame_delay,
233 FlushAndGetStats().total_squared_inter_frame_delay);
Tommi74fc5742020-04-27 10:43:06 +0200234
235 fake_clock_.AdvanceTime(kInterFrameDelay1);
236 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
237 VideoContentType::UNSPECIFIED);
238 expected_total_inter_frame_delay += kInterFrameDelay1.seconds<double>();
239 expected_total_squared_inter_frame_delay +=
240 pow(kInterFrameDelay1.seconds<double>(), 2.0);
241 EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
Tommid93bf122020-05-10 20:24:59 +0200242 FlushAndGetStats().total_inter_frame_delay);
Tommi74fc5742020-04-27 10:43:06 +0200243 EXPECT_DOUBLE_EQ(
244 expected_total_squared_inter_frame_delay,
245 statistics_proxy_->GetStats().total_squared_inter_frame_delay);
246
247 fake_clock_.AdvanceTime(kInterFrameDelay2);
248 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
249 VideoContentType::UNSPECIFIED);
250 expected_total_inter_frame_delay += kInterFrameDelay2.seconds<double>();
251 expected_total_squared_inter_frame_delay +=
252 pow(kInterFrameDelay2.seconds<double>(), 2.0);
253 EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
Tommid93bf122020-05-10 20:24:59 +0200254 FlushAndGetStats().total_inter_frame_delay);
Tommi74fc5742020-04-27 10:43:06 +0200255 EXPECT_DOUBLE_EQ(
256 expected_total_squared_inter_frame_delay,
257 statistics_proxy_->GetStats().total_squared_inter_frame_delay);
258
259 fake_clock_.AdvanceTime(kInterFrameDelay3);
260 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
261 VideoContentType::UNSPECIFIED);
262 expected_total_inter_frame_delay += kInterFrameDelay3.seconds<double>();
263 expected_total_squared_inter_frame_delay +=
264 pow(kInterFrameDelay3.seconds<double>(), 2.0);
265 EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
Tommid93bf122020-05-10 20:24:59 +0200266 FlushAndGetStats().total_inter_frame_delay);
Tommi74fc5742020-04-27 10:43:06 +0200267 EXPECT_DOUBLE_EQ(
268 expected_total_squared_inter_frame_delay,
269 statistics_proxy_->GetStats().total_squared_inter_frame_delay);
270}
271
272TEST_F(ReceiveStatisticsProxy2Test, ReportsMaxInterframeDelay) {
273 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
274 const int64_t kInterframeDelayMs1 = 100;
275 const int64_t kInterframeDelayMs2 = 200;
276 const int64_t kInterframeDelayMs3 = 100;
277 EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
278 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
279 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200280 EXPECT_EQ(-1, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200281
282 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs1);
283 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
284 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200285 EXPECT_EQ(kInterframeDelayMs1, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200286
287 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs2);
288 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
289 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200290 EXPECT_EQ(kInterframeDelayMs2, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200291
292 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs3);
293 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
294 VideoContentType::UNSPECIFIED);
295 // kInterframeDelayMs3 is smaller than kInterframeDelayMs2.
Tommid93bf122020-05-10 20:24:59 +0200296 EXPECT_EQ(kInterframeDelayMs2, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200297}
298
299TEST_F(ReceiveStatisticsProxy2Test, ReportInterframeDelayInWindow) {
300 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
301 const int64_t kInterframeDelayMs1 = 900;
302 const int64_t kInterframeDelayMs2 = 750;
303 const int64_t kInterframeDelayMs3 = 700;
304 EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
305 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
306 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200307 EXPECT_EQ(-1, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200308
309 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs1);
310 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
311 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200312 EXPECT_EQ(kInterframeDelayMs1, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200313
314 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs2);
315 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
316 VideoContentType::UNSPECIFIED);
317 // Still first delay is the maximum
Tommid93bf122020-05-10 20:24:59 +0200318 EXPECT_EQ(kInterframeDelayMs1, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200319
320 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs3);
321 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
322 VideoContentType::UNSPECIFIED);
323 // Now the first sample is out of the window, so the second is the maximum.
Tommid93bf122020-05-10 20:24:59 +0200324 EXPECT_EQ(kInterframeDelayMs2, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200325}
326
327TEST_F(ReceiveStatisticsProxy2Test, ReportsFreezeMetrics) {
328 const int64_t kFreezeDurationMs = 1000;
329
330 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
331 EXPECT_EQ(0u, stats.freeze_count);
332 EXPECT_FALSE(stats.total_freezes_duration_ms);
333
334 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
335 for (size_t i = 0; i < VideoQualityObserver::kMinFrameSamplesToDetectFreeze;
336 ++i) {
337 fake_clock_.AdvanceTimeMilliseconds(30);
Tommid7e08c82020-05-10 11:24:43 +0200338 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200339 }
340
341 // Freeze.
342 fake_clock_.AdvanceTimeMilliseconds(kFreezeDurationMs);
Tommid7e08c82020-05-10 11:24:43 +0200343 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200344
345 stats = statistics_proxy_->GetStats();
346 EXPECT_EQ(1u, stats.freeze_count);
347 EXPECT_EQ(kFreezeDurationMs, stats.total_freezes_duration_ms);
348}
349
350TEST_F(ReceiveStatisticsProxy2Test, ReportsPauseMetrics) {
351 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
352 ASSERT_EQ(0u, stats.pause_count);
353 ASSERT_EQ(0u, stats.total_pauses_duration_ms);
354
355 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
Tommid7e08c82020-05-10 11:24:43 +0200356 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200357
358 // Pause.
359 fake_clock_.AdvanceTimeMilliseconds(5432);
360 statistics_proxy_->OnStreamInactive();
Tommid7e08c82020-05-10 11:24:43 +0200361 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200362
363 stats = statistics_proxy_->GetStats();
364 EXPECT_EQ(1u, stats.pause_count);
365 EXPECT_EQ(5432u, stats.total_pauses_duration_ms);
366}
367
368TEST_F(ReceiveStatisticsProxy2Test, PauseBeforeFirstAndAfterLastFrameIgnored) {
369 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
370 ASSERT_EQ(0u, stats.pause_count);
371 ASSERT_EQ(0u, stats.total_pauses_duration_ms);
372
373 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
374
375 // Pause -> Frame -> Pause
376 fake_clock_.AdvanceTimeMilliseconds(5000);
377 statistics_proxy_->OnStreamInactive();
Tommid7e08c82020-05-10 11:24:43 +0200378 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200379
380 fake_clock_.AdvanceTimeMilliseconds(30);
Tommid7e08c82020-05-10 11:24:43 +0200381 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200382
383 fake_clock_.AdvanceTimeMilliseconds(5000);
384 statistics_proxy_->OnStreamInactive();
385
386 stats = statistics_proxy_->GetStats();
387 EXPECT_EQ(0u, stats.pause_count);
388 EXPECT_EQ(0u, stats.total_pauses_duration_ms);
389}
390
391TEST_F(ReceiveStatisticsProxy2Test, ReportsFramesDuration) {
392 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
393 ASSERT_EQ(0u, stats.total_frames_duration_ms);
394
395 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
396
397 // Emulate delay before first frame is rendered. This is needed to ensure
398 // that frame duration only covers time since first frame is rendered and
399 // not the total time.
400 fake_clock_.AdvanceTimeMilliseconds(5432);
401
402 for (int i = 0; i <= 10; ++i) {
403 fake_clock_.AdvanceTimeMilliseconds(30);
Tommid7e08c82020-05-10 11:24:43 +0200404 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200405 }
406
407 stats = statistics_proxy_->GetStats();
408 EXPECT_EQ(10 * 30u, stats.total_frames_duration_ms);
409}
410
411TEST_F(ReceiveStatisticsProxy2Test, ReportsSumSquaredFrameDurations) {
412 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
413 ASSERT_EQ(0u, stats.sum_squared_frame_durations);
414
415 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
416 for (int i = 0; i <= 10; ++i) {
417 fake_clock_.AdvanceTimeMilliseconds(30);
Tommid7e08c82020-05-10 11:24:43 +0200418 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200419 }
420
421 stats = statistics_proxy_->GetStats();
422 const double kExpectedSumSquaredFrameDurationsSecs =
423 10 * (30 / 1000.0 * 30 / 1000.0);
424 EXPECT_EQ(kExpectedSumSquaredFrameDurationsSecs,
425 stats.sum_squared_frame_durations);
426}
427
428TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameWithoutQpQpSumWontExist) {
429 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
430 EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
431 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
432 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200433 EXPECT_EQ(absl::nullopt, FlushAndGetStats().qp_sum);
Tommi74fc5742020-04-27 10:43:06 +0200434}
435
436TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameWithoutQpResetsQpSum) {
437 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
438 EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
439 statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
440 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200441 EXPECT_EQ(3u, FlushAndGetStats().qp_sum);
Tommi74fc5742020-04-27 10:43:06 +0200442 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
443 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200444 EXPECT_EQ(absl::nullopt, FlushAndGetStats().qp_sum);
Tommi74fc5742020-04-27 10:43:06 +0200445}
446
447TEST_F(ReceiveStatisticsProxy2Test, OnRenderedFrameIncreasesFramesRendered) {
448 EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_rendered);
449 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
450 for (uint32_t i = 1; i <= 3; ++i) {
Tommid7e08c82020-05-10 11:24:43 +0200451 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200452 EXPECT_EQ(i, statistics_proxy_->GetStats().frames_rendered);
453 }
454}
455
456TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsSsrc) {
457 EXPECT_EQ(kRemoteSsrc, statistics_proxy_->GetStats().ssrc);
458}
459
460TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsIncomingPayloadType) {
461 const int kPayloadType = 111;
462 statistics_proxy_->OnIncomingPayloadType(kPayloadType);
Tommi674b0c82020-05-10 21:52:17 +0200463 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200464 EXPECT_EQ(kPayloadType, statistics_proxy_->GetStats().current_payload_type);
465}
466
467TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsDecoderImplementationName) {
468 const char* kName = "decoderName";
469 statistics_proxy_->OnDecoderImplementationName(kName);
Tommi674b0c82020-05-10 21:52:17 +0200470 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200471 EXPECT_STREQ(
472 kName, statistics_proxy_->GetStats().decoder_implementation_name.c_str());
473}
474
475TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsOnCompleteFrame) {
476 const int kFrameSizeBytes = 1000;
477 statistics_proxy_->OnCompleteFrame(true, kFrameSizeBytes,
478 VideoContentType::UNSPECIFIED);
479 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
480 EXPECT_EQ(1, stats.network_frame_rate);
481 EXPECT_EQ(1, stats.frame_counts.key_frames);
482 EXPECT_EQ(0, stats.frame_counts.delta_frames);
483}
484
485TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsOnDroppedFrame) {
486 unsigned int dropped_frames = 0;
487 for (int i = 0; i < 10; ++i) {
488 statistics_proxy_->OnDroppedFrames(i);
489 dropped_frames += i;
490 }
Tommi674b0c82020-05-10 21:52:17 +0200491 VideoReceiveStream::Stats stats = FlushAndGetStats();
Tommi74fc5742020-04-27 10:43:06 +0200492 EXPECT_EQ(dropped_frames, stats.frames_dropped);
493}
494
495TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsDecodeTimingStats) {
496 const int kMaxDecodeMs = 2;
497 const int kCurrentDelayMs = 3;
498 const int kTargetDelayMs = 4;
499 const int kJitterBufferMs = 5;
500 const int kMinPlayoutDelayMs = 6;
501 const int kRenderDelayMs = 7;
502 const int64_t kRttMs = 8;
Tommi674b0c82020-05-10 21:52:17 +0200503 statistics_proxy_->OnRttUpdate(kRttMs);
Tommi74fc5742020-04-27 10:43:06 +0200504 statistics_proxy_->OnFrameBufferTimingsUpdated(
505 kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
506 kMinPlayoutDelayMs, kRenderDelayMs);
Tommi674b0c82020-05-10 21:52:17 +0200507 VideoReceiveStream::Stats stats = FlushAndGetStats();
Tommi74fc5742020-04-27 10:43:06 +0200508 EXPECT_EQ(kMaxDecodeMs, stats.max_decode_ms);
509 EXPECT_EQ(kCurrentDelayMs, stats.current_delay_ms);
510 EXPECT_EQ(kTargetDelayMs, stats.target_delay_ms);
511 EXPECT_EQ(kJitterBufferMs, stats.jitter_buffer_ms);
512 EXPECT_EQ(kMinPlayoutDelayMs, stats.min_playout_delay_ms);
513 EXPECT_EQ(kRenderDelayMs, stats.render_delay_ms);
514}
515
516TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsRtcpPacketTypeCounts) {
517 const uint32_t kFirPackets = 33;
518 const uint32_t kPliPackets = 44;
519 const uint32_t kNackPackets = 55;
520 RtcpPacketTypeCounter counter;
521 counter.fir_packets = kFirPackets;
522 counter.pli_packets = kPliPackets;
523 counter.nack_packets = kNackPackets;
524 statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc, counter);
525 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
526 EXPECT_EQ(kFirPackets, stats.rtcp_packet_type_counts.fir_packets);
527 EXPECT_EQ(kPliPackets, stats.rtcp_packet_type_counts.pli_packets);
528 EXPECT_EQ(kNackPackets, stats.rtcp_packet_type_counts.nack_packets);
529}
530
531TEST_F(ReceiveStatisticsProxy2Test,
532 GetStatsReportsNoRtcpPacketTypeCountsForUnknownSsrc) {
533 RtcpPacketTypeCounter counter;
534 counter.fir_packets = 33;
535 statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc + 1, counter);
536 EXPECT_EQ(0u,
537 statistics_proxy_->GetStats().rtcp_packet_type_counts.fir_packets);
538}
539
540TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsFrameCounts) {
541 const int kKeyFrames = 3;
542 const int kDeltaFrames = 22;
543 for (int i = 0; i < kKeyFrames; i++) {
544 statistics_proxy_->OnCompleteFrame(true, 0, VideoContentType::UNSPECIFIED);
545 }
546 for (int i = 0; i < kDeltaFrames; i++) {
547 statistics_proxy_->OnCompleteFrame(false, 0, VideoContentType::UNSPECIFIED);
548 }
549
550 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
551 EXPECT_EQ(kKeyFrames, stats.frame_counts.key_frames);
552 EXPECT_EQ(kDeltaFrames, stats.frame_counts.delta_frames);
553}
554
555TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsCName) {
556 const char* kName = "cName";
557 statistics_proxy_->OnCname(kRemoteSsrc, kName);
558 EXPECT_STREQ(kName, statistics_proxy_->GetStats().c_name.c_str());
559}
560
561TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsNoCNameForUnknownSsrc) {
562 const char* kName = "cName";
563 statistics_proxy_->OnCname(kRemoteSsrc + 1, kName);
564 EXPECT_STREQ("", statistics_proxy_->GetStats().c_name.c_str());
565}
566
567TEST_F(ReceiveStatisticsProxy2Test, ReportsLongestTimingFrameInfo) {
568 const int64_t kShortEndToEndDelay = 10;
569 const int64_t kMedEndToEndDelay = 20;
570 const int64_t kLongEndToEndDelay = 100;
571 const uint32_t kExpectedRtpTimestamp = 2;
572 TimingFrameInfo info;
573 absl::optional<TimingFrameInfo> result;
574 info.rtp_timestamp = kExpectedRtpTimestamp - 1;
575 info.capture_time_ms = 0;
576 info.decode_finish_ms = kShortEndToEndDelay;
577 statistics_proxy_->OnTimingFrameInfoUpdated(info);
578 info.rtp_timestamp =
579 kExpectedRtpTimestamp; // this frame should be reported in the end.
580 info.capture_time_ms = 0;
581 info.decode_finish_ms = kLongEndToEndDelay;
582 statistics_proxy_->OnTimingFrameInfoUpdated(info);
583 info.rtp_timestamp = kExpectedRtpTimestamp + 1;
584 info.capture_time_ms = 0;
585 info.decode_finish_ms = kMedEndToEndDelay;
586 statistics_proxy_->OnTimingFrameInfoUpdated(info);
Tommi674b0c82020-05-10 21:52:17 +0200587 result = FlushAndGetStats().timing_frame_info;
Tommi74fc5742020-04-27 10:43:06 +0200588 EXPECT_TRUE(result);
589 EXPECT_EQ(kExpectedRtpTimestamp, result->rtp_timestamp);
590}
591
592TEST_F(ReceiveStatisticsProxy2Test, RespectsReportingIntervalForTimingFrames) {
593 TimingFrameInfo info;
594 const int64_t kShortEndToEndDelay = 10;
595 const uint32_t kExpectedRtpTimestamp = 2;
596 const int64_t kShortDelayMs = 1000;
597 const int64_t kLongDelayMs = 10000;
598 absl::optional<TimingFrameInfo> result;
599 info.rtp_timestamp = kExpectedRtpTimestamp;
600 info.capture_time_ms = 0;
601 info.decode_finish_ms = kShortEndToEndDelay;
602 statistics_proxy_->OnTimingFrameInfoUpdated(info);
603 fake_clock_.AdvanceTimeMilliseconds(kShortDelayMs);
Tommi674b0c82020-05-10 21:52:17 +0200604 result = FlushAndGetStats().timing_frame_info;
Tommi74fc5742020-04-27 10:43:06 +0200605 EXPECT_TRUE(result);
606 EXPECT_EQ(kExpectedRtpTimestamp, result->rtp_timestamp);
607 fake_clock_.AdvanceTimeMilliseconds(kLongDelayMs);
608 result = statistics_proxy_->GetStats().timing_frame_info;
609 EXPECT_FALSE(result);
610}
611
612TEST_F(ReceiveStatisticsProxy2Test, LifetimeHistogramIsUpdated) {
613 const int64_t kTimeSec = 3;
614 fake_clock_.AdvanceTimeMilliseconds(kTimeSec * 1000);
615 // Need at least one frame to report stream lifetime.
616 statistics_proxy_->OnCompleteFrame(true, 1000, VideoContentType::UNSPECIFIED);
617 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
618 nullptr);
619 EXPECT_METRIC_EQ(
620 1, metrics::NumSamples("WebRTC.Video.ReceiveStreamLifetimeInSeconds"));
621 EXPECT_METRIC_EQ(
622 1, metrics::NumEvents("WebRTC.Video.ReceiveStreamLifetimeInSeconds",
623 kTimeSec));
624}
625
626TEST_F(ReceiveStatisticsProxy2Test,
627 LifetimeHistogramNotReportedForEmptyStreams) {
628 const int64_t kTimeSec = 3;
629 fake_clock_.AdvanceTimeMilliseconds(kTimeSec * 1000);
630 // No frames received.
631 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
632 nullptr);
633 EXPECT_METRIC_EQ(
634 0, metrics::NumSamples("WebRTC.Video.ReceiveStreamLifetimeInSeconds"));
635}
636
637TEST_F(ReceiveStatisticsProxy2Test, BadCallHistogramsAreUpdated) {
638 // Based on the tuning parameters this will produce 7 uncertain states,
639 // then 10 certainly bad states. There has to be 10 certain states before
640 // any histograms are recorded.
641 const int kNumBadSamples = 17;
642 // We only count one sample per second.
643 const int kBadFameIntervalMs = 1100;
644
645 StreamDataCounters counters;
646 counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
647
648 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
649
650 for (int i = 0; i < kNumBadSamples; ++i) {
651 fake_clock_.AdvanceTimeMilliseconds(kBadFameIntervalMs);
Tommid7e08c82020-05-10 11:24:43 +0200652 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200653 }
654 statistics_proxy_->UpdateHistograms(absl::nullopt, counters, nullptr);
655 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.BadCall.Any"));
656 EXPECT_METRIC_EQ(1, metrics::NumEvents("WebRTC.Video.BadCall.Any", 100));
657
658 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.BadCall.FrameRate"));
659 EXPECT_METRIC_EQ(1,
660 metrics::NumEvents("WebRTC.Video.BadCall.FrameRate", 100));
661
662 EXPECT_METRIC_EQ(
663 0, metrics::NumSamples("WebRTC.Video.BadCall.FrameRateVariance"));
664
665 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.BadCall.Qp"));
666}
667
668TEST_F(ReceiveStatisticsProxy2Test, PacketLossHistogramIsUpdated) {
669 statistics_proxy_->UpdateHistograms(10, StreamDataCounters(), nullptr);
670 EXPECT_METRIC_EQ(
671 0, metrics::NumSamples("WebRTC.Video.ReceivedPacketsLostInPercent"));
672
673 // Restart
674 SetUp();
675
676 // Min run time has passed.
677 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
678 statistics_proxy_->UpdateHistograms(10, StreamDataCounters(), nullptr);
679 EXPECT_METRIC_EQ(
680 1, metrics::NumSamples("WebRTC.Video.ReceivedPacketsLostInPercent"));
681 EXPECT_METRIC_EQ(
682 1, metrics::NumEvents("WebRTC.Video.ReceivedPacketsLostInPercent", 10));
683}
684
685TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsPlayoutTimestamp) {
686 const int64_t kVideoNtpMs = 21;
687 const int64_t kSyncOffsetMs = 22;
688 const double kFreqKhz = 90.0;
689 EXPECT_EQ(absl::nullopt,
690 statistics_proxy_->GetStats().estimated_playout_ntp_timestamp_ms);
691 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs, kFreqKhz);
Tommi674b0c82020-05-10 21:52:17 +0200692 EXPECT_EQ(kVideoNtpMs, FlushAndGetStats().estimated_playout_ntp_timestamp_ms);
Tommi74fc5742020-04-27 10:43:06 +0200693 fake_clock_.AdvanceTimeMilliseconds(13);
694 EXPECT_EQ(kVideoNtpMs + 13,
695 statistics_proxy_->GetStats().estimated_playout_ntp_timestamp_ms);
696 fake_clock_.AdvanceTimeMilliseconds(5);
697 EXPECT_EQ(kVideoNtpMs + 13 + 5,
698 statistics_proxy_->GetStats().estimated_playout_ntp_timestamp_ms);
699}
700
701TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsAvSyncOffset) {
702 const int64_t kVideoNtpMs = 21;
703 const int64_t kSyncOffsetMs = 22;
704 const double kFreqKhz = 90.0;
705 EXPECT_EQ(std::numeric_limits<int>::max(),
706 statistics_proxy_->GetStats().sync_offset_ms);
707 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs, kFreqKhz);
Tommi674b0c82020-05-10 21:52:17 +0200708 EXPECT_EQ(kSyncOffsetMs, FlushAndGetStats().sync_offset_ms);
Tommi74fc5742020-04-27 10:43:06 +0200709}
710
711TEST_F(ReceiveStatisticsProxy2Test, AvSyncOffsetHistogramIsUpdated) {
712 const int64_t kVideoNtpMs = 21;
713 const int64_t kSyncOffsetMs = 22;
714 const double kFreqKhz = 90.0;
Tommi674b0c82020-05-10 21:52:17 +0200715 for (int i = 0; i < kMinRequiredSamples; ++i) {
Tommi74fc5742020-04-27 10:43:06 +0200716 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
717 kFreqKhz);
Tommi674b0c82020-05-10 21:52:17 +0200718 }
719 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200720 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.AVSyncOffsetInMs"));
721 EXPECT_METRIC_EQ(
722 1, metrics::NumEvents("WebRTC.Video.AVSyncOffsetInMs", kSyncOffsetMs));
723}
724
725TEST_F(ReceiveStatisticsProxy2Test, RtpToNtpFrequencyOffsetHistogramIsUpdated) {
726 const int64_t kVideoNtpMs = 21;
727 const int64_t kSyncOffsetMs = 22;
728 const double kFreqKhz = 90.0;
729 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs, kFreqKhz);
730 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
731 kFreqKhz + 2.2);
Tommi674b0c82020-05-10 21:52:17 +0200732 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200733 fake_clock_.AdvanceTimeMilliseconds(kFreqOffsetProcessIntervalInMs);
734 // Process interval passed, max diff: 2.
735 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
736 kFreqKhz + 1.1);
737 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
738 kFreqKhz - 4.2);
739 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
740 kFreqKhz - 0.9);
Tommi674b0c82020-05-10 21:52:17 +0200741 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200742 fake_clock_.AdvanceTimeMilliseconds(kFreqOffsetProcessIntervalInMs);
743 // Process interval passed, max diff: 4.
744 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs, kFreqKhz);
Tommi674b0c82020-05-10 21:52:17 +0200745 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200746 // Average reported: (2 + 4) / 2 = 3.
747 EXPECT_METRIC_EQ(1,
748 metrics::NumSamples("WebRTC.Video.RtpToNtpFreqOffsetInKhz"));
749 EXPECT_METRIC_EQ(
750 1, metrics::NumEvents("WebRTC.Video.RtpToNtpFreqOffsetInKhz", 3));
751}
752
753TEST_F(ReceiveStatisticsProxy2Test, Vp8QpHistogramIsUpdated) {
754 const int kQp = 22;
755
756 for (int i = 0; i < kMinRequiredSamples; ++i)
757 statistics_proxy_->OnPreDecode(kVideoCodecVP8, kQp);
758
Tommi674b0c82020-05-10 21:52:17 +0200759 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200760 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.Decoded.Vp8.Qp"));
761 EXPECT_METRIC_EQ(1, metrics::NumEvents("WebRTC.Video.Decoded.Vp8.Qp", kQp));
762}
763
764TEST_F(ReceiveStatisticsProxy2Test,
765 Vp8QpHistogramIsNotUpdatedForTooFewSamples) {
766 const int kQp = 22;
767
768 for (int i = 0; i < kMinRequiredSamples - 1; ++i)
769 statistics_proxy_->OnPreDecode(kVideoCodecVP8, kQp);
770
771 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
772 nullptr);
773 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.Decoded.Vp8.Qp"));
774}
775
776TEST_F(ReceiveStatisticsProxy2Test, Vp8QpHistogramIsNotUpdatedIfNoQpValue) {
777 for (int i = 0; i < kMinRequiredSamples; ++i)
778 statistics_proxy_->OnPreDecode(kVideoCodecVP8, -1);
779
780 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
781 nullptr);
782 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.Decoded.Vp8.Qp"));
783}
784
785TEST_F(ReceiveStatisticsProxy2Test,
786 KeyFrameHistogramNotUpdatedForTooFewSamples) {
787 const bool kIsKeyFrame = false;
788 const int kFrameSizeBytes = 1000;
789
790 for (int i = 0; i < kMinRequiredSamples - 1; ++i)
791 statistics_proxy_->OnCompleteFrame(kIsKeyFrame, kFrameSizeBytes,
792 VideoContentType::UNSPECIFIED);
793
794 EXPECT_EQ(0, statistics_proxy_->GetStats().frame_counts.key_frames);
795 EXPECT_EQ(kMinRequiredSamples - 1,
796 statistics_proxy_->GetStats().frame_counts.delta_frames);
797
798 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
799 nullptr);
800 EXPECT_METRIC_EQ(
801 0, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
802}
803
804TEST_F(ReceiveStatisticsProxy2Test,
805 KeyFrameHistogramUpdatedForMinRequiredSamples) {
806 const bool kIsKeyFrame = false;
807 const int kFrameSizeBytes = 1000;
808
809 for (int i = 0; i < kMinRequiredSamples; ++i)
810 statistics_proxy_->OnCompleteFrame(kIsKeyFrame, kFrameSizeBytes,
811 VideoContentType::UNSPECIFIED);
812
813 EXPECT_EQ(0, statistics_proxy_->GetStats().frame_counts.key_frames);
814 EXPECT_EQ(kMinRequiredSamples,
815 statistics_proxy_->GetStats().frame_counts.delta_frames);
816
817 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
818 nullptr);
819 EXPECT_METRIC_EQ(
820 1, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
821 EXPECT_METRIC_EQ(
822 1, metrics::NumEvents("WebRTC.Video.KeyFramesReceivedInPermille", 0));
823}
824
825TEST_F(ReceiveStatisticsProxy2Test, KeyFrameHistogramIsUpdated) {
826 const int kFrameSizeBytes = 1000;
827
828 for (int i = 0; i < kMinRequiredSamples; ++i)
829 statistics_proxy_->OnCompleteFrame(true, kFrameSizeBytes,
830 VideoContentType::UNSPECIFIED);
831
832 for (int i = 0; i < kMinRequiredSamples; ++i)
833 statistics_proxy_->OnCompleteFrame(false, kFrameSizeBytes,
834 VideoContentType::UNSPECIFIED);
835
836 EXPECT_EQ(kMinRequiredSamples,
837 statistics_proxy_->GetStats().frame_counts.key_frames);
838 EXPECT_EQ(kMinRequiredSamples,
839 statistics_proxy_->GetStats().frame_counts.delta_frames);
840
841 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
842 nullptr);
843 EXPECT_METRIC_EQ(
844 1, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
845 EXPECT_METRIC_EQ(
846 1, metrics::NumEvents("WebRTC.Video.KeyFramesReceivedInPermille", 500));
847}
848
849TEST_F(ReceiveStatisticsProxy2Test,
850 TimingHistogramsNotUpdatedForTooFewSamples) {
851 const int kMaxDecodeMs = 2;
852 const int kCurrentDelayMs = 3;
853 const int kTargetDelayMs = 4;
854 const int kJitterBufferMs = 5;
855 const int kMinPlayoutDelayMs = 6;
856 const int kRenderDelayMs = 7;
857
858 for (int i = 0; i < kMinRequiredSamples - 1; ++i) {
859 statistics_proxy_->OnFrameBufferTimingsUpdated(
860 kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
861 kMinPlayoutDelayMs, kRenderDelayMs);
862 }
863
864 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
865 nullptr);
866 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.DecodeTimeInMs"));
867 EXPECT_METRIC_EQ(0,
868 metrics::NumSamples("WebRTC.Video.JitterBufferDelayInMs"));
869 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.TargetDelayInMs"));
870 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.CurrentDelayInMs"));
871 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.OnewayDelayInMs"));
872}
873
874TEST_F(ReceiveStatisticsProxy2Test, TimingHistogramsAreUpdated) {
875 const int kMaxDecodeMs = 2;
876 const int kCurrentDelayMs = 3;
877 const int kTargetDelayMs = 4;
878 const int kJitterBufferMs = 5;
879 const int kMinPlayoutDelayMs = 6;
880 const int kRenderDelayMs = 7;
881
882 for (int i = 0; i < kMinRequiredSamples; ++i) {
883 statistics_proxy_->OnFrameBufferTimingsUpdated(
884 kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
885 kMinPlayoutDelayMs, kRenderDelayMs);
886 }
887
Tommi674b0c82020-05-10 21:52:17 +0200888 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200889 EXPECT_METRIC_EQ(1,
890 metrics::NumSamples("WebRTC.Video.JitterBufferDelayInMs"));
891 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.TargetDelayInMs"));
892 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.CurrentDelayInMs"));
893 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.OnewayDelayInMs"));
894
895 EXPECT_METRIC_EQ(1, metrics::NumEvents("WebRTC.Video.JitterBufferDelayInMs",
896 kJitterBufferMs));
897 EXPECT_METRIC_EQ(
898 1, metrics::NumEvents("WebRTC.Video.TargetDelayInMs", kTargetDelayMs));
899 EXPECT_METRIC_EQ(
900 1, metrics::NumEvents("WebRTC.Video.CurrentDelayInMs", kCurrentDelayMs));
901 EXPECT_METRIC_EQ(
902 1, metrics::NumEvents("WebRTC.Video.OnewayDelayInMs", kTargetDelayMs));
903}
904
905TEST_F(ReceiveStatisticsProxy2Test, DoesNotReportStaleFramerates) {
906 const int kDefaultFps = 30;
907 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
908
909 for (int i = 0; i < kDefaultFps; ++i) {
910 // Since OnRenderedFrame is never called the fps in each sample will be 0,
911 // i.e. bad
912 frame.set_ntp_time_ms(fake_clock_.CurrentNtpInMilliseconds());
913 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
914 VideoContentType::UNSPECIFIED);
Tommid7e08c82020-05-10 11:24:43 +0200915 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200916 fake_clock_.AdvanceTimeMilliseconds(1000 / kDefaultFps);
917 }
918
Tommid93bf122020-05-10 20:24:59 +0200919 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200920 EXPECT_EQ(kDefaultFps, statistics_proxy_->GetStats().decode_frame_rate);
921 EXPECT_EQ(kDefaultFps, statistics_proxy_->GetStats().render_frame_rate);
922
923 // FPS trackers in stats proxy have a 1000ms sliding window.
924 fake_clock_.AdvanceTimeMilliseconds(1000);
925 EXPECT_EQ(0, statistics_proxy_->GetStats().decode_frame_rate);
926 EXPECT_EQ(0, statistics_proxy_->GetStats().render_frame_rate);
927}
928
929TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsReceivedFrameStats) {
930 EXPECT_EQ(0, statistics_proxy_->GetStats().width);
931 EXPECT_EQ(0, statistics_proxy_->GetStats().height);
932 EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_rendered);
933
Tommid7e08c82020-05-10 11:24:43 +0200934 statistics_proxy_->OnRenderedFrame(MetaData(CreateFrame(kWidth, kHeight)));
Tommi74fc5742020-04-27 10:43:06 +0200935
936 EXPECT_EQ(kWidth, statistics_proxy_->GetStats().width);
937 EXPECT_EQ(kHeight, statistics_proxy_->GetStats().height);
938 EXPECT_EQ(1u, statistics_proxy_->GetStats().frames_rendered);
939}
940
941TEST_F(ReceiveStatisticsProxy2Test,
942 ReceivedFrameHistogramsAreNotUpdatedForTooFewSamples) {
Tommid7e08c82020-05-10 11:24:43 +0200943 for (int i = 0; i < kMinRequiredSamples - 1; ++i) {
944 statistics_proxy_->OnRenderedFrame(MetaData(CreateFrame(kWidth, kHeight)));
945 }
Tommi74fc5742020-04-27 10:43:06 +0200946
947 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
948 nullptr);
949 EXPECT_METRIC_EQ(0,
950 metrics::NumSamples("WebRTC.Video.ReceivedWidthInPixels"));
951 EXPECT_METRIC_EQ(0,
952 metrics::NumSamples("WebRTC.Video.ReceivedHeightInPixels"));
953 EXPECT_METRIC_EQ(0,
954 metrics::NumSamples("WebRTC.Video.RenderFramesPerSecond"));
955 EXPECT_METRIC_EQ(
956 0, metrics::NumSamples("WebRTC.Video.RenderSqrtPixelsPerSecond"));
957}
958
959TEST_F(ReceiveStatisticsProxy2Test, ReceivedFrameHistogramsAreUpdated) {
Tommid7e08c82020-05-10 11:24:43 +0200960 for (int i = 0; i < kMinRequiredSamples; ++i) {
961 statistics_proxy_->OnRenderedFrame(MetaData(CreateFrame(kWidth, kHeight)));
962 }
Tommi74fc5742020-04-27 10:43:06 +0200963
964 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
965 nullptr);
966 EXPECT_METRIC_EQ(1,
967 metrics::NumSamples("WebRTC.Video.ReceivedWidthInPixels"));
968 EXPECT_METRIC_EQ(1,
969 metrics::NumSamples("WebRTC.Video.ReceivedHeightInPixels"));
970 EXPECT_METRIC_EQ(1,
971 metrics::NumSamples("WebRTC.Video.RenderFramesPerSecond"));
972 EXPECT_METRIC_EQ(
973 1, metrics::NumSamples("WebRTC.Video.RenderSqrtPixelsPerSecond"));
974 EXPECT_METRIC_EQ(
975 1, metrics::NumEvents("WebRTC.Video.ReceivedWidthInPixels", kWidth));
976 EXPECT_METRIC_EQ(
977 1, metrics::NumEvents("WebRTC.Video.ReceivedHeightInPixels", kHeight));
978}
979
980TEST_F(ReceiveStatisticsProxy2Test, ZeroDelayReportedIfFrameNotDelayed) {
981 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
982 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
983 VideoContentType::UNSPECIFIED);
984
985 // Frame not delayed, delayed frames to render: 0%.
Tommid7e08c82020-05-10 11:24:43 +0200986 statistics_proxy_->OnRenderedFrame(
987 MetaData(CreateFrameWithRenderTime(Now())));
Tommi74fc5742020-04-27 10:43:06 +0200988
989 // Min run time has passed.
990 fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
Tommid93bf122020-05-10 20:24:59 +0200991 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200992 EXPECT_METRIC_EQ(1,
993 metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
994 EXPECT_METRIC_EQ(
995 1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer", 0));
996 EXPECT_METRIC_EQ(0, metrics::NumSamples(
997 "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
998}
999
1000TEST_F(ReceiveStatisticsProxy2Test,
1001 DelayedFrameHistogramsAreNotUpdatedIfMinRuntimeHasNotPassed) {
1002 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1003 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
1004 VideoContentType::UNSPECIFIED);
1005
1006 // Frame not delayed, delayed frames to render: 0%.
Tommid7e08c82020-05-10 11:24:43 +02001007 statistics_proxy_->OnRenderedFrame(
1008 MetaData(CreateFrameWithRenderTime(Now())));
Tommi74fc5742020-04-27 10:43:06 +02001009
1010 // Min run time has not passed.
1011 fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000) -
1012 1);
1013 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
1014 nullptr);
1015 EXPECT_METRIC_EQ(0,
1016 metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
1017 EXPECT_METRIC_EQ(0, metrics::NumSamples(
1018 "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
1019}
1020
1021TEST_F(ReceiveStatisticsProxy2Test,
1022 DelayedFramesHistogramsAreNotUpdatedIfNoRenderedFrames) {
1023 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1024 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
1025 VideoContentType::UNSPECIFIED);
1026
1027 // Min run time has passed. No rendered frames.
1028 fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
1029 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
1030 nullptr);
1031 EXPECT_METRIC_EQ(0,
1032 metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
1033 EXPECT_METRIC_EQ(0, metrics::NumSamples(
1034 "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
1035}
1036
1037TEST_F(ReceiveStatisticsProxy2Test, DelayReportedIfFrameIsDelayed) {
1038 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1039 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
1040 VideoContentType::UNSPECIFIED);
1041
1042 // Frame delayed 1 ms, delayed frames to render: 100%.
Tommid7e08c82020-05-10 11:24:43 +02001043 statistics_proxy_->OnRenderedFrame(
1044 MetaData(CreateFrameWithRenderTimeMs(Now().ms() - 1)));
Tommi74fc5742020-04-27 10:43:06 +02001045
1046 // Min run time has passed.
1047 fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
Tommid93bf122020-05-10 20:24:59 +02001048 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001049 EXPECT_METRIC_EQ(1,
1050 metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
1051 EXPECT_METRIC_EQ(
1052 1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer", 100));
1053 EXPECT_METRIC_EQ(1, metrics::NumSamples(
1054 "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
1055 EXPECT_METRIC_EQ(
1056 1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs",
1057 1));
1058}
1059
1060TEST_F(ReceiveStatisticsProxy2Test, AverageDelayOfDelayedFramesIsReported) {
1061 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1062 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
1063 VideoContentType::UNSPECIFIED);
1064
1065 // Two frames delayed (6 ms, 10 ms), delayed frames to render: 50%.
Tommid7e08c82020-05-10 11:24:43 +02001066 const int64_t kNowMs = Now().ms();
1067
1068 statistics_proxy_->OnRenderedFrame(
1069 MetaData(CreateFrameWithRenderTimeMs(kNowMs - 10)));
1070 statistics_proxy_->OnRenderedFrame(
1071 MetaData(CreateFrameWithRenderTimeMs(kNowMs - 6)));
1072 statistics_proxy_->OnRenderedFrame(
1073 MetaData(CreateFrameWithRenderTimeMs(kNowMs)));
1074 statistics_proxy_->OnRenderedFrame(
1075 MetaData(CreateFrameWithRenderTimeMs(kNowMs + 1)));
Tommi74fc5742020-04-27 10:43:06 +02001076
1077 // Min run time has passed.
1078 fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
Tommid93bf122020-05-10 20:24:59 +02001079 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001080 EXPECT_METRIC_EQ(1,
1081 metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
1082 EXPECT_METRIC_EQ(
1083 1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer", 50));
1084 EXPECT_METRIC_EQ(1, metrics::NumSamples(
1085 "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
1086 EXPECT_METRIC_EQ(
1087 1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs",
1088 8));
1089}
1090
1091TEST_F(ReceiveStatisticsProxy2Test,
1092 RtcpHistogramsNotUpdatedIfMinRuntimeHasNotPassed) {
1093 StreamDataCounters data_counters;
1094 data_counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
1095
1096 fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000) -
1097 1);
1098
1099 RtcpPacketTypeCounter counter;
1100 statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc, counter);
1101
1102 statistics_proxy_->UpdateHistograms(absl::nullopt, data_counters, nullptr);
1103 EXPECT_METRIC_EQ(0,
1104 metrics::NumSamples("WebRTC.Video.FirPacketsSentPerMinute"));
1105 EXPECT_METRIC_EQ(0,
1106 metrics::NumSamples("WebRTC.Video.PliPacketsSentPerMinute"));
1107 EXPECT_METRIC_EQ(
1108 0, metrics::NumSamples("WebRTC.Video.NackPacketsSentPerMinute"));
1109}
1110
1111TEST_F(ReceiveStatisticsProxy2Test, RtcpHistogramsAreUpdated) {
1112 StreamDataCounters data_counters;
1113 data_counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
1114 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
1115
1116 const uint32_t kFirPackets = 100;
1117 const uint32_t kPliPackets = 200;
1118 const uint32_t kNackPackets = 300;
1119
1120 RtcpPacketTypeCounter counter;
1121 counter.fir_packets = kFirPackets;
1122 counter.pli_packets = kPliPackets;
1123 counter.nack_packets = kNackPackets;
1124 statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc, counter);
1125
1126 statistics_proxy_->UpdateHistograms(absl::nullopt, data_counters, nullptr);
1127 EXPECT_METRIC_EQ(1,
1128 metrics::NumSamples("WebRTC.Video.FirPacketsSentPerMinute"));
1129 EXPECT_METRIC_EQ(1,
1130 metrics::NumSamples("WebRTC.Video.PliPacketsSentPerMinute"));
1131 EXPECT_METRIC_EQ(
1132 1, metrics::NumSamples("WebRTC.Video.NackPacketsSentPerMinute"));
1133 EXPECT_METRIC_EQ(
1134 1, metrics::NumEvents("WebRTC.Video.FirPacketsSentPerMinute",
1135 kFirPackets * 60 / metrics::kMinRunTimeInSeconds));
1136 EXPECT_METRIC_EQ(
1137 1, metrics::NumEvents("WebRTC.Video.PliPacketsSentPerMinute",
1138 kPliPackets * 60 / metrics::kMinRunTimeInSeconds));
1139 EXPECT_METRIC_EQ(
1140 1, metrics::NumEvents("WebRTC.Video.NackPacketsSentPerMinute",
1141 kNackPackets * 60 / metrics::kMinRunTimeInSeconds));
1142}
1143
1144class ReceiveStatisticsProxy2TestWithFreezeDuration
1145 : public ReceiveStatisticsProxy2Test,
1146 public ::testing::WithParamInterface<
1147 std::tuple<uint32_t, uint32_t, uint32_t>> {
1148 protected:
1149 const uint32_t frame_duration_ms_ = {std::get<0>(GetParam())};
1150 const uint32_t freeze_duration_ms_ = {std::get<1>(GetParam())};
1151 const uint32_t expected_freeze_count_ = {std::get<2>(GetParam())};
1152};
1153
1154// It is a freeze if:
1155// frame_duration_ms >= max(3 * avg_frame_duration, avg_frame_duration + 150)
1156// where avg_frame_duration is average duration of last 30 frames including
1157// the current one.
1158//
1159// Condition 1: 3 * avg_frame_duration > avg_frame_duration + 150
1160const auto kFreezeDetectionCond1Freeze = std::make_tuple(150, 483, 1);
1161const auto kFreezeDetectionCond1NotFreeze = std::make_tuple(150, 482, 0);
1162// Condition 2: 3 * avg_frame_duration < avg_frame_duration + 150
1163const auto kFreezeDetectionCond2Freeze = std::make_tuple(30, 185, 1);
1164const auto kFreezeDetectionCond2NotFreeze = std::make_tuple(30, 184, 0);
1165
1166INSTANTIATE_TEST_SUITE_P(_,
1167 ReceiveStatisticsProxy2TestWithFreezeDuration,
1168 ::testing::Values(kFreezeDetectionCond1Freeze,
1169 kFreezeDetectionCond1NotFreeze,
1170 kFreezeDetectionCond2Freeze,
1171 kFreezeDetectionCond2NotFreeze));
1172
1173TEST_P(ReceiveStatisticsProxy2TestWithFreezeDuration, FreezeDetection) {
1174 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
1175 EXPECT_EQ(0u, stats.freeze_count);
1176 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1177
1178 // Add a very long frame. This is need to verify that average frame
1179 // duration, which is supposed to be calculated as mean of durations of
1180 // last 30 frames, is calculated correctly.
Tommid7e08c82020-05-10 11:24:43 +02001181 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001182 fake_clock_.AdvanceTimeMilliseconds(2000);
1183
1184 for (size_t i = 0;
1185 i <= VideoQualityObserver::kAvgInterframeDelaysWindowSizeFrames; ++i) {
1186 fake_clock_.AdvanceTimeMilliseconds(frame_duration_ms_);
Tommid7e08c82020-05-10 11:24:43 +02001187 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001188 }
1189
1190 fake_clock_.AdvanceTimeMilliseconds(freeze_duration_ms_);
Tommid7e08c82020-05-10 11:24:43 +02001191 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001192
1193 stats = statistics_proxy_->GetStats();
1194 EXPECT_EQ(stats.freeze_count, expected_freeze_count_);
1195}
1196
1197class ReceiveStatisticsProxy2TestWithContent
1198 : public ReceiveStatisticsProxy2Test,
1199 public ::testing::WithParamInterface<webrtc::VideoContentType> {
1200 protected:
1201 const webrtc::VideoContentType content_type_{GetParam()};
1202};
1203
1204INSTANTIATE_TEST_SUITE_P(ContentTypes,
1205 ReceiveStatisticsProxy2TestWithContent,
1206 ::testing::Values(VideoContentType::UNSPECIFIED,
1207 VideoContentType::SCREENSHARE));
1208
1209TEST_P(ReceiveStatisticsProxy2TestWithContent, InterFrameDelaysAreReported) {
1210 const int kInterFrameDelayMs = 33;
1211 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1212
1213 for (int i = 0; i < kMinRequiredSamples; ++i) {
1214 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1215 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1216 }
1217 // One extra with double the interval.
1218 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1219 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1220
Tommid93bf122020-05-10 20:24:59 +02001221 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001222 const int kExpectedInterFrame =
1223 (kInterFrameDelayMs * (kMinRequiredSamples - 1) +
1224 kInterFrameDelayMs * 2) /
1225 kMinRequiredSamples;
1226 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1227 EXPECT_METRIC_EQ(
1228 kExpectedInterFrame,
1229 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs"));
1230 EXPECT_METRIC_EQ(
1231 kInterFrameDelayMs * 2,
1232 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
1233 } else {
1234 EXPECT_METRIC_EQ(kExpectedInterFrame,
1235 metrics::MinSample("WebRTC.Video.InterframeDelayInMs"));
1236 EXPECT_METRIC_EQ(kInterFrameDelayMs * 2,
1237 metrics::MinSample("WebRTC.Video.InterframeDelayMaxInMs"));
1238 }
1239}
1240
1241TEST_P(ReceiveStatisticsProxy2TestWithContent,
1242 InterFrameDelaysPercentilesAreReported) {
1243 const int kInterFrameDelayMs = 33;
1244 const int kLastFivePercentsSamples = kMinRequiredSamples * 5 / 100;
1245 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1246
1247 for (int i = 0; i <= kMinRequiredSamples - kLastFivePercentsSamples; ++i) {
1248 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1249 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1250 }
1251 // Last 5% of intervals are double in size.
1252 for (int i = 0; i < kLastFivePercentsSamples; ++i) {
1253 fake_clock_.AdvanceTimeMilliseconds(2 * kInterFrameDelayMs);
1254 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1255 }
1256 // Final sample is outlier and 10 times as big.
1257 fake_clock_.AdvanceTimeMilliseconds(10 * kInterFrameDelayMs);
1258 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1259
Tommid93bf122020-05-10 20:24:59 +02001260 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001261 const int kExpectedInterFrame = kInterFrameDelayMs * 2;
1262 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1263 EXPECT_METRIC_EQ(
1264 kExpectedInterFrame,
1265 metrics::MinSample(
1266 "WebRTC.Video.Screenshare.InterframeDelay95PercentileInMs"));
1267 } else {
1268 EXPECT_METRIC_EQ(
1269 kExpectedInterFrame,
1270 metrics::MinSample("WebRTC.Video.InterframeDelay95PercentileInMs"));
1271 }
1272}
1273
1274TEST_P(ReceiveStatisticsProxy2TestWithContent,
1275 MaxInterFrameDelayOnlyWithValidAverage) {
1276 const int kInterFrameDelayMs = 33;
1277 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1278
1279 for (int i = 0; i < kMinRequiredSamples; ++i) {
1280 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1281 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1282 }
1283
Artem Titovab30d722021-07-27 16:22:11 +02001284 // `kMinRequiredSamples` samples, and thereby intervals, is required. That
Tommi74fc5742020-04-27 10:43:06 +02001285 // means we're one frame short of having a valid data set.
1286 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
1287 nullptr);
1288 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"));
1289 EXPECT_METRIC_EQ(0,
1290 metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"));
1291 EXPECT_METRIC_EQ(
1292 0, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"));
1293 EXPECT_METRIC_EQ(0, metrics::NumSamples(
1294 "WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
1295}
1296
1297TEST_P(ReceiveStatisticsProxy2TestWithContent,
1298 MaxInterFrameDelayOnlyWithPause) {
1299 const int kInterFrameDelayMs = 33;
1300 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1301
1302 for (int i = 0; i <= kMinRequiredSamples; ++i) {
1303 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1304 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1305 }
1306
Tommid93bf122020-05-10 20:24:59 +02001307 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +02001308 // At this state, we should have a valid inter-frame delay.
1309 // Indicate stream paused and make a large jump in time.
1310 statistics_proxy_->OnStreamInactive();
1311 fake_clock_.AdvanceTimeMilliseconds(5000);
1312
Tommid7e08c82020-05-10 11:24:43 +02001313 // Insert two more frames. The interval during the pause should be
1314 // disregarded in the stats.
Tommi74fc5742020-04-27 10:43:06 +02001315 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1316 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1317 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1318
Tommid93bf122020-05-10 20:24:59 +02001319 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001320 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1321 EXPECT_METRIC_EQ(
1322 1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"));
1323 EXPECT_METRIC_EQ(1, metrics::NumSamples(
1324 "WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
1325 EXPECT_METRIC_EQ(
1326 kInterFrameDelayMs,
1327 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs"));
1328 EXPECT_METRIC_EQ(
1329 kInterFrameDelayMs,
1330 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
1331 } else {
1332 EXPECT_METRIC_EQ(1,
1333 metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"));
1334 EXPECT_METRIC_EQ(
1335 1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"));
1336 EXPECT_METRIC_EQ(kInterFrameDelayMs,
1337 metrics::MinSample("WebRTC.Video.InterframeDelayInMs"));
1338 EXPECT_METRIC_EQ(kInterFrameDelayMs,
1339 metrics::MinSample("WebRTC.Video.InterframeDelayMaxInMs"));
1340 }
1341}
1342
1343TEST_P(ReceiveStatisticsProxy2TestWithContent, FreezesAreReported) {
1344 const int kInterFrameDelayMs = 33;
1345 const int kFreezeDelayMs = 200;
1346 const int kCallDurationMs =
1347 kMinRequiredSamples * kInterFrameDelayMs + kFreezeDelayMs;
1348 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1349
1350 for (int i = 0; i < kMinRequiredSamples; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001351 VideoFrameMetaData meta = MetaData(frame);
1352 statistics_proxy_->OnDecodedFrame(meta, absl::nullopt, 0, content_type_);
1353 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001354 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1355 }
1356 // Add extra freeze.
1357 fake_clock_.AdvanceTimeMilliseconds(kFreezeDelayMs);
Tommid93bf122020-05-10 20:24:59 +02001358 VideoFrameMetaData meta = MetaData(frame);
1359 statistics_proxy_->OnDecodedFrame(meta, absl::nullopt, 0, content_type_);
1360 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001361
Tommid93bf122020-05-10 20:24:59 +02001362 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001363 const int kExpectedTimeBetweenFreezes =
1364 kInterFrameDelayMs * (kMinRequiredSamples - 1);
1365 const int kExpectedNumberFreezesPerMinute = 60 * 1000 / kCallDurationMs;
1366 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1367 EXPECT_METRIC_EQ(
1368 kFreezeDelayMs + kInterFrameDelayMs,
1369 metrics::MinSample("WebRTC.Video.Screenshare.MeanFreezeDurationMs"));
1370 EXPECT_METRIC_EQ(kExpectedTimeBetweenFreezes,
1371 metrics::MinSample(
1372 "WebRTC.Video.Screenshare.MeanTimeBetweenFreezesMs"));
1373 EXPECT_METRIC_EQ(
1374 kExpectedNumberFreezesPerMinute,
1375 metrics::MinSample("WebRTC.Video.Screenshare.NumberFreezesPerMinute"));
1376 } else {
1377 EXPECT_METRIC_EQ(kFreezeDelayMs + kInterFrameDelayMs,
1378 metrics::MinSample("WebRTC.Video.MeanFreezeDurationMs"));
1379 EXPECT_METRIC_EQ(
1380 kExpectedTimeBetweenFreezes,
1381 metrics::MinSample("WebRTC.Video.MeanTimeBetweenFreezesMs"));
1382 EXPECT_METRIC_EQ(kExpectedNumberFreezesPerMinute,
1383 metrics::MinSample("WebRTC.Video.NumberFreezesPerMinute"));
1384 }
1385}
1386
1387TEST_P(ReceiveStatisticsProxy2TestWithContent, HarmonicFrameRateIsReported) {
1388 const int kFrameDurationMs = 33;
1389 const int kFreezeDurationMs = 200;
1390 const int kPauseDurationMs = 10000;
1391 const int kCallDurationMs = kMinRequiredSamples * kFrameDurationMs +
1392 kFreezeDurationMs + kPauseDurationMs;
1393 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1394
1395 for (int i = 0; i < kMinRequiredSamples; ++i) {
1396 fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs);
1397 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
Tommid7e08c82020-05-10 11:24:43 +02001398 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001399 }
1400
1401 // Freezes and pauses should be included into harmonic frame rate.
1402 // Add freeze.
Tommid93bf122020-05-10 20:24:59 +02001403 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +02001404 fake_clock_.AdvanceTimeMilliseconds(kFreezeDurationMs);
1405 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
Tommid7e08c82020-05-10 11:24:43 +02001406 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001407
1408 // Add pause.
Tommid93bf122020-05-10 20:24:59 +02001409 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +02001410 fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
1411 statistics_proxy_->OnStreamInactive();
1412 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
Tommid7e08c82020-05-10 11:24:43 +02001413 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001414
Tommid93bf122020-05-10 20:24:59 +02001415 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001416 double kSumSquaredFrameDurationSecs =
1417 (kMinRequiredSamples - 1) *
1418 (kFrameDurationMs / 1000.0 * kFrameDurationMs / 1000.0);
1419 kSumSquaredFrameDurationSecs +=
1420 kFreezeDurationMs / 1000.0 * kFreezeDurationMs / 1000.0;
1421 kSumSquaredFrameDurationSecs +=
1422 kPauseDurationMs / 1000.0 * kPauseDurationMs / 1000.0;
1423 const int kExpectedHarmonicFrameRateFps =
1424 std::round(kCallDurationMs / (1000 * kSumSquaredFrameDurationSecs));
1425 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1426 EXPECT_METRIC_EQ(
1427 kExpectedHarmonicFrameRateFps,
1428 metrics::MinSample("WebRTC.Video.Screenshare.HarmonicFrameRate"));
1429 } else {
1430 EXPECT_METRIC_EQ(kExpectedHarmonicFrameRateFps,
1431 metrics::MinSample("WebRTC.Video.HarmonicFrameRate"));
1432 }
1433}
1434
1435TEST_P(ReceiveStatisticsProxy2TestWithContent, PausesAreIgnored) {
1436 const int kInterFrameDelayMs = 33;
1437 const int kPauseDurationMs = 10000;
1438 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1439
1440 for (int i = 0; i <= kMinRequiredSamples; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001441 VideoFrameMetaData meta = MetaData(frame);
1442 statistics_proxy_->OnDecodedFrame(meta, absl::nullopt, 0, content_type_);
1443 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001444 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1445 }
1446 // Add a pause.
1447 fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
1448 statistics_proxy_->OnStreamInactive();
Tommi74fc5742020-04-27 10:43:06 +02001449 // Second playback interval with triple the length.
1450 for (int i = 0; i <= kMinRequiredSamples * 3; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001451 VideoFrameMetaData meta = MetaData(frame);
1452 statistics_proxy_->OnDecodedFrame(meta, absl::nullopt, 0, content_type_);
1453 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001454 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1455 }
1456
Tommid93bf122020-05-10 20:24:59 +02001457 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001458 // Average of two playback intervals.
1459 const int kExpectedTimeBetweenFreezes =
1460 kInterFrameDelayMs * kMinRequiredSamples * 2;
1461 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1462 EXPECT_METRIC_EQ(-1, metrics::MinSample(
1463 "WebRTC.Video.Screenshare.MeanFreezeDurationMs"));
1464 EXPECT_METRIC_EQ(kExpectedTimeBetweenFreezes,
1465 metrics::MinSample(
1466 "WebRTC.Video.Screenshare.MeanTimeBetweenFreezesMs"));
1467 } else {
1468 EXPECT_METRIC_EQ(-1,
1469 metrics::MinSample("WebRTC.Video.MeanFreezeDurationMs"));
1470 EXPECT_METRIC_EQ(
1471 kExpectedTimeBetweenFreezes,
1472 metrics::MinSample("WebRTC.Video.MeanTimeBetweenFreezesMs"));
1473 }
1474}
1475
1476TEST_P(ReceiveStatisticsProxy2TestWithContent, ManyPausesAtTheBeginning) {
1477 const int kInterFrameDelayMs = 33;
1478 const int kPauseDurationMs = 10000;
1479 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1480
1481 for (int i = 0; i <= kMinRequiredSamples; ++i) {
1482 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1483 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1484
1485 statistics_proxy_->OnStreamInactive();
1486 fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
1487
1488 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1489 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1490 }
1491
1492 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
1493 nullptr);
Tommid7e08c82020-05-10 11:24:43 +02001494 // No freezes should be detected, as all long inter-frame delays were
1495 // pauses.
Tommi74fc5742020-04-27 10:43:06 +02001496 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1497 EXPECT_METRIC_EQ(-1, metrics::MinSample(
1498 "WebRTC.Video.Screenshare.MeanFreezeDurationMs"));
1499 } else {
1500 EXPECT_METRIC_EQ(-1,
1501 metrics::MinSample("WebRTC.Video.MeanFreezeDurationMs"));
1502 }
1503}
1504
1505TEST_P(ReceiveStatisticsProxy2TestWithContent, TimeInHdReported) {
1506 const int kInterFrameDelayMs = 20;
1507 webrtc::VideoFrame frame_hd = CreateFrame(1280, 720);
1508 webrtc::VideoFrame frame_sd = CreateFrame(640, 360);
1509
1510 // HD frames.
1511 for (int i = 0; i < kMinRequiredSamples; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001512 VideoFrameMetaData meta = MetaData(frame_hd);
1513 statistics_proxy_->OnDecodedFrame(meta, absl::nullopt, 0, content_type_);
1514 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001515 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1516 }
1517 // SD frames.
1518 for (int i = 0; i < 2 * kMinRequiredSamples; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001519 VideoFrameMetaData meta = MetaData(frame_sd);
1520 statistics_proxy_->OnDecodedFrame(meta, absl::nullopt, 0, content_type_);
1521 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001522 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1523 }
1524 // Extra last frame.
Tommid7e08c82020-05-10 11:24:43 +02001525 statistics_proxy_->OnRenderedFrame(MetaData(frame_sd));
Tommi74fc5742020-04-27 10:43:06 +02001526
1527 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
1528 nullptr);
1529 const int kExpectedTimeInHdPercents = 33;
1530 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1531 EXPECT_METRIC_EQ(
1532 kExpectedTimeInHdPercents,
1533 metrics::MinSample("WebRTC.Video.Screenshare.TimeInHdPercentage"));
1534 } else {
1535 EXPECT_METRIC_EQ(kExpectedTimeInHdPercents,
1536 metrics::MinSample("WebRTC.Video.TimeInHdPercentage"));
1537 }
1538}
1539
1540TEST_P(ReceiveStatisticsProxy2TestWithContent, TimeInBlockyVideoReported) {
1541 const int kInterFrameDelayMs = 20;
1542 const int kHighQp = 80;
1543 const int kLowQp = 30;
1544 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1545
1546 // High quality frames.
1547 for (int i = 0; i < kMinRequiredSamples; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001548 VideoFrameMetaData meta = MetaData(frame);
1549 statistics_proxy_->OnDecodedFrame(meta, kLowQp, 0, content_type_);
1550 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001551 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1552 }
1553 // Blocky frames.
1554 for (int i = 0; i < 2 * kMinRequiredSamples; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001555 VideoFrameMetaData meta = MetaData(frame);
1556 statistics_proxy_->OnDecodedFrame(meta, kHighQp, 0, content_type_);
1557 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001558 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1559 }
1560 // Extra last frame.
1561 statistics_proxy_->OnDecodedFrame(frame, kHighQp, 0, content_type_);
Tommid7e08c82020-05-10 11:24:43 +02001562 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001563
Tommid93bf122020-05-10 20:24:59 +02001564 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001565 const int kExpectedTimeInHdPercents = 66;
1566 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1567 EXPECT_METRIC_EQ(
1568 kExpectedTimeInHdPercents,
1569 metrics::MinSample(
1570 "WebRTC.Video.Screenshare.TimeInBlockyVideoPercentage"));
1571 } else {
1572 EXPECT_METRIC_EQ(
1573 kExpectedTimeInHdPercents,
1574 metrics::MinSample("WebRTC.Video.TimeInBlockyVideoPercentage"));
1575 }
1576}
1577
1578TEST_P(ReceiveStatisticsProxy2TestWithContent, DownscalesReported) {
1579 const int kInterFrameDelayMs = 2000; // To ensure long enough call duration.
1580
1581 webrtc::VideoFrame frame_hd = CreateFrame(1280, 720);
1582 webrtc::VideoFrame frame_sd = CreateFrame(640, 360);
1583 webrtc::VideoFrame frame_ld = CreateFrame(320, 180);
1584
1585 // Call once to pass content type.
1586 statistics_proxy_->OnDecodedFrame(frame_hd, absl::nullopt, 0, content_type_);
1587
Tommid93bf122020-05-10 20:24:59 +02001588 loop_.Flush();
Tommid7e08c82020-05-10 11:24:43 +02001589 statistics_proxy_->OnRenderedFrame(MetaData(frame_hd));
Tommi74fc5742020-04-27 10:43:06 +02001590 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1591
1592 // Downscale.
Tommid7e08c82020-05-10 11:24:43 +02001593 statistics_proxy_->OnRenderedFrame(MetaData(frame_sd));
Tommi74fc5742020-04-27 10:43:06 +02001594 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1595
1596 // Downscale.
Tommid7e08c82020-05-10 11:24:43 +02001597 statistics_proxy_->OnRenderedFrame(MetaData(frame_ld));
Tommi74fc5742020-04-27 10:43:06 +02001598 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1599
1600 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
1601 nullptr);
1602 const int kExpectedDownscales = 30; // 2 per 4 seconds = 30 per minute.
1603 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1604 EXPECT_METRIC_EQ(
1605 kExpectedDownscales,
Tommid7e08c82020-05-10 11:24:43 +02001606 metrics::MinSample("WebRTC.Video.Screenshare."
1607 "NumberResolutionDownswitchesPerMinute"));
Tommi74fc5742020-04-27 10:43:06 +02001608 } else {
1609 EXPECT_METRIC_EQ(kExpectedDownscales,
1610 metrics::MinSample(
1611 "WebRTC.Video.NumberResolutionDownswitchesPerMinute"));
1612 }
1613}
1614
1615TEST_P(ReceiveStatisticsProxy2TestWithContent, DecodeTimeReported) {
1616 const int kInterFrameDelayMs = 20;
1617 const int kLowQp = 30;
1618 const int kDecodeMs = 7;
1619
1620 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1621
1622 for (int i = 0; i < kMinRequiredSamples; ++i) {
1623 statistics_proxy_->OnDecodedFrame(frame, kLowQp, kDecodeMs, content_type_);
1624 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1625 }
Tommid93bf122020-05-10 20:24:59 +02001626 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001627 EXPECT_METRIC_EQ(
1628 1, metrics::NumEvents("WebRTC.Video.DecodeTimeInMs", kDecodeMs));
1629}
1630
1631TEST_P(ReceiveStatisticsProxy2TestWithContent,
1632 StatsAreSlicedOnSimulcastAndExperiment) {
1633 const uint8_t experiment_id = 1;
1634 webrtc::VideoContentType content_type = content_type_;
1635 videocontenttypehelpers::SetExperimentId(&content_type, experiment_id);
1636 const int kInterFrameDelayMs1 = 30;
1637 const int kInterFrameDelayMs2 = 50;
1638 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1639
1640 videocontenttypehelpers::SetSimulcastId(&content_type, 1);
1641 for (int i = 0; i <= kMinRequiredSamples; ++i) {
1642 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs1);
1643 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type);
1644 }
1645
1646 videocontenttypehelpers::SetSimulcastId(&content_type, 2);
1647 for (int i = 0; i <= kMinRequiredSamples; ++i) {
1648 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs2);
1649 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type);
1650 }
Tommid93bf122020-05-10 20:24:59 +02001651 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001652
1653 if (videocontenttypehelpers::IsScreenshare(content_type)) {
1654 EXPECT_METRIC_EQ(
1655 1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"));
1656 EXPECT_METRIC_EQ(1, metrics::NumSamples(
1657 "WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
1658 EXPECT_METRIC_EQ(1, metrics::NumSamples(
1659 "WebRTC.Video.Screenshare.InterframeDelayInMs.S0"));
1660 EXPECT_METRIC_EQ(1,
1661 metrics::NumSamples(
1662 "WebRTC.Video.Screenshare.InterframeDelayMaxInMs.S0"));
1663 EXPECT_METRIC_EQ(1, metrics::NumSamples(
1664 "WebRTC.Video.Screenshare.InterframeDelayInMs.S1"));
1665 EXPECT_METRIC_EQ(1,
1666 metrics::NumSamples(
1667 "WebRTC.Video.Screenshare.InterframeDelayMaxInMs.S1"));
1668 EXPECT_METRIC_EQ(
1669 1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"
1670 ".ExperimentGroup0"));
1671 EXPECT_METRIC_EQ(
1672 1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayMaxInMs"
1673 ".ExperimentGroup0"));
1674 EXPECT_METRIC_EQ(
1675 kInterFrameDelayMs1,
1676 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs.S0"));
1677 EXPECT_METRIC_EQ(
1678 kInterFrameDelayMs2,
1679 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs.S1"));
1680 EXPECT_METRIC_EQ(
1681 (kInterFrameDelayMs1 + kInterFrameDelayMs2) / 2,
1682 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs"));
1683 EXPECT_METRIC_EQ(
1684 kInterFrameDelayMs2,
1685 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
1686 EXPECT_METRIC_EQ(
1687 (kInterFrameDelayMs1 + kInterFrameDelayMs2) / 2,
1688 metrics::MinSample(
1689 "WebRTC.Video.Screenshare.InterframeDelayInMs.ExperimentGroup0"));
1690 } else {
1691 EXPECT_METRIC_EQ(1,
1692 metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"));
1693 EXPECT_METRIC_EQ(
1694 1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"));
1695 EXPECT_METRIC_EQ(
1696 1, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs.S0"));
1697 EXPECT_METRIC_EQ(
1698 1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs.S0"));
1699 EXPECT_METRIC_EQ(
1700 1, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs.S1"));
1701 EXPECT_METRIC_EQ(
1702 1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs.S1"));
1703 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"
1704 ".ExperimentGroup0"));
1705 EXPECT_METRIC_EQ(1,
1706 metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"
1707 ".ExperimentGroup0"));
1708 EXPECT_METRIC_EQ(kInterFrameDelayMs1,
1709 metrics::MinSample("WebRTC.Video.InterframeDelayInMs.S0"));
1710 EXPECT_METRIC_EQ(kInterFrameDelayMs2,
1711 metrics::MinSample("WebRTC.Video.InterframeDelayInMs.S1"));
1712 EXPECT_METRIC_EQ((kInterFrameDelayMs1 + kInterFrameDelayMs2) / 2,
1713 metrics::MinSample("WebRTC.Video.InterframeDelayInMs"));
1714 EXPECT_METRIC_EQ(kInterFrameDelayMs2,
1715 metrics::MinSample("WebRTC.Video.InterframeDelayMaxInMs"));
1716 EXPECT_METRIC_EQ((kInterFrameDelayMs1 + kInterFrameDelayMs2) / 2,
1717 metrics::MinSample(
1718 "WebRTC.Video.InterframeDelayInMs.ExperimentGroup0"));
1719 }
1720}
1721
1722class DecodeTimeHistogramsKillswitch {
1723 public:
1724 explicit DecodeTimeHistogramsKillswitch(bool disable_histograms)
1725 : field_trial_(disable_histograms
1726 ? "WebRTC-DecodeTimeHistogramsKillSwitch/Enabled/"
1727 : "") {}
1728
1729 private:
1730 webrtc::test::ScopedFieldTrials field_trial_;
1731};
1732
1733class ReceiveStatisticsProxy2TestWithDecodeTimeHistograms
1734 : public DecodeTimeHistogramsKillswitch,
1735 public ::testing::WithParamInterface<
1736 std::tuple<bool, int, int, int, VideoCodecType, std::string>>,
1737 public ReceiveStatisticsProxy2Test {
1738 public:
1739 ReceiveStatisticsProxy2TestWithDecodeTimeHistograms()
1740 : DecodeTimeHistogramsKillswitch(std::get<0>(GetParam())) {}
1741
1742 protected:
1743 const std::string kUmaPrefix = "WebRTC.Video.DecodeTimePerFrameInMs.";
1744 const int expected_number_of_samples_ = {std::get<1>(GetParam())};
1745 const int width_ = {std::get<2>(GetParam())};
1746 const int height_ = {std::get<3>(GetParam())};
1747 const VideoCodecType codec_type_ = {std::get<4>(GetParam())};
1748 const std::string implementation_name_ = {std::get<5>(GetParam())};
1749 const std::string uma_histogram_name_ =
1750 kUmaPrefix + (codec_type_ == kVideoCodecVP9 ? "Vp9." : "H264.") +
1751 (height_ == 2160 ? "4k." : "Hd.") +
1752 (implementation_name_.compare("ExternalDecoder") == 0 ? "Hw" : "Sw");
1753};
1754
1755TEST_P(ReceiveStatisticsProxy2TestWithDecodeTimeHistograms,
1756 DecodeTimeHistogramsUpdated) {
1757 constexpr int kNumberOfFrames = 10;
1758 constexpr int kDecodeTimeMs = 7;
1759 constexpr int kFrameDurationMs = 1000 / 60;
1760
1761 webrtc::VideoFrame frame = CreateFrame(width_, height_);
1762
1763 statistics_proxy_->OnDecoderImplementationName(implementation_name_.c_str());
1764 statistics_proxy_->OnPreDecode(codec_type_, /*qp=*/0);
1765
1766 for (int i = 0; i < kNumberOfFrames; ++i) {
1767 statistics_proxy_->OnDecodedFrame(frame, /*qp=*/absl::nullopt,
1768 kDecodeTimeMs,
1769 VideoContentType::UNSPECIFIED);
1770 fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs);
1771 }
1772
Tommid93bf122020-05-10 20:24:59 +02001773 loop_.Flush();
1774
Tommi74fc5742020-04-27 10:43:06 +02001775 EXPECT_METRIC_EQ(expected_number_of_samples_,
1776 metrics::NumSamples(uma_histogram_name_));
1777 EXPECT_METRIC_EQ(expected_number_of_samples_,
1778 metrics::NumEvents(uma_histogram_name_, kDecodeTimeMs));
1779}
1780
1781const auto kVp94kHw = std::make_tuple(/*killswitch=*/false,
1782 /*expected_number_of_samples=*/10,
1783 /*width=*/3840,
1784 /*height=*/2160,
1785 kVideoCodecVP9,
1786 /*implementation=*/"ExternalDecoder");
1787const auto kVp94kSw = std::make_tuple(/*killswitch=*/false,
1788 /*expected_number_of_samples=*/10,
1789 /*width=*/3840,
1790 /*height=*/2160,
1791 kVideoCodecVP9,
1792 /*implementation=*/"libvpx");
1793const auto kVp9HdHw = std::make_tuple(/*killswitch=*/false,
1794 /*expected_number_of_samples=*/10,
1795 /*width=*/1920,
1796 /*height=*/1080,
1797 kVideoCodecVP9,
1798 /*implementation=*/"ExternalDecoder");
1799const auto kVp9HdSw = std::make_tuple(/*killswitch=*/false,
1800 /*expected_number_of_samples=*/10,
1801 /*width=*/1920,
1802 /*height=*/1080,
1803 kVideoCodecVP9,
1804 /*implementation=*/"libvpx");
1805const auto kH2644kHw = std::make_tuple(/*killswitch=*/false,
1806 /*expected_number_of_samples=*/10,
1807 /*width=*/3840,
1808 /*height=*/2160,
1809 kVideoCodecH264,
1810 /*implementation=*/"ExternalDecoder");
1811const auto kH2644kSw = std::make_tuple(/*killswitch=*/false,
1812 /*expected_number_of_samples=*/10,
1813 /*width=*/3840,
1814 /*height=*/2160,
1815 kVideoCodecH264,
1816 /*implementation=*/"FFmpeg");
1817const auto kH264HdHw = std::make_tuple(/*killswitch=*/false,
1818 /*expected_number_of_samples=*/10,
1819 /*width=*/1920,
1820 /*height=*/1080,
1821 kVideoCodecH264,
1822 /*implementation=*/"ExternalDecoder");
1823const auto kH264HdSw = std::make_tuple(/*killswitch=*/false,
1824 /*expected_number_of_samples=*/10,
1825 /*width=*/1920,
1826 /*height=*/1080,
1827 kVideoCodecH264,
1828 /*implementation=*/"FFmpeg");
1829
1830INSTANTIATE_TEST_SUITE_P(AllHistogramsPopulated,
1831 ReceiveStatisticsProxy2TestWithDecodeTimeHistograms,
1832 ::testing::Values(kVp94kHw,
1833 kVp94kSw,
1834 kVp9HdHw,
1835 kVp9HdSw,
1836 kH2644kHw,
1837 kH2644kSw,
1838 kH264HdHw,
1839 kH264HdSw));
1840
1841const auto kKillswitchDisabled =
1842 std::make_tuple(/*killswitch=*/false,
1843 /*expected_number_of_samples=*/10,
1844 /*width=*/1920,
1845 /*height=*/1080,
1846 kVideoCodecVP9,
1847 /*implementation=*/"libvpx");
1848const auto kKillswitchEnabled =
1849 std::make_tuple(/*killswitch=*/true,
1850 /*expected_number_of_samples=*/0,
1851 /*width=*/1920,
1852 /*height=*/1080,
1853 kVideoCodecVP9,
1854 /*implementation=*/"libvpx");
1855
1856INSTANTIATE_TEST_SUITE_P(KillswitchEffective,
1857 ReceiveStatisticsProxy2TestWithDecodeTimeHistograms,
1858 ::testing::Values(kKillswitchDisabled,
1859 kKillswitchEnabled));
1860
1861} // namespace internal
1862} // namespace webrtc