1 /*
2 * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "video/frame_cadence_adapter.h"
12
13 #include <utility>
14 #include <vector>
15
16 #include "absl/functional/any_invocable.h"
17 #include "api/task_queue/default_task_queue_factory.h"
18 #include "api/task_queue/task_queue_base.h"
19 #include "api/task_queue/task_queue_factory.h"
20 #include "api/units/time_delta.h"
21 #include "api/units/timestamp.h"
22 #include "api/video/nv12_buffer.h"
23 #include "api/video/video_frame.h"
24 #include "rtc_base/event.h"
25 #include "rtc_base/rate_statistics.h"
26 #include "rtc_base/time_utils.h"
27 #include "system_wrappers/include/metrics.h"
28 #include "system_wrappers/include/ntp_time.h"
29 #include "system_wrappers/include/sleep.h"
30 #include "test/gmock.h"
31 #include "test/gtest.h"
32 #include "test/scoped_key_value_config.h"
33 #include "test/time_controller/simulated_time_controller.h"
34
35 namespace webrtc {
36 namespace {
37
38 using ::testing::_;
39 using ::testing::ElementsAre;
40 using ::testing::Invoke;
41 using ::testing::Mock;
42 using ::testing::Pair;
43 using ::testing::Values;
44
CreateFrame()45 VideoFrame CreateFrame() {
46 return VideoFrame::Builder()
47 .set_video_frame_buffer(
48 rtc::make_ref_counted<NV12Buffer>(/*width=*/16, /*height=*/16))
49 .build();
50 }
51
CreateFrameWithTimestamps(GlobalSimulatedTimeController * time_controller)52 VideoFrame CreateFrameWithTimestamps(
53 GlobalSimulatedTimeController* time_controller) {
54 return VideoFrame::Builder()
55 .set_video_frame_buffer(
56 rtc::make_ref_counted<NV12Buffer>(/*width=*/16, /*height=*/16))
57 .set_ntp_time_ms(time_controller->GetClock()->CurrentNtpInMilliseconds())
58 .set_timestamp_us(time_controller->GetClock()->CurrentTime().us())
59 .build();
60 }
61
CreateAdapter(const FieldTrialsView & field_trials,Clock * clock)62 std::unique_ptr<FrameCadenceAdapterInterface> CreateAdapter(
63 const FieldTrialsView& field_trials,
64 Clock* clock) {
65 return FrameCadenceAdapterInterface::Create(clock, TaskQueueBase::Current(),
66 field_trials);
67 }
68
69 class MockCallback : public FrameCadenceAdapterInterface::Callback {
70 public:
71 MOCK_METHOD(void, OnFrame, (Timestamp, int, const VideoFrame&), (override));
72 MOCK_METHOD(void, OnDiscardedFrame, (), (override));
73 MOCK_METHOD(void, RequestRefreshFrame, (), (override));
74 };
75
76 class ZeroHertzFieldTrialDisabler : public test::ScopedKeyValueConfig {
77 public:
ZeroHertzFieldTrialDisabler()78 ZeroHertzFieldTrialDisabler()
79 : test::ScopedKeyValueConfig("WebRTC-ZeroHertzScreenshare/Disabled/") {}
80 };
81
82 class ZeroHertzFieldTrialEnabler : public test::ScopedKeyValueConfig {
83 public:
ZeroHertzFieldTrialEnabler()84 ZeroHertzFieldTrialEnabler()
85 : test::ScopedKeyValueConfig("WebRTC-ZeroHertzScreenshare/Enabled/") {}
86 };
87
TEST(FrameCadenceAdapterTest,ForwardsFramesOnConstructionAndUnderDisabledFieldTrial)88 TEST(FrameCadenceAdapterTest,
89 ForwardsFramesOnConstructionAndUnderDisabledFieldTrial) {
90 GlobalSimulatedTimeController time_controller(Timestamp::Millis(1));
91 ZeroHertzFieldTrialDisabler disabled_field_trials;
92 test::ScopedKeyValueConfig no_field_trials;
93 for (int i = 0; i != 2; i++) {
94 MockCallback callback;
95 auto adapter =
96 CreateAdapter(i == 0 ? disabled_field_trials : no_field_trials,
97 time_controller.GetClock());
98 adapter->Initialize(&callback);
99 VideoFrame frame = CreateFrame();
100 EXPECT_CALL(callback, OnFrame).Times(1);
101 adapter->OnFrame(frame);
102 time_controller.AdvanceTime(TimeDelta::Zero());
103 Mock::VerifyAndClearExpectations(&callback);
104 EXPECT_CALL(callback, OnDiscardedFrame).Times(1);
105 adapter->OnDiscardedFrame();
106 Mock::VerifyAndClearExpectations(&callback);
107 }
108 }
109
TEST(FrameCadenceAdapterTest,CountsOutstandingFramesToProcess)110 TEST(FrameCadenceAdapterTest, CountsOutstandingFramesToProcess) {
111 test::ScopedKeyValueConfig no_field_trials;
112 GlobalSimulatedTimeController time_controller(Timestamp::Millis(1));
113 MockCallback callback;
114 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
115 adapter->Initialize(&callback);
116 EXPECT_CALL(callback, OnFrame(_, 2, _)).Times(1);
117 EXPECT_CALL(callback, OnFrame(_, 1, _)).Times(1);
118 auto frame = CreateFrame();
119 adapter->OnFrame(frame);
120 adapter->OnFrame(frame);
121 time_controller.AdvanceTime(TimeDelta::Zero());
122 EXPECT_CALL(callback, OnFrame(_, 1, _)).Times(1);
123 adapter->OnFrame(frame);
124 time_controller.AdvanceTime(TimeDelta::Zero());
125 }
126
TEST(FrameCadenceAdapterTest,FrameRateFollowsRateStatisticsByDefault)127 TEST(FrameCadenceAdapterTest, FrameRateFollowsRateStatisticsByDefault) {
128 test::ScopedKeyValueConfig no_field_trials;
129 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
130 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
131 adapter->Initialize(nullptr);
132
133 // Create an "oracle" rate statistics which should be followed on a sequence
134 // of frames.
135 RateStatistics rate(
136 FrameCadenceAdapterInterface::kFrameRateAveragingWindowSizeMs, 1000);
137
138 for (int frame = 0; frame != 10; ++frame) {
139 time_controller.AdvanceTime(TimeDelta::Millis(10));
140 rate.Update(1, time_controller.GetClock()->TimeInMilliseconds());
141 adapter->UpdateFrameRate();
142 EXPECT_EQ(rate.Rate(time_controller.GetClock()->TimeInMilliseconds()),
143 adapter->GetInputFrameRateFps())
144 << " failed for frame " << frame;
145 }
146 }
147
TEST(FrameCadenceAdapterTest,FrameRateFollowsRateStatisticsWhenFeatureDisabled)148 TEST(FrameCadenceAdapterTest,
149 FrameRateFollowsRateStatisticsWhenFeatureDisabled) {
150 ZeroHertzFieldTrialDisabler feature_disabler;
151 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
152 auto adapter = CreateAdapter(feature_disabler, time_controller.GetClock());
153 adapter->Initialize(nullptr);
154
155 // Create an "oracle" rate statistics which should be followed on a sequence
156 // of frames.
157 RateStatistics rate(
158 FrameCadenceAdapterInterface::kFrameRateAveragingWindowSizeMs, 1000);
159
160 for (int frame = 0; frame != 10; ++frame) {
161 time_controller.AdvanceTime(TimeDelta::Millis(10));
162 rate.Update(1, time_controller.GetClock()->TimeInMilliseconds());
163 adapter->UpdateFrameRate();
164 EXPECT_EQ(rate.Rate(time_controller.GetClock()->TimeInMilliseconds()),
165 adapter->GetInputFrameRateFps())
166 << " failed for frame " << frame;
167 }
168 }
169
TEST(FrameCadenceAdapterTest,FrameRateFollowsMaxFpsWhenZeroHertzActivated)170 TEST(FrameCadenceAdapterTest, FrameRateFollowsMaxFpsWhenZeroHertzActivated) {
171 ZeroHertzFieldTrialEnabler enabler;
172 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
173 auto adapter = CreateAdapter(enabler, time_controller.GetClock());
174 adapter->Initialize(nullptr);
175 adapter->SetZeroHertzModeEnabled(
176 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
177 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
178 for (int frame = 0; frame != 10; ++frame) {
179 time_controller.AdvanceTime(TimeDelta::Millis(10));
180 adapter->UpdateFrameRate();
181 EXPECT_EQ(adapter->GetInputFrameRateFps(), 1u);
182 }
183 }
184
TEST(FrameCadenceAdapterTest,FrameRateFollowsRateStatisticsAfterZeroHertzDeactivated)185 TEST(FrameCadenceAdapterTest,
186 FrameRateFollowsRateStatisticsAfterZeroHertzDeactivated) {
187 ZeroHertzFieldTrialEnabler enabler;
188 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
189 auto adapter = CreateAdapter(enabler, time_controller.GetClock());
190 adapter->Initialize(nullptr);
191 adapter->SetZeroHertzModeEnabled(
192 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
193 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
194 RateStatistics rate(
195 FrameCadenceAdapterInterface::kFrameRateAveragingWindowSizeMs, 1000);
196 constexpr int MAX = 10;
197 for (int frame = 0; frame != MAX; ++frame) {
198 time_controller.AdvanceTime(TimeDelta::Millis(10));
199 rate.Update(1, time_controller.GetClock()->TimeInMilliseconds());
200 adapter->UpdateFrameRate();
201 }
202 // Turn off zero hertz on the next-last frame; after the last frame we
203 // should see a value that tracks the rate oracle.
204 adapter->SetZeroHertzModeEnabled(absl::nullopt);
205 // Last frame.
206 time_controller.AdvanceTime(TimeDelta::Millis(10));
207 rate.Update(1, time_controller.GetClock()->TimeInMilliseconds());
208 adapter->UpdateFrameRate();
209
210 EXPECT_EQ(rate.Rate(time_controller.GetClock()->TimeInMilliseconds()),
211 adapter->GetInputFrameRateFps());
212 }
213
TEST(FrameCadenceAdapterTest,ForwardsFramesDelayed)214 TEST(FrameCadenceAdapterTest, ForwardsFramesDelayed) {
215 ZeroHertzFieldTrialEnabler enabler;
216 MockCallback callback;
217 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
218 auto adapter = CreateAdapter(enabler, time_controller.GetClock());
219 adapter->Initialize(&callback);
220 adapter->SetZeroHertzModeEnabled(
221 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
222 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
223 constexpr int kNumFrames = 3;
224 NtpTime original_ntp_time = time_controller.GetClock()->CurrentNtpTime();
225 auto frame = CreateFrameWithTimestamps(&time_controller);
226 int64_t original_timestamp_us = frame.timestamp_us();
227 for (int index = 0; index != kNumFrames; ++index) {
228 EXPECT_CALL(callback, OnFrame).Times(0);
229 adapter->OnFrame(frame);
230 EXPECT_CALL(callback, OnFrame)
231 .WillOnce(Invoke([&](Timestamp post_time, int,
232 const VideoFrame& frame) {
233 EXPECT_EQ(post_time, time_controller.GetClock()->CurrentTime());
234 EXPECT_EQ(frame.timestamp_us(),
235 original_timestamp_us + index * rtc::kNumMicrosecsPerSec);
236 EXPECT_EQ(frame.ntp_time_ms(), original_ntp_time.ToMs() +
237 index * rtc::kNumMillisecsPerSec);
238 }));
239 time_controller.AdvanceTime(TimeDelta::Seconds(1));
240 frame = CreateFrameWithTimestamps(&time_controller);
241 }
242 }
243
TEST(FrameCadenceAdapterTest,RepeatsFramesDelayed)244 TEST(FrameCadenceAdapterTest, RepeatsFramesDelayed) {
245 // Logic in the frame cadence adapter avoids modifying frame NTP and render
246 // timestamps if these timestamps looks unset, which is the case when the
247 // clock is initialized running from 0. For this reason we choose the
248 // `time_controller` initialization constant to something arbitrary which is
249 // not 0.
250 ZeroHertzFieldTrialEnabler enabler;
251 MockCallback callback;
252 GlobalSimulatedTimeController time_controller(Timestamp::Millis(47892223));
253 auto adapter = CreateAdapter(enabler, time_controller.GetClock());
254 adapter->Initialize(&callback);
255 adapter->SetZeroHertzModeEnabled(
256 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
257 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
258 NtpTime original_ntp_time = time_controller.GetClock()->CurrentNtpTime();
259
260 // Send one frame, expect 2 subsequent repeats.
261 auto frame = CreateFrameWithTimestamps(&time_controller);
262 int64_t original_timestamp_us = frame.timestamp_us();
263 adapter->OnFrame(frame);
264
265 EXPECT_CALL(callback, OnFrame)
266 .WillOnce(Invoke([&](Timestamp post_time, int, const VideoFrame& frame) {
267 EXPECT_EQ(post_time, time_controller.GetClock()->CurrentTime());
268 EXPECT_EQ(frame.timestamp_us(), original_timestamp_us);
269 EXPECT_EQ(frame.ntp_time_ms(), original_ntp_time.ToMs());
270 }));
271 time_controller.AdvanceTime(TimeDelta::Seconds(1));
272 Mock::VerifyAndClearExpectations(&callback);
273
274 EXPECT_CALL(callback, OnFrame)
275 .WillOnce(Invoke([&](Timestamp post_time, int, const VideoFrame& frame) {
276 EXPECT_EQ(post_time, time_controller.GetClock()->CurrentTime());
277 EXPECT_EQ(frame.timestamp_us(),
278 original_timestamp_us + rtc::kNumMicrosecsPerSec);
279 EXPECT_EQ(frame.ntp_time_ms(),
280 original_ntp_time.ToMs() + rtc::kNumMillisecsPerSec);
281 }));
282 time_controller.AdvanceTime(TimeDelta::Seconds(1));
283 Mock::VerifyAndClearExpectations(&callback);
284
285 EXPECT_CALL(callback, OnFrame)
286 .WillOnce(Invoke([&](Timestamp post_time, int, const VideoFrame& frame) {
287 EXPECT_EQ(post_time, time_controller.GetClock()->CurrentTime());
288 EXPECT_EQ(frame.timestamp_us(),
289 original_timestamp_us + 2 * rtc::kNumMicrosecsPerSec);
290 EXPECT_EQ(frame.ntp_time_ms(),
291 original_ntp_time.ToMs() + 2 * rtc::kNumMillisecsPerSec);
292 }));
293 time_controller.AdvanceTime(TimeDelta::Seconds(1));
294 }
295
TEST(FrameCadenceAdapterTest,RepeatsFramesWithoutTimestampsWithUnsetTimestamps)296 TEST(FrameCadenceAdapterTest,
297 RepeatsFramesWithoutTimestampsWithUnsetTimestamps) {
298 // Logic in the frame cadence adapter avoids modifying frame NTP and render
299 // timestamps if these timestamps looks unset, which is the case when the
300 // clock is initialized running from 0. In this test we deliberately don't set
301 // it to zero, but select unset timestamps in the frames (via CreateFrame())
302 // and verify that the timestamp modifying logic doesn't depend on the current
303 // time.
304 ZeroHertzFieldTrialEnabler enabler;
305 MockCallback callback;
306 GlobalSimulatedTimeController time_controller(Timestamp::Millis(4711));
307 auto adapter = CreateAdapter(enabler, time_controller.GetClock());
308 adapter->Initialize(&callback);
309 adapter->SetZeroHertzModeEnabled(
310 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
311 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
312
313 // Send one frame, expect a repeat.
314 adapter->OnFrame(CreateFrame());
315 EXPECT_CALL(callback, OnFrame)
316 .WillOnce(Invoke([&](Timestamp post_time, int, const VideoFrame& frame) {
317 EXPECT_EQ(post_time, time_controller.GetClock()->CurrentTime());
318 EXPECT_EQ(frame.timestamp_us(), 0);
319 EXPECT_EQ(frame.ntp_time_ms(), 0);
320 }));
321 time_controller.AdvanceTime(TimeDelta::Seconds(1));
322 Mock::VerifyAndClearExpectations(&callback);
323 EXPECT_CALL(callback, OnFrame)
324 .WillOnce(Invoke([&](Timestamp post_time, int, const VideoFrame& frame) {
325 EXPECT_EQ(post_time, time_controller.GetClock()->CurrentTime());
326 EXPECT_EQ(frame.timestamp_us(), 0);
327 EXPECT_EQ(frame.ntp_time_ms(), 0);
328 }));
329 time_controller.AdvanceTime(TimeDelta::Seconds(1));
330 }
331
TEST(FrameCadenceAdapterTest,StopsRepeatingFramesDelayed)332 TEST(FrameCadenceAdapterTest, StopsRepeatingFramesDelayed) {
333 // At 1s, the initially scheduled frame appears.
334 // At 2s, the repeated initial frame appears.
335 // At 2.5s, we schedule another new frame.
336 // At 3.5s, we receive this frame.
337 ZeroHertzFieldTrialEnabler enabler;
338 MockCallback callback;
339 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
340 auto adapter = CreateAdapter(enabler, time_controller.GetClock());
341 adapter->Initialize(&callback);
342 adapter->SetZeroHertzModeEnabled(
343 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
344 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
345 NtpTime original_ntp_time = time_controller.GetClock()->CurrentNtpTime();
346
347 // Send one frame, expect 1 subsequent repeat.
348 adapter->OnFrame(CreateFrameWithTimestamps(&time_controller));
349 EXPECT_CALL(callback, OnFrame).Times(2);
350 time_controller.AdvanceTime(TimeDelta::Seconds(2.5));
351 Mock::VerifyAndClearExpectations(&callback);
352
353 // Send the new frame at 2.5s, which should appear after 3.5s.
354 adapter->OnFrame(CreateFrameWithTimestamps(&time_controller));
355 EXPECT_CALL(callback, OnFrame)
356 .WillOnce(Invoke([&](Timestamp, int, const VideoFrame& frame) {
357 EXPECT_EQ(frame.timestamp_us(), 5 * rtc::kNumMicrosecsPerSec / 2);
358 EXPECT_EQ(frame.ntp_time_ms(),
359 original_ntp_time.ToMs() + 5u * rtc::kNumMillisecsPerSec / 2);
360 }));
361 time_controller.AdvanceTime(TimeDelta::Seconds(1));
362 }
363
TEST(FrameCadenceAdapterTest,RequestsRefreshFrameOnKeyFrameRequestWhenNew)364 TEST(FrameCadenceAdapterTest, RequestsRefreshFrameOnKeyFrameRequestWhenNew) {
365 ZeroHertzFieldTrialEnabler enabler;
366 MockCallback callback;
367 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
368 auto adapter = CreateAdapter(enabler, time_controller.GetClock());
369 adapter->Initialize(&callback);
370 adapter->SetZeroHertzModeEnabled(
371 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
372 constexpr int kMaxFps = 10;
373 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFps});
374 EXPECT_CALL(callback, RequestRefreshFrame);
375 time_controller.AdvanceTime(
376 TimeDelta::Seconds(1) *
377 FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod /
378 kMaxFps);
379 adapter->ProcessKeyFrameRequest();
380 }
381
TEST(FrameCadenceAdapterTest,IgnoresKeyFrameRequestShortlyAfterFrame)382 TEST(FrameCadenceAdapterTest, IgnoresKeyFrameRequestShortlyAfterFrame) {
383 ZeroHertzFieldTrialEnabler enabler;
384 MockCallback callback;
385 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
386 auto adapter = CreateAdapter(enabler, time_controller.GetClock());
387 adapter->Initialize(&callback);
388 adapter->SetZeroHertzModeEnabled(
389 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
390 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 10});
391 adapter->OnFrame(CreateFrame());
392 time_controller.AdvanceTime(TimeDelta::Zero());
393 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
394 adapter->ProcessKeyFrameRequest();
395 }
396
TEST(FrameCadenceAdapterTest,RequestsRefreshFramesUntilArrival)397 TEST(FrameCadenceAdapterTest, RequestsRefreshFramesUntilArrival) {
398 ZeroHertzFieldTrialEnabler enabler;
399 MockCallback callback;
400 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
401 auto adapter = CreateAdapter(enabler, time_controller.GetClock());
402 adapter->Initialize(&callback);
403 adapter->SetZeroHertzModeEnabled(
404 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
405 constexpr int kMaxFps = 10;
406 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFps});
407
408 // We should see max_fps + 1 -
409 // FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod refresh
410 // frame requests during the one second we wait until we send a single frame,
411 // after which refresh frame requests should cease (we should see no such
412 // requests during a second).
413 EXPECT_CALL(callback, RequestRefreshFrame)
414 .Times(kMaxFps + 1 -
415 FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod);
416 time_controller.AdvanceTime(TimeDelta::Seconds(1));
417 Mock::VerifyAndClearExpectations(&callback);
418 adapter->OnFrame(CreateFrame());
419 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
420 time_controller.AdvanceTime(TimeDelta::Seconds(1));
421 }
422
TEST(FrameCadenceAdapterTest,RequestsRefreshAfterFrameDrop)423 TEST(FrameCadenceAdapterTest, RequestsRefreshAfterFrameDrop) {
424 ZeroHertzFieldTrialEnabler enabler;
425 MockCallback callback;
426 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
427 auto adapter = CreateAdapter(enabler, time_controller.GetClock());
428 adapter->Initialize(&callback);
429 adapter->SetZeroHertzModeEnabled(
430 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
431 constexpr int kMaxFps = 10;
432 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFps});
433
434 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
435
436 // Send a frame through to cancel the initial delayed timer waiting for first
437 // frame entry.
438 adapter->OnFrame(CreateFrame());
439 time_controller.AdvanceTime(TimeDelta::Seconds(1));
440 Mock::VerifyAndClearExpectations(&callback);
441
442 // Send a dropped frame indication without any following frames received.
443 // After FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod
444 // frame periods, we should receive a first refresh request.
445 adapter->OnDiscardedFrame();
446 EXPECT_CALL(callback, RequestRefreshFrame);
447 time_controller.AdvanceTime(
448 TimeDelta::Seconds(1) *
449 FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod /
450 kMaxFps);
451 Mock::VerifyAndClearExpectations(&callback);
452
453 // We will now receive a refresh frame request for every frame period.
454 EXPECT_CALL(callback, RequestRefreshFrame).Times(kMaxFps);
455 time_controller.AdvanceTime(TimeDelta::Seconds(1));
456 Mock::VerifyAndClearExpectations(&callback);
457
458 // After a frame is passed the requests will cease.
459 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
460 adapter->OnFrame(CreateFrame());
461 time_controller.AdvanceTime(TimeDelta::Seconds(1));
462 }
463
TEST(FrameCadenceAdapterTest,OmitsRefreshAfterFrameDropWithTimelyFrameEntry)464 TEST(FrameCadenceAdapterTest, OmitsRefreshAfterFrameDropWithTimelyFrameEntry) {
465 ZeroHertzFieldTrialEnabler enabler;
466 MockCallback callback;
467 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
468 auto adapter = CreateAdapter(enabler, time_controller.GetClock());
469 adapter->Initialize(&callback);
470 adapter->SetZeroHertzModeEnabled(
471 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
472 constexpr int kMaxFps = 10;
473 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFps});
474
475 // Send a frame through to cancel the initial delayed timer waiting for first
476 // frame entry.
477 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
478 adapter->OnFrame(CreateFrame());
479 time_controller.AdvanceTime(TimeDelta::Seconds(1));
480 Mock::VerifyAndClearExpectations(&callback);
481
482 // Send a frame drop indication. No refresh frames should be requested
483 // until FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod
484 // intervals pass. Stop short of this.
485 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
486 adapter->OnDiscardedFrame();
487 time_controller.AdvanceTime(
488 TimeDelta::Seconds(1) *
489 FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod /
490 kMaxFps -
491 TimeDelta::Micros(1));
492 Mock::VerifyAndClearExpectations(&callback);
493
494 // Send a frame. The timer to request the refresh frame should be cancelled by
495 // the reception, so no refreshes should be requested.
496 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
497 adapter->OnFrame(CreateFrame());
498 time_controller.AdvanceTime(TimeDelta::Seconds(1));
499 Mock::VerifyAndClearExpectations(&callback);
500 }
501
TEST(FrameCadenceAdapterTest,AcceptsUnconfiguredLayerFeedback)502 TEST(FrameCadenceAdapterTest, AcceptsUnconfiguredLayerFeedback) {
503 // This is a regression test for bugs.webrtc.org/14417.
504 ZeroHertzFieldTrialEnabler enabler;
505 MockCallback callback;
506 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
507 auto adapter = CreateAdapter(enabler, time_controller.GetClock());
508 adapter->Initialize(&callback);
509 adapter->SetZeroHertzModeEnabled(
510 FrameCadenceAdapterInterface::ZeroHertzModeParams{.num_simulcast_layers =
511 1});
512 constexpr int kMaxFps = 10;
513 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFps});
514 time_controller.AdvanceTime(TimeDelta::Zero());
515
516 adapter->UpdateLayerQualityConvergence(2, false);
517 adapter->UpdateLayerStatus(2, false);
518 }
519
520 class FrameCadenceAdapterSimulcastLayersParamTest
521 : public ::testing::TestWithParam<int> {
522 public:
523 static constexpr int kMaxFpsHz = 8;
524 static constexpr TimeDelta kMinFrameDelay =
525 TimeDelta::Millis(1000 / kMaxFpsHz);
526 static constexpr TimeDelta kIdleFrameDelay =
527 FrameCadenceAdapterInterface::kZeroHertzIdleRepeatRatePeriod;
528
FrameCadenceAdapterSimulcastLayersParamTest()529 FrameCadenceAdapterSimulcastLayersParamTest() {
530 adapter_->Initialize(&callback_);
531 adapter_->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFpsHz});
532 time_controller_.AdvanceTime(TimeDelta::Zero());
533 adapter_->SetZeroHertzModeEnabled(
534 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
535 const size_t num_spatial_layers = GetParam();
536 adapter_->SetZeroHertzModeEnabled(
537 FrameCadenceAdapterInterface::ZeroHertzModeParams{num_spatial_layers});
538 }
539
NumSpatialLayers() const540 int NumSpatialLayers() const { return GetParam(); }
541
542 protected:
543 ZeroHertzFieldTrialEnabler enabler_;
544 MockCallback callback_;
545 GlobalSimulatedTimeController time_controller_{Timestamp::Zero()};
546 const std::unique_ptr<FrameCadenceAdapterInterface> adapter_{
547 CreateAdapter(enabler_, time_controller_.GetClock())};
548 };
549
TEST_P(FrameCadenceAdapterSimulcastLayersParamTest,LayerReconfigurationResetsConvergenceInfo)550 TEST_P(FrameCadenceAdapterSimulcastLayersParamTest,
551 LayerReconfigurationResetsConvergenceInfo) {
552 // Assumes layer reconfiguration has just happened.
553 // Verify the state is unconverged.
554 adapter_->OnFrame(CreateFrame());
555 EXPECT_CALL(callback_, OnFrame).Times(kMaxFpsHz);
556 time_controller_.AdvanceTime(kMaxFpsHz * kMinFrameDelay);
557 }
558
TEST_P(FrameCadenceAdapterSimulcastLayersParamTest,IgnoresKeyFrameRequestWhileShortRepeating)559 TEST_P(FrameCadenceAdapterSimulcastLayersParamTest,
560 IgnoresKeyFrameRequestWhileShortRepeating) {
561 // Plot:
562 // 1. 0 * kMinFrameDelay: Start unconverged. Frame -> adapter.
563 // 2. 1 * kMinFrameDelay: Frame -> callback.
564 // 3. 2 * kMinFrameDelay: 1st short repeat.
565 // Since we're unconverged we assume the process continues.
566 adapter_->OnFrame(CreateFrame());
567 time_controller_.AdvanceTime(2 * kMinFrameDelay);
568 EXPECT_CALL(callback_, RequestRefreshFrame).Times(0);
569 adapter_->ProcessKeyFrameRequest();
570
571 // Expect short repeating as ususal.
572 EXPECT_CALL(callback_, OnFrame).Times(8);
573 time_controller_.AdvanceTime(8 * kMinFrameDelay);
574 }
575
TEST_P(FrameCadenceAdapterSimulcastLayersParamTest,IgnoresKeyFrameRequestJustBeforeIdleRepeating)576 TEST_P(FrameCadenceAdapterSimulcastLayersParamTest,
577 IgnoresKeyFrameRequestJustBeforeIdleRepeating) {
578 // (Only for > 0 spatial layers as we assume not converged with 0 layers)
579 if (NumSpatialLayers() == 0)
580 return;
581
582 // Plot:
583 // 1. 0 * kMinFrameDelay: Start converged. Frame -> adapter.
584 // 2. 1 * kMinFrameDelay: Frame -> callback. New repeat scheduled at
585 // (kMaxFpsHz + 1) * kMinFrameDelay.
586 // 3. kMaxFpsHz * kMinFrameDelay: Process keyframe.
587 // 4. (kMaxFpsHz + N) * kMinFrameDelay (1 <= N <= kMaxFpsHz): Short repeats
588 // due to not converged.
589 for (int i = 0; i != NumSpatialLayers(); i++) {
590 adapter_->UpdateLayerStatus(i, /*enabled=*/true);
591 adapter_->UpdateLayerQualityConvergence(i, /*converged=*/true);
592 }
593 adapter_->OnFrame(CreateFrame());
594 time_controller_.AdvanceTime(kIdleFrameDelay);
595
596 // We process the key frame request kMinFrameDelay before the first idle
597 // repeat should happen. The resulting repeats should happen spaced by
598 // kMinFrameDelay before we get new convergence info.
599 EXPECT_CALL(callback_, RequestRefreshFrame).Times(0);
600 adapter_->ProcessKeyFrameRequest();
601 EXPECT_CALL(callback_, OnFrame).Times(kMaxFpsHz);
602 time_controller_.AdvanceTime(kMaxFpsHz * kMinFrameDelay);
603 }
604
TEST_P(FrameCadenceAdapterSimulcastLayersParamTest,IgnoresKeyFrameRequestShortRepeatsBeforeIdleRepeat)605 TEST_P(FrameCadenceAdapterSimulcastLayersParamTest,
606 IgnoresKeyFrameRequestShortRepeatsBeforeIdleRepeat) {
607 // (Only for > 0 spatial layers as we assume not converged with 0 layers)
608 if (NumSpatialLayers() == 0)
609 return;
610 // Plot:
611 // 1. 0 * kMinFrameDelay: Start converged. Frame -> adapter.
612 // 2. 1 * kMinFrameDelay: Frame -> callback. New repeat scheduled at
613 // (kMaxFpsHz + 1) * kMinFrameDelay.
614 // 3. 2 * kMinFrameDelay: Process keyframe.
615 // 4. (2 + N) * kMinFrameDelay (1 <= N <= kMaxFpsHz): Short repeats due to not
616 // converged.
617 for (int i = 0; i != NumSpatialLayers(); i++) {
618 adapter_->UpdateLayerStatus(i, /*enabled=*/true);
619 adapter_->UpdateLayerQualityConvergence(i, /*converged=*/true);
620 }
621 adapter_->OnFrame(CreateFrame());
622 time_controller_.AdvanceTime(2 * kMinFrameDelay);
623
624 // We process the key frame request (kMaxFpsHz - 1) * kMinFrameDelay before
625 // the first idle repeat should happen. The resulting repeats should happen
626 // spaced kMinFrameDelay before we get new convergence info.
627 EXPECT_CALL(callback_, RequestRefreshFrame).Times(0);
628 adapter_->ProcessKeyFrameRequest();
629 EXPECT_CALL(callback_, OnFrame).Times(kMaxFpsHz);
630 time_controller_.AdvanceTime(kMaxFpsHz * kMinFrameDelay);
631 }
632
633 INSTANTIATE_TEST_SUITE_P(,
634 FrameCadenceAdapterSimulcastLayersParamTest,
635 Values(0, 1, 2));
636
637 class ZeroHertzLayerQualityConvergenceTest : public ::testing::Test {
638 public:
639 static constexpr TimeDelta kMinFrameDelay = TimeDelta::Millis(100);
640 static constexpr TimeDelta kIdleFrameDelay =
641 FrameCadenceAdapterInterface::kZeroHertzIdleRepeatRatePeriod;
642
ZeroHertzLayerQualityConvergenceTest()643 ZeroHertzLayerQualityConvergenceTest() {
644 adapter_->Initialize(&callback_);
645 adapter_->SetZeroHertzModeEnabled(
646 FrameCadenceAdapterInterface::ZeroHertzModeParams{
647 /*num_simulcast_layers=*/2});
648 adapter_->OnConstraintsChanged(VideoTrackSourceConstraints{
649 /*min_fps=*/0, /*max_fps=*/TimeDelta::Seconds(1) / kMinFrameDelay});
650 time_controller_.AdvanceTime(TimeDelta::Zero());
651 }
652
PassFrame()653 void PassFrame() { adapter_->OnFrame(CreateFrame()); }
654
ExpectFrameEntriesAtDelaysFromNow(std::initializer_list<TimeDelta> list)655 void ExpectFrameEntriesAtDelaysFromNow(
656 std::initializer_list<TimeDelta> list) {
657 Timestamp origin = time_controller_.GetClock()->CurrentTime();
658 for (auto delay : list) {
659 EXPECT_CALL(callback_, OnFrame(origin + delay, _, _));
660 time_controller_.AdvanceTime(origin + delay -
661 time_controller_.GetClock()->CurrentTime());
662 }
663 }
664
ScheduleDelayed(TimeDelta delay,absl::AnyInvocable<void ()&&> task)665 void ScheduleDelayed(TimeDelta delay, absl::AnyInvocable<void() &&> task) {
666 TaskQueueBase::Current()->PostDelayedTask(std::move(task), delay);
667 }
668
669 protected:
670 ZeroHertzFieldTrialEnabler field_trial_enabler_;
671 MockCallback callback_;
672 GlobalSimulatedTimeController time_controller_{Timestamp::Zero()};
673 std::unique_ptr<FrameCadenceAdapterInterface> adapter_{
674 CreateAdapter(field_trial_enabler_, time_controller_.GetClock())};
675 };
676
TEST_F(ZeroHertzLayerQualityConvergenceTest,InitialStateUnconverged)677 TEST_F(ZeroHertzLayerQualityConvergenceTest, InitialStateUnconverged) {
678 // As the layer count is just configured, assume we start out as unconverged.
679 PassFrame();
680 ExpectFrameEntriesAtDelaysFromNow({
681 1 * kMinFrameDelay, // Original frame emitted
682 2 * kMinFrameDelay, // Short repeats.
683 3 * kMinFrameDelay, // ...
684 });
685 }
686
TEST_F(ZeroHertzLayerQualityConvergenceTest,UnconvergedAfterLayersEnabled)687 TEST_F(ZeroHertzLayerQualityConvergenceTest, UnconvergedAfterLayersEnabled) {
688 // With newly enabled layers we assume quality is unconverged.
689 adapter_->UpdateLayerStatus(0, /*enabled=*/true);
690 adapter_->UpdateLayerStatus(1, /*enabled=*/true);
691 PassFrame();
692 ExpectFrameEntriesAtDelaysFromNow({
693 kMinFrameDelay, // Original frame emitted
694 2 * kMinFrameDelay, // Unconverged repeats.
695 3 * kMinFrameDelay, // ...
696 });
697 }
698
TEST_F(ZeroHertzLayerQualityConvergenceTest,RepeatsPassedFramesUntilConvergence)699 TEST_F(ZeroHertzLayerQualityConvergenceTest,
700 RepeatsPassedFramesUntilConvergence) {
701 ScheduleDelayed(TimeDelta::Zero(), [&] {
702 adapter_->UpdateLayerStatus(0, /*enabled=*/true);
703 adapter_->UpdateLayerStatus(1, /*enabled=*/true);
704 PassFrame();
705 });
706 ScheduleDelayed(2.5 * kMinFrameDelay, [&] {
707 adapter_->UpdateLayerQualityConvergence(/*spatial_index=*/1, true);
708 });
709 ScheduleDelayed(3.5 * kMinFrameDelay, [&] {
710 adapter_->UpdateLayerQualityConvergence(/*spatial_index=*/0, true);
711 });
712 ScheduleDelayed(8 * kMinFrameDelay, [&] { PassFrame(); });
713 ScheduleDelayed(9.5 * kMinFrameDelay, [&] {
714 adapter_->UpdateLayerQualityConvergence(/*spatial_index=*/0, true);
715 });
716 ScheduleDelayed(10.5 * kMinFrameDelay, [&] {
717 adapter_->UpdateLayerQualityConvergence(/*spatial_index=*/1, true);
718 });
719 ExpectFrameEntriesAtDelaysFromNow({
720 kMinFrameDelay, // Original frame emitted
721 2 * kMinFrameDelay, // Repeat from kMinFrameDelay.
722
723 // 2.5 * kMinFrameDelay: Converged in layer 1, layer 0 still unconverged.
724 3 * kMinFrameDelay, // Repeat from 2 * kMinFrameDelay.
725
726 // 3.5 * kMinFrameDelay: Converged in layer 0 as well.
727 4 * kMinFrameDelay, // Repeat from 3 * kMinFrameDelay. An idle repeat is
728 // scheduled for kIdleFrameDelay + 3 *
729 // kMinFrameDelay.
730
731 // A new frame is passed at 8 * kMinFrameDelay.
732 9 * kMinFrameDelay, // Original frame emitted
733
734 // 9.5 * kMinFrameDelay: Converged in layer 0, layer 1 still unconverged.
735 10 * kMinFrameDelay, // Repeat from 9 * kMinFrameDelay.
736 // 10.5 * kMinFrameDelay: Converged in layer 0 as well.
737 11 * kMinFrameDelay, // Idle repeats from 1000.
738 11 * kMinFrameDelay + kIdleFrameDelay, // ...
739 11 * kMinFrameDelay + 2 * kIdleFrameDelay, // ...
740 // ...
741 });
742 }
743
744 class FrameCadenceAdapterMetricsTest : public ::testing::Test {
745 public:
FrameCadenceAdapterMetricsTest()746 FrameCadenceAdapterMetricsTest() : time_controller_(Timestamp::Millis(1)) {
747 metrics::Reset();
748 }
DepleteTaskQueues()749 void DepleteTaskQueues() { time_controller_.AdvanceTime(TimeDelta::Zero()); }
750
751 protected:
752 GlobalSimulatedTimeController time_controller_;
753 };
754
TEST_F(FrameCadenceAdapterMetricsTest,RecordsNoUmasWithNoFrameTransfer)755 TEST_F(FrameCadenceAdapterMetricsTest, RecordsNoUmasWithNoFrameTransfer) {
756 MockCallback callback;
757 test::ScopedKeyValueConfig no_field_trials;
758 auto adapter = CreateAdapter(no_field_trials, nullptr);
759 adapter->Initialize(&callback);
760 adapter->OnConstraintsChanged(
761 VideoTrackSourceConstraints{absl::nullopt, absl::nullopt});
762 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{absl::nullopt, 1});
763 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{2, 3});
764 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{4, 4});
765 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{5, absl::nullopt});
766 DepleteTaskQueues();
767 EXPECT_TRUE(metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Exists")
768 .empty());
769 EXPECT_TRUE(
770 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Min.Exists")
771 .empty());
772 EXPECT_TRUE(
773 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Min.Value")
774 .empty());
775 EXPECT_TRUE(
776 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Max.Exists")
777 .empty());
778 EXPECT_TRUE(
779 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Max.Value")
780 .empty());
781 EXPECT_TRUE(
782 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.MinUnset.Max")
783 .empty());
784 EXPECT_TRUE(metrics::Samples(
785 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Min")
786 .empty());
787 EXPECT_TRUE(metrics::Samples(
788 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Max")
789 .empty());
790 EXPECT_TRUE(
791 metrics::Samples(
792 "WebRTC.Screenshare.FrameRateConstraints.60MinPlusMaxMinusOne")
793 .empty());
794 }
795
TEST_F(FrameCadenceAdapterMetricsTest,RecordsNoUmasWithoutEnabledContentType)796 TEST_F(FrameCadenceAdapterMetricsTest, RecordsNoUmasWithoutEnabledContentType) {
797 MockCallback callback;
798 test::ScopedKeyValueConfig no_field_trials;
799 auto adapter = CreateAdapter(no_field_trials, time_controller_.GetClock());
800 adapter->Initialize(&callback);
801 adapter->OnFrame(CreateFrame());
802 adapter->OnConstraintsChanged(
803 VideoTrackSourceConstraints{absl::nullopt, absl::nullopt});
804 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{absl::nullopt, 1});
805 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{2, 3});
806 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{4, 4});
807 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{5, absl::nullopt});
808 DepleteTaskQueues();
809 EXPECT_TRUE(metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Exists")
810 .empty());
811 EXPECT_TRUE(
812 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Min.Exists")
813 .empty());
814 EXPECT_TRUE(
815 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Min.Value")
816 .empty());
817 EXPECT_TRUE(
818 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Max.Exists")
819 .empty());
820 EXPECT_TRUE(
821 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Max.Value")
822 .empty());
823 EXPECT_TRUE(
824 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.MinUnset.Max")
825 .empty());
826 EXPECT_TRUE(metrics::Samples(
827 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Min")
828 .empty());
829 EXPECT_TRUE(metrics::Samples(
830 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Max")
831 .empty());
832 EXPECT_TRUE(
833 metrics::Samples(
834 "WebRTC.Screenshare.FrameRateConstraints.60MinPlusMaxMinusOne")
835 .empty());
836 }
837
TEST_F(FrameCadenceAdapterMetricsTest,RecordsNoConstraintsIfUnsetOnFrame)838 TEST_F(FrameCadenceAdapterMetricsTest, RecordsNoConstraintsIfUnsetOnFrame) {
839 MockCallback callback;
840 test::ScopedKeyValueConfig no_field_trials;
841 auto adapter = CreateAdapter(no_field_trials, time_controller_.GetClock());
842 adapter->Initialize(&callback);
843 adapter->SetZeroHertzModeEnabled(
844 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
845 adapter->OnFrame(CreateFrame());
846 DepleteTaskQueues();
847 EXPECT_THAT(
848 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Exists"),
849 ElementsAre(Pair(false, 1)));
850 }
851
TEST_F(FrameCadenceAdapterMetricsTest,RecordsEmptyConstraintsIfSetOnFrame)852 TEST_F(FrameCadenceAdapterMetricsTest, RecordsEmptyConstraintsIfSetOnFrame) {
853 MockCallback callback;
854 test::ScopedKeyValueConfig no_field_trials;
855 auto adapter = CreateAdapter(no_field_trials, time_controller_.GetClock());
856 adapter->Initialize(&callback);
857 adapter->SetZeroHertzModeEnabled(
858 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
859 adapter->OnConstraintsChanged(
860 VideoTrackSourceConstraints{absl::nullopt, absl::nullopt});
861 adapter->OnFrame(CreateFrame());
862 DepleteTaskQueues();
863 EXPECT_THAT(
864 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Exists"),
865 ElementsAre(Pair(true, 1)));
866 EXPECT_THAT(
867 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Min.Exists"),
868 ElementsAre(Pair(false, 1)));
869 EXPECT_TRUE(
870 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Min.Value")
871 .empty());
872 EXPECT_THAT(
873 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Max.Exists"),
874 ElementsAre(Pair(false, 1)));
875 EXPECT_TRUE(
876 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Max.Value")
877 .empty());
878 EXPECT_TRUE(
879 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.MinUnset.Max")
880 .empty());
881 EXPECT_TRUE(metrics::Samples(
882 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Min")
883 .empty());
884 EXPECT_TRUE(metrics::Samples(
885 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Max")
886 .empty());
887 EXPECT_TRUE(
888 metrics::Samples(
889 "WebRTC.Screenshare.FrameRateConstraints.60MinPlusMaxMinusOne")
890 .empty());
891 }
892
TEST_F(FrameCadenceAdapterMetricsTest,RecordsMaxConstraintIfSetOnFrame)893 TEST_F(FrameCadenceAdapterMetricsTest, RecordsMaxConstraintIfSetOnFrame) {
894 MockCallback callback;
895 test::ScopedKeyValueConfig no_field_trials;
896 auto adapter = CreateAdapter(no_field_trials, time_controller_.GetClock());
897 adapter->Initialize(&callback);
898 adapter->SetZeroHertzModeEnabled(
899 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
900 adapter->OnConstraintsChanged(
901 VideoTrackSourceConstraints{absl::nullopt, 2.0});
902 adapter->OnFrame(CreateFrame());
903 DepleteTaskQueues();
904 EXPECT_THAT(
905 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Min.Exists"),
906 ElementsAre(Pair(false, 1)));
907 EXPECT_TRUE(
908 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Min.Value")
909 .empty());
910 EXPECT_THAT(
911 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Max.Exists"),
912 ElementsAre(Pair(true, 1)));
913 EXPECT_THAT(
914 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Max.Value"),
915 ElementsAre(Pair(2.0, 1)));
916 EXPECT_THAT(
917 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.MinUnset.Max"),
918 ElementsAre(Pair(2.0, 1)));
919 EXPECT_TRUE(metrics::Samples(
920 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Min")
921 .empty());
922 EXPECT_TRUE(metrics::Samples(
923 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Max")
924 .empty());
925 EXPECT_TRUE(
926 metrics::Samples(
927 "WebRTC.Screenshare.FrameRateConstraints.60MinPlusMaxMinusOne")
928 .empty());
929 }
930
TEST_F(FrameCadenceAdapterMetricsTest,RecordsMinConstraintIfSetOnFrame)931 TEST_F(FrameCadenceAdapterMetricsTest, RecordsMinConstraintIfSetOnFrame) {
932 MockCallback callback;
933 test::ScopedKeyValueConfig no_field_trials;
934 auto adapter = CreateAdapter(no_field_trials, time_controller_.GetClock());
935 adapter->Initialize(&callback);
936 adapter->SetZeroHertzModeEnabled(
937 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
938 adapter->OnConstraintsChanged(
939 VideoTrackSourceConstraints{3.0, absl::nullopt});
940 adapter->OnFrame(CreateFrame());
941 DepleteTaskQueues();
942 EXPECT_THAT(
943 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Min.Exists"),
944 ElementsAre(Pair(true, 1)));
945 EXPECT_THAT(
946 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Min.Value"),
947 ElementsAre(Pair(3.0, 1)));
948 EXPECT_THAT(
949 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Max.Exists"),
950 ElementsAre(Pair(false, 1)));
951 EXPECT_TRUE(
952 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Max.Value")
953 .empty());
954 EXPECT_TRUE(
955 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.MinUnset.Max")
956 .empty());
957 EXPECT_TRUE(metrics::Samples(
958 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Min")
959 .empty());
960 EXPECT_TRUE(metrics::Samples(
961 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Max")
962 .empty());
963 EXPECT_TRUE(
964 metrics::Samples(
965 "WebRTC.Screenshare.FrameRateConstraints.60MinPlusMaxMinusOne")
966 .empty());
967 }
968
TEST_F(FrameCadenceAdapterMetricsTest,RecordsMinGtMaxConstraintIfSetOnFrame)969 TEST_F(FrameCadenceAdapterMetricsTest, RecordsMinGtMaxConstraintIfSetOnFrame) {
970 MockCallback callback;
971 test::ScopedKeyValueConfig no_field_trials;
972 auto adapter = CreateAdapter(no_field_trials, time_controller_.GetClock());
973 adapter->Initialize(&callback);
974 adapter->SetZeroHertzModeEnabled(
975 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
976 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{5.0, 4.0});
977 adapter->OnFrame(CreateFrame());
978 DepleteTaskQueues();
979 EXPECT_THAT(
980 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Min.Exists"),
981 ElementsAre(Pair(true, 1)));
982 EXPECT_THAT(
983 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Min.Value"),
984 ElementsAre(Pair(5.0, 1)));
985 EXPECT_THAT(
986 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Max.Exists"),
987 ElementsAre(Pair(true, 1)));
988 EXPECT_THAT(
989 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.Max.Value"),
990 ElementsAre(Pair(4.0, 1)));
991 EXPECT_TRUE(
992 metrics::Samples("WebRTC.Screenshare.FrameRateConstraints.MinUnset.Max")
993 .empty());
994 EXPECT_TRUE(metrics::Samples(
995 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Min")
996 .empty());
997 EXPECT_TRUE(metrics::Samples(
998 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Max")
999 .empty());
1000 EXPECT_THAT(
1001 metrics::Samples(
1002 "WebRTC.Screenshare.FrameRateConstraints.60MinPlusMaxMinusOne"),
1003 ElementsAre(Pair(60 * 5.0 + 4.0 - 1, 1)));
1004 }
1005
TEST_F(FrameCadenceAdapterMetricsTest,RecordsMinLtMaxConstraintIfSetOnFrame)1006 TEST_F(FrameCadenceAdapterMetricsTest, RecordsMinLtMaxConstraintIfSetOnFrame) {
1007 MockCallback callback;
1008 test::ScopedKeyValueConfig no_field_trials;
1009 auto adapter = CreateAdapter(no_field_trials, time_controller_.GetClock());
1010 adapter->Initialize(&callback);
1011 adapter->SetZeroHertzModeEnabled(
1012 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
1013 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{4.0, 5.0});
1014 adapter->OnFrame(CreateFrame());
1015 DepleteTaskQueues();
1016 EXPECT_THAT(metrics::Samples(
1017 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Min"),
1018 ElementsAre(Pair(4.0, 1)));
1019 EXPECT_THAT(metrics::Samples(
1020 "WebRTC.Screenshare.FrameRateConstraints.MinLessThanMax.Max"),
1021 ElementsAre(Pair(5.0, 1)));
1022 EXPECT_THAT(
1023 metrics::Samples(
1024 "WebRTC.Screenshare.FrameRateConstraints.60MinPlusMaxMinusOne"),
1025 ElementsAre(Pair(60 * 4.0 + 5.0 - 1, 1)));
1026 }
1027
TEST_F(FrameCadenceAdapterMetricsTest,RecordsTimeUntilFirstFrame)1028 TEST_F(FrameCadenceAdapterMetricsTest, RecordsTimeUntilFirstFrame) {
1029 MockCallback callback;
1030 test::ScopedKeyValueConfig no_field_trials;
1031 auto adapter = CreateAdapter(no_field_trials, time_controller_.GetClock());
1032 adapter->Initialize(&callback);
1033 adapter->SetZeroHertzModeEnabled(
1034 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
1035 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 5.0});
1036 time_controller_.AdvanceTime(TimeDelta::Millis(666));
1037 adapter->OnFrame(CreateFrame());
1038 DepleteTaskQueues();
1039 EXPECT_THAT(
1040 metrics::Samples("WebRTC.Screenshare.ZeroHz.TimeUntilFirstFrameMs"),
1041 ElementsAre(Pair(666, 1)));
1042 }
1043
TEST(FrameCadenceAdapterRealTimeTest,TimestampsDoNotDrift)1044 TEST(FrameCadenceAdapterRealTimeTest, TimestampsDoNotDrift) {
1045 // This regression test must be performed in realtime because of limitations
1046 // in GlobalSimulatedTimeController.
1047 //
1048 // We sleep for a long while in OnFrame when a repeat was scheduled which
1049 // should reflect in accordingly increased ntp_time_ms() and timestamp_us() in
1050 // the repeated frames.
1051 auto factory = CreateDefaultTaskQueueFactory();
1052 auto queue =
1053 factory->CreateTaskQueue("test", TaskQueueFactory::Priority::NORMAL);
1054 ZeroHertzFieldTrialEnabler enabler;
1055 MockCallback callback;
1056 Clock* clock = Clock::GetRealTimeClock();
1057 std::unique_ptr<FrameCadenceAdapterInterface> adapter;
1058 int frame_counter = 0;
1059 int64_t original_ntp_time_ms;
1060 int64_t original_timestamp_us;
1061 rtc::Event event;
1062 queue->PostTask([&] {
1063 adapter = CreateAdapter(enabler, clock);
1064 adapter->Initialize(&callback);
1065 adapter->SetZeroHertzModeEnabled(
1066 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
1067 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 30});
1068 auto frame = CreateFrame();
1069 original_ntp_time_ms = clock->CurrentNtpInMilliseconds();
1070 frame.set_ntp_time_ms(original_ntp_time_ms);
1071 original_timestamp_us = clock->CurrentTime().us();
1072 frame.set_timestamp_us(original_timestamp_us);
1073 constexpr int kSleepMs = rtc::kNumMillisecsPerSec / 2;
1074 EXPECT_CALL(callback, OnFrame)
1075 .WillRepeatedly(
1076 Invoke([&](Timestamp, int, const VideoFrame& incoming_frame) {
1077 ++frame_counter;
1078 // Avoid the first OnFrame and sleep on the second.
1079 if (frame_counter == 2) {
1080 SleepMs(kSleepMs);
1081 } else if (frame_counter == 3) {
1082 EXPECT_GE(incoming_frame.ntp_time_ms(),
1083 original_ntp_time_ms + kSleepMs);
1084 EXPECT_GE(incoming_frame.timestamp_us(),
1085 original_timestamp_us + kSleepMs);
1086 event.Set();
1087 }
1088 }));
1089 adapter->OnFrame(frame);
1090 });
1091 event.Wait(rtc::Event::kForever);
1092 rtc::Event finalized;
1093 queue->PostTask([&] {
1094 adapter = nullptr;
1095 finalized.Set();
1096 });
1097 finalized.Wait(rtc::Event::kForever);
1098 }
1099
1100 } // namespace
1101 } // namespace webrtc
1102