xref: /aosp_15_r20/external/webrtc/modules/video_coding/timing/timing_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2011 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 "modules/video_coding/timing/timing.h"
12 
13 #include "api/units/frequency.h"
14 #include "api/units/time_delta.h"
15 #include "system_wrappers/include/clock.h"
16 #include "test/gtest.h"
17 #include "test/scoped_key_value_config.h"
18 
19 namespace webrtc {
20 namespace {
21 
22 constexpr Frequency k25Fps = Frequency::Hertz(25);
23 constexpr Frequency k90kHz = Frequency::KiloHertz(90);
24 
25 }  // namespace
26 
TEST(ReceiverTimingTest,JitterDelay)27 TEST(ReceiverTimingTest, JitterDelay) {
28   test::ScopedKeyValueConfig field_trials;
29   SimulatedClock clock(0);
30   VCMTiming timing(&clock, field_trials);
31   timing.Reset();
32 
33   uint32_t timestamp = 0;
34   timing.UpdateCurrentDelay(timestamp);
35 
36   timing.Reset();
37 
38   timing.IncomingTimestamp(timestamp, clock.CurrentTime());
39   TimeDelta jitter_delay = TimeDelta::Millis(20);
40   timing.SetJitterDelay(jitter_delay);
41   timing.UpdateCurrentDelay(timestamp);
42   timing.set_render_delay(TimeDelta::Zero());
43   auto wait_time = timing.MaxWaitingTime(
44       timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(),
45       /*too_many_frames_queued=*/false);
46   // First update initializes the render time. Since we have no decode delay
47   // we get wait_time = renderTime - now - renderDelay = jitter.
48   EXPECT_EQ(jitter_delay, wait_time);
49 
50   jitter_delay += TimeDelta::Millis(VCMTiming::kDelayMaxChangeMsPerS + 10);
51   timestamp += 90000;
52   clock.AdvanceTimeMilliseconds(1000);
53   timing.SetJitterDelay(jitter_delay);
54   timing.UpdateCurrentDelay(timestamp);
55   wait_time = timing.MaxWaitingTime(
56       timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(),
57       /*too_many_frames_queued=*/false);
58   // Since we gradually increase the delay we only get 100 ms every second.
59   EXPECT_EQ(jitter_delay - TimeDelta::Millis(10), wait_time);
60 
61   timestamp += 90000;
62   clock.AdvanceTimeMilliseconds(1000);
63   timing.UpdateCurrentDelay(timestamp);
64   wait_time = timing.MaxWaitingTime(
65       timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(),
66       /*too_many_frames_queued=*/false);
67   EXPECT_EQ(jitter_delay, wait_time);
68 
69   // Insert frames without jitter, verify that this gives the exact wait time.
70   const int kNumFrames = 300;
71   for (int i = 0; i < kNumFrames; i++) {
72     clock.AdvanceTime(1 / k25Fps);
73     timestamp += k90kHz / k25Fps;
74     timing.IncomingTimestamp(timestamp, clock.CurrentTime());
75   }
76   timing.UpdateCurrentDelay(timestamp);
77   wait_time = timing.MaxWaitingTime(
78       timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(),
79       /*too_many_frames_queued=*/false);
80   EXPECT_EQ(jitter_delay, wait_time);
81 
82   // Add decode time estimates for 1 second.
83   const TimeDelta kDecodeTime = TimeDelta::Millis(10);
84   for (int i = 0; i < k25Fps.hertz(); i++) {
85     clock.AdvanceTime(kDecodeTime);
86     timing.StopDecodeTimer(kDecodeTime, clock.CurrentTime());
87     timestamp += k90kHz / k25Fps;
88     clock.AdvanceTime(1 / k25Fps - kDecodeTime);
89     timing.IncomingTimestamp(timestamp, clock.CurrentTime());
90   }
91   timing.UpdateCurrentDelay(timestamp);
92   wait_time = timing.MaxWaitingTime(
93       timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(),
94       /*too_many_frames_queued=*/false);
95   EXPECT_EQ(jitter_delay, wait_time);
96 
97   const TimeDelta kMinTotalDelay = TimeDelta::Millis(200);
98   timing.set_min_playout_delay(kMinTotalDelay);
99   clock.AdvanceTimeMilliseconds(5000);
100   timestamp += 5 * 90000;
101   timing.UpdateCurrentDelay(timestamp);
102   const TimeDelta kRenderDelay = TimeDelta::Millis(10);
103   timing.set_render_delay(kRenderDelay);
104   wait_time = timing.MaxWaitingTime(
105       timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(),
106       /*too_many_frames_queued=*/false);
107   // We should at least have kMinTotalDelayMs - decodeTime (10) - renderTime
108   // (10) to wait.
109   EXPECT_EQ(kMinTotalDelay - kDecodeTime - kRenderDelay, wait_time);
110   // The total video delay should be equal to the min total delay.
111   EXPECT_EQ(kMinTotalDelay, timing.TargetVideoDelay());
112 
113   // Reset playout delay.
114   timing.set_min_playout_delay(TimeDelta::Zero());
115   clock.AdvanceTimeMilliseconds(5000);
116   timestamp += 5 * 90000;
117   timing.UpdateCurrentDelay(timestamp);
118 }
119 
TEST(ReceiverTimingTest,TimestampWrapAround)120 TEST(ReceiverTimingTest, TimestampWrapAround) {
121   constexpr auto kStartTime = Timestamp::Millis(1337);
122   test::ScopedKeyValueConfig field_trials;
123   SimulatedClock clock(kStartTime);
124   VCMTiming timing(&clock, field_trials);
125 
126   // Provoke a wrap-around. The fifth frame will have wrapped at 25 fps.
127   constexpr uint32_t kRtpTicksPerFrame = k90kHz / k25Fps;
128   uint32_t timestamp = 0xFFFFFFFFu - 3 * kRtpTicksPerFrame;
129   for (int i = 0; i < 5; ++i) {
130     timing.IncomingTimestamp(timestamp, clock.CurrentTime());
131     clock.AdvanceTime(1 / k25Fps);
132     timestamp += kRtpTicksPerFrame;
133     EXPECT_EQ(kStartTime + 3 / k25Fps,
134               timing.RenderTime(0xFFFFFFFFu, clock.CurrentTime()));
135     // One ms later in 90 kHz.
136     EXPECT_EQ(kStartTime + 3 / k25Fps + TimeDelta::Millis(1),
137               timing.RenderTime(89u, clock.CurrentTime()));
138   }
139 }
140 
TEST(ReceiverTimingTest,UseLowLatencyRenderer)141 TEST(ReceiverTimingTest, UseLowLatencyRenderer) {
142   test::ScopedKeyValueConfig field_trials;
143   SimulatedClock clock(0);
144   VCMTiming timing(&clock, field_trials);
145   timing.Reset();
146   // Default is false.
147   EXPECT_FALSE(timing.RenderParameters().use_low_latency_rendering);
148   // False if min playout delay > 0.
149   timing.set_min_playout_delay(TimeDelta::Millis(10));
150   timing.set_max_playout_delay(TimeDelta::Millis(20));
151   EXPECT_FALSE(timing.RenderParameters().use_low_latency_rendering);
152   // True if min==0, max > 0.
153   timing.set_min_playout_delay(TimeDelta::Zero());
154   EXPECT_TRUE(timing.RenderParameters().use_low_latency_rendering);
155   // True if min==max==0.
156   timing.set_max_playout_delay(TimeDelta::Zero());
157   EXPECT_TRUE(timing.RenderParameters().use_low_latency_rendering);
158   // True also for max playout delay==500 ms.
159   timing.set_max_playout_delay(TimeDelta::Millis(500));
160   EXPECT_TRUE(timing.RenderParameters().use_low_latency_rendering);
161   // False if max playout delay > 500 ms.
162   timing.set_max_playout_delay(TimeDelta::Millis(501));
163   EXPECT_FALSE(timing.RenderParameters().use_low_latency_rendering);
164 }
165 
TEST(ReceiverTimingTest,MaxWaitingTimeIsZeroForZeroRenderTime)166 TEST(ReceiverTimingTest, MaxWaitingTimeIsZeroForZeroRenderTime) {
167   // This is the default path when the RTP playout delay header extension is set
168   // to min==0 and max==0.
169   constexpr int64_t kStartTimeUs = 3.15e13;  // About one year in us.
170   constexpr TimeDelta kTimeDelta = 1 / Frequency::Hertz(60);
171   constexpr Timestamp kZeroRenderTime = Timestamp::Zero();
172   SimulatedClock clock(kStartTimeUs);
173   test::ScopedKeyValueConfig field_trials;
174   VCMTiming timing(&clock, field_trials);
175   timing.Reset();
176   timing.set_max_playout_delay(TimeDelta::Zero());
177   for (int i = 0; i < 10; ++i) {
178     clock.AdvanceTime(kTimeDelta);
179     Timestamp now = clock.CurrentTime();
180     EXPECT_LT(timing.MaxWaitingTime(kZeroRenderTime, now,
181                                     /*too_many_frames_queued=*/false),
182               TimeDelta::Zero());
183   }
184   // Another frame submitted at the same time also returns a negative max
185   // waiting time.
186   Timestamp now = clock.CurrentTime();
187   EXPECT_LT(timing.MaxWaitingTime(kZeroRenderTime, now,
188                                   /*too_many_frames_queued=*/false),
189             TimeDelta::Zero());
190   // MaxWaitingTime should be less than zero even if there's a burst of frames.
191   EXPECT_LT(timing.MaxWaitingTime(kZeroRenderTime, now,
192                                   /*too_many_frames_queued=*/false),
193             TimeDelta::Zero());
194   EXPECT_LT(timing.MaxWaitingTime(kZeroRenderTime, now,
195                                   /*too_many_frames_queued=*/false),
196             TimeDelta::Zero());
197   EXPECT_LT(timing.MaxWaitingTime(kZeroRenderTime, now,
198                                   /*too_many_frames_queued=*/false),
199             TimeDelta::Zero());
200 }
201 
TEST(ReceiverTimingTest,MaxWaitingTimeZeroDelayPacingExperiment)202 TEST(ReceiverTimingTest, MaxWaitingTimeZeroDelayPacingExperiment) {
203   // The minimum pacing is enabled by a field trial and active if the RTP
204   // playout delay header extension is set to min==0.
205   constexpr TimeDelta kMinPacing = TimeDelta::Millis(3);
206   test::ScopedKeyValueConfig field_trials(
207       "WebRTC-ZeroPlayoutDelay/min_pacing:3ms/");
208   constexpr int64_t kStartTimeUs = 3.15e13;  // About one year in us.
209   constexpr TimeDelta kTimeDelta = 1 / Frequency::Hertz(60);
210   constexpr auto kZeroRenderTime = Timestamp::Zero();
211   SimulatedClock clock(kStartTimeUs);
212   VCMTiming timing(&clock, field_trials);
213   timing.Reset();
214   // MaxWaitingTime() returns zero for evenly spaced video frames.
215   for (int i = 0; i < 10; ++i) {
216     clock.AdvanceTime(kTimeDelta);
217     Timestamp now = clock.CurrentTime();
218     EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now,
219                                     /*too_many_frames_queued=*/false),
220               TimeDelta::Zero());
221     timing.SetLastDecodeScheduledTimestamp(now);
222   }
223   // Another frame submitted at the same time is paced according to the field
224   // trial setting.
225   auto now = clock.CurrentTime();
226   EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now,
227                                   /*too_many_frames_queued=*/false),
228             kMinPacing);
229   // If there's a burst of frames, the wait time is calculated based on next
230   // decode time.
231   EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now,
232                                   /*too_many_frames_queued=*/false),
233             kMinPacing);
234   EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now,
235                                   /*too_many_frames_queued=*/false),
236             kMinPacing);
237   // Allow a few ms to pass, this should be subtracted from the MaxWaitingTime.
238   constexpr TimeDelta kTwoMs = TimeDelta::Millis(2);
239   clock.AdvanceTime(kTwoMs);
240   now = clock.CurrentTime();
241   EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now,
242                                   /*too_many_frames_queued=*/false),
243             kMinPacing - kTwoMs);
244   // A frame is decoded at the current time, the wait time should be restored to
245   // pacing delay.
246   timing.SetLastDecodeScheduledTimestamp(now);
247   EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now,
248                                   /*too_many_frames_queued=*/false),
249             kMinPacing);
250 }
251 
TEST(ReceiverTimingTest,DefaultMaxWaitingTimeUnaffectedByPacingExperiment)252 TEST(ReceiverTimingTest, DefaultMaxWaitingTimeUnaffectedByPacingExperiment) {
253   // The minimum pacing is enabled by a field trial but should not have any
254   // effect if render_time_ms is greater than 0;
255   test::ScopedKeyValueConfig field_trials(
256       "WebRTC-ZeroPlayoutDelay/min_pacing:3ms/");
257   constexpr int64_t kStartTimeUs = 3.15e13;  // About one year in us.
258   const TimeDelta kTimeDelta = TimeDelta::Millis(1000.0 / 60.0);
259   SimulatedClock clock(kStartTimeUs);
260   VCMTiming timing(&clock, field_trials);
261   timing.Reset();
262   clock.AdvanceTime(kTimeDelta);
263   auto now = clock.CurrentTime();
264   Timestamp render_time = now + TimeDelta::Millis(30);
265   // Estimate the internal processing delay from the first frame.
266   TimeDelta estimated_processing_delay =
267       (render_time - now) -
268       timing.MaxWaitingTime(render_time, now,
269                             /*too_many_frames_queued=*/false);
270   EXPECT_GT(estimated_processing_delay, TimeDelta::Zero());
271 
272   // Any other frame submitted at the same time should be scheduled according to
273   // its render time.
274   for (int i = 0; i < 5; ++i) {
275     render_time += kTimeDelta;
276     EXPECT_EQ(timing.MaxWaitingTime(render_time, now,
277                                     /*too_many_frames_queued=*/false),
278               render_time - now - estimated_processing_delay);
279   }
280 }
281 
TEST(ReceiverTimingTest,MaxWaitingTimeReturnsZeroIfTooManyFramesQueuedIsTrue)282 TEST(ReceiverTimingTest, MaxWaitingTimeReturnsZeroIfTooManyFramesQueuedIsTrue) {
283   // The minimum pacing is enabled by a field trial and active if the RTP
284   // playout delay header extension is set to min==0.
285   constexpr TimeDelta kMinPacing = TimeDelta::Millis(3);
286   test::ScopedKeyValueConfig field_trials(
287       "WebRTC-ZeroPlayoutDelay/min_pacing:3ms/");
288   constexpr int64_t kStartTimeUs = 3.15e13;  // About one year in us.
289   const TimeDelta kTimeDelta = TimeDelta::Millis(1000.0 / 60.0);
290   constexpr auto kZeroRenderTime = Timestamp::Zero();
291   SimulatedClock clock(kStartTimeUs);
292   VCMTiming timing(&clock, field_trials);
293   timing.Reset();
294   // MaxWaitingTime() returns zero for evenly spaced video frames.
295   for (int i = 0; i < 10; ++i) {
296     clock.AdvanceTime(kTimeDelta);
297     auto now = clock.CurrentTime();
298     EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now,
299                                     /*too_many_frames_queued=*/false),
300               TimeDelta::Zero());
301     timing.SetLastDecodeScheduledTimestamp(now);
302   }
303   // Another frame submitted at the same time is paced according to the field
304   // trial setting.
305   auto now_ms = clock.CurrentTime();
306   EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now_ms,
307                                   /*too_many_frames_queued=*/false),
308             kMinPacing);
309   // MaxWaitingTime returns 0 even if there's a burst of frames if
310   // too_many_frames_queued is set to true.
311   EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now_ms,
312                                   /*too_many_frames_queued=*/true),
313             TimeDelta::Zero());
314   EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now_ms,
315                                   /*too_many_frames_queued=*/true),
316             TimeDelta::Zero());
317 }
318 
TEST(ReceiverTimingTest,UpdateCurrentDelayCapsWhenOffByMicroseconds)319 TEST(ReceiverTimingTest, UpdateCurrentDelayCapsWhenOffByMicroseconds) {
320   test::ScopedKeyValueConfig field_trials;
321   SimulatedClock clock(0);
322   VCMTiming timing(&clock, field_trials);
323   timing.Reset();
324 
325   // Set larger initial current delay.
326   timing.set_min_playout_delay(TimeDelta::Millis(200));
327   timing.UpdateCurrentDelay(Timestamp::Millis(900), Timestamp::Millis(1000));
328 
329   // Add a few microseconds to ensure that the delta of decode time is 0 after
330   // rounding, and should reset to the target delay.
331   timing.set_min_playout_delay(TimeDelta::Millis(50));
332   Timestamp decode_time = Timestamp::Millis(1337);
333   Timestamp render_time =
334       decode_time + TimeDelta::Millis(10) + TimeDelta::Micros(37);
335   timing.UpdateCurrentDelay(render_time, decode_time);
336   EXPECT_EQ(timing.GetTimings().current_delay, timing.TargetVideoDelay());
337 }
338 
339 }  // namespace webrtc
340