xref: /aosp_15_r20/external/webrtc/video/frame_cadence_adapter_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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