blob: 50f16c538597ad83ed606f60b3d1b08754b2afab [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;
37const uint32_t kLocalSsrc = 123;
38const uint32_t kRemoteSsrc = 456;
39const int kMinRequiredSamples = 200;
40const int kWidth = 1280;
41const int kHeight = 720;
42} // namespace
43
44// TODO(sakal): ReceiveStatisticsProxy is lacking unittesting.
45class ReceiveStatisticsProxy2Test : public ::testing::Test {
46 public:
Tommi553c8692020-05-05 15:35:45 +020047 ReceiveStatisticsProxy2Test() : fake_clock_(1234), config_(GetTestConfig()) {
Tommi74fc5742020-04-27 10:43:06 +020048 metrics::Reset();
Tommi553c8692020-05-05 15:35:45 +020049 statistics_proxy_.reset(
50 new ReceiveStatisticsProxy(&config_, &fake_clock_, loop_.task_queue()));
Tommi74fc5742020-04-27 10:43:06 +020051 }
52
Tommi553c8692020-05-05 15:35:45 +020053 ~ReceiveStatisticsProxy2Test() override { statistics_proxy_.reset(); }
54
55 protected:
Tommid93bf122020-05-10 20:24:59 +020056 // Convenience method to avoid too many explict flushes.
57 VideoReceiveStream::Stats FlushAndGetStats() {
58 loop_.Flush();
59 return statistics_proxy_->GetStats();
60 }
61
62 void FlushAndUpdateHistograms(absl::optional<int> fraction_lost,
63 const StreamDataCounters& rtp_stats,
64 const StreamDataCounters* rtx_stats) {
65 loop_.Flush();
66 statistics_proxy_->UpdateHistograms(fraction_lost, rtp_stats, rtx_stats);
67 }
68
Tommi74fc5742020-04-27 10:43:06 +020069 VideoReceiveStream::Config GetTestConfig() {
70 VideoReceiveStream::Config config(nullptr);
71 config.rtp.local_ssrc = kLocalSsrc;
72 config.rtp.remote_ssrc = kRemoteSsrc;
73 return config;
74 }
75
76 VideoFrame CreateFrame(int width, int height) {
77 return CreateVideoFrame(width, height, 0);
78 }
79
Tommid7e08c82020-05-10 11:24:43 +020080 VideoFrame CreateFrameWithRenderTime(Timestamp render_time) {
81 return CreateFrameWithRenderTimeMs(render_time.ms());
82 }
83
Tommi74fc5742020-04-27 10:43:06 +020084 VideoFrame CreateFrameWithRenderTimeMs(int64_t render_time_ms) {
85 return CreateVideoFrame(kWidth, kHeight, render_time_ms);
86 }
87
88 VideoFrame CreateVideoFrame(int width, int height, int64_t render_time_ms) {
89 VideoFrame frame =
90 VideoFrame::Builder()
91 .set_video_frame_buffer(I420Buffer::Create(width, height))
92 .set_timestamp_rtp(0)
93 .set_timestamp_ms(render_time_ms)
94 .set_rotation(kVideoRotation_0)
95 .build();
96 frame.set_ntp_time_ms(fake_clock_.CurrentNtpInMilliseconds());
97 return frame;
98 }
99
Tommid7e08c82020-05-10 11:24:43 +0200100 // Return the current fake time as a Timestamp.
101 Timestamp Now() { return fake_clock_.CurrentTime(); }
102
103 // Creates a VideoFrameMetaData instance with a timestamp.
104 VideoFrameMetaData MetaData(const VideoFrame& frame, Timestamp ts) {
105 return VideoFrameMetaData(frame, ts);
106 }
107
108 // Creates a VideoFrameMetaData instance with the current fake time.
109 VideoFrameMetaData MetaData(const VideoFrame& frame) {
110 return VideoFrameMetaData(frame, Now());
111 }
112
Tommi74fc5742020-04-27 10:43:06 +0200113 SimulatedClock fake_clock_;
114 const VideoReceiveStream::Config config_;
115 std::unique_ptr<ReceiveStatisticsProxy> statistics_proxy_;
Tommi553c8692020-05-05 15:35:45 +0200116 test::RunLoop loop_;
Tommi74fc5742020-04-27 10:43:06 +0200117};
118
119TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesFramesDecoded) {
120 EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded);
121 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
122 for (uint32_t i = 1; i <= 3; ++i) {
123 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
124 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200125 EXPECT_EQ(i, FlushAndGetStats().frames_decoded);
Tommi74fc5742020-04-27 10:43:06 +0200126 }
127}
128
129TEST_F(ReceiveStatisticsProxy2Test, DecodedFpsIsReported) {
130 const int kFps = 20;
131 const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps;
132 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
133 for (int i = 0; i < kRequiredSamples; ++i) {
134 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
135 VideoContentType::UNSPECIFIED);
136 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
137 }
Tommid93bf122020-05-10 20:24:59 +0200138 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200139 EXPECT_METRIC_EQ(1,
140 metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond"));
141 EXPECT_METRIC_EQ(
142 1, metrics::NumEvents("WebRTC.Video.DecodedFramesPerSecond", kFps));
143}
144
145TEST_F(ReceiveStatisticsProxy2Test, DecodedFpsIsNotReportedForTooFewSamples) {
146 const int kFps = 20;
147 const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps;
148 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
149 for (int i = 0; i < kRequiredSamples - 1; ++i) {
150 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
151 VideoContentType::UNSPECIFIED);
152 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
153 }
Tommid93bf122020-05-10 20:24:59 +0200154 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200155 EXPECT_METRIC_EQ(0,
156 metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond"));
157}
158
159TEST_F(ReceiveStatisticsProxy2Test,
160 OnDecodedFrameWithQpDoesNotResetFramesDecodedOrTotalDecodeTime) {
161 EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded);
162 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
163 unsigned int expected_total_decode_time_ms = 0;
164 unsigned int expected_frames_decoded = 0;
165 for (uint32_t i = 1; i <= 3; ++i) {
166 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 1,
167 VideoContentType::UNSPECIFIED);
168 expected_total_decode_time_ms += 1;
169 ++expected_frames_decoded;
Tommid93bf122020-05-10 20:24:59 +0200170 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200171 EXPECT_EQ(expected_frames_decoded,
172 statistics_proxy_->GetStats().frames_decoded);
173 EXPECT_EQ(expected_total_decode_time_ms,
174 statistics_proxy_->GetStats().total_decode_time_ms);
175 }
176 statistics_proxy_->OnDecodedFrame(frame, 1u, 3,
177 VideoContentType::UNSPECIFIED);
178 ++expected_frames_decoded;
179 expected_total_decode_time_ms += 3;
Tommid93bf122020-05-10 20:24:59 +0200180 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200181 EXPECT_EQ(expected_frames_decoded,
182 statistics_proxy_->GetStats().frames_decoded);
183 EXPECT_EQ(expected_total_decode_time_ms,
184 statistics_proxy_->GetStats().total_decode_time_ms);
185}
186
187TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesQpSum) {
188 EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
189 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
190 statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
191 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200192 EXPECT_EQ(3u, FlushAndGetStats().qp_sum);
Tommi74fc5742020-04-27 10:43:06 +0200193 statistics_proxy_->OnDecodedFrame(frame, 127u, 0,
194 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200195 EXPECT_EQ(130u, FlushAndGetStats().qp_sum);
Tommi74fc5742020-04-27 10:43:06 +0200196}
197
198TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameIncreasesTotalDecodeTime) {
199 EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
200 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
201 statistics_proxy_->OnDecodedFrame(frame, 3u, 4,
202 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200203 EXPECT_EQ(4u, FlushAndGetStats().total_decode_time_ms);
Tommi74fc5742020-04-27 10:43:06 +0200204 statistics_proxy_->OnDecodedFrame(frame, 127u, 7,
205 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200206 EXPECT_EQ(11u, FlushAndGetStats().total_decode_time_ms);
Tommi74fc5742020-04-27 10:43:06 +0200207}
208
209TEST_F(ReceiveStatisticsProxy2Test, ReportsContentType) {
210 const std::string kRealtimeString("realtime");
211 const std::string kScreenshareString("screen");
212 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
213 EXPECT_EQ(kRealtimeString, videocontenttypehelpers::ToString(
214 statistics_proxy_->GetStats().content_type));
215 statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
216 VideoContentType::SCREENSHARE);
217 EXPECT_EQ(kScreenshareString,
Tommid93bf122020-05-10 20:24:59 +0200218 videocontenttypehelpers::ToString(FlushAndGetStats().content_type));
Tommi74fc5742020-04-27 10:43:06 +0200219 statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
220 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200221 EXPECT_EQ(kRealtimeString,
222 videocontenttypehelpers::ToString(FlushAndGetStats().content_type));
Tommi74fc5742020-04-27 10:43:06 +0200223}
224
225TEST_F(ReceiveStatisticsProxy2Test, ReportsMaxTotalInterFrameDelay) {
226 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
227 const TimeDelta kInterFrameDelay1 = TimeDelta::Millis(100);
228 const TimeDelta kInterFrameDelay2 = TimeDelta::Millis(200);
229 const TimeDelta kInterFrameDelay3 = TimeDelta::Millis(300);
230 double expected_total_inter_frame_delay = 0;
231 double expected_total_squared_inter_frame_delay = 0;
232 EXPECT_EQ(expected_total_inter_frame_delay,
233 statistics_proxy_->GetStats().total_inter_frame_delay);
234 EXPECT_EQ(expected_total_squared_inter_frame_delay,
235 statistics_proxy_->GetStats().total_squared_inter_frame_delay);
236
237 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
238 VideoContentType::UNSPECIFIED);
239 EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
Tommid93bf122020-05-10 20:24:59 +0200240 FlushAndGetStats().total_inter_frame_delay);
241 EXPECT_DOUBLE_EQ(expected_total_squared_inter_frame_delay,
242 FlushAndGetStats().total_squared_inter_frame_delay);
Tommi74fc5742020-04-27 10:43:06 +0200243
244 fake_clock_.AdvanceTime(kInterFrameDelay1);
245 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
246 VideoContentType::UNSPECIFIED);
247 expected_total_inter_frame_delay += kInterFrameDelay1.seconds<double>();
248 expected_total_squared_inter_frame_delay +=
249 pow(kInterFrameDelay1.seconds<double>(), 2.0);
250 EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
Tommid93bf122020-05-10 20:24:59 +0200251 FlushAndGetStats().total_inter_frame_delay);
Tommi74fc5742020-04-27 10:43:06 +0200252 EXPECT_DOUBLE_EQ(
253 expected_total_squared_inter_frame_delay,
254 statistics_proxy_->GetStats().total_squared_inter_frame_delay);
255
256 fake_clock_.AdvanceTime(kInterFrameDelay2);
257 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
258 VideoContentType::UNSPECIFIED);
259 expected_total_inter_frame_delay += kInterFrameDelay2.seconds<double>();
260 expected_total_squared_inter_frame_delay +=
261 pow(kInterFrameDelay2.seconds<double>(), 2.0);
262 EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
Tommid93bf122020-05-10 20:24:59 +0200263 FlushAndGetStats().total_inter_frame_delay);
Tommi74fc5742020-04-27 10:43:06 +0200264 EXPECT_DOUBLE_EQ(
265 expected_total_squared_inter_frame_delay,
266 statistics_proxy_->GetStats().total_squared_inter_frame_delay);
267
268 fake_clock_.AdvanceTime(kInterFrameDelay3);
269 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
270 VideoContentType::UNSPECIFIED);
271 expected_total_inter_frame_delay += kInterFrameDelay3.seconds<double>();
272 expected_total_squared_inter_frame_delay +=
273 pow(kInterFrameDelay3.seconds<double>(), 2.0);
274 EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
Tommid93bf122020-05-10 20:24:59 +0200275 FlushAndGetStats().total_inter_frame_delay);
Tommi74fc5742020-04-27 10:43:06 +0200276 EXPECT_DOUBLE_EQ(
277 expected_total_squared_inter_frame_delay,
278 statistics_proxy_->GetStats().total_squared_inter_frame_delay);
279}
280
281TEST_F(ReceiveStatisticsProxy2Test, ReportsMaxInterframeDelay) {
282 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
283 const int64_t kInterframeDelayMs1 = 100;
284 const int64_t kInterframeDelayMs2 = 200;
285 const int64_t kInterframeDelayMs3 = 100;
286 EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
287 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
288 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200289 EXPECT_EQ(-1, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200290
291 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs1);
292 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
293 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200294 EXPECT_EQ(kInterframeDelayMs1, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200295
296 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs2);
297 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
298 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200299 EXPECT_EQ(kInterframeDelayMs2, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200300
301 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs3);
302 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
303 VideoContentType::UNSPECIFIED);
304 // kInterframeDelayMs3 is smaller than kInterframeDelayMs2.
Tommid93bf122020-05-10 20:24:59 +0200305 EXPECT_EQ(kInterframeDelayMs2, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200306}
307
308TEST_F(ReceiveStatisticsProxy2Test, ReportInterframeDelayInWindow) {
309 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
310 const int64_t kInterframeDelayMs1 = 900;
311 const int64_t kInterframeDelayMs2 = 750;
312 const int64_t kInterframeDelayMs3 = 700;
313 EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
314 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
315 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200316 EXPECT_EQ(-1, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200317
318 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs1);
319 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
320 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200321 EXPECT_EQ(kInterframeDelayMs1, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200322
323 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs2);
324 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
325 VideoContentType::UNSPECIFIED);
326 // Still first delay is the maximum
Tommid93bf122020-05-10 20:24:59 +0200327 EXPECT_EQ(kInterframeDelayMs1, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200328
329 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs3);
330 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
331 VideoContentType::UNSPECIFIED);
332 // Now the first sample is out of the window, so the second is the maximum.
Tommid93bf122020-05-10 20:24:59 +0200333 EXPECT_EQ(kInterframeDelayMs2, FlushAndGetStats().interframe_delay_max_ms);
Tommi74fc5742020-04-27 10:43:06 +0200334}
335
336TEST_F(ReceiveStatisticsProxy2Test, ReportsFreezeMetrics) {
337 const int64_t kFreezeDurationMs = 1000;
338
339 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
340 EXPECT_EQ(0u, stats.freeze_count);
341 EXPECT_FALSE(stats.total_freezes_duration_ms);
342
343 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
344 for (size_t i = 0; i < VideoQualityObserver::kMinFrameSamplesToDetectFreeze;
345 ++i) {
346 fake_clock_.AdvanceTimeMilliseconds(30);
Tommid7e08c82020-05-10 11:24:43 +0200347 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200348 }
349
350 // Freeze.
351 fake_clock_.AdvanceTimeMilliseconds(kFreezeDurationMs);
Tommid7e08c82020-05-10 11:24:43 +0200352 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200353
354 stats = statistics_proxy_->GetStats();
355 EXPECT_EQ(1u, stats.freeze_count);
356 EXPECT_EQ(kFreezeDurationMs, stats.total_freezes_duration_ms);
357}
358
359TEST_F(ReceiveStatisticsProxy2Test, ReportsPauseMetrics) {
360 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
361 ASSERT_EQ(0u, stats.pause_count);
362 ASSERT_EQ(0u, stats.total_pauses_duration_ms);
363
364 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
Tommid7e08c82020-05-10 11:24:43 +0200365 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200366
367 // Pause.
368 fake_clock_.AdvanceTimeMilliseconds(5432);
369 statistics_proxy_->OnStreamInactive();
Tommid7e08c82020-05-10 11:24:43 +0200370 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200371
372 stats = statistics_proxy_->GetStats();
373 EXPECT_EQ(1u, stats.pause_count);
374 EXPECT_EQ(5432u, stats.total_pauses_duration_ms);
375}
376
377TEST_F(ReceiveStatisticsProxy2Test, PauseBeforeFirstAndAfterLastFrameIgnored) {
378 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
379 ASSERT_EQ(0u, stats.pause_count);
380 ASSERT_EQ(0u, stats.total_pauses_duration_ms);
381
382 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
383
384 // Pause -> Frame -> Pause
385 fake_clock_.AdvanceTimeMilliseconds(5000);
386 statistics_proxy_->OnStreamInactive();
Tommid7e08c82020-05-10 11:24:43 +0200387 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200388
389 fake_clock_.AdvanceTimeMilliseconds(30);
Tommid7e08c82020-05-10 11:24:43 +0200390 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200391
392 fake_clock_.AdvanceTimeMilliseconds(5000);
393 statistics_proxy_->OnStreamInactive();
394
395 stats = statistics_proxy_->GetStats();
396 EXPECT_EQ(0u, stats.pause_count);
397 EXPECT_EQ(0u, stats.total_pauses_duration_ms);
398}
399
400TEST_F(ReceiveStatisticsProxy2Test, ReportsFramesDuration) {
401 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
402 ASSERT_EQ(0u, stats.total_frames_duration_ms);
403
404 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
405
406 // Emulate delay before first frame is rendered. This is needed to ensure
407 // that frame duration only covers time since first frame is rendered and
408 // not the total time.
409 fake_clock_.AdvanceTimeMilliseconds(5432);
410
411 for (int i = 0; i <= 10; ++i) {
412 fake_clock_.AdvanceTimeMilliseconds(30);
Tommid7e08c82020-05-10 11:24:43 +0200413 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200414 }
415
416 stats = statistics_proxy_->GetStats();
417 EXPECT_EQ(10 * 30u, stats.total_frames_duration_ms);
418}
419
420TEST_F(ReceiveStatisticsProxy2Test, ReportsSumSquaredFrameDurations) {
421 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
422 ASSERT_EQ(0u, stats.sum_squared_frame_durations);
423
424 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
425 for (int i = 0; i <= 10; ++i) {
426 fake_clock_.AdvanceTimeMilliseconds(30);
Tommid7e08c82020-05-10 11:24:43 +0200427 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200428 }
429
430 stats = statistics_proxy_->GetStats();
431 const double kExpectedSumSquaredFrameDurationsSecs =
432 10 * (30 / 1000.0 * 30 / 1000.0);
433 EXPECT_EQ(kExpectedSumSquaredFrameDurationsSecs,
434 stats.sum_squared_frame_durations);
435}
436
437TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameWithoutQpQpSumWontExist) {
438 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
439 EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
440 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
441 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200442 EXPECT_EQ(absl::nullopt, FlushAndGetStats().qp_sum);
Tommi74fc5742020-04-27 10:43:06 +0200443}
444
445TEST_F(ReceiveStatisticsProxy2Test, OnDecodedFrameWithoutQpResetsQpSum) {
446 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
447 EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
448 statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
449 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200450 EXPECT_EQ(3u, FlushAndGetStats().qp_sum);
Tommi74fc5742020-04-27 10:43:06 +0200451 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
452 VideoContentType::UNSPECIFIED);
Tommid93bf122020-05-10 20:24:59 +0200453 EXPECT_EQ(absl::nullopt, FlushAndGetStats().qp_sum);
Tommi74fc5742020-04-27 10:43:06 +0200454}
455
456TEST_F(ReceiveStatisticsProxy2Test, OnRenderedFrameIncreasesFramesRendered) {
457 EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_rendered);
458 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
459 for (uint32_t i = 1; i <= 3; ++i) {
Tommid7e08c82020-05-10 11:24:43 +0200460 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200461 EXPECT_EQ(i, statistics_proxy_->GetStats().frames_rendered);
462 }
463}
464
465TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsSsrc) {
466 EXPECT_EQ(kRemoteSsrc, statistics_proxy_->GetStats().ssrc);
467}
468
469TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsIncomingPayloadType) {
470 const int kPayloadType = 111;
471 statistics_proxy_->OnIncomingPayloadType(kPayloadType);
Tommi674b0c82020-05-10 21:52:17 +0200472 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200473 EXPECT_EQ(kPayloadType, statistics_proxy_->GetStats().current_payload_type);
474}
475
476TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsDecoderImplementationName) {
477 const char* kName = "decoderName";
478 statistics_proxy_->OnDecoderImplementationName(kName);
Tommi674b0c82020-05-10 21:52:17 +0200479 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200480 EXPECT_STREQ(
481 kName, statistics_proxy_->GetStats().decoder_implementation_name.c_str());
482}
483
484TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsOnCompleteFrame) {
485 const int kFrameSizeBytes = 1000;
486 statistics_proxy_->OnCompleteFrame(true, kFrameSizeBytes,
487 VideoContentType::UNSPECIFIED);
488 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
489 EXPECT_EQ(1, stats.network_frame_rate);
490 EXPECT_EQ(1, stats.frame_counts.key_frames);
491 EXPECT_EQ(0, stats.frame_counts.delta_frames);
492}
493
494TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsOnDroppedFrame) {
495 unsigned int dropped_frames = 0;
496 for (int i = 0; i < 10; ++i) {
497 statistics_proxy_->OnDroppedFrames(i);
498 dropped_frames += i;
499 }
Tommi674b0c82020-05-10 21:52:17 +0200500 VideoReceiveStream::Stats stats = FlushAndGetStats();
Tommi74fc5742020-04-27 10:43:06 +0200501 EXPECT_EQ(dropped_frames, stats.frames_dropped);
502}
503
504TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsDecodeTimingStats) {
505 const int kMaxDecodeMs = 2;
506 const int kCurrentDelayMs = 3;
507 const int kTargetDelayMs = 4;
508 const int kJitterBufferMs = 5;
509 const int kMinPlayoutDelayMs = 6;
510 const int kRenderDelayMs = 7;
511 const int64_t kRttMs = 8;
Tommi674b0c82020-05-10 21:52:17 +0200512 statistics_proxy_->OnRttUpdate(kRttMs);
Tommi74fc5742020-04-27 10:43:06 +0200513 statistics_proxy_->OnFrameBufferTimingsUpdated(
514 kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
515 kMinPlayoutDelayMs, kRenderDelayMs);
Tommi674b0c82020-05-10 21:52:17 +0200516 VideoReceiveStream::Stats stats = FlushAndGetStats();
Tommi74fc5742020-04-27 10:43:06 +0200517 EXPECT_EQ(kMaxDecodeMs, stats.max_decode_ms);
518 EXPECT_EQ(kCurrentDelayMs, stats.current_delay_ms);
519 EXPECT_EQ(kTargetDelayMs, stats.target_delay_ms);
520 EXPECT_EQ(kJitterBufferMs, stats.jitter_buffer_ms);
521 EXPECT_EQ(kMinPlayoutDelayMs, stats.min_playout_delay_ms);
522 EXPECT_EQ(kRenderDelayMs, stats.render_delay_ms);
523}
524
525TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsRtcpPacketTypeCounts) {
526 const uint32_t kFirPackets = 33;
527 const uint32_t kPliPackets = 44;
528 const uint32_t kNackPackets = 55;
529 RtcpPacketTypeCounter counter;
530 counter.fir_packets = kFirPackets;
531 counter.pli_packets = kPliPackets;
532 counter.nack_packets = kNackPackets;
533 statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc, counter);
534 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
535 EXPECT_EQ(kFirPackets, stats.rtcp_packet_type_counts.fir_packets);
536 EXPECT_EQ(kPliPackets, stats.rtcp_packet_type_counts.pli_packets);
537 EXPECT_EQ(kNackPackets, stats.rtcp_packet_type_counts.nack_packets);
538}
539
540TEST_F(ReceiveStatisticsProxy2Test,
541 GetStatsReportsNoRtcpPacketTypeCountsForUnknownSsrc) {
542 RtcpPacketTypeCounter counter;
543 counter.fir_packets = 33;
544 statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc + 1, counter);
545 EXPECT_EQ(0u,
546 statistics_proxy_->GetStats().rtcp_packet_type_counts.fir_packets);
547}
548
549TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsFrameCounts) {
550 const int kKeyFrames = 3;
551 const int kDeltaFrames = 22;
552 for (int i = 0; i < kKeyFrames; i++) {
553 statistics_proxy_->OnCompleteFrame(true, 0, VideoContentType::UNSPECIFIED);
554 }
555 for (int i = 0; i < kDeltaFrames; i++) {
556 statistics_proxy_->OnCompleteFrame(false, 0, VideoContentType::UNSPECIFIED);
557 }
558
559 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
560 EXPECT_EQ(kKeyFrames, stats.frame_counts.key_frames);
561 EXPECT_EQ(kDeltaFrames, stats.frame_counts.delta_frames);
562}
563
564TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsCName) {
565 const char* kName = "cName";
566 statistics_proxy_->OnCname(kRemoteSsrc, kName);
567 EXPECT_STREQ(kName, statistics_proxy_->GetStats().c_name.c_str());
568}
569
570TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsNoCNameForUnknownSsrc) {
571 const char* kName = "cName";
572 statistics_proxy_->OnCname(kRemoteSsrc + 1, kName);
573 EXPECT_STREQ("", statistics_proxy_->GetStats().c_name.c_str());
574}
575
576TEST_F(ReceiveStatisticsProxy2Test, ReportsLongestTimingFrameInfo) {
577 const int64_t kShortEndToEndDelay = 10;
578 const int64_t kMedEndToEndDelay = 20;
579 const int64_t kLongEndToEndDelay = 100;
580 const uint32_t kExpectedRtpTimestamp = 2;
581 TimingFrameInfo info;
582 absl::optional<TimingFrameInfo> result;
583 info.rtp_timestamp = kExpectedRtpTimestamp - 1;
584 info.capture_time_ms = 0;
585 info.decode_finish_ms = kShortEndToEndDelay;
586 statistics_proxy_->OnTimingFrameInfoUpdated(info);
587 info.rtp_timestamp =
588 kExpectedRtpTimestamp; // this frame should be reported in the end.
589 info.capture_time_ms = 0;
590 info.decode_finish_ms = kLongEndToEndDelay;
591 statistics_proxy_->OnTimingFrameInfoUpdated(info);
592 info.rtp_timestamp = kExpectedRtpTimestamp + 1;
593 info.capture_time_ms = 0;
594 info.decode_finish_ms = kMedEndToEndDelay;
595 statistics_proxy_->OnTimingFrameInfoUpdated(info);
Tommi674b0c82020-05-10 21:52:17 +0200596 result = FlushAndGetStats().timing_frame_info;
Tommi74fc5742020-04-27 10:43:06 +0200597 EXPECT_TRUE(result);
598 EXPECT_EQ(kExpectedRtpTimestamp, result->rtp_timestamp);
599}
600
601TEST_F(ReceiveStatisticsProxy2Test, RespectsReportingIntervalForTimingFrames) {
602 TimingFrameInfo info;
603 const int64_t kShortEndToEndDelay = 10;
604 const uint32_t kExpectedRtpTimestamp = 2;
605 const int64_t kShortDelayMs = 1000;
606 const int64_t kLongDelayMs = 10000;
607 absl::optional<TimingFrameInfo> result;
608 info.rtp_timestamp = kExpectedRtpTimestamp;
609 info.capture_time_ms = 0;
610 info.decode_finish_ms = kShortEndToEndDelay;
611 statistics_proxy_->OnTimingFrameInfoUpdated(info);
612 fake_clock_.AdvanceTimeMilliseconds(kShortDelayMs);
Tommi674b0c82020-05-10 21:52:17 +0200613 result = FlushAndGetStats().timing_frame_info;
Tommi74fc5742020-04-27 10:43:06 +0200614 EXPECT_TRUE(result);
615 EXPECT_EQ(kExpectedRtpTimestamp, result->rtp_timestamp);
616 fake_clock_.AdvanceTimeMilliseconds(kLongDelayMs);
617 result = statistics_proxy_->GetStats().timing_frame_info;
618 EXPECT_FALSE(result);
619}
620
621TEST_F(ReceiveStatisticsProxy2Test, LifetimeHistogramIsUpdated) {
622 const int64_t kTimeSec = 3;
623 fake_clock_.AdvanceTimeMilliseconds(kTimeSec * 1000);
624 // Need at least one frame to report stream lifetime.
625 statistics_proxy_->OnCompleteFrame(true, 1000, VideoContentType::UNSPECIFIED);
626 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
627 nullptr);
628 EXPECT_METRIC_EQ(
629 1, metrics::NumSamples("WebRTC.Video.ReceiveStreamLifetimeInSeconds"));
630 EXPECT_METRIC_EQ(
631 1, metrics::NumEvents("WebRTC.Video.ReceiveStreamLifetimeInSeconds",
632 kTimeSec));
633}
634
635TEST_F(ReceiveStatisticsProxy2Test,
636 LifetimeHistogramNotReportedForEmptyStreams) {
637 const int64_t kTimeSec = 3;
638 fake_clock_.AdvanceTimeMilliseconds(kTimeSec * 1000);
639 // No frames received.
640 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
641 nullptr);
642 EXPECT_METRIC_EQ(
643 0, metrics::NumSamples("WebRTC.Video.ReceiveStreamLifetimeInSeconds"));
644}
645
646TEST_F(ReceiveStatisticsProxy2Test, BadCallHistogramsAreUpdated) {
647 // Based on the tuning parameters this will produce 7 uncertain states,
648 // then 10 certainly bad states. There has to be 10 certain states before
649 // any histograms are recorded.
650 const int kNumBadSamples = 17;
651 // We only count one sample per second.
652 const int kBadFameIntervalMs = 1100;
653
654 StreamDataCounters counters;
655 counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
656
657 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
658
659 for (int i = 0; i < kNumBadSamples; ++i) {
660 fake_clock_.AdvanceTimeMilliseconds(kBadFameIntervalMs);
Tommid7e08c82020-05-10 11:24:43 +0200661 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200662 }
663 statistics_proxy_->UpdateHistograms(absl::nullopt, counters, nullptr);
664 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.BadCall.Any"));
665 EXPECT_METRIC_EQ(1, metrics::NumEvents("WebRTC.Video.BadCall.Any", 100));
666
667 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.BadCall.FrameRate"));
668 EXPECT_METRIC_EQ(1,
669 metrics::NumEvents("WebRTC.Video.BadCall.FrameRate", 100));
670
671 EXPECT_METRIC_EQ(
672 0, metrics::NumSamples("WebRTC.Video.BadCall.FrameRateVariance"));
673
674 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.BadCall.Qp"));
675}
676
677TEST_F(ReceiveStatisticsProxy2Test, PacketLossHistogramIsUpdated) {
678 statistics_proxy_->UpdateHistograms(10, StreamDataCounters(), nullptr);
679 EXPECT_METRIC_EQ(
680 0, metrics::NumSamples("WebRTC.Video.ReceivedPacketsLostInPercent"));
681
682 // Restart
683 SetUp();
684
685 // Min run time has passed.
686 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
687 statistics_proxy_->UpdateHistograms(10, StreamDataCounters(), nullptr);
688 EXPECT_METRIC_EQ(
689 1, metrics::NumSamples("WebRTC.Video.ReceivedPacketsLostInPercent"));
690 EXPECT_METRIC_EQ(
691 1, metrics::NumEvents("WebRTC.Video.ReceivedPacketsLostInPercent", 10));
692}
693
694TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsPlayoutTimestamp) {
695 const int64_t kVideoNtpMs = 21;
696 const int64_t kSyncOffsetMs = 22;
697 const double kFreqKhz = 90.0;
698 EXPECT_EQ(absl::nullopt,
699 statistics_proxy_->GetStats().estimated_playout_ntp_timestamp_ms);
700 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs, kFreqKhz);
Tommi674b0c82020-05-10 21:52:17 +0200701 EXPECT_EQ(kVideoNtpMs, FlushAndGetStats().estimated_playout_ntp_timestamp_ms);
Tommi74fc5742020-04-27 10:43:06 +0200702 fake_clock_.AdvanceTimeMilliseconds(13);
703 EXPECT_EQ(kVideoNtpMs + 13,
704 statistics_proxy_->GetStats().estimated_playout_ntp_timestamp_ms);
705 fake_clock_.AdvanceTimeMilliseconds(5);
706 EXPECT_EQ(kVideoNtpMs + 13 + 5,
707 statistics_proxy_->GetStats().estimated_playout_ntp_timestamp_ms);
708}
709
710TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsAvSyncOffset) {
711 const int64_t kVideoNtpMs = 21;
712 const int64_t kSyncOffsetMs = 22;
713 const double kFreqKhz = 90.0;
714 EXPECT_EQ(std::numeric_limits<int>::max(),
715 statistics_proxy_->GetStats().sync_offset_ms);
716 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs, kFreqKhz);
Tommi674b0c82020-05-10 21:52:17 +0200717 EXPECT_EQ(kSyncOffsetMs, FlushAndGetStats().sync_offset_ms);
Tommi74fc5742020-04-27 10:43:06 +0200718}
719
720TEST_F(ReceiveStatisticsProxy2Test, AvSyncOffsetHistogramIsUpdated) {
721 const int64_t kVideoNtpMs = 21;
722 const int64_t kSyncOffsetMs = 22;
723 const double kFreqKhz = 90.0;
Tommi674b0c82020-05-10 21:52:17 +0200724 for (int i = 0; i < kMinRequiredSamples; ++i) {
Tommi74fc5742020-04-27 10:43:06 +0200725 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
726 kFreqKhz);
Tommi674b0c82020-05-10 21:52:17 +0200727 }
728 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200729 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.AVSyncOffsetInMs"));
730 EXPECT_METRIC_EQ(
731 1, metrics::NumEvents("WebRTC.Video.AVSyncOffsetInMs", kSyncOffsetMs));
732}
733
734TEST_F(ReceiveStatisticsProxy2Test, RtpToNtpFrequencyOffsetHistogramIsUpdated) {
735 const int64_t kVideoNtpMs = 21;
736 const int64_t kSyncOffsetMs = 22;
737 const double kFreqKhz = 90.0;
738 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs, kFreqKhz);
739 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
740 kFreqKhz + 2.2);
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: 2.
744 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
745 kFreqKhz + 1.1);
746 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
747 kFreqKhz - 4.2);
748 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
749 kFreqKhz - 0.9);
Tommi674b0c82020-05-10 21:52:17 +0200750 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200751 fake_clock_.AdvanceTimeMilliseconds(kFreqOffsetProcessIntervalInMs);
752 // Process interval passed, max diff: 4.
753 statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs, kFreqKhz);
Tommi674b0c82020-05-10 21:52:17 +0200754 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200755 // Average reported: (2 + 4) / 2 = 3.
756 EXPECT_METRIC_EQ(1,
757 metrics::NumSamples("WebRTC.Video.RtpToNtpFreqOffsetInKhz"));
758 EXPECT_METRIC_EQ(
759 1, metrics::NumEvents("WebRTC.Video.RtpToNtpFreqOffsetInKhz", 3));
760}
761
762TEST_F(ReceiveStatisticsProxy2Test, Vp8QpHistogramIsUpdated) {
763 const int kQp = 22;
764
765 for (int i = 0; i < kMinRequiredSamples; ++i)
766 statistics_proxy_->OnPreDecode(kVideoCodecVP8, kQp);
767
Tommi674b0c82020-05-10 21:52:17 +0200768 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200769 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.Decoded.Vp8.Qp"));
770 EXPECT_METRIC_EQ(1, metrics::NumEvents("WebRTC.Video.Decoded.Vp8.Qp", kQp));
771}
772
773TEST_F(ReceiveStatisticsProxy2Test,
774 Vp8QpHistogramIsNotUpdatedForTooFewSamples) {
775 const int kQp = 22;
776
777 for (int i = 0; i < kMinRequiredSamples - 1; ++i)
778 statistics_proxy_->OnPreDecode(kVideoCodecVP8, kQp);
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, Vp8QpHistogramIsNotUpdatedIfNoQpValue) {
786 for (int i = 0; i < kMinRequiredSamples; ++i)
787 statistics_proxy_->OnPreDecode(kVideoCodecVP8, -1);
788
789 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
790 nullptr);
791 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.Decoded.Vp8.Qp"));
792}
793
794TEST_F(ReceiveStatisticsProxy2Test,
795 KeyFrameHistogramNotUpdatedForTooFewSamples) {
796 const bool kIsKeyFrame = false;
797 const int kFrameSizeBytes = 1000;
798
799 for (int i = 0; i < kMinRequiredSamples - 1; ++i)
800 statistics_proxy_->OnCompleteFrame(kIsKeyFrame, kFrameSizeBytes,
801 VideoContentType::UNSPECIFIED);
802
803 EXPECT_EQ(0, statistics_proxy_->GetStats().frame_counts.key_frames);
804 EXPECT_EQ(kMinRequiredSamples - 1,
805 statistics_proxy_->GetStats().frame_counts.delta_frames);
806
807 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
808 nullptr);
809 EXPECT_METRIC_EQ(
810 0, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
811}
812
813TEST_F(ReceiveStatisticsProxy2Test,
814 KeyFrameHistogramUpdatedForMinRequiredSamples) {
815 const bool kIsKeyFrame = false;
816 const int kFrameSizeBytes = 1000;
817
818 for (int i = 0; i < kMinRequiredSamples; ++i)
819 statistics_proxy_->OnCompleteFrame(kIsKeyFrame, kFrameSizeBytes,
820 VideoContentType::UNSPECIFIED);
821
822 EXPECT_EQ(0, statistics_proxy_->GetStats().frame_counts.key_frames);
823 EXPECT_EQ(kMinRequiredSamples,
824 statistics_proxy_->GetStats().frame_counts.delta_frames);
825
826 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
827 nullptr);
828 EXPECT_METRIC_EQ(
829 1, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
830 EXPECT_METRIC_EQ(
831 1, metrics::NumEvents("WebRTC.Video.KeyFramesReceivedInPermille", 0));
832}
833
834TEST_F(ReceiveStatisticsProxy2Test, KeyFrameHistogramIsUpdated) {
835 const int kFrameSizeBytes = 1000;
836
837 for (int i = 0; i < kMinRequiredSamples; ++i)
838 statistics_proxy_->OnCompleteFrame(true, kFrameSizeBytes,
839 VideoContentType::UNSPECIFIED);
840
841 for (int i = 0; i < kMinRequiredSamples; ++i)
842 statistics_proxy_->OnCompleteFrame(false, kFrameSizeBytes,
843 VideoContentType::UNSPECIFIED);
844
845 EXPECT_EQ(kMinRequiredSamples,
846 statistics_proxy_->GetStats().frame_counts.key_frames);
847 EXPECT_EQ(kMinRequiredSamples,
848 statistics_proxy_->GetStats().frame_counts.delta_frames);
849
850 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
851 nullptr);
852 EXPECT_METRIC_EQ(
853 1, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
854 EXPECT_METRIC_EQ(
855 1, metrics::NumEvents("WebRTC.Video.KeyFramesReceivedInPermille", 500));
856}
857
858TEST_F(ReceiveStatisticsProxy2Test,
859 TimingHistogramsNotUpdatedForTooFewSamples) {
860 const int kMaxDecodeMs = 2;
861 const int kCurrentDelayMs = 3;
862 const int kTargetDelayMs = 4;
863 const int kJitterBufferMs = 5;
864 const int kMinPlayoutDelayMs = 6;
865 const int kRenderDelayMs = 7;
866
867 for (int i = 0; i < kMinRequiredSamples - 1; ++i) {
868 statistics_proxy_->OnFrameBufferTimingsUpdated(
869 kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
870 kMinPlayoutDelayMs, kRenderDelayMs);
871 }
872
873 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
874 nullptr);
875 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.DecodeTimeInMs"));
876 EXPECT_METRIC_EQ(0,
877 metrics::NumSamples("WebRTC.Video.JitterBufferDelayInMs"));
878 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.TargetDelayInMs"));
879 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.CurrentDelayInMs"));
880 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.OnewayDelayInMs"));
881}
882
883TEST_F(ReceiveStatisticsProxy2Test, TimingHistogramsAreUpdated) {
884 const int kMaxDecodeMs = 2;
885 const int kCurrentDelayMs = 3;
886 const int kTargetDelayMs = 4;
887 const int kJitterBufferMs = 5;
888 const int kMinPlayoutDelayMs = 6;
889 const int kRenderDelayMs = 7;
890
891 for (int i = 0; i < kMinRequiredSamples; ++i) {
892 statistics_proxy_->OnFrameBufferTimingsUpdated(
893 kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
894 kMinPlayoutDelayMs, kRenderDelayMs);
895 }
896
Tommi674b0c82020-05-10 21:52:17 +0200897 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +0200898 EXPECT_METRIC_EQ(1,
899 metrics::NumSamples("WebRTC.Video.JitterBufferDelayInMs"));
900 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.TargetDelayInMs"));
901 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.CurrentDelayInMs"));
902 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.OnewayDelayInMs"));
903
904 EXPECT_METRIC_EQ(1, metrics::NumEvents("WebRTC.Video.JitterBufferDelayInMs",
905 kJitterBufferMs));
906 EXPECT_METRIC_EQ(
907 1, metrics::NumEvents("WebRTC.Video.TargetDelayInMs", kTargetDelayMs));
908 EXPECT_METRIC_EQ(
909 1, metrics::NumEvents("WebRTC.Video.CurrentDelayInMs", kCurrentDelayMs));
910 EXPECT_METRIC_EQ(
911 1, metrics::NumEvents("WebRTC.Video.OnewayDelayInMs", kTargetDelayMs));
912}
913
914TEST_F(ReceiveStatisticsProxy2Test, DoesNotReportStaleFramerates) {
915 const int kDefaultFps = 30;
916 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
917
918 for (int i = 0; i < kDefaultFps; ++i) {
919 // Since OnRenderedFrame is never called the fps in each sample will be 0,
920 // i.e. bad
921 frame.set_ntp_time_ms(fake_clock_.CurrentNtpInMilliseconds());
922 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
923 VideoContentType::UNSPECIFIED);
Tommid7e08c82020-05-10 11:24:43 +0200924 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +0200925 fake_clock_.AdvanceTimeMilliseconds(1000 / kDefaultFps);
926 }
927
Tommid93bf122020-05-10 20:24:59 +0200928 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +0200929 EXPECT_EQ(kDefaultFps, statistics_proxy_->GetStats().decode_frame_rate);
930 EXPECT_EQ(kDefaultFps, statistics_proxy_->GetStats().render_frame_rate);
931
932 // FPS trackers in stats proxy have a 1000ms sliding window.
933 fake_clock_.AdvanceTimeMilliseconds(1000);
934 EXPECT_EQ(0, statistics_proxy_->GetStats().decode_frame_rate);
935 EXPECT_EQ(0, statistics_proxy_->GetStats().render_frame_rate);
936}
937
938TEST_F(ReceiveStatisticsProxy2Test, GetStatsReportsReceivedFrameStats) {
939 EXPECT_EQ(0, statistics_proxy_->GetStats().width);
940 EXPECT_EQ(0, statistics_proxy_->GetStats().height);
941 EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_rendered);
942
Tommid7e08c82020-05-10 11:24:43 +0200943 statistics_proxy_->OnRenderedFrame(MetaData(CreateFrame(kWidth, kHeight)));
Tommi74fc5742020-04-27 10:43:06 +0200944
945 EXPECT_EQ(kWidth, statistics_proxy_->GetStats().width);
946 EXPECT_EQ(kHeight, statistics_proxy_->GetStats().height);
947 EXPECT_EQ(1u, statistics_proxy_->GetStats().frames_rendered);
948}
949
950TEST_F(ReceiveStatisticsProxy2Test,
951 ReceivedFrameHistogramsAreNotUpdatedForTooFewSamples) {
Tommid7e08c82020-05-10 11:24:43 +0200952 for (int i = 0; i < kMinRequiredSamples - 1; ++i) {
953 statistics_proxy_->OnRenderedFrame(MetaData(CreateFrame(kWidth, kHeight)));
954 }
Tommi74fc5742020-04-27 10:43:06 +0200955
956 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
957 nullptr);
958 EXPECT_METRIC_EQ(0,
959 metrics::NumSamples("WebRTC.Video.ReceivedWidthInPixels"));
960 EXPECT_METRIC_EQ(0,
961 metrics::NumSamples("WebRTC.Video.ReceivedHeightInPixels"));
962 EXPECT_METRIC_EQ(0,
963 metrics::NumSamples("WebRTC.Video.RenderFramesPerSecond"));
964 EXPECT_METRIC_EQ(
965 0, metrics::NumSamples("WebRTC.Video.RenderSqrtPixelsPerSecond"));
966}
967
968TEST_F(ReceiveStatisticsProxy2Test, ReceivedFrameHistogramsAreUpdated) {
Tommid7e08c82020-05-10 11:24:43 +0200969 for (int i = 0; i < kMinRequiredSamples; ++i) {
970 statistics_proxy_->OnRenderedFrame(MetaData(CreateFrame(kWidth, kHeight)));
971 }
Tommi74fc5742020-04-27 10:43:06 +0200972
973 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
974 nullptr);
975 EXPECT_METRIC_EQ(1,
976 metrics::NumSamples("WebRTC.Video.ReceivedWidthInPixels"));
977 EXPECT_METRIC_EQ(1,
978 metrics::NumSamples("WebRTC.Video.ReceivedHeightInPixels"));
979 EXPECT_METRIC_EQ(1,
980 metrics::NumSamples("WebRTC.Video.RenderFramesPerSecond"));
981 EXPECT_METRIC_EQ(
982 1, metrics::NumSamples("WebRTC.Video.RenderSqrtPixelsPerSecond"));
983 EXPECT_METRIC_EQ(
984 1, metrics::NumEvents("WebRTC.Video.ReceivedWidthInPixels", kWidth));
985 EXPECT_METRIC_EQ(
986 1, metrics::NumEvents("WebRTC.Video.ReceivedHeightInPixels", kHeight));
987}
988
989TEST_F(ReceiveStatisticsProxy2Test, ZeroDelayReportedIfFrameNotDelayed) {
990 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
991 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
992 VideoContentType::UNSPECIFIED);
993
994 // Frame not delayed, delayed frames to render: 0%.
Tommid7e08c82020-05-10 11:24:43 +0200995 statistics_proxy_->OnRenderedFrame(
996 MetaData(CreateFrameWithRenderTime(Now())));
Tommi74fc5742020-04-27 10:43:06 +0200997
998 // Min run time has passed.
999 fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
Tommid93bf122020-05-10 20:24:59 +02001000 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001001 EXPECT_METRIC_EQ(1,
1002 metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
1003 EXPECT_METRIC_EQ(
1004 1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer", 0));
1005 EXPECT_METRIC_EQ(0, metrics::NumSamples(
1006 "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
1007}
1008
1009TEST_F(ReceiveStatisticsProxy2Test,
1010 DelayedFrameHistogramsAreNotUpdatedIfMinRuntimeHasNotPassed) {
1011 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1012 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
1013 VideoContentType::UNSPECIFIED);
1014
1015 // Frame not delayed, delayed frames to render: 0%.
Tommid7e08c82020-05-10 11:24:43 +02001016 statistics_proxy_->OnRenderedFrame(
1017 MetaData(CreateFrameWithRenderTime(Now())));
Tommi74fc5742020-04-27 10:43:06 +02001018
1019 // Min run time has not passed.
1020 fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000) -
1021 1);
1022 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
1023 nullptr);
1024 EXPECT_METRIC_EQ(0,
1025 metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
1026 EXPECT_METRIC_EQ(0, metrics::NumSamples(
1027 "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
1028}
1029
1030TEST_F(ReceiveStatisticsProxy2Test,
1031 DelayedFramesHistogramsAreNotUpdatedIfNoRenderedFrames) {
1032 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1033 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
1034 VideoContentType::UNSPECIFIED);
1035
1036 // Min run time has passed. No rendered frames.
1037 fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
1038 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
1039 nullptr);
1040 EXPECT_METRIC_EQ(0,
1041 metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
1042 EXPECT_METRIC_EQ(0, metrics::NumSamples(
1043 "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
1044}
1045
1046TEST_F(ReceiveStatisticsProxy2Test, DelayReportedIfFrameIsDelayed) {
1047 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1048 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
1049 VideoContentType::UNSPECIFIED);
1050
1051 // Frame delayed 1 ms, delayed frames to render: 100%.
Tommid7e08c82020-05-10 11:24:43 +02001052 statistics_proxy_->OnRenderedFrame(
1053 MetaData(CreateFrameWithRenderTimeMs(Now().ms() - 1)));
Tommi74fc5742020-04-27 10:43:06 +02001054
1055 // Min run time has passed.
1056 fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
Tommid93bf122020-05-10 20:24:59 +02001057 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001058 EXPECT_METRIC_EQ(1,
1059 metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
1060 EXPECT_METRIC_EQ(
1061 1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer", 100));
1062 EXPECT_METRIC_EQ(1, metrics::NumSamples(
1063 "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
1064 EXPECT_METRIC_EQ(
1065 1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs",
1066 1));
1067}
1068
1069TEST_F(ReceiveStatisticsProxy2Test, AverageDelayOfDelayedFramesIsReported) {
1070 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1071 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
1072 VideoContentType::UNSPECIFIED);
1073
1074 // Two frames delayed (6 ms, 10 ms), delayed frames to render: 50%.
Tommid7e08c82020-05-10 11:24:43 +02001075 const int64_t kNowMs = Now().ms();
1076
1077 statistics_proxy_->OnRenderedFrame(
1078 MetaData(CreateFrameWithRenderTimeMs(kNowMs - 10)));
1079 statistics_proxy_->OnRenderedFrame(
1080 MetaData(CreateFrameWithRenderTimeMs(kNowMs - 6)));
1081 statistics_proxy_->OnRenderedFrame(
1082 MetaData(CreateFrameWithRenderTimeMs(kNowMs)));
1083 statistics_proxy_->OnRenderedFrame(
1084 MetaData(CreateFrameWithRenderTimeMs(kNowMs + 1)));
Tommi74fc5742020-04-27 10:43:06 +02001085
1086 // Min run time has passed.
1087 fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
Tommid93bf122020-05-10 20:24:59 +02001088 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001089 EXPECT_METRIC_EQ(1,
1090 metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
1091 EXPECT_METRIC_EQ(
1092 1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer", 50));
1093 EXPECT_METRIC_EQ(1, metrics::NumSamples(
1094 "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
1095 EXPECT_METRIC_EQ(
1096 1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs",
1097 8));
1098}
1099
1100TEST_F(ReceiveStatisticsProxy2Test,
1101 RtcpHistogramsNotUpdatedIfMinRuntimeHasNotPassed) {
1102 StreamDataCounters data_counters;
1103 data_counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
1104
1105 fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000) -
1106 1);
1107
1108 RtcpPacketTypeCounter counter;
1109 statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc, counter);
1110
1111 statistics_proxy_->UpdateHistograms(absl::nullopt, data_counters, nullptr);
1112 EXPECT_METRIC_EQ(0,
1113 metrics::NumSamples("WebRTC.Video.FirPacketsSentPerMinute"));
1114 EXPECT_METRIC_EQ(0,
1115 metrics::NumSamples("WebRTC.Video.PliPacketsSentPerMinute"));
1116 EXPECT_METRIC_EQ(
1117 0, metrics::NumSamples("WebRTC.Video.NackPacketsSentPerMinute"));
1118}
1119
1120TEST_F(ReceiveStatisticsProxy2Test, RtcpHistogramsAreUpdated) {
1121 StreamDataCounters data_counters;
1122 data_counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
1123 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
1124
1125 const uint32_t kFirPackets = 100;
1126 const uint32_t kPliPackets = 200;
1127 const uint32_t kNackPackets = 300;
1128
1129 RtcpPacketTypeCounter counter;
1130 counter.fir_packets = kFirPackets;
1131 counter.pli_packets = kPliPackets;
1132 counter.nack_packets = kNackPackets;
1133 statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc, counter);
1134
1135 statistics_proxy_->UpdateHistograms(absl::nullopt, data_counters, nullptr);
1136 EXPECT_METRIC_EQ(1,
1137 metrics::NumSamples("WebRTC.Video.FirPacketsSentPerMinute"));
1138 EXPECT_METRIC_EQ(1,
1139 metrics::NumSamples("WebRTC.Video.PliPacketsSentPerMinute"));
1140 EXPECT_METRIC_EQ(
1141 1, metrics::NumSamples("WebRTC.Video.NackPacketsSentPerMinute"));
1142 EXPECT_METRIC_EQ(
1143 1, metrics::NumEvents("WebRTC.Video.FirPacketsSentPerMinute",
1144 kFirPackets * 60 / metrics::kMinRunTimeInSeconds));
1145 EXPECT_METRIC_EQ(
1146 1, metrics::NumEvents("WebRTC.Video.PliPacketsSentPerMinute",
1147 kPliPackets * 60 / metrics::kMinRunTimeInSeconds));
1148 EXPECT_METRIC_EQ(
1149 1, metrics::NumEvents("WebRTC.Video.NackPacketsSentPerMinute",
1150 kNackPackets * 60 / metrics::kMinRunTimeInSeconds));
1151}
1152
1153class ReceiveStatisticsProxy2TestWithFreezeDuration
1154 : public ReceiveStatisticsProxy2Test,
1155 public ::testing::WithParamInterface<
1156 std::tuple<uint32_t, uint32_t, uint32_t>> {
1157 protected:
1158 const uint32_t frame_duration_ms_ = {std::get<0>(GetParam())};
1159 const uint32_t freeze_duration_ms_ = {std::get<1>(GetParam())};
1160 const uint32_t expected_freeze_count_ = {std::get<2>(GetParam())};
1161};
1162
1163// It is a freeze if:
1164// frame_duration_ms >= max(3 * avg_frame_duration, avg_frame_duration + 150)
1165// where avg_frame_duration is average duration of last 30 frames including
1166// the current one.
1167//
1168// Condition 1: 3 * avg_frame_duration > avg_frame_duration + 150
1169const auto kFreezeDetectionCond1Freeze = std::make_tuple(150, 483, 1);
1170const auto kFreezeDetectionCond1NotFreeze = std::make_tuple(150, 482, 0);
1171// Condition 2: 3 * avg_frame_duration < avg_frame_duration + 150
1172const auto kFreezeDetectionCond2Freeze = std::make_tuple(30, 185, 1);
1173const auto kFreezeDetectionCond2NotFreeze = std::make_tuple(30, 184, 0);
1174
1175INSTANTIATE_TEST_SUITE_P(_,
1176 ReceiveStatisticsProxy2TestWithFreezeDuration,
1177 ::testing::Values(kFreezeDetectionCond1Freeze,
1178 kFreezeDetectionCond1NotFreeze,
1179 kFreezeDetectionCond2Freeze,
1180 kFreezeDetectionCond2NotFreeze));
1181
1182TEST_P(ReceiveStatisticsProxy2TestWithFreezeDuration, FreezeDetection) {
1183 VideoReceiveStream::Stats stats = statistics_proxy_->GetStats();
1184 EXPECT_EQ(0u, stats.freeze_count);
1185 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1186
1187 // Add a very long frame. This is need to verify that average frame
1188 // duration, which is supposed to be calculated as mean of durations of
1189 // last 30 frames, is calculated correctly.
Tommid7e08c82020-05-10 11:24:43 +02001190 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001191 fake_clock_.AdvanceTimeMilliseconds(2000);
1192
1193 for (size_t i = 0;
1194 i <= VideoQualityObserver::kAvgInterframeDelaysWindowSizeFrames; ++i) {
1195 fake_clock_.AdvanceTimeMilliseconds(frame_duration_ms_);
Tommid7e08c82020-05-10 11:24:43 +02001196 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001197 }
1198
1199 fake_clock_.AdvanceTimeMilliseconds(freeze_duration_ms_);
Tommid7e08c82020-05-10 11:24:43 +02001200 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001201
1202 stats = statistics_proxy_->GetStats();
1203 EXPECT_EQ(stats.freeze_count, expected_freeze_count_);
1204}
1205
1206class ReceiveStatisticsProxy2TestWithContent
1207 : public ReceiveStatisticsProxy2Test,
1208 public ::testing::WithParamInterface<webrtc::VideoContentType> {
1209 protected:
1210 const webrtc::VideoContentType content_type_{GetParam()};
1211};
1212
1213INSTANTIATE_TEST_SUITE_P(ContentTypes,
1214 ReceiveStatisticsProxy2TestWithContent,
1215 ::testing::Values(VideoContentType::UNSPECIFIED,
1216 VideoContentType::SCREENSHARE));
1217
1218TEST_P(ReceiveStatisticsProxy2TestWithContent, InterFrameDelaysAreReported) {
1219 const int kInterFrameDelayMs = 33;
1220 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1221
1222 for (int i = 0; i < kMinRequiredSamples; ++i) {
1223 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1224 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1225 }
1226 // One extra with double the interval.
1227 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1228 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1229
Tommid93bf122020-05-10 20:24:59 +02001230 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001231 const int kExpectedInterFrame =
1232 (kInterFrameDelayMs * (kMinRequiredSamples - 1) +
1233 kInterFrameDelayMs * 2) /
1234 kMinRequiredSamples;
1235 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1236 EXPECT_METRIC_EQ(
1237 kExpectedInterFrame,
1238 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs"));
1239 EXPECT_METRIC_EQ(
1240 kInterFrameDelayMs * 2,
1241 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
1242 } else {
1243 EXPECT_METRIC_EQ(kExpectedInterFrame,
1244 metrics::MinSample("WebRTC.Video.InterframeDelayInMs"));
1245 EXPECT_METRIC_EQ(kInterFrameDelayMs * 2,
1246 metrics::MinSample("WebRTC.Video.InterframeDelayMaxInMs"));
1247 }
1248}
1249
1250TEST_P(ReceiveStatisticsProxy2TestWithContent,
1251 InterFrameDelaysPercentilesAreReported) {
1252 const int kInterFrameDelayMs = 33;
1253 const int kLastFivePercentsSamples = kMinRequiredSamples * 5 / 100;
1254 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1255
1256 for (int i = 0; i <= kMinRequiredSamples - kLastFivePercentsSamples; ++i) {
1257 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1258 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1259 }
1260 // Last 5% of intervals are double in size.
1261 for (int i = 0; i < kLastFivePercentsSamples; ++i) {
1262 fake_clock_.AdvanceTimeMilliseconds(2 * kInterFrameDelayMs);
1263 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1264 }
1265 // Final sample is outlier and 10 times as big.
1266 fake_clock_.AdvanceTimeMilliseconds(10 * kInterFrameDelayMs);
1267 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1268
Tommid93bf122020-05-10 20:24:59 +02001269 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001270 const int kExpectedInterFrame = kInterFrameDelayMs * 2;
1271 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1272 EXPECT_METRIC_EQ(
1273 kExpectedInterFrame,
1274 metrics::MinSample(
1275 "WebRTC.Video.Screenshare.InterframeDelay95PercentileInMs"));
1276 } else {
1277 EXPECT_METRIC_EQ(
1278 kExpectedInterFrame,
1279 metrics::MinSample("WebRTC.Video.InterframeDelay95PercentileInMs"));
1280 }
1281}
1282
1283TEST_P(ReceiveStatisticsProxy2TestWithContent,
1284 MaxInterFrameDelayOnlyWithValidAverage) {
1285 const int kInterFrameDelayMs = 33;
1286 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1287
1288 for (int i = 0; i < kMinRequiredSamples; ++i) {
1289 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1290 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1291 }
1292
Artem Titovab30d722021-07-27 16:22:11 +02001293 // `kMinRequiredSamples` samples, and thereby intervals, is required. That
Tommi74fc5742020-04-27 10:43:06 +02001294 // means we're one frame short of having a valid data set.
1295 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
1296 nullptr);
1297 EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"));
1298 EXPECT_METRIC_EQ(0,
1299 metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"));
1300 EXPECT_METRIC_EQ(
1301 0, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"));
1302 EXPECT_METRIC_EQ(0, metrics::NumSamples(
1303 "WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
1304}
1305
1306TEST_P(ReceiveStatisticsProxy2TestWithContent,
1307 MaxInterFrameDelayOnlyWithPause) {
1308 const int kInterFrameDelayMs = 33;
1309 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1310
1311 for (int i = 0; i <= kMinRequiredSamples; ++i) {
1312 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1313 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1314 }
1315
Tommid93bf122020-05-10 20:24:59 +02001316 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +02001317 // At this state, we should have a valid inter-frame delay.
1318 // Indicate stream paused and make a large jump in time.
1319 statistics_proxy_->OnStreamInactive();
1320 fake_clock_.AdvanceTimeMilliseconds(5000);
1321
Tommid7e08c82020-05-10 11:24:43 +02001322 // Insert two more frames. The interval during the pause should be
1323 // disregarded in the stats.
Tommi74fc5742020-04-27 10:43:06 +02001324 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1325 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1326 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1327
Tommid93bf122020-05-10 20:24:59 +02001328 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001329 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1330 EXPECT_METRIC_EQ(
1331 1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"));
1332 EXPECT_METRIC_EQ(1, metrics::NumSamples(
1333 "WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
1334 EXPECT_METRIC_EQ(
1335 kInterFrameDelayMs,
1336 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs"));
1337 EXPECT_METRIC_EQ(
1338 kInterFrameDelayMs,
1339 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
1340 } else {
1341 EXPECT_METRIC_EQ(1,
1342 metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"));
1343 EXPECT_METRIC_EQ(
1344 1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"));
1345 EXPECT_METRIC_EQ(kInterFrameDelayMs,
1346 metrics::MinSample("WebRTC.Video.InterframeDelayInMs"));
1347 EXPECT_METRIC_EQ(kInterFrameDelayMs,
1348 metrics::MinSample("WebRTC.Video.InterframeDelayMaxInMs"));
1349 }
1350}
1351
1352TEST_P(ReceiveStatisticsProxy2TestWithContent, FreezesAreReported) {
1353 const int kInterFrameDelayMs = 33;
1354 const int kFreezeDelayMs = 200;
1355 const int kCallDurationMs =
1356 kMinRequiredSamples * kInterFrameDelayMs + kFreezeDelayMs;
1357 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1358
1359 for (int i = 0; i < kMinRequiredSamples; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001360 VideoFrameMetaData meta = MetaData(frame);
1361 statistics_proxy_->OnDecodedFrame(meta, absl::nullopt, 0, content_type_);
1362 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001363 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1364 }
1365 // Add extra freeze.
1366 fake_clock_.AdvanceTimeMilliseconds(kFreezeDelayMs);
Tommid93bf122020-05-10 20:24:59 +02001367 VideoFrameMetaData meta = MetaData(frame);
1368 statistics_proxy_->OnDecodedFrame(meta, absl::nullopt, 0, content_type_);
1369 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001370
Tommid93bf122020-05-10 20:24:59 +02001371 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001372 const int kExpectedTimeBetweenFreezes =
1373 kInterFrameDelayMs * (kMinRequiredSamples - 1);
1374 const int kExpectedNumberFreezesPerMinute = 60 * 1000 / kCallDurationMs;
1375 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1376 EXPECT_METRIC_EQ(
1377 kFreezeDelayMs + kInterFrameDelayMs,
1378 metrics::MinSample("WebRTC.Video.Screenshare.MeanFreezeDurationMs"));
1379 EXPECT_METRIC_EQ(kExpectedTimeBetweenFreezes,
1380 metrics::MinSample(
1381 "WebRTC.Video.Screenshare.MeanTimeBetweenFreezesMs"));
1382 EXPECT_METRIC_EQ(
1383 kExpectedNumberFreezesPerMinute,
1384 metrics::MinSample("WebRTC.Video.Screenshare.NumberFreezesPerMinute"));
1385 } else {
1386 EXPECT_METRIC_EQ(kFreezeDelayMs + kInterFrameDelayMs,
1387 metrics::MinSample("WebRTC.Video.MeanFreezeDurationMs"));
1388 EXPECT_METRIC_EQ(
1389 kExpectedTimeBetweenFreezes,
1390 metrics::MinSample("WebRTC.Video.MeanTimeBetweenFreezesMs"));
1391 EXPECT_METRIC_EQ(kExpectedNumberFreezesPerMinute,
1392 metrics::MinSample("WebRTC.Video.NumberFreezesPerMinute"));
1393 }
1394}
1395
1396TEST_P(ReceiveStatisticsProxy2TestWithContent, HarmonicFrameRateIsReported) {
1397 const int kFrameDurationMs = 33;
1398 const int kFreezeDurationMs = 200;
1399 const int kPauseDurationMs = 10000;
1400 const int kCallDurationMs = kMinRequiredSamples * kFrameDurationMs +
1401 kFreezeDurationMs + kPauseDurationMs;
1402 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1403
1404 for (int i = 0; i < kMinRequiredSamples; ++i) {
1405 fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs);
1406 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
Tommid7e08c82020-05-10 11:24:43 +02001407 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001408 }
1409
1410 // Freezes and pauses should be included into harmonic frame rate.
1411 // Add freeze.
Tommid93bf122020-05-10 20:24:59 +02001412 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +02001413 fake_clock_.AdvanceTimeMilliseconds(kFreezeDurationMs);
1414 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
Tommid7e08c82020-05-10 11:24:43 +02001415 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001416
1417 // Add pause.
Tommid93bf122020-05-10 20:24:59 +02001418 loop_.Flush();
Tommi74fc5742020-04-27 10:43:06 +02001419 fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
1420 statistics_proxy_->OnStreamInactive();
1421 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
Tommid7e08c82020-05-10 11:24:43 +02001422 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001423
Tommid93bf122020-05-10 20:24:59 +02001424 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001425 double kSumSquaredFrameDurationSecs =
1426 (kMinRequiredSamples - 1) *
1427 (kFrameDurationMs / 1000.0 * kFrameDurationMs / 1000.0);
1428 kSumSquaredFrameDurationSecs +=
1429 kFreezeDurationMs / 1000.0 * kFreezeDurationMs / 1000.0;
1430 kSumSquaredFrameDurationSecs +=
1431 kPauseDurationMs / 1000.0 * kPauseDurationMs / 1000.0;
1432 const int kExpectedHarmonicFrameRateFps =
1433 std::round(kCallDurationMs / (1000 * kSumSquaredFrameDurationSecs));
1434 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1435 EXPECT_METRIC_EQ(
1436 kExpectedHarmonicFrameRateFps,
1437 metrics::MinSample("WebRTC.Video.Screenshare.HarmonicFrameRate"));
1438 } else {
1439 EXPECT_METRIC_EQ(kExpectedHarmonicFrameRateFps,
1440 metrics::MinSample("WebRTC.Video.HarmonicFrameRate"));
1441 }
1442}
1443
1444TEST_P(ReceiveStatisticsProxy2TestWithContent, PausesAreIgnored) {
1445 const int kInterFrameDelayMs = 33;
1446 const int kPauseDurationMs = 10000;
1447 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1448
1449 for (int i = 0; i <= kMinRequiredSamples; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001450 VideoFrameMetaData meta = MetaData(frame);
1451 statistics_proxy_->OnDecodedFrame(meta, absl::nullopt, 0, content_type_);
1452 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001453 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1454 }
1455 // Add a pause.
1456 fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
1457 statistics_proxy_->OnStreamInactive();
Tommi74fc5742020-04-27 10:43:06 +02001458 // Second playback interval with triple the length.
1459 for (int i = 0; i <= kMinRequiredSamples * 3; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001460 VideoFrameMetaData meta = MetaData(frame);
1461 statistics_proxy_->OnDecodedFrame(meta, absl::nullopt, 0, content_type_);
1462 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001463 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1464 }
1465
Tommid93bf122020-05-10 20:24:59 +02001466 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001467 // Average of two playback intervals.
1468 const int kExpectedTimeBetweenFreezes =
1469 kInterFrameDelayMs * kMinRequiredSamples * 2;
1470 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1471 EXPECT_METRIC_EQ(-1, metrics::MinSample(
1472 "WebRTC.Video.Screenshare.MeanFreezeDurationMs"));
1473 EXPECT_METRIC_EQ(kExpectedTimeBetweenFreezes,
1474 metrics::MinSample(
1475 "WebRTC.Video.Screenshare.MeanTimeBetweenFreezesMs"));
1476 } else {
1477 EXPECT_METRIC_EQ(-1,
1478 metrics::MinSample("WebRTC.Video.MeanFreezeDurationMs"));
1479 EXPECT_METRIC_EQ(
1480 kExpectedTimeBetweenFreezes,
1481 metrics::MinSample("WebRTC.Video.MeanTimeBetweenFreezesMs"));
1482 }
1483}
1484
1485TEST_P(ReceiveStatisticsProxy2TestWithContent, ManyPausesAtTheBeginning) {
1486 const int kInterFrameDelayMs = 33;
1487 const int kPauseDurationMs = 10000;
1488 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1489
1490 for (int i = 0; i <= kMinRequiredSamples; ++i) {
1491 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1492 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1493
1494 statistics_proxy_->OnStreamInactive();
1495 fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
1496
1497 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
1498 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1499 }
1500
1501 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
1502 nullptr);
Tommid7e08c82020-05-10 11:24:43 +02001503 // No freezes should be detected, as all long inter-frame delays were
1504 // pauses.
Tommi74fc5742020-04-27 10:43:06 +02001505 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1506 EXPECT_METRIC_EQ(-1, metrics::MinSample(
1507 "WebRTC.Video.Screenshare.MeanFreezeDurationMs"));
1508 } else {
1509 EXPECT_METRIC_EQ(-1,
1510 metrics::MinSample("WebRTC.Video.MeanFreezeDurationMs"));
1511 }
1512}
1513
1514TEST_P(ReceiveStatisticsProxy2TestWithContent, TimeInHdReported) {
1515 const int kInterFrameDelayMs = 20;
1516 webrtc::VideoFrame frame_hd = CreateFrame(1280, 720);
1517 webrtc::VideoFrame frame_sd = CreateFrame(640, 360);
1518
1519 // HD frames.
1520 for (int i = 0; i < kMinRequiredSamples; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001521 VideoFrameMetaData meta = MetaData(frame_hd);
1522 statistics_proxy_->OnDecodedFrame(meta, absl::nullopt, 0, content_type_);
1523 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001524 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1525 }
1526 // SD frames.
1527 for (int i = 0; i < 2 * kMinRequiredSamples; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001528 VideoFrameMetaData meta = MetaData(frame_sd);
1529 statistics_proxy_->OnDecodedFrame(meta, absl::nullopt, 0, content_type_);
1530 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001531 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1532 }
1533 // Extra last frame.
Tommid7e08c82020-05-10 11:24:43 +02001534 statistics_proxy_->OnRenderedFrame(MetaData(frame_sd));
Tommi74fc5742020-04-27 10:43:06 +02001535
1536 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
1537 nullptr);
1538 const int kExpectedTimeInHdPercents = 33;
1539 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1540 EXPECT_METRIC_EQ(
1541 kExpectedTimeInHdPercents,
1542 metrics::MinSample("WebRTC.Video.Screenshare.TimeInHdPercentage"));
1543 } else {
1544 EXPECT_METRIC_EQ(kExpectedTimeInHdPercents,
1545 metrics::MinSample("WebRTC.Video.TimeInHdPercentage"));
1546 }
1547}
1548
1549TEST_P(ReceiveStatisticsProxy2TestWithContent, TimeInBlockyVideoReported) {
1550 const int kInterFrameDelayMs = 20;
1551 const int kHighQp = 80;
1552 const int kLowQp = 30;
1553 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1554
1555 // High quality frames.
1556 for (int i = 0; i < kMinRequiredSamples; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001557 VideoFrameMetaData meta = MetaData(frame);
1558 statistics_proxy_->OnDecodedFrame(meta, kLowQp, 0, content_type_);
1559 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001560 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1561 }
1562 // Blocky frames.
1563 for (int i = 0; i < 2 * kMinRequiredSamples; ++i) {
Tommid93bf122020-05-10 20:24:59 +02001564 VideoFrameMetaData meta = MetaData(frame);
1565 statistics_proxy_->OnDecodedFrame(meta, kHighQp, 0, content_type_);
1566 statistics_proxy_->OnRenderedFrame(meta);
Tommi74fc5742020-04-27 10:43:06 +02001567 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1568 }
1569 // Extra last frame.
1570 statistics_proxy_->OnDecodedFrame(frame, kHighQp, 0, content_type_);
Tommid7e08c82020-05-10 11:24:43 +02001571 statistics_proxy_->OnRenderedFrame(MetaData(frame));
Tommi74fc5742020-04-27 10:43:06 +02001572
Tommid93bf122020-05-10 20:24:59 +02001573 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001574 const int kExpectedTimeInHdPercents = 66;
1575 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1576 EXPECT_METRIC_EQ(
1577 kExpectedTimeInHdPercents,
1578 metrics::MinSample(
1579 "WebRTC.Video.Screenshare.TimeInBlockyVideoPercentage"));
1580 } else {
1581 EXPECT_METRIC_EQ(
1582 kExpectedTimeInHdPercents,
1583 metrics::MinSample("WebRTC.Video.TimeInBlockyVideoPercentage"));
1584 }
1585}
1586
1587TEST_P(ReceiveStatisticsProxy2TestWithContent, DownscalesReported) {
1588 const int kInterFrameDelayMs = 2000; // To ensure long enough call duration.
1589
1590 webrtc::VideoFrame frame_hd = CreateFrame(1280, 720);
1591 webrtc::VideoFrame frame_sd = CreateFrame(640, 360);
1592 webrtc::VideoFrame frame_ld = CreateFrame(320, 180);
1593
1594 // Call once to pass content type.
1595 statistics_proxy_->OnDecodedFrame(frame_hd, absl::nullopt, 0, content_type_);
1596
Tommid93bf122020-05-10 20:24:59 +02001597 loop_.Flush();
Tommid7e08c82020-05-10 11:24:43 +02001598 statistics_proxy_->OnRenderedFrame(MetaData(frame_hd));
Tommi74fc5742020-04-27 10:43:06 +02001599 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1600
1601 // Downscale.
Tommid7e08c82020-05-10 11:24:43 +02001602 statistics_proxy_->OnRenderedFrame(MetaData(frame_sd));
Tommi74fc5742020-04-27 10:43:06 +02001603 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1604
1605 // Downscale.
Tommid7e08c82020-05-10 11:24:43 +02001606 statistics_proxy_->OnRenderedFrame(MetaData(frame_ld));
Tommi74fc5742020-04-27 10:43:06 +02001607 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1608
1609 statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
1610 nullptr);
1611 const int kExpectedDownscales = 30; // 2 per 4 seconds = 30 per minute.
1612 if (videocontenttypehelpers::IsScreenshare(content_type_)) {
1613 EXPECT_METRIC_EQ(
1614 kExpectedDownscales,
Tommid7e08c82020-05-10 11:24:43 +02001615 metrics::MinSample("WebRTC.Video.Screenshare."
1616 "NumberResolutionDownswitchesPerMinute"));
Tommi74fc5742020-04-27 10:43:06 +02001617 } else {
1618 EXPECT_METRIC_EQ(kExpectedDownscales,
1619 metrics::MinSample(
1620 "WebRTC.Video.NumberResolutionDownswitchesPerMinute"));
1621 }
1622}
1623
1624TEST_P(ReceiveStatisticsProxy2TestWithContent, DecodeTimeReported) {
1625 const int kInterFrameDelayMs = 20;
1626 const int kLowQp = 30;
1627 const int kDecodeMs = 7;
1628
1629 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1630
1631 for (int i = 0; i < kMinRequiredSamples; ++i) {
1632 statistics_proxy_->OnDecodedFrame(frame, kLowQp, kDecodeMs, content_type_);
1633 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
1634 }
Tommid93bf122020-05-10 20:24:59 +02001635 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001636 EXPECT_METRIC_EQ(
1637 1, metrics::NumEvents("WebRTC.Video.DecodeTimeInMs", kDecodeMs));
1638}
1639
1640TEST_P(ReceiveStatisticsProxy2TestWithContent,
1641 StatsAreSlicedOnSimulcastAndExperiment) {
1642 const uint8_t experiment_id = 1;
1643 webrtc::VideoContentType content_type = content_type_;
1644 videocontenttypehelpers::SetExperimentId(&content_type, experiment_id);
1645 const int kInterFrameDelayMs1 = 30;
1646 const int kInterFrameDelayMs2 = 50;
1647 webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
1648
1649 videocontenttypehelpers::SetSimulcastId(&content_type, 1);
1650 for (int i = 0; i <= kMinRequiredSamples; ++i) {
1651 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs1);
1652 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type);
1653 }
1654
1655 videocontenttypehelpers::SetSimulcastId(&content_type, 2);
1656 for (int i = 0; i <= kMinRequiredSamples; ++i) {
1657 fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs2);
1658 statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type);
1659 }
Tommid93bf122020-05-10 20:24:59 +02001660 FlushAndUpdateHistograms(absl::nullopt, StreamDataCounters(), nullptr);
Tommi74fc5742020-04-27 10:43:06 +02001661
1662 if (videocontenttypehelpers::IsScreenshare(content_type)) {
1663 EXPECT_METRIC_EQ(
1664 1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"));
1665 EXPECT_METRIC_EQ(1, metrics::NumSamples(
1666 "WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
1667 EXPECT_METRIC_EQ(1, metrics::NumSamples(
1668 "WebRTC.Video.Screenshare.InterframeDelayInMs.S0"));
1669 EXPECT_METRIC_EQ(1,
1670 metrics::NumSamples(
1671 "WebRTC.Video.Screenshare.InterframeDelayMaxInMs.S0"));
1672 EXPECT_METRIC_EQ(1, metrics::NumSamples(
1673 "WebRTC.Video.Screenshare.InterframeDelayInMs.S1"));
1674 EXPECT_METRIC_EQ(1,
1675 metrics::NumSamples(
1676 "WebRTC.Video.Screenshare.InterframeDelayMaxInMs.S1"));
1677 EXPECT_METRIC_EQ(
1678 1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"
1679 ".ExperimentGroup0"));
1680 EXPECT_METRIC_EQ(
1681 1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayMaxInMs"
1682 ".ExperimentGroup0"));
1683 EXPECT_METRIC_EQ(
1684 kInterFrameDelayMs1,
1685 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs.S0"));
1686 EXPECT_METRIC_EQ(
1687 kInterFrameDelayMs2,
1688 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs.S1"));
1689 EXPECT_METRIC_EQ(
1690 (kInterFrameDelayMs1 + kInterFrameDelayMs2) / 2,
1691 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs"));
1692 EXPECT_METRIC_EQ(
1693 kInterFrameDelayMs2,
1694 metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
1695 EXPECT_METRIC_EQ(
1696 (kInterFrameDelayMs1 + kInterFrameDelayMs2) / 2,
1697 metrics::MinSample(
1698 "WebRTC.Video.Screenshare.InterframeDelayInMs.ExperimentGroup0"));
1699 } else {
1700 EXPECT_METRIC_EQ(1,
1701 metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"));
1702 EXPECT_METRIC_EQ(
1703 1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"));
1704 EXPECT_METRIC_EQ(
1705 1, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs.S0"));
1706 EXPECT_METRIC_EQ(
1707 1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs.S0"));
1708 EXPECT_METRIC_EQ(
1709 1, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs.S1"));
1710 EXPECT_METRIC_EQ(
1711 1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs.S1"));
1712 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"
1713 ".ExperimentGroup0"));
1714 EXPECT_METRIC_EQ(1,
1715 metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"
1716 ".ExperimentGroup0"));
1717 EXPECT_METRIC_EQ(kInterFrameDelayMs1,
1718 metrics::MinSample("WebRTC.Video.InterframeDelayInMs.S0"));
1719 EXPECT_METRIC_EQ(kInterFrameDelayMs2,
1720 metrics::MinSample("WebRTC.Video.InterframeDelayInMs.S1"));
1721 EXPECT_METRIC_EQ((kInterFrameDelayMs1 + kInterFrameDelayMs2) / 2,
1722 metrics::MinSample("WebRTC.Video.InterframeDelayInMs"));
1723 EXPECT_METRIC_EQ(kInterFrameDelayMs2,
1724 metrics::MinSample("WebRTC.Video.InterframeDelayMaxInMs"));
1725 EXPECT_METRIC_EQ((kInterFrameDelayMs1 + kInterFrameDelayMs2) / 2,
1726 metrics::MinSample(
1727 "WebRTC.Video.InterframeDelayInMs.ExperimentGroup0"));
1728 }
1729}
1730
1731class DecodeTimeHistogramsKillswitch {
1732 public:
1733 explicit DecodeTimeHistogramsKillswitch(bool disable_histograms)
1734 : field_trial_(disable_histograms
1735 ? "WebRTC-DecodeTimeHistogramsKillSwitch/Enabled/"
1736 : "") {}
1737
1738 private:
1739 webrtc::test::ScopedFieldTrials field_trial_;
1740};
1741
1742class ReceiveStatisticsProxy2TestWithDecodeTimeHistograms
1743 : public DecodeTimeHistogramsKillswitch,
1744 public ::testing::WithParamInterface<
1745 std::tuple<bool, int, int, int, VideoCodecType, std::string>>,
1746 public ReceiveStatisticsProxy2Test {
1747 public:
1748 ReceiveStatisticsProxy2TestWithDecodeTimeHistograms()
1749 : DecodeTimeHistogramsKillswitch(std::get<0>(GetParam())) {}
1750
1751 protected:
1752 const std::string kUmaPrefix = "WebRTC.Video.DecodeTimePerFrameInMs.";
1753 const int expected_number_of_samples_ = {std::get<1>(GetParam())};
1754 const int width_ = {std::get<2>(GetParam())};
1755 const int height_ = {std::get<3>(GetParam())};
1756 const VideoCodecType codec_type_ = {std::get<4>(GetParam())};
1757 const std::string implementation_name_ = {std::get<5>(GetParam())};
1758 const std::string uma_histogram_name_ =
1759 kUmaPrefix + (codec_type_ == kVideoCodecVP9 ? "Vp9." : "H264.") +
1760 (height_ == 2160 ? "4k." : "Hd.") +
1761 (implementation_name_.compare("ExternalDecoder") == 0 ? "Hw" : "Sw");
1762};
1763
1764TEST_P(ReceiveStatisticsProxy2TestWithDecodeTimeHistograms,
1765 DecodeTimeHistogramsUpdated) {
1766 constexpr int kNumberOfFrames = 10;
1767 constexpr int kDecodeTimeMs = 7;
1768 constexpr int kFrameDurationMs = 1000 / 60;
1769
1770 webrtc::VideoFrame frame = CreateFrame(width_, height_);
1771
1772 statistics_proxy_->OnDecoderImplementationName(implementation_name_.c_str());
1773 statistics_proxy_->OnPreDecode(codec_type_, /*qp=*/0);
1774
1775 for (int i = 0; i < kNumberOfFrames; ++i) {
1776 statistics_proxy_->OnDecodedFrame(frame, /*qp=*/absl::nullopt,
1777 kDecodeTimeMs,
1778 VideoContentType::UNSPECIFIED);
1779 fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs);
1780 }
1781
Tommid93bf122020-05-10 20:24:59 +02001782 loop_.Flush();
1783
Tommi74fc5742020-04-27 10:43:06 +02001784 EXPECT_METRIC_EQ(expected_number_of_samples_,
1785 metrics::NumSamples(uma_histogram_name_));
1786 EXPECT_METRIC_EQ(expected_number_of_samples_,
1787 metrics::NumEvents(uma_histogram_name_, kDecodeTimeMs));
1788}
1789
1790const auto kVp94kHw = std::make_tuple(/*killswitch=*/false,
1791 /*expected_number_of_samples=*/10,
1792 /*width=*/3840,
1793 /*height=*/2160,
1794 kVideoCodecVP9,
1795 /*implementation=*/"ExternalDecoder");
1796const auto kVp94kSw = std::make_tuple(/*killswitch=*/false,
1797 /*expected_number_of_samples=*/10,
1798 /*width=*/3840,
1799 /*height=*/2160,
1800 kVideoCodecVP9,
1801 /*implementation=*/"libvpx");
1802const auto kVp9HdHw = std::make_tuple(/*killswitch=*/false,
1803 /*expected_number_of_samples=*/10,
1804 /*width=*/1920,
1805 /*height=*/1080,
1806 kVideoCodecVP9,
1807 /*implementation=*/"ExternalDecoder");
1808const auto kVp9HdSw = std::make_tuple(/*killswitch=*/false,
1809 /*expected_number_of_samples=*/10,
1810 /*width=*/1920,
1811 /*height=*/1080,
1812 kVideoCodecVP9,
1813 /*implementation=*/"libvpx");
1814const auto kH2644kHw = std::make_tuple(/*killswitch=*/false,
1815 /*expected_number_of_samples=*/10,
1816 /*width=*/3840,
1817 /*height=*/2160,
1818 kVideoCodecH264,
1819 /*implementation=*/"ExternalDecoder");
1820const auto kH2644kSw = std::make_tuple(/*killswitch=*/false,
1821 /*expected_number_of_samples=*/10,
1822 /*width=*/3840,
1823 /*height=*/2160,
1824 kVideoCodecH264,
1825 /*implementation=*/"FFmpeg");
1826const auto kH264HdHw = std::make_tuple(/*killswitch=*/false,
1827 /*expected_number_of_samples=*/10,
1828 /*width=*/1920,
1829 /*height=*/1080,
1830 kVideoCodecH264,
1831 /*implementation=*/"ExternalDecoder");
1832const auto kH264HdSw = std::make_tuple(/*killswitch=*/false,
1833 /*expected_number_of_samples=*/10,
1834 /*width=*/1920,
1835 /*height=*/1080,
1836 kVideoCodecH264,
1837 /*implementation=*/"FFmpeg");
1838
1839INSTANTIATE_TEST_SUITE_P(AllHistogramsPopulated,
1840 ReceiveStatisticsProxy2TestWithDecodeTimeHistograms,
1841 ::testing::Values(kVp94kHw,
1842 kVp94kSw,
1843 kVp9HdHw,
1844 kVp9HdSw,
1845 kH2644kHw,
1846 kH2644kSw,
1847 kH264HdHw,
1848 kH264HdSw));
1849
1850const auto kKillswitchDisabled =
1851 std::make_tuple(/*killswitch=*/false,
1852 /*expected_number_of_samples=*/10,
1853 /*width=*/1920,
1854 /*height=*/1080,
1855 kVideoCodecVP9,
1856 /*implementation=*/"libvpx");
1857const auto kKillswitchEnabled =
1858 std::make_tuple(/*killswitch=*/true,
1859 /*expected_number_of_samples=*/0,
1860 /*width=*/1920,
1861 /*height=*/1080,
1862 kVideoCodecVP9,
1863 /*implementation=*/"libvpx");
1864
1865INSTANTIATE_TEST_SUITE_P(KillswitchEffective,
1866 ReceiveStatisticsProxy2TestWithDecodeTimeHistograms,
1867 ::testing::Values(kKillswitchDisabled,
1868 kKillswitchEnabled));
1869
1870} // namespace internal
1871} // namespace webrtc