blob: 37f73eedfbea5acdd3f5f8bba832b5a488581ed5 [file] [log] [blame]
Markus Handellb4e96d42021-11-05 11:00:551/*
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
Philipp Hancke94db4c42025-05-06 20:55:1313#include <cstddef>
Per Ke975b442024-03-27 10:28:4414#include <cstdint>
Philipp Hancke94db4c42025-05-06 20:55:1315#include <initializer_list>
Per Ke975b442024-03-27 10:28:4416#include <memory>
Philipp Hancke94db4c42025-05-06 20:55:1317#include <optional>
Markus Handellb4e96d42021-11-05 11:00:5518#include <utility>
Markus Handellb4e96d42021-11-05 11:00:5519
Danil Chapovalov95eeaa72022-07-06 08:14:2920#include "absl/functional/any_invocable.h"
Philipp Hancke94db4c42025-05-06 20:55:1321#include "api/field_trials_view.h"
22#include "api/make_ref_counted.h"
Zhaoliang Maf089d7e2024-01-08 02:44:1523#include "api/metronome/test/fake_metronome.h"
Markus Handell90a7e2c2021-12-29 22:32:3024#include "api/task_queue/default_task_queue_factory.h"
Markus Handell28c71802021-11-08 09:11:5525#include "api/task_queue/task_queue_base.h"
Markus Handell8d87c462021-12-16 10:37:1626#include "api/task_queue/task_queue_factory.h"
Danil Chapovalov95eeaa72022-07-06 08:14:2927#include "api/units/time_delta.h"
Markus Handell8d87c462021-12-16 10:37:1628#include "api/units/timestamp.h"
Markus Handellb4e96d42021-11-05 11:00:5529#include "api/video/nv12_buffer.h"
30#include "api/video/video_frame.h"
Philipp Hancke94db4c42025-05-06 20:55:1331#include "api/video_track_source_constraints.h"
Markus Handell90a7e2c2021-12-29 22:32:3032#include "rtc_base/event.h"
Markus Handellf2827c42023-09-02 07:41:1033#include "rtc_base/logging.h"
Markus Handellee225432021-11-29 11:35:1234#include "rtc_base/rate_statistics.h"
Markus Handelle864dec2024-08-07 14:11:1835#include "rtc_base/task_queue_for_test.h"
Fredrik Solenberg4ecf1112025-05-21 09:05:5636#include "rtc_base/thread.h"
Markus Handell29dd8d82021-12-15 11:19:1537#include "rtc_base/time_utils.h"
Philipp Hancke94db4c42025-05-06 20:55:1338#include "system_wrappers/include/clock.h"
Markus Handellb4e96d42021-11-05 11:00:5539#include "system_wrappers/include/metrics.h"
Markus Handell29dd8d82021-12-15 11:19:1540#include "system_wrappers/include/ntp_time.h"
Markus Handellb4e96d42021-11-05 11:00:5541#include "test/gmock.h"
42#include "test/gtest.h"
Jonas Oreland8ca06132022-03-14 11:52:4843#include "test/scoped_key_value_config.h"
Markus Handell28c71802021-11-08 09:11:5544#include "test/time_controller/simulated_time_controller.h"
Markus Handellb4e96d42021-11-05 11:00:5545
46namespace webrtc {
47namespace {
48
Markus Handell9a478b52021-11-18 15:07:0149using ::testing::_;
Markus Handellb4e96d42021-11-05 11:00:5550using ::testing::ElementsAre;
henrikab7ec0572024-01-09 09:48:5251using ::testing::InSequence;
Markus Handell29dd8d82021-12-15 11:19:1552using ::testing::Invoke;
Markus Handell8fa86192023-08-31 09:59:0653using ::testing::InvokeWithoutArgs;
Markus Handellb4e96d42021-11-05 11:00:5554using ::testing::Mock;
henrikab7ec0572024-01-09 09:48:5255using ::testing::NiceMock;
Markus Handellb4e96d42021-11-05 11:00:5556using ::testing::Pair;
Markus Handellcb237f82021-12-29 20:31:5757using ::testing::Values;
Markus Handellb4e96d42021-11-05 11:00:5558
59VideoFrame CreateFrame() {
60 return VideoFrame::Builder()
61 .set_video_frame_buffer(
Evan Shrubsole6bb90142025-04-16 09:45:5862 make_ref_counted<NV12Buffer>(/*width=*/16, /*height=*/16))
Markus Handellb4e96d42021-11-05 11:00:5563 .build();
64}
65
Markus Handell29dd8d82021-12-15 11:19:1566VideoFrame CreateFrameWithTimestamps(
67 GlobalSimulatedTimeController* time_controller) {
68 return VideoFrame::Builder()
69 .set_video_frame_buffer(
Evan Shrubsole6bb90142025-04-16 09:45:5870 make_ref_counted<NV12Buffer>(/*width=*/16, /*height=*/16))
Markus Handell29dd8d82021-12-15 11:19:1571 .set_ntp_time_ms(time_controller->GetClock()->CurrentNtpInMilliseconds())
72 .set_timestamp_us(time_controller->GetClock()->CurrentTime().us())
73 .build();
74}
75
Jonas Oreland8ca06132022-03-14 11:52:4876std::unique_ptr<FrameCadenceAdapterInterface> CreateAdapter(
Jonas Orelande62c2f22022-03-29 09:04:4877 const FieldTrialsView& field_trials,
Jonas Oreland8ca06132022-03-14 11:52:4878 Clock* clock) {
Zhaoliang Maf089d7e2024-01-08 02:44:1579 return FrameCadenceAdapterInterface::Create(
80 clock, TaskQueueBase::Current(), /*metronome=*/nullptr,
81 /*worker_queue=*/nullptr, field_trials);
Markus Handell28c71802021-11-08 09:11:5582}
83
Markus Handellb4e96d42021-11-05 11:00:5584class MockCallback : public FrameCadenceAdapterInterface::Callback {
85 public:
Markus Handell84c016a2023-11-23 12:41:4486 MOCK_METHOD(void, OnFrame, (Timestamp, bool, const VideoFrame&), (override));
Markus Handellb4e96d42021-11-05 11:00:5587 MOCK_METHOD(void, OnDiscardedFrame, (), (override));
Markus Handell818e7fb2021-12-30 12:01:3388 MOCK_METHOD(void, RequestRefreshFrame, (), (override));
Markus Handellb4e96d42021-11-05 11:00:5589};
90
Markus Handell9a478b52021-11-18 15:07:0191TEST(FrameCadenceAdapterTest, CountsOutstandingFramesToProcess) {
Jonas Oreland8ca06132022-03-14 11:52:4892 test::ScopedKeyValueConfig no_field_trials;
Markus Handell9a478b52021-11-18 15:07:0193 GlobalSimulatedTimeController time_controller(Timestamp::Millis(1));
94 MockCallback callback;
Jonas Oreland8ca06132022-03-14 11:52:4895 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handell9a478b52021-11-18 15:07:0196 adapter->Initialize(&callback);
Markus Handell84c016a2023-11-23 12:41:4497 EXPECT_CALL(callback, OnFrame(_, true, _)).Times(1);
98 EXPECT_CALL(callback, OnFrame(_, false, _)).Times(1);
Markus Handell9a478b52021-11-18 15:07:0199 auto frame = CreateFrame();
100 adapter->OnFrame(frame);
101 adapter->OnFrame(frame);
102 time_controller.AdvanceTime(TimeDelta::Zero());
Markus Handell84c016a2023-11-23 12:41:44103 EXPECT_CALL(callback, OnFrame(_, false, _)).Times(1);
Markus Handell9a478b52021-11-18 15:07:01104 adapter->OnFrame(frame);
105 time_controller.AdvanceTime(TimeDelta::Zero());
106}
107
Markus Handellee225432021-11-29 11:35:12108TEST(FrameCadenceAdapterTest, FrameRateFollowsRateStatisticsByDefault) {
Jonas Oreland8ca06132022-03-14 11:52:48109 test::ScopedKeyValueConfig no_field_trials;
Philipp Hanckea204ad22022-07-08 16:43:25110 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Jonas Oreland8ca06132022-03-14 11:52:48111 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Per Ke975b442024-03-27 10:28:44112 MockCallback callback;
113 adapter->Initialize(&callback);
Markus Handellee225432021-11-29 11:35:12114
115 // Create an "oracle" rate statistics which should be followed on a sequence
116 // of frames.
117 RateStatistics rate(
118 FrameCadenceAdapterInterface::kFrameRateAveragingWindowSizeMs, 1000);
119
120 for (int frame = 0; frame != 10; ++frame) {
121 time_controller.AdvanceTime(TimeDelta::Millis(10));
Florent Castelli8037fc62024-08-29 13:00:40122 std::optional<int64_t> expected_fps =
Per Ke975b442024-03-27 10:28:44123 rate.Rate(time_controller.GetClock()->TimeInMilliseconds());
Markus Handellee225432021-11-29 11:35:12124 rate.Update(1, time_controller.GetClock()->TimeInMilliseconds());
Per Ke975b442024-03-27 10:28:44125 // FrameCadanceAdapter::OnFrame post the frame to another sequence.
126 adapter->OnFrame(CreateFrameWithTimestamps(&time_controller));
127 time_controller.AdvanceTime(TimeDelta::Millis(0));
128 EXPECT_EQ(expected_fps, adapter->GetInputFrameRateFps())
Markus Handellee225432021-11-29 11:35:12129 << " failed for frame " << frame;
130 }
131}
132
Markus Handellee225432021-11-29 11:35:12133TEST(FrameCadenceAdapterTest, FrameRateFollowsMaxFpsWhenZeroHertzActivated) {
Philipp Hanckea204ad22022-07-08 16:43:25134 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45135 test::ScopedKeyValueConfig no_field_trials;
136 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Per Ke975b442024-03-27 10:28:44137 MockCallback callback;
138 adapter->Initialize(&callback);
Markus Handell8d87c462021-12-16 10:37:16139 adapter->SetZeroHertzModeEnabled(
140 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
Markus Handellee225432021-11-29 11:35:12141 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
142 for (int frame = 0; frame != 10; ++frame) {
143 time_controller.AdvanceTime(TimeDelta::Millis(10));
Per Ke975b442024-03-27 10:28:44144 // FrameCadanceAdapter::OnFrame post the frame to another sequence.
145 adapter->OnFrame(CreateFrameWithTimestamps(&time_controller));
146 time_controller.AdvanceTime(TimeDelta::Millis(0));
Markus Handellee225432021-11-29 11:35:12147 EXPECT_EQ(adapter->GetInputFrameRateFps(), 1u);
148 }
149}
150
henrika644025c2023-11-07 17:22:02151TEST(FrameCadenceAdapterTest, ZeroHertzAdapterSupportsMaxFpsChange) {
henrika644025c2023-11-07 17:22:02152 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45153 test::ScopedKeyValueConfig no_field_trials;
154 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
henrika644025c2023-11-07 17:22:02155 MockCallback callback;
156 adapter->Initialize(&callback);
157 adapter->SetZeroHertzModeEnabled(
158 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
159 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
160 time_controller.AdvanceTime(TimeDelta::Zero());
161 EXPECT_EQ(adapter->GetInputFrameRateFps(), 1u);
162 adapter->OnFrame(CreateFrame());
163 time_controller.AdvanceTime(TimeDelta::Seconds(1));
164 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 2});
165 time_controller.AdvanceTime(TimeDelta::Zero());
166 EXPECT_EQ(adapter->GetInputFrameRateFps(), 2u);
167 adapter->OnFrame(CreateFrame());
168 // Ensure that the max_fps has been changed from 1 to 2 fps even if it was
169 // changed while zero hertz was already active.
170 EXPECT_CALL(callback, OnFrame);
171 time_controller.AdvanceTime(TimeDelta::Millis(500));
172}
173
Markus Handellee225432021-11-29 11:35:12174TEST(FrameCadenceAdapterTest,
175 FrameRateFollowsRateStatisticsAfterZeroHertzDeactivated) {
Philipp Hanckea204ad22022-07-08 16:43:25176 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45177 test::ScopedKeyValueConfig no_field_trials;
178 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Per Ke975b442024-03-27 10:28:44179 MockCallback callback;
180 adapter->Initialize(&callback);
Markus Handell8d87c462021-12-16 10:37:16181 adapter->SetZeroHertzModeEnabled(
182 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
Markus Handellee225432021-11-29 11:35:12183 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
184 RateStatistics rate(
185 FrameCadenceAdapterInterface::kFrameRateAveragingWindowSizeMs, 1000);
186 constexpr int MAX = 10;
187 for (int frame = 0; frame != MAX; ++frame) {
188 time_controller.AdvanceTime(TimeDelta::Millis(10));
189 rate.Update(1, time_controller.GetClock()->TimeInMilliseconds());
Per Ke975b442024-03-27 10:28:44190 adapter->OnFrame(CreateFrameWithTimestamps(&time_controller));
191 time_controller.AdvanceTime(TimeDelta::Millis(0));
Markus Handellee225432021-11-29 11:35:12192 }
193 // Turn off zero hertz on the next-last frame; after the last frame we
194 // should see a value that tracks the rate oracle.
Florent Castelli8037fc62024-08-29 13:00:40195 adapter->SetZeroHertzModeEnabled(std::nullopt);
Markus Handellee225432021-11-29 11:35:12196 // Last frame.
197 time_controller.AdvanceTime(TimeDelta::Millis(10));
Per Ke975b442024-03-27 10:28:44198 adapter->OnFrame(CreateFrameWithTimestamps(&time_controller));
199 time_controller.AdvanceTime(TimeDelta::Millis(0));
Markus Handellee225432021-11-29 11:35:12200
201 EXPECT_EQ(rate.Rate(time_controller.GetClock()->TimeInMilliseconds()),
202 adapter->GetInputFrameRateFps());
203}
204
Markus Handell29dd8d82021-12-15 11:19:15205TEST(FrameCadenceAdapterTest, ForwardsFramesDelayed) {
Markus Handell29dd8d82021-12-15 11:19:15206 MockCallback callback;
Philipp Hanckea204ad22022-07-08 16:43:25207 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45208 test::ScopedKeyValueConfig no_field_trials;
209 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handell29dd8d82021-12-15 11:19:15210 adapter->Initialize(&callback);
Markus Handell8d87c462021-12-16 10:37:16211 adapter->SetZeroHertzModeEnabled(
212 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
Markus Handell29dd8d82021-12-15 11:19:15213 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
214 constexpr int kNumFrames = 3;
215 NtpTime original_ntp_time = time_controller.GetClock()->CurrentNtpTime();
216 auto frame = CreateFrameWithTimestamps(&time_controller);
217 int64_t original_timestamp_us = frame.timestamp_us();
218 for (int index = 0; index != kNumFrames; ++index) {
219 EXPECT_CALL(callback, OnFrame).Times(0);
220 adapter->OnFrame(frame);
221 EXPECT_CALL(callback, OnFrame)
Markus Handell84c016a2023-11-23 12:41:44222 .WillOnce(Invoke([&](Timestamp post_time, bool,
Markus Handell29dd8d82021-12-15 11:19:15223 const VideoFrame& frame) {
224 EXPECT_EQ(post_time, time_controller.GetClock()->CurrentTime());
225 EXPECT_EQ(frame.timestamp_us(),
Evan Shrubsole652c7712025-03-21 09:47:35226 original_timestamp_us + index * kNumMicrosecsPerSec);
227 EXPECT_EQ(frame.ntp_time_ms(),
228 original_ntp_time.ToMs() + index * kNumMillisecsPerSec);
Markus Handell29dd8d82021-12-15 11:19:15229 }));
230 time_controller.AdvanceTime(TimeDelta::Seconds(1));
231 frame = CreateFrameWithTimestamps(&time_controller);
232 }
233}
234
Markus Handell8fa86192023-08-31 09:59:06235TEST(FrameCadenceAdapterTest, DelayedProcessingUnderSlightContention) {
Markus Handell8fa86192023-08-31 09:59:06236 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45237 test::ScopedKeyValueConfig no_field_trials;
238 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handell8fa86192023-08-31 09:59:06239 MockCallback callback;
240 adapter->Initialize(&callback);
241 adapter->SetZeroHertzModeEnabled(
242 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
243 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
244
245 // Expect frame delivery at 1 sec despite target sequence not running
246 // callbacks for the time skipped.
247 constexpr TimeDelta time_skipped = TimeDelta::Millis(999);
248 EXPECT_CALL(callback, OnFrame).WillOnce(InvokeWithoutArgs([&] {
249 EXPECT_EQ(time_controller.GetClock()->CurrentTime(),
250 Timestamp::Zero() + TimeDelta::Seconds(1));
251 }));
252 adapter->OnFrame(CreateFrame());
253 time_controller.SkipForwardBy(time_skipped);
254 time_controller.AdvanceTime(TimeDelta::Seconds(1) - time_skipped);
255}
256
257TEST(FrameCadenceAdapterTest, DelayedProcessingUnderHeavyContention) {
Markus Handell8fa86192023-08-31 09:59:06258 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45259 test::ScopedKeyValueConfig no_field_trials;
260 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handell8fa86192023-08-31 09:59:06261 MockCallback callback;
262 adapter->Initialize(&callback);
263 adapter->SetZeroHertzModeEnabled(
264 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
265 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
266
267 // Expect frame delivery at origin + `time_skipped` when the target sequence
268 // is not running callbacks for the initial 1+ sec.
269 constexpr TimeDelta time_skipped =
270 TimeDelta::Seconds(1) + TimeDelta::Micros(1);
271 EXPECT_CALL(callback, OnFrame).WillOnce(InvokeWithoutArgs([&] {
272 EXPECT_EQ(time_controller.GetClock()->CurrentTime(),
273 Timestamp::Zero() + time_skipped);
274 }));
275 adapter->OnFrame(CreateFrame());
276 time_controller.SkipForwardBy(time_skipped);
henrikab7ec0572024-01-09 09:48:52277 time_controller.AdvanceTime(TimeDelta::Zero());
Markus Handell8fa86192023-08-31 09:59:06278}
279
Markus Handell29dd8d82021-12-15 11:19:15280TEST(FrameCadenceAdapterTest, RepeatsFramesDelayed) {
281 // Logic in the frame cadence adapter avoids modifying frame NTP and render
282 // timestamps if these timestamps looks unset, which is the case when the
283 // clock is initialized running from 0. For this reason we choose the
284 // `time_controller` initialization constant to something arbitrary which is
285 // not 0.
Markus Handell29dd8d82021-12-15 11:19:15286 MockCallback callback;
287 GlobalSimulatedTimeController time_controller(Timestamp::Millis(47892223));
Markus Handella57229b2024-04-16 08:40:45288 test::ScopedKeyValueConfig no_field_trials;
289 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handell29dd8d82021-12-15 11:19:15290 adapter->Initialize(&callback);
Markus Handell8d87c462021-12-16 10:37:16291 adapter->SetZeroHertzModeEnabled(
292 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
Markus Handell29dd8d82021-12-15 11:19:15293 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
294 NtpTime original_ntp_time = time_controller.GetClock()->CurrentNtpTime();
295
296 // Send one frame, expect 2 subsequent repeats.
297 auto frame = CreateFrameWithTimestamps(&time_controller);
298 int64_t original_timestamp_us = frame.timestamp_us();
299 adapter->OnFrame(frame);
300
301 EXPECT_CALL(callback, OnFrame)
Markus Handell84c016a2023-11-23 12:41:44302 .WillOnce(Invoke([&](Timestamp post_time, bool, const VideoFrame& frame) {
Markus Handell29dd8d82021-12-15 11:19:15303 EXPECT_EQ(post_time, time_controller.GetClock()->CurrentTime());
304 EXPECT_EQ(frame.timestamp_us(), original_timestamp_us);
305 EXPECT_EQ(frame.ntp_time_ms(), original_ntp_time.ToMs());
306 }));
307 time_controller.AdvanceTime(TimeDelta::Seconds(1));
308 Mock::VerifyAndClearExpectations(&callback);
309
310 EXPECT_CALL(callback, OnFrame)
Markus Handell84c016a2023-11-23 12:41:44311 .WillOnce(Invoke([&](Timestamp post_time, bool, const VideoFrame& frame) {
Markus Handell29dd8d82021-12-15 11:19:15312 EXPECT_EQ(post_time, time_controller.GetClock()->CurrentTime());
313 EXPECT_EQ(frame.timestamp_us(),
Evan Shrubsole652c7712025-03-21 09:47:35314 original_timestamp_us + kNumMicrosecsPerSec);
Markus Handell29dd8d82021-12-15 11:19:15315 EXPECT_EQ(frame.ntp_time_ms(),
Evan Shrubsole652c7712025-03-21 09:47:35316 original_ntp_time.ToMs() + kNumMillisecsPerSec);
Markus Handell29dd8d82021-12-15 11:19:15317 }));
318 time_controller.AdvanceTime(TimeDelta::Seconds(1));
319 Mock::VerifyAndClearExpectations(&callback);
320
321 EXPECT_CALL(callback, OnFrame)
Markus Handell84c016a2023-11-23 12:41:44322 .WillOnce(Invoke([&](Timestamp post_time, bool, const VideoFrame& frame) {
Markus Handell29dd8d82021-12-15 11:19:15323 EXPECT_EQ(post_time, time_controller.GetClock()->CurrentTime());
324 EXPECT_EQ(frame.timestamp_us(),
Evan Shrubsole652c7712025-03-21 09:47:35325 original_timestamp_us + 2 * kNumMicrosecsPerSec);
Markus Handell29dd8d82021-12-15 11:19:15326 EXPECT_EQ(frame.ntp_time_ms(),
Evan Shrubsole652c7712025-03-21 09:47:35327 original_ntp_time.ToMs() + 2 * kNumMillisecsPerSec);
Markus Handell29dd8d82021-12-15 11:19:15328 }));
329 time_controller.AdvanceTime(TimeDelta::Seconds(1));
330}
331
332TEST(FrameCadenceAdapterTest,
333 RepeatsFramesWithoutTimestampsWithUnsetTimestamps) {
334 // Logic in the frame cadence adapter avoids modifying frame NTP and render
335 // timestamps if these timestamps looks unset, which is the case when the
336 // clock is initialized running from 0. In this test we deliberately don't set
337 // it to zero, but select unset timestamps in the frames (via CreateFrame())
338 // and verify that the timestamp modifying logic doesn't depend on the current
339 // time.
Markus Handell29dd8d82021-12-15 11:19:15340 MockCallback callback;
341 GlobalSimulatedTimeController time_controller(Timestamp::Millis(4711));
Markus Handella57229b2024-04-16 08:40:45342 test::ScopedKeyValueConfig no_field_trials;
343 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handell29dd8d82021-12-15 11:19:15344 adapter->Initialize(&callback);
Markus Handell8d87c462021-12-16 10:37:16345 adapter->SetZeroHertzModeEnabled(
346 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
Markus Handell29dd8d82021-12-15 11:19:15347 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
348
349 // Send one frame, expect a repeat.
350 adapter->OnFrame(CreateFrame());
351 EXPECT_CALL(callback, OnFrame)
Markus Handell84c016a2023-11-23 12:41:44352 .WillOnce(Invoke([&](Timestamp post_time, bool, const VideoFrame& frame) {
Markus Handell29dd8d82021-12-15 11:19:15353 EXPECT_EQ(post_time, time_controller.GetClock()->CurrentTime());
354 EXPECT_EQ(frame.timestamp_us(), 0);
355 EXPECT_EQ(frame.ntp_time_ms(), 0);
356 }));
357 time_controller.AdvanceTime(TimeDelta::Seconds(1));
358 Mock::VerifyAndClearExpectations(&callback);
359 EXPECT_CALL(callback, OnFrame)
Markus Handell84c016a2023-11-23 12:41:44360 .WillOnce(Invoke([&](Timestamp post_time, bool, const VideoFrame& frame) {
Markus Handell29dd8d82021-12-15 11:19:15361 EXPECT_EQ(post_time, time_controller.GetClock()->CurrentTime());
362 EXPECT_EQ(frame.timestamp_us(), 0);
363 EXPECT_EQ(frame.ntp_time_ms(), 0);
364 }));
365 time_controller.AdvanceTime(TimeDelta::Seconds(1));
366}
367
368TEST(FrameCadenceAdapterTest, StopsRepeatingFramesDelayed) {
369 // At 1s, the initially scheduled frame appears.
370 // At 2s, the repeated initial frame appears.
371 // At 2.5s, we schedule another new frame.
372 // At 3.5s, we receive this frame.
Markus Handell29dd8d82021-12-15 11:19:15373 MockCallback callback;
Philipp Hanckea204ad22022-07-08 16:43:25374 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45375 test::ScopedKeyValueConfig no_field_trials;
376 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handell29dd8d82021-12-15 11:19:15377 adapter->Initialize(&callback);
Markus Handell8d87c462021-12-16 10:37:16378 adapter->SetZeroHertzModeEnabled(
379 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
Markus Handell29dd8d82021-12-15 11:19:15380 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
381 NtpTime original_ntp_time = time_controller.GetClock()->CurrentNtpTime();
382
383 // Send one frame, expect 1 subsequent repeat.
384 adapter->OnFrame(CreateFrameWithTimestamps(&time_controller));
385 EXPECT_CALL(callback, OnFrame).Times(2);
386 time_controller.AdvanceTime(TimeDelta::Seconds(2.5));
387 Mock::VerifyAndClearExpectations(&callback);
388
389 // Send the new frame at 2.5s, which should appear after 3.5s.
390 adapter->OnFrame(CreateFrameWithTimestamps(&time_controller));
391 EXPECT_CALL(callback, OnFrame)
Markus Handell84c016a2023-11-23 12:41:44392 .WillOnce(Invoke([&](Timestamp, bool, const VideoFrame& frame) {
Evan Shrubsole652c7712025-03-21 09:47:35393 EXPECT_EQ(frame.timestamp_us(), 5 * kNumMicrosecsPerSec / 2);
Markus Handell29dd8d82021-12-15 11:19:15394 EXPECT_EQ(frame.ntp_time_ms(),
Evan Shrubsole652c7712025-03-21 09:47:35395 original_ntp_time.ToMs() + 5u * kNumMillisecsPerSec / 2);
Markus Handell29dd8d82021-12-15 11:19:15396 }));
397 time_controller.AdvanceTime(TimeDelta::Seconds(1));
398}
399
Markus Handell2e0f4f02021-12-21 18:14:58400TEST(FrameCadenceAdapterTest, RequestsRefreshFrameOnKeyFrameRequestWhenNew) {
Markus Handell2e0f4f02021-12-21 18:14:58401 MockCallback callback;
Philipp Hanckea204ad22022-07-08 16:43:25402 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45403 test::ScopedKeyValueConfig no_field_trials;
404 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handell2e0f4f02021-12-21 18:14:58405 adapter->Initialize(&callback);
406 adapter->SetZeroHertzModeEnabled(
407 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
Markus Handellf5a50792022-06-16 12:25:15408 constexpr int kMaxFps = 10;
409 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFps});
Markus Handell818e7fb2021-12-30 12:01:33410 EXPECT_CALL(callback, RequestRefreshFrame);
Markus Handellf5a50792022-06-16 12:25:15411 time_controller.AdvanceTime(
412 TimeDelta::Seconds(1) *
413 FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod /
414 kMaxFps);
Markus Handell818e7fb2021-12-30 12:01:33415 adapter->ProcessKeyFrameRequest();
Markus Handell2e0f4f02021-12-21 18:14:58416}
417
418TEST(FrameCadenceAdapterTest, IgnoresKeyFrameRequestShortlyAfterFrame) {
Markus Handell2e0f4f02021-12-21 18:14:58419 MockCallback callback;
Philipp Hanckea204ad22022-07-08 16:43:25420 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45421 test::ScopedKeyValueConfig no_field_trials;
422 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handell2e0f4f02021-12-21 18:14:58423 adapter->Initialize(&callback);
424 adapter->SetZeroHertzModeEnabled(
425 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
426 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 10});
427 adapter->OnFrame(CreateFrame());
428 time_controller.AdvanceTime(TimeDelta::Zero());
Markus Handell818e7fb2021-12-30 12:01:33429 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
430 adapter->ProcessKeyFrameRequest();
Markus Handell2e0f4f02021-12-21 18:14:58431}
432
Markus Handellf7f0b212022-05-24 16:39:39433TEST(FrameCadenceAdapterTest, RequestsRefreshFramesUntilArrival) {
Markus Handellf7f0b212022-05-24 16:39:39434 MockCallback callback;
Philipp Hanckea204ad22022-07-08 16:43:25435 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45436 test::ScopedKeyValueConfig no_field_trials;
437 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handellf7f0b212022-05-24 16:39:39438 adapter->Initialize(&callback);
439 adapter->SetZeroHertzModeEnabled(
440 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
441 constexpr int kMaxFps = 10;
442 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFps});
443
Markus Handellf5a50792022-06-16 12:25:15444 // We should see max_fps + 1 -
445 // FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod refresh
446 // frame requests during the one second we wait until we send a single frame,
447 // after which refresh frame requests should cease (we should see no such
448 // requests during a second).
449 EXPECT_CALL(callback, RequestRefreshFrame)
450 .Times(kMaxFps + 1 -
451 FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod);
Markus Handellf7f0b212022-05-24 16:39:39452 time_controller.AdvanceTime(TimeDelta::Seconds(1));
453 Mock::VerifyAndClearExpectations(&callback);
454 adapter->OnFrame(CreateFrame());
455 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
456 time_controller.AdvanceTime(TimeDelta::Seconds(1));
457}
458
Markus Handellf5a50792022-06-16 12:25:15459TEST(FrameCadenceAdapterTest, RequestsRefreshAfterFrameDrop) {
Markus Handellf5a50792022-06-16 12:25:15460 MockCallback callback;
Philipp Hanckea204ad22022-07-08 16:43:25461 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45462 test::ScopedKeyValueConfig no_field_trials;
463 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handellf5a50792022-06-16 12:25:15464 adapter->Initialize(&callback);
465 adapter->SetZeroHertzModeEnabled(
466 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
467 constexpr int kMaxFps = 10;
468 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFps});
469
470 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
471
472 // Send a frame through to cancel the initial delayed timer waiting for first
473 // frame entry.
474 adapter->OnFrame(CreateFrame());
475 time_controller.AdvanceTime(TimeDelta::Seconds(1));
476 Mock::VerifyAndClearExpectations(&callback);
477
478 // Send a dropped frame indication without any following frames received.
479 // After FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod
480 // frame periods, we should receive a first refresh request.
481 adapter->OnDiscardedFrame();
482 EXPECT_CALL(callback, RequestRefreshFrame);
483 time_controller.AdvanceTime(
484 TimeDelta::Seconds(1) *
485 FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod /
486 kMaxFps);
487 Mock::VerifyAndClearExpectations(&callback);
488
489 // We will now receive a refresh frame request for every frame period.
490 EXPECT_CALL(callback, RequestRefreshFrame).Times(kMaxFps);
491 time_controller.AdvanceTime(TimeDelta::Seconds(1));
492 Mock::VerifyAndClearExpectations(&callback);
493
494 // After a frame is passed the requests will cease.
495 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
496 adapter->OnFrame(CreateFrame());
497 time_controller.AdvanceTime(TimeDelta::Seconds(1));
498}
499
500TEST(FrameCadenceAdapterTest, OmitsRefreshAfterFrameDropWithTimelyFrameEntry) {
Markus Handellf5a50792022-06-16 12:25:15501 MockCallback callback;
Philipp Hanckea204ad22022-07-08 16:43:25502 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45503 test::ScopedKeyValueConfig no_field_trials;
504 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handellf5a50792022-06-16 12:25:15505 adapter->Initialize(&callback);
506 adapter->SetZeroHertzModeEnabled(
507 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
508 constexpr int kMaxFps = 10;
509 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFps});
510
511 // Send a frame through to cancel the initial delayed timer waiting for first
512 // frame entry.
513 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
514 adapter->OnFrame(CreateFrame());
515 time_controller.AdvanceTime(TimeDelta::Seconds(1));
516 Mock::VerifyAndClearExpectations(&callback);
517
518 // Send a frame drop indication. No refresh frames should be requested
519 // until FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod
520 // intervals pass. Stop short of this.
521 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
522 adapter->OnDiscardedFrame();
523 time_controller.AdvanceTime(
524 TimeDelta::Seconds(1) *
525 FrameCadenceAdapterInterface::kOnDiscardedFrameRefreshFramePeriod /
526 kMaxFps -
527 TimeDelta::Micros(1));
528 Mock::VerifyAndClearExpectations(&callback);
529
530 // Send a frame. The timer to request the refresh frame should be cancelled by
531 // the reception, so no refreshes should be requested.
532 EXPECT_CALL(callback, RequestRefreshFrame).Times(0);
533 adapter->OnFrame(CreateFrame());
534 time_controller.AdvanceTime(TimeDelta::Seconds(1));
535 Mock::VerifyAndClearExpectations(&callback);
536}
537
Markus Handell5a77e512022-09-01 12:51:50538TEST(FrameCadenceAdapterTest, AcceptsUnconfiguredLayerFeedback) {
539 // This is a regression test for bugs.webrtc.org/14417.
Markus Handell5a77e512022-09-01 12:51:50540 MockCallback callback;
541 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
Markus Handella57229b2024-04-16 08:40:45542 test::ScopedKeyValueConfig no_field_trials;
543 auto adapter = CreateAdapter(no_field_trials, time_controller.GetClock());
Markus Handell5a77e512022-09-01 12:51:50544 adapter->Initialize(&callback);
545 adapter->SetZeroHertzModeEnabled(
546 FrameCadenceAdapterInterface::ZeroHertzModeParams{.num_simulcast_layers =
547 1});
548 constexpr int kMaxFps = 10;
549 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFps});
550 time_controller.AdvanceTime(TimeDelta::Zero());
551
552 adapter->UpdateLayerQualityConvergence(2, false);
553 adapter->UpdateLayerStatus(2, false);
554}
555
Markus Handellfb98b012023-09-13 22:31:11556TEST(FrameCadenceAdapterTest, IgnoresDropInducedCallbacksPostDestruction) {
Markus Handellfb98b012023-09-13 22:31:11557 auto callback = std::make_unique<MockCallback>();
558 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
559 auto queue = time_controller.GetTaskQueueFactory()->CreateTaskQueue(
560 "queue", TaskQueueFactory::Priority::NORMAL);
Markus Handella57229b2024-04-16 08:40:45561 test::ScopedKeyValueConfig no_field_trials;
Markus Handellfb98b012023-09-13 22:31:11562 auto adapter = FrameCadenceAdapterInterface::Create(
Zhaoliang Maf089d7e2024-01-08 02:44:15563 time_controller.GetClock(), queue.get(), /*metronome=*/nullptr,
Markus Handella57229b2024-04-16 08:40:45564 /*worker_queue=*/nullptr, no_field_trials);
Markus Handellfb98b012023-09-13 22:31:11565 queue->PostTask([&adapter, &callback] {
566 adapter->Initialize(callback.get());
567 adapter->SetZeroHertzModeEnabled(
568 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
569 });
570 time_controller.AdvanceTime(TimeDelta::Zero());
571 constexpr int kMaxFps = 10;
572 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFps});
573 adapter->OnDiscardedFrame();
574 time_controller.AdvanceTime(TimeDelta::Zero());
575 callback = nullptr;
576 queue->PostTask([adapter = std::move(adapter)]() mutable {});
577 time_controller.AdvanceTime(3 * TimeDelta::Seconds(1) / kMaxFps);
578}
579
Zhaoliang Maf089d7e2024-01-08 02:44:15580TEST(FrameCadenceAdapterTest, EncodeFramesAreAlignedWithMetronomeTick) {
Zhaoliang Maf089d7e2024-01-08 02:44:15581 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
582 // Here the metronome interval is 33ms, because the metronome is not
583 // infrequent then the encode tasks are aligned with the tick period.
584 static constexpr TimeDelta kTickPeriod = TimeDelta::Millis(33);
585 auto queue = time_controller.GetTaskQueueFactory()->CreateTaskQueue(
586 "queue", TaskQueueFactory::Priority::NORMAL);
587 auto worker_queue = time_controller.GetTaskQueueFactory()->CreateTaskQueue(
588 "work_queue", TaskQueueFactory::Priority::NORMAL);
Markus Handelle864dec2024-08-07 14:11:18589 test::FakeMetronome metronome(kTickPeriod);
Markus Handella57229b2024-04-16 08:40:45590 test::ScopedKeyValueConfig no_field_trials;
Zhaoliang Maf089d7e2024-01-08 02:44:15591 auto adapter = FrameCadenceAdapterInterface::Create(
592 time_controller.GetClock(), queue.get(), &metronome, worker_queue.get(),
Markus Handella57229b2024-04-16 08:40:45593 no_field_trials);
Zhaoliang Maf089d7e2024-01-08 02:44:15594 MockCallback callback;
595 adapter->Initialize(&callback);
596 auto frame = CreateFrame();
597
598 // `callback->OnFrame()` would not be called if only 32ms went by after
599 // `adapter->OnFrame()`.
600 EXPECT_CALL(callback, OnFrame(_, false, _)).Times(0);
601 adapter->OnFrame(frame);
602 time_controller.AdvanceTime(TimeDelta::Millis(32));
603 Mock::VerifyAndClearExpectations(&callback);
604
605 // `callback->OnFrame()` should be called if 33ms went by after
606 // `adapter->OnFrame()`.
607 EXPECT_CALL(callback, OnFrame(_, false, _)).Times(1);
608 time_controller.AdvanceTime(TimeDelta::Millis(1));
609 Mock::VerifyAndClearExpectations(&callback);
610
611 // `callback->OnFrame()` would not be called if only 32ms went by after
612 // `adapter->OnFrame()`.
613 EXPECT_CALL(callback, OnFrame(_, false, _)).Times(0);
614 // Send two frame before next tick.
615 adapter->OnFrame(frame);
616 adapter->OnFrame(frame);
617 time_controller.AdvanceTime(TimeDelta::Millis(32));
618 Mock::VerifyAndClearExpectations(&callback);
619
620 // `callback->OnFrame()` should be called if 33ms went by after
621 // `adapter->OnFrame()`.
622 EXPECT_CALL(callback, OnFrame(_, false, _)).Times(2);
623 time_controller.AdvanceTime(TimeDelta::Millis(1));
624 Mock::VerifyAndClearExpectations(&callback);
625
626 // Change the metronome tick period to 67ms (15Hz).
627 metronome.SetTickPeriod(TimeDelta::Millis(67));
628 // Expect the encode would happen immediately.
629 EXPECT_CALL(callback, OnFrame(_, false, _)).Times(1);
630 adapter->OnFrame(frame);
631 time_controller.AdvanceTime(TimeDelta::Zero());
632 Mock::VerifyAndClearExpectations(&callback);
633
634 // Change the metronome tick period to 16ms (60Hz).
635 metronome.SetTickPeriod(TimeDelta::Millis(16));
636 // Expect the encode would not happen if only 15ms went by after
637 // `adapter->OnFrame()`.
638 EXPECT_CALL(callback, OnFrame(_, false, _)).Times(0);
639 adapter->OnFrame(frame);
640 time_controller.AdvanceTime(TimeDelta::Millis(15));
641 Mock::VerifyAndClearExpectations(&callback);
642 // `callback->OnFrame()` should be called if 16ms went by after
643 // `adapter->OnFrame()`.
644 EXPECT_CALL(callback, OnFrame(_, false, _)).Times(1);
645 time_controller.AdvanceTime(TimeDelta::Millis(1));
646 Mock::VerifyAndClearExpectations(&callback);
647
Evan Shrubsole39c1c7e2025-03-20 10:10:50648 Event finalized;
Zhaoliang Maf089d7e2024-01-08 02:44:15649 queue->PostTask([&] {
650 adapter = nullptr;
651 finalized.Set();
652 });
Evan Shrubsole39c1c7e2025-03-20 10:10:50653 finalized.Wait(Event::kForever);
Zhaoliang Maf089d7e2024-01-08 02:44:15654}
655
Markus Handelle864dec2024-08-07 14:11:18656TEST(FrameCadenceAdapterTest, ShutdownUnderMetronome) {
657 // Regression test for crbug.com/356423094.
658 // The current thread takes the role of worker queue.
659 GlobalSimulatedTimeController time_controller(Timestamp::Zero());
660 static constexpr TimeDelta kTickPeriod = TimeDelta::Millis(100);
661 auto queue = time_controller.GetTaskQueueFactory()->CreateTaskQueue(
662 "queue", TaskQueueFactory::Priority::NORMAL);
663 test::FakeMetronome metronome(kTickPeriod);
664 test::ScopedKeyValueConfig no_field_trials;
665 auto adapter = FrameCadenceAdapterInterface::Create(
666 time_controller.GetClock(), queue.get(), &metronome,
667 TaskQueueBase::Current(), no_field_trials);
668 MockCallback callback;
669 EXPECT_CALL(callback, OnFrame).Times(0);
670 adapter->Initialize(&callback);
671
672 // Pass a frame, this is expected to trigger an encode call in the future.
673 adapter->OnFrame(CreateFrame());
674
675 // Then post destruction of the adapter and destroy the encode queue from the
676 // worker (i.e. current).
677 SendTask(queue.get(), [&] { adapter = nullptr; });
678 queue = nullptr;
679
680 // Now that we advance time, there should be no encoding happening.
681 time_controller.AdvanceTime(TimeDelta::Millis(100));
682}
683
Markus Handellcb237f82021-12-29 20:31:57684class FrameCadenceAdapterSimulcastLayersParamTest
685 : public ::testing::TestWithParam<int> {
686 public:
687 static constexpr int kMaxFpsHz = 8;
688 static constexpr TimeDelta kMinFrameDelay =
689 TimeDelta::Millis(1000 / kMaxFpsHz);
690 static constexpr TimeDelta kIdleFrameDelay =
691 FrameCadenceAdapterInterface::kZeroHertzIdleRepeatRatePeriod;
Markus Handell2e0f4f02021-12-21 18:14:58692
Markus Handellcb237f82021-12-29 20:31:57693 FrameCadenceAdapterSimulcastLayersParamTest() {
694 adapter_->Initialize(&callback_);
695 adapter_->OnConstraintsChanged(VideoTrackSourceConstraints{0, kMaxFpsHz});
696 time_controller_.AdvanceTime(TimeDelta::Zero());
697 adapter_->SetZeroHertzModeEnabled(
698 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
Markus Handell5a77e512022-09-01 12:51:50699 const size_t num_spatial_layers = GetParam();
Markus Handellcb237f82021-12-29 20:31:57700 adapter_->SetZeroHertzModeEnabled(
701 FrameCadenceAdapterInterface::ZeroHertzModeParams{num_spatial_layers});
702 }
703
704 int NumSpatialLayers() const { return GetParam(); }
705
706 protected:
Markus Handella57229b2024-04-16 08:40:45707 test::ScopedKeyValueConfig no_field_trials_;
Markus Handellcb237f82021-12-29 20:31:57708 MockCallback callback_;
Philipp Hanckea204ad22022-07-08 16:43:25709 GlobalSimulatedTimeController time_controller_{Timestamp::Zero()};
Markus Handellcb237f82021-12-29 20:31:57710 const std::unique_ptr<FrameCadenceAdapterInterface> adapter_{
Markus Handella57229b2024-04-16 08:40:45711 CreateAdapter(no_field_trials_, time_controller_.GetClock())};
Markus Handellcb237f82021-12-29 20:31:57712};
713
714TEST_P(FrameCadenceAdapterSimulcastLayersParamTest,
715 LayerReconfigurationResetsConvergenceInfo) {
716 // Assumes layer reconfiguration has just happened.
717 // Verify the state is unconverged.
718 adapter_->OnFrame(CreateFrame());
719 EXPECT_CALL(callback_, OnFrame).Times(kMaxFpsHz);
720 time_controller_.AdvanceTime(kMaxFpsHz * kMinFrameDelay);
Markus Handell2e0f4f02021-12-21 18:14:58721}
722
Markus Handellcb237f82021-12-29 20:31:57723TEST_P(FrameCadenceAdapterSimulcastLayersParamTest,
724 IgnoresKeyFrameRequestWhileShortRepeating) {
725 // Plot:
726 // 1. 0 * kMinFrameDelay: Start unconverged. Frame -> adapter.
727 // 2. 1 * kMinFrameDelay: Frame -> callback.
728 // 3. 2 * kMinFrameDelay: 1st short repeat.
729 // Since we're unconverged we assume the process continues.
730 adapter_->OnFrame(CreateFrame());
731 time_controller_.AdvanceTime(2 * kMinFrameDelay);
Markus Handell818e7fb2021-12-30 12:01:33732 EXPECT_CALL(callback_, RequestRefreshFrame).Times(0);
733 adapter_->ProcessKeyFrameRequest();
Markus Handellcb237f82021-12-29 20:31:57734
735 // Expect short repeating as ususal.
736 EXPECT_CALL(callback_, OnFrame).Times(8);
737 time_controller_.AdvanceTime(8 * kMinFrameDelay);
738}
739
740TEST_P(FrameCadenceAdapterSimulcastLayersParamTest,
741 IgnoresKeyFrameRequestJustBeforeIdleRepeating) {
742 // (Only for > 0 spatial layers as we assume not converged with 0 layers)
743 if (NumSpatialLayers() == 0)
744 return;
745
746 // Plot:
747 // 1. 0 * kMinFrameDelay: Start converged. Frame -> adapter.
748 // 2. 1 * kMinFrameDelay: Frame -> callback. New repeat scheduled at
749 // (kMaxFpsHz + 1) * kMinFrameDelay.
750 // 3. kMaxFpsHz * kMinFrameDelay: Process keyframe.
751 // 4. (kMaxFpsHz + N) * kMinFrameDelay (1 <= N <= kMaxFpsHz): Short repeats
752 // due to not converged.
753 for (int i = 0; i != NumSpatialLayers(); i++) {
754 adapter_->UpdateLayerStatus(i, /*enabled=*/true);
755 adapter_->UpdateLayerQualityConvergence(i, /*converged=*/true);
756 }
757 adapter_->OnFrame(CreateFrame());
758 time_controller_.AdvanceTime(kIdleFrameDelay);
Markus Handell2e0f4f02021-12-21 18:14:58759
760 // We process the key frame request kMinFrameDelay before the first idle
Markus Handellcb237f82021-12-29 20:31:57761 // repeat should happen. The resulting repeats should happen spaced by
762 // kMinFrameDelay before we get new convergence info.
Markus Handell818e7fb2021-12-30 12:01:33763 EXPECT_CALL(callback_, RequestRefreshFrame).Times(0);
764 adapter_->ProcessKeyFrameRequest();
Markus Handellcb237f82021-12-29 20:31:57765 EXPECT_CALL(callback_, OnFrame).Times(kMaxFpsHz);
766 time_controller_.AdvanceTime(kMaxFpsHz * kMinFrameDelay);
Markus Handell2e0f4f02021-12-21 18:14:58767}
768
Markus Handellcb237f82021-12-29 20:31:57769TEST_P(FrameCadenceAdapterSimulcastLayersParamTest,
770 IgnoresKeyFrameRequestShortRepeatsBeforeIdleRepeat) {
771 // (Only for > 0 spatial layers as we assume not converged with 0 layers)
772 if (NumSpatialLayers() == 0)
773 return;
774 // Plot:
775 // 1. 0 * kMinFrameDelay: Start converged. Frame -> adapter.
776 // 2. 1 * kMinFrameDelay: Frame -> callback. New repeat scheduled at
777 // (kMaxFpsHz + 1) * kMinFrameDelay.
778 // 3. 2 * kMinFrameDelay: Process keyframe.
779 // 4. (2 + N) * kMinFrameDelay (1 <= N <= kMaxFpsHz): Short repeats due to not
780 // converged.
781 for (int i = 0; i != NumSpatialLayers(); i++) {
782 adapter_->UpdateLayerStatus(i, /*enabled=*/true);
783 adapter_->UpdateLayerQualityConvergence(i, /*converged=*/true);
784 }
785 adapter_->OnFrame(CreateFrame());
786 time_controller_.AdvanceTime(2 * kMinFrameDelay);
Markus Handell2e0f4f02021-12-21 18:14:58787
Markus Handellcb237f82021-12-29 20:31:57788 // We process the key frame request (kMaxFpsHz - 1) * kMinFrameDelay before
789 // the first idle repeat should happen. The resulting repeats should happen
790 // spaced kMinFrameDelay before we get new convergence info.
Markus Handell818e7fb2021-12-30 12:01:33791 EXPECT_CALL(callback_, RequestRefreshFrame).Times(0);
792 adapter_->ProcessKeyFrameRequest();
Markus Handellcb237f82021-12-29 20:31:57793 EXPECT_CALL(callback_, OnFrame).Times(kMaxFpsHz);
794 time_controller_.AdvanceTime(kMaxFpsHz * kMinFrameDelay);
Markus Handell2e0f4f02021-12-21 18:14:58795}
796
Markus Handellcb237f82021-12-29 20:31:57797INSTANTIATE_TEST_SUITE_P(,
798 FrameCadenceAdapterSimulcastLayersParamTest,
799 Values(0, 1, 2));
Markus Handelle59fee82021-12-23 08:29:23800
Markus Handell8d87c462021-12-16 10:37:16801class ZeroHertzLayerQualityConvergenceTest : public ::testing::Test {
802 public:
803 static constexpr TimeDelta kMinFrameDelay = TimeDelta::Millis(100);
804 static constexpr TimeDelta kIdleFrameDelay =
805 FrameCadenceAdapterInterface::kZeroHertzIdleRepeatRatePeriod;
henrika8f16ce92023-12-04 13:03:52806 // Restricts non-idle repeat rate to 5 fps (default is 10 fps);
807 static constexpr int kRestrictedMaxFps = 5;
Markus Handell8d87c462021-12-16 10:37:16808
809 ZeroHertzLayerQualityConvergenceTest() {
810 adapter_->Initialize(&callback_);
811 adapter_->SetZeroHertzModeEnabled(
812 FrameCadenceAdapterInterface::ZeroHertzModeParams{
813 /*num_simulcast_layers=*/2});
814 adapter_->OnConstraintsChanged(VideoTrackSourceConstraints{
815 /*min_fps=*/0, /*max_fps=*/TimeDelta::Seconds(1) / kMinFrameDelay});
816 time_controller_.AdvanceTime(TimeDelta::Zero());
817 }
818
819 void PassFrame() { adapter_->OnFrame(CreateFrame()); }
820
821 void ExpectFrameEntriesAtDelaysFromNow(
822 std::initializer_list<TimeDelta> list) {
823 Timestamp origin = time_controller_.GetClock()->CurrentTime();
824 for (auto delay : list) {
Markus Handell84c016a2023-11-23 12:41:44825 EXPECT_CALL(callback_, OnFrame(origin + delay, false, _));
Markus Handell8d87c462021-12-16 10:37:16826 time_controller_.AdvanceTime(origin + delay -
827 time_controller_.GetClock()->CurrentTime());
828 }
829 }
830
Danil Chapovalov95eeaa72022-07-06 08:14:29831 void ScheduleDelayed(TimeDelta delay, absl::AnyInvocable<void() &&> task) {
832 TaskQueueBase::Current()->PostDelayedTask(std::move(task), delay);
Markus Handell8d87c462021-12-16 10:37:16833 }
834
835 protected:
Markus Handella57229b2024-04-16 08:40:45836 test::ScopedKeyValueConfig no_field_trials_;
Markus Handell8d87c462021-12-16 10:37:16837 MockCallback callback_;
Philipp Hanckea204ad22022-07-08 16:43:25838 GlobalSimulatedTimeController time_controller_{Timestamp::Zero()};
Markus Handell8d87c462021-12-16 10:37:16839 std::unique_ptr<FrameCadenceAdapterInterface> adapter_{
Markus Handella57229b2024-04-16 08:40:45840 CreateAdapter(no_field_trials_, time_controller_.GetClock())};
Markus Handell8d87c462021-12-16 10:37:16841};
842
Markus Handelle59fee82021-12-23 08:29:23843TEST_F(ZeroHertzLayerQualityConvergenceTest, InitialStateUnconverged) {
844 // As the layer count is just configured, assume we start out as unconverged.
Markus Handell8d87c462021-12-16 10:37:16845 PassFrame();
846 ExpectFrameEntriesAtDelaysFromNow({
Markus Handelle59fee82021-12-23 08:29:23847 1 * kMinFrameDelay, // Original frame emitted
848 2 * kMinFrameDelay, // Short repeats.
849 3 * kMinFrameDelay, // ...
Markus Handell8d87c462021-12-16 10:37:16850 });
851}
852
853TEST_F(ZeroHertzLayerQualityConvergenceTest, UnconvergedAfterLayersEnabled) {
854 // With newly enabled layers we assume quality is unconverged.
855 adapter_->UpdateLayerStatus(0, /*enabled=*/true);
856 adapter_->UpdateLayerStatus(1, /*enabled=*/true);
857 PassFrame();
858 ExpectFrameEntriesAtDelaysFromNow({
859 kMinFrameDelay, // Original frame emitted
860 2 * kMinFrameDelay, // Unconverged repeats.
861 3 * kMinFrameDelay, // ...
862 });
863}
864
865TEST_F(ZeroHertzLayerQualityConvergenceTest,
866 RepeatsPassedFramesUntilConvergence) {
867 ScheduleDelayed(TimeDelta::Zero(), [&] {
868 adapter_->UpdateLayerStatus(0, /*enabled=*/true);
869 adapter_->UpdateLayerStatus(1, /*enabled=*/true);
870 PassFrame();
871 });
872 ScheduleDelayed(2.5 * kMinFrameDelay, [&] {
873 adapter_->UpdateLayerQualityConvergence(/*spatial_index=*/1, true);
874 });
875 ScheduleDelayed(3.5 * kMinFrameDelay, [&] {
876 adapter_->UpdateLayerQualityConvergence(/*spatial_index=*/0, true);
877 });
878 ScheduleDelayed(8 * kMinFrameDelay, [&] { PassFrame(); });
879 ScheduleDelayed(9.5 * kMinFrameDelay, [&] {
880 adapter_->UpdateLayerQualityConvergence(/*spatial_index=*/0, true);
881 });
882 ScheduleDelayed(10.5 * kMinFrameDelay, [&] {
883 adapter_->UpdateLayerQualityConvergence(/*spatial_index=*/1, true);
884 });
885 ExpectFrameEntriesAtDelaysFromNow({
886 kMinFrameDelay, // Original frame emitted
887 2 * kMinFrameDelay, // Repeat from kMinFrameDelay.
888
889 // 2.5 * kMinFrameDelay: Converged in layer 1, layer 0 still unconverged.
890 3 * kMinFrameDelay, // Repeat from 2 * kMinFrameDelay.
891
892 // 3.5 * kMinFrameDelay: Converged in layer 0 as well.
893 4 * kMinFrameDelay, // Repeat from 3 * kMinFrameDelay. An idle repeat is
894 // scheduled for kIdleFrameDelay + 3 *
895 // kMinFrameDelay.
896
897 // A new frame is passed at 8 * kMinFrameDelay.
898 9 * kMinFrameDelay, // Original frame emitted
899
900 // 9.5 * kMinFrameDelay: Converged in layer 0, layer 1 still unconverged.
901 10 * kMinFrameDelay, // Repeat from 9 * kMinFrameDelay.
902 // 10.5 * kMinFrameDelay: Converged in layer 0 as well.
903 11 * kMinFrameDelay, // Idle repeats from 1000.
904 11 * kMinFrameDelay + kIdleFrameDelay, // ...
905 11 * kMinFrameDelay + 2 * kIdleFrameDelay, // ...
906 // ...
907 });
908}
909
henrika8f16ce92023-12-04 13:03:52910TEST_F(ZeroHertzLayerQualityConvergenceTest,
911 UnconvergedRepeatRateAdaptsDownWhenRestricted) {
912 PassFrame();
913 ScheduleDelayed(1.5 * kMinFrameDelay, [&] {
914 adapter_->UpdateVideoSourceRestrictions(kRestrictedMaxFps);
915 });
916 ExpectFrameEntriesAtDelaysFromNow({
917 1 * kMinFrameDelay, // Original frame emitted at non-restricted rate.
918
919 // 1.5 * kMinFrameDelay: restricts max fps to 5 fps which should result
920 // in a new non-idle repeat delay of 2 * kMinFrameDelay.
921 2 * kMinFrameDelay, // Unconverged repeat at non-restricted rate.
922 4 * kMinFrameDelay, // Unconverged repeats at restricted rate. This
923 // happens 2 * kMinFrameDelay after the last frame.
924 6 * kMinFrameDelay, // ...
925 });
926}
927
928TEST_F(ZeroHertzLayerQualityConvergenceTest,
929 UnconvergedRepeatRateAdaptsUpWhenGoingFromRestrictedToUnrestricted) {
930 PassFrame();
931 ScheduleDelayed(1.5 * kMinFrameDelay, [&] {
932 adapter_->UpdateVideoSourceRestrictions(kRestrictedMaxFps);
933 });
934 ScheduleDelayed(5.5 * kMinFrameDelay, [&] {
Florent Castelli8037fc62024-08-29 13:00:40935 adapter_->UpdateVideoSourceRestrictions(std::nullopt);
henrika8f16ce92023-12-04 13:03:52936 });
937 ExpectFrameEntriesAtDelaysFromNow({
938 1 * kMinFrameDelay, // Original frame emitted at non-restricted rate.
939
940 // 1.5 * kMinFrameDelay: restricts max fps to 5 fps which should result
941 // in a new non-idle repeat delay of 2 * kMinFrameDelay.
942 2 * kMinFrameDelay, // Unconverged repeat at non-restricted rate.
943 4 * kMinFrameDelay, // Unconverged repeat at restricted rate.
944
945 // 5.5 * kMinFrameDelay: removes frame-rate restriction and we should
946 // then go back to 10 fps as unconverged repeat rate.
947 6 * kMinFrameDelay, // Last unconverged repeat at restricted rate.
948 7 * kMinFrameDelay, // Back to unconverged repeat at non-restricted rate.
949 8 * kMinFrameDelay, // We are now unrestricted.
950 9 * kMinFrameDelay, // ...
951 });
952}
953
954TEST_F(ZeroHertzLayerQualityConvergenceTest,
955 UnconvergedRepeatRateMaintainsRestrictionOnReconfigureToHigherMaxFps) {
956 PassFrame();
957 ScheduleDelayed(1.5 * kMinFrameDelay, [&] {
958 adapter_->UpdateVideoSourceRestrictions(kRestrictedMaxFps);
959 });
960 ScheduleDelayed(2.5 * kMinFrameDelay, [&] {
961 adapter_->OnConstraintsChanged(VideoTrackSourceConstraints{
962 /*min_fps=*/0, /*max_fps=*/2 * TimeDelta::Seconds(1) / kMinFrameDelay});
963 });
964 ScheduleDelayed(3 * kMinFrameDelay, [&] { PassFrame(); });
965 ScheduleDelayed(8 * kMinFrameDelay, [&] {
966 adapter_->OnConstraintsChanged(VideoTrackSourceConstraints{
967 /*min_fps=*/0,
968 /*max_fps=*/0.2 * TimeDelta::Seconds(1) / kMinFrameDelay});
969 });
970 ScheduleDelayed(9 * kMinFrameDelay, [&] { PassFrame(); });
971 ExpectFrameEntriesAtDelaysFromNow({
972 1 * kMinFrameDelay, // Original frame emitted at non-restricted rate.
973
974 // 1.5 * kMinFrameDelay: restricts max fps to 5 fps which should result
975 // in a new non-idle repeat delay of 2 * kMinFrameDelay.
976 2 * kMinFrameDelay, // Unconverged repeat at non-restricted rate.
977
978 // 2.5 * kMinFrameDelay: new constraint asks for max rate of 20 fps.
979 // The 0Hz adapter is reconstructed for 20 fps but inherits the current
980 // restriction for rate of non-converged frames of 5 fps.
981
982 // A new frame is passed at 3 * kMinFrameDelay. The previous repeat
983 // cadence was stopped by the change in constraints.
984 3.5 * kMinFrameDelay, // Original frame emitted at non-restricted 20 fps.
985 // The delay is 0.5 * kMinFrameDelay.
986 5.5 * kMinFrameDelay, // Unconverged repeat at restricted rate.
987 // The delay is 2 * kMinFrameDelay when restricted.
988 7.5 * kMinFrameDelay, // ...
989
990 // 8 * kMinFrameDelay: new constraint asks for max rate of 2 fps.
991 // The 0Hz adapter is reconstructed for 2 fps and will therefore not obey
992 // the current restriction for rate of non-converged frames of 5 fps
993 // since the new max rate is lower.
994
995 // A new frame is passed at 9 * kMinFrameDelay. The previous repeat
996 // cadence was stopped by the change in constraints.
997 14 * kMinFrameDelay, // Original frame emitted at non-restricted 2 fps.
998 // The delay is 5 * kMinFrameDelay.
999 19 * kMinFrameDelay, // Unconverged repeat at non-restricted rate.
1000 24 * kMinFrameDelay, // ...
1001 });
1002}
1003
Markus Handellb4e96d42021-11-05 11:00:551004class FrameCadenceAdapterMetricsTest : public ::testing::Test {
1005 public:
Markus Handell28c71802021-11-08 09:11:551006 FrameCadenceAdapterMetricsTest() : time_controller_(Timestamp::Millis(1)) {
1007 metrics::Reset();
1008 }
1009 void DepleteTaskQueues() { time_controller_.AdvanceTime(TimeDelta::Zero()); }
1010
Markus Handell9a478b52021-11-18 15:07:011011 protected:
Markus Handell28c71802021-11-08 09:11:551012 GlobalSimulatedTimeController time_controller_;
Markus Handellb4e96d42021-11-05 11:00:551013};
1014
Markus Handell9d04a782022-05-12 16:38:571015TEST_F(FrameCadenceAdapterMetricsTest, RecordsTimeUntilFirstFrame) {
1016 MockCallback callback;
1017 test::ScopedKeyValueConfig no_field_trials;
1018 auto adapter = CreateAdapter(no_field_trials, time_controller_.GetClock());
1019 adapter->Initialize(&callback);
1020 adapter->SetZeroHertzModeEnabled(
1021 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
1022 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 5.0});
1023 time_controller_.AdvanceTime(TimeDelta::Millis(666));
1024 adapter->OnFrame(CreateFrame());
1025 DepleteTaskQueues();
1026 EXPECT_THAT(
1027 metrics::Samples("WebRTC.Screenshare.ZeroHz.TimeUntilFirstFrameMs"),
1028 ElementsAre(Pair(666, 1)));
1029}
1030
Per Ke975b442024-03-27 10:28:441031TEST_F(FrameCadenceAdapterMetricsTest,
1032 RecordsFrameTimestampMonotonicallyIncreasing) {
1033 MockCallback callback;
1034 test::ScopedKeyValueConfig no_field_trials;
1035 std::unique_ptr<FrameCadenceAdapterInterface> adapter =
1036 CreateAdapter(no_field_trials, time_controller_.GetClock());
1037 adapter->Initialize(&callback);
1038 time_controller_.AdvanceTime(TimeDelta::Millis(666));
1039 adapter->OnFrame(CreateFrameWithTimestamps(&time_controller_));
1040 adapter->OnFrame(CreateFrameWithTimestamps(&time_controller_));
1041 time_controller_.AdvanceTime(TimeDelta::Zero());
1042 adapter = nullptr;
1043 DepleteTaskQueues();
1044 EXPECT_THAT(metrics::Samples(
1045 "WebRTC.Video.InputFrameTimestampMonotonicallyIncreasing"),
1046 ElementsAre(Pair(false, 1)));
1047}
1048
Markus Handell90a7e2c2021-12-29 22:32:301049TEST(FrameCadenceAdapterRealTimeTest, TimestampsDoNotDrift) {
1050 // This regression test must be performed in realtime because of limitations
1051 // in GlobalSimulatedTimeController.
1052 //
1053 // We sleep for a long while in OnFrame when a repeat was scheduled which
1054 // should reflect in accordingly increased ntp_time_ms() and timestamp_us() in
1055 // the repeated frames.
1056 auto factory = CreateDefaultTaskQueueFactory();
1057 auto queue =
1058 factory->CreateTaskQueue("test", TaskQueueFactory::Priority::NORMAL);
Markus Handell90a7e2c2021-12-29 22:32:301059 MockCallback callback;
1060 Clock* clock = Clock::GetRealTimeClock();
1061 std::unique_ptr<FrameCadenceAdapterInterface> adapter;
1062 int frame_counter = 0;
1063 int64_t original_ntp_time_ms;
1064 int64_t original_timestamp_us;
Evan Shrubsole39c1c7e2025-03-20 10:10:501065 Event event;
Markus Handella57229b2024-04-16 08:40:451066 test::ScopedKeyValueConfig no_field_trials;
Danil Chapovalov95eeaa72022-07-06 08:14:291067 queue->PostTask([&] {
Markus Handella57229b2024-04-16 08:40:451068 adapter = CreateAdapter(no_field_trials, clock);
Markus Handell90a7e2c2021-12-29 22:32:301069 adapter->Initialize(&callback);
1070 adapter->SetZeroHertzModeEnabled(
1071 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
1072 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 30});
1073 auto frame = CreateFrame();
1074 original_ntp_time_ms = clock->CurrentNtpInMilliseconds();
1075 frame.set_ntp_time_ms(original_ntp_time_ms);
1076 original_timestamp_us = clock->CurrentTime().us();
1077 frame.set_timestamp_us(original_timestamp_us);
Evan Shrubsole652c7712025-03-21 09:47:351078 constexpr int kSleepMs = kNumMillisecsPerSec / 2;
Markus Handell90a7e2c2021-12-29 22:32:301079 EXPECT_CALL(callback, OnFrame)
1080 .WillRepeatedly(
Markus Handell84c016a2023-11-23 12:41:441081 Invoke([&](Timestamp, bool, const VideoFrame& incoming_frame) {
Markus Handell90a7e2c2021-12-29 22:32:301082 ++frame_counter;
1083 // Avoid the first OnFrame and sleep on the second.
1084 if (frame_counter == 2) {
Fredrik Solenberg4ecf1112025-05-21 09:05:561085 Thread::SleepMs(kSleepMs);
Markus Handell90a7e2c2021-12-29 22:32:301086 } else if (frame_counter == 3) {
1087 EXPECT_GE(incoming_frame.ntp_time_ms(),
1088 original_ntp_time_ms + kSleepMs);
1089 EXPECT_GE(incoming_frame.timestamp_us(),
1090 original_timestamp_us + kSleepMs);
1091 event.Set();
1092 }
1093 }));
1094 adapter->OnFrame(frame);
Danil Chapovalov95eeaa72022-07-06 08:14:291095 });
Evan Shrubsole39c1c7e2025-03-20 10:10:501096 event.Wait(Event::kForever);
1097 Event finalized;
Danil Chapovalov95eeaa72022-07-06 08:14:291098 queue->PostTask([&] {
Markus Handell90a7e2c2021-12-29 22:32:301099 adapter = nullptr;
1100 finalized.Set();
Danil Chapovalov95eeaa72022-07-06 08:14:291101 });
Evan Shrubsole39c1c7e2025-03-20 10:10:501102 finalized.Wait(Event::kForever);
Markus Handell90a7e2c2021-12-29 22:32:301103}
1104
Markus Handell74ace1a2024-12-10 10:25:031105TEST(FrameCadenceAdapterRealTimeTest, ScheduledRepeatAllowsForSlowEncode) {
Markus Handellf2827c42023-09-02 07:41:101106 // This regression test must be performed in realtime because of limitations
1107 // in GlobalSimulatedTimeController.
1108 //
1109 // We sleep for a long while (but less than max fps) in the first repeated
1110 // OnFrame (frame 2). This should not lead to a belated second repeated
1111 // OnFrame (frame 3).
1112 auto factory = CreateDefaultTaskQueueFactory();
1113 auto queue =
1114 factory->CreateTaskQueue("test", TaskQueueFactory::Priority::NORMAL);
Markus Handellf2827c42023-09-02 07:41:101115 MockCallback callback;
1116 Clock* clock = Clock::GetRealTimeClock();
1117 std::unique_ptr<FrameCadenceAdapterInterface> adapter;
1118 int frame_counter = 0;
Evan Shrubsole39c1c7e2025-03-20 10:10:501119 Event event;
Florent Castelli8037fc62024-08-29 13:00:401120 std::optional<Timestamp> start_time;
Markus Handella57229b2024-04-16 08:40:451121 test::ScopedKeyValueConfig no_field_trials;
Markus Handellf2827c42023-09-02 07:41:101122 queue->PostTask([&] {
Markus Handella57229b2024-04-16 08:40:451123 adapter = CreateAdapter(no_field_trials, clock);
Markus Handellf2827c42023-09-02 07:41:101124 adapter->Initialize(&callback);
1125 adapter->SetZeroHertzModeEnabled(
1126 FrameCadenceAdapterInterface::ZeroHertzModeParams{});
1127 adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 2});
1128 auto frame = CreateFrame();
1129 constexpr int kSleepMs = 400;
1130 constexpr TimeDelta kAllowedBelate = TimeDelta::Millis(150);
1131 EXPECT_CALL(callback, OnFrame)
1132 .WillRepeatedly(InvokeWithoutArgs([&, kAllowedBelate] {
1133 ++frame_counter;
1134 // Avoid the first OnFrame and sleep on the second.
1135 if (frame_counter == 2) {
1136 start_time = clock->CurrentTime();
Fredrik Solenberg4ecf1112025-05-21 09:05:561137 Thread::SleepMs(kSleepMs);
Markus Handellf2827c42023-09-02 07:41:101138 } else if (frame_counter == 3) {
1139 TimeDelta diff =
1140 clock->CurrentTime() - (*start_time + TimeDelta::Millis(500));
1141 RTC_LOG(LS_ERROR)
1142 << "Difference in when frame should vs is appearing: " << diff;
1143 EXPECT_LT(diff, kAllowedBelate);
1144 event.Set();
1145 }
1146 }));
1147 adapter->OnFrame(frame);
1148 });
Evan Shrubsole39c1c7e2025-03-20 10:10:501149 event.Wait(Event::kForever);
1150 Event finalized;
Markus Handellf2827c42023-09-02 07:41:101151 queue->PostTask([&] {
1152 adapter = nullptr;
1153 finalized.Set();
1154 });
Evan Shrubsole39c1c7e2025-03-20 10:10:501155 finalized.Wait(Event::kForever);
Markus Handellf2827c42023-09-02 07:41:101156}
1157
henrikab7ec0572024-01-09 09:48:521158class ZeroHertzQueueOverloadTest : public ::testing::Test {
1159 public:
1160 static constexpr int kMaxFps = 10;
1161
1162 ZeroHertzQueueOverloadTest() {
1163 Initialize();
1164 metrics::Reset();
1165 }
1166
1167 void Initialize() {
1168 adapter_->Initialize(&callback_);
1169 adapter_->SetZeroHertzModeEnabled(
1170 FrameCadenceAdapterInterface::ZeroHertzModeParams{
1171 /*num_simulcast_layers=*/1});
1172 adapter_->OnConstraintsChanged(
1173 VideoTrackSourceConstraints{/*min_fps=*/0, kMaxFps});
1174 time_controller_.AdvanceTime(TimeDelta::Zero());
1175 }
1176
1177 void ScheduleDelayed(TimeDelta delay, absl::AnyInvocable<void() &&> task) {
1178 TaskQueueBase::Current()->PostDelayedTask(std::move(task), delay);
1179 }
1180
1181 void PassFrame() { adapter_->OnFrame(CreateFrame()); }
1182
1183 void AdvanceTime(TimeDelta duration) {
1184 time_controller_.AdvanceTime(duration);
1185 }
1186
1187 void SkipForwardBy(TimeDelta duration) {
1188 time_controller_.SkipForwardBy(duration);
1189 }
1190
1191 Timestamp CurrentTime() { return time_controller_.GetClock()->CurrentTime(); }
1192
1193 protected:
1194 test::ScopedKeyValueConfig field_trials_;
1195 NiceMock<MockCallback> callback_;
1196 GlobalSimulatedTimeController time_controller_{Timestamp::Zero()};
1197 std::unique_ptr<FrameCadenceAdapterInterface> adapter_{
1198 CreateAdapter(field_trials_, time_controller_.GetClock())};
1199};
1200
1201TEST_F(ZeroHertzQueueOverloadTest,
1202 ForwardedFramesDuringTooLongEncodeTimeAreFlaggedWithQueueOverload) {
1203 InSequence s;
1204 PassFrame();
1205 EXPECT_CALL(callback_, OnFrame(_, false, _)).WillOnce(InvokeWithoutArgs([&] {
1206 PassFrame();
1207 PassFrame();
1208 PassFrame();
1209 SkipForwardBy(TimeDelta::Millis(301));
1210 }));
1211 EXPECT_CALL(callback_, OnFrame(_, true, _)).Times(3);
1212 AdvanceTime(TimeDelta::Millis(100));
1213 EXPECT_THAT(metrics::Samples("WebRTC.Screenshare.ZeroHz.QueueOverload"),
1214 ElementsAre(Pair(false, 1), Pair(true, 3)));
1215}
1216
1217TEST_F(ZeroHertzQueueOverloadTest,
1218 ForwardedFramesAfterOverloadBurstAreNotFlaggedWithQueueOverload) {
1219 InSequence s;
1220 PassFrame();
1221 EXPECT_CALL(callback_, OnFrame(_, false, _)).WillOnce(InvokeWithoutArgs([&] {
1222 PassFrame();
1223 PassFrame();
1224 PassFrame();
1225 SkipForwardBy(TimeDelta::Millis(301));
1226 }));
1227 EXPECT_CALL(callback_, OnFrame(_, true, _)).Times(3);
1228 AdvanceTime(TimeDelta::Millis(100));
1229 EXPECT_CALL(callback_, OnFrame(_, false, _)).Times(2);
1230 PassFrame();
1231 PassFrame();
1232 AdvanceTime(TimeDelta::Millis(100));
1233 EXPECT_THAT(metrics::Samples("WebRTC.Screenshare.ZeroHz.QueueOverload"),
1234 ElementsAre(Pair(false, 3), Pair(true, 3)));
1235}
1236
1237TEST_F(ZeroHertzQueueOverloadTest,
1238 ForwardedFramesDuringNormalEncodeTimeAreNotFlaggedWithQueueOverload) {
1239 InSequence s;
1240 PassFrame();
1241 EXPECT_CALL(callback_, OnFrame(_, false, _)).WillOnce(InvokeWithoutArgs([&] {
1242 PassFrame();
1243 PassFrame();
1244 PassFrame();
1245 // Long but not too long encode time.
1246 SkipForwardBy(TimeDelta::Millis(99));
1247 }));
1248 EXPECT_CALL(callback_, OnFrame(_, false, _)).Times(3);
1249 AdvanceTime(TimeDelta::Millis(199));
1250 EXPECT_THAT(metrics::Samples("WebRTC.Screenshare.ZeroHz.QueueOverload"),
1251 ElementsAre(Pair(false, 4)));
1252}
1253
1254TEST_F(
1255 ZeroHertzQueueOverloadTest,
1256 AvoidSettingQueueOverloadAndSendRepeatWhenNoNewPacketsWhileTooLongEncode) {
1257 // Receive one frame only and let OnFrame take such a long time that an
1258 // overload normally is warranted. But the fact that no new frames arrive
1259 // while being blocked should trigger a non-idle repeat to ensure that the
1260 // video stream does not freeze and queue overload should be false.
1261 PassFrame();
1262 EXPECT_CALL(callback_, OnFrame(_, false, _))
1263 .WillOnce(
1264 InvokeWithoutArgs([&] { SkipForwardBy(TimeDelta::Millis(101)); }))
1265 .WillOnce(InvokeWithoutArgs([&] {
1266 // Non-idle repeat.
1267 EXPECT_EQ(CurrentTime(), Timestamp::Zero() + TimeDelta::Millis(201));
1268 }));
1269 AdvanceTime(TimeDelta::Millis(100));
1270 EXPECT_THAT(metrics::Samples("WebRTC.Screenshare.ZeroHz.QueueOverload"),
1271 ElementsAre(Pair(false, 2)));
1272}
1273
1274TEST_F(ZeroHertzQueueOverloadTest,
1275 EnterFastRepeatAfterQueueOverloadWhenReceivedOnlyOneFrameDuringEncode) {
1276 InSequence s;
1277 // - Forward one frame frame during high load which triggers queue overload.
1278 // - Receive only one new frame while being blocked and verify that the
1279 // cancelled repeat was for the first frame and not the second.
1280 // - Fast repeat mode should happen after second frame.
1281 PassFrame();
1282 EXPECT_CALL(callback_, OnFrame(_, false, _)).WillOnce(InvokeWithoutArgs([&] {
1283 PassFrame();
1284 SkipForwardBy(TimeDelta::Millis(101));
1285 }));
1286 EXPECT_CALL(callback_, OnFrame(_, true, _));
1287 AdvanceTime(TimeDelta::Millis(100));
1288
1289 // Fast repeats should take place from here on.
1290 EXPECT_CALL(callback_, OnFrame(_, false, _)).Times(5);
1291 AdvanceTime(TimeDelta::Millis(500));
1292 EXPECT_THAT(metrics::Samples("WebRTC.Screenshare.ZeroHz.QueueOverload"),
1293 ElementsAre(Pair(false, 6), Pair(true, 1)));
1294}
1295
1296TEST_F(ZeroHertzQueueOverloadTest,
1297 QueueOverloadIsDisabledForZeroHerzWhenKillSwitchIsEnabled) {
Evan Shrubsole2b87a422025-05-09 10:35:381298 test::ScopedKeyValueConfig field_trials(
henrikab7ec0572024-01-09 09:48:521299 field_trials_, "WebRTC-ZeroHertzQueueOverload/Disabled/");
1300 adapter_.reset();
1301 adapter_ = CreateAdapter(field_trials, time_controller_.GetClock());
1302 Initialize();
1303
1304 // Same as ForwardedFramesDuringTooLongEncodeTimeAreFlaggedWithQueueOverload
1305 // but this time the queue overload mechanism is disabled.
1306 InSequence s;
1307 PassFrame();
1308 EXPECT_CALL(callback_, OnFrame(_, false, _)).WillOnce(InvokeWithoutArgs([&] {
1309 PassFrame();
1310 PassFrame();
1311 PassFrame();
1312 SkipForwardBy(TimeDelta::Millis(301));
1313 }));
1314 EXPECT_CALL(callback_, OnFrame(_, false, _)).Times(3);
1315 AdvanceTime(TimeDelta::Millis(100));
1316 EXPECT_EQ(metrics::NumSamples("WebRTC.Screenshare.ZeroHz.QueueOverload"), 0);
1317}
1318
Markus Handellb4e96d42021-11-05 11:00:551319} // namespace
1320} // namespace webrtc