1 /*
2 * Copyright (c) 2022 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/inter_frame_delay.h"
12
13 #include <limits>
14
15 #include "absl/types/optional.h"
16 #include "api/units/frequency.h"
17 #include "api/units/time_delta.h"
18 #include "api/units/timestamp.h"
19 #include "system_wrappers/include/clock.h"
20 #include "test/gmock.h"
21 #include "test/gtest.h"
22
23 namespace webrtc {
24
25 namespace {
26
27 // Test is for frames at 30fps. At 30fps, RTP timestamps will increase by
28 // 90000 / 30 = 3000 ticks per frame.
29 constexpr Frequency k30Fps = Frequency::Hertz(30);
30 constexpr TimeDelta kFrameDelay = 1 / k30Fps;
31 constexpr uint32_t kRtpTicksPerFrame = Frequency::KiloHertz(90) / k30Fps;
32 constexpr Timestamp kStartTime = Timestamp::Millis(1337);
33
34 } // namespace
35
36 using ::testing::Eq;
37 using ::testing::Optional;
38
TEST(InterFrameDelayTest,OldRtpTimestamp)39 TEST(InterFrameDelayTest, OldRtpTimestamp) {
40 InterFrameDelay inter_frame_delay;
41 EXPECT_THAT(inter_frame_delay.CalculateDelay(180000, kStartTime),
42 Optional(TimeDelta::Zero()));
43 EXPECT_THAT(inter_frame_delay.CalculateDelay(90000, kStartTime),
44 Eq(absl::nullopt));
45 }
46
TEST(InterFrameDelayTest,NegativeWrapAroundIsSameAsOldRtpTimestamp)47 TEST(InterFrameDelayTest, NegativeWrapAroundIsSameAsOldRtpTimestamp) {
48 InterFrameDelay inter_frame_delay;
49 uint32_t rtp = 1500;
50 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, kStartTime),
51 Optional(TimeDelta::Zero()));
52 // RTP has wrapped around backwards.
53 rtp -= 3000;
54 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, kStartTime),
55 Eq(absl::nullopt));
56 }
57
TEST(InterFrameDelayTest,CorrectDelayForFrames)58 TEST(InterFrameDelayTest, CorrectDelayForFrames) {
59 InterFrameDelay inter_frame_delay;
60 // Use a fake clock to simplify time keeping.
61 SimulatedClock clock(kStartTime);
62
63 // First frame is always delay 0.
64 uint32_t rtp = 90000;
65 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
66 Optional(TimeDelta::Zero()));
67
68 // Perfectly timed frame has 0 delay.
69 clock.AdvanceTime(kFrameDelay);
70 rtp += kRtpTicksPerFrame;
71 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
72 Optional(TimeDelta::Zero()));
73
74 // Slightly early frame will have a negative delay.
75 clock.AdvanceTime(kFrameDelay - TimeDelta::Millis(3));
76 rtp += kRtpTicksPerFrame;
77 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
78 Optional(-TimeDelta::Millis(3)));
79
80 // Slightly late frame will have positive delay.
81 clock.AdvanceTime(kFrameDelay + TimeDelta::Micros(5125));
82 rtp += kRtpTicksPerFrame;
83 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
84 Optional(TimeDelta::Micros(5125)));
85
86 // Simulate faster frame RTP at the same clock delay. The frame arrives late,
87 // since the RTP timestamp is faster than the delay, and thus is positive.
88 clock.AdvanceTime(kFrameDelay);
89 rtp += kRtpTicksPerFrame / 2;
90 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
91 Optional(kFrameDelay / 2.0));
92
93 // Simulate slower frame RTP at the same clock delay. The frame is early,
94 // since the RTP timestamp advanced more than the delay, and thus is negative.
95 clock.AdvanceTime(kFrameDelay);
96 rtp += 1.5 * kRtpTicksPerFrame;
97 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
98 Optional(-kFrameDelay / 2.0));
99 }
100
TEST(InterFrameDelayTest,PositiveWrapAround)101 TEST(InterFrameDelayTest, PositiveWrapAround) {
102 InterFrameDelay inter_frame_delay;
103 // Use a fake clock to simplify time keeping.
104 SimulatedClock clock(kStartTime);
105
106 // First frame is behind the max RTP by 1500.
107 uint32_t rtp = std::numeric_limits<uint32_t>::max() - 1500;
108 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
109 Optional(TimeDelta::Zero()));
110
111 // Rtp wraps around, now 1499.
112 rtp += kRtpTicksPerFrame;
113
114 // Frame delay should be as normal, in this case simulated as 1ms late.
115 clock.AdvanceTime(kFrameDelay + TimeDelta::Millis(1));
116 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
117 Optional(TimeDelta::Millis(1)));
118 }
119
TEST(InterFrameDelayTest,MultipleWrapArounds)120 TEST(InterFrameDelayTest, MultipleWrapArounds) {
121 // Simulate a long pauses which cause wrap arounds multiple times.
122 constexpr Frequency k90Khz = Frequency::KiloHertz(90);
123 constexpr uint32_t kHalfRtp = std::numeric_limits<uint32_t>::max() / 2;
124 constexpr TimeDelta kWrapAroundDelay = kHalfRtp / k90Khz;
125
126 InterFrameDelay inter_frame_delay;
127 // Use a fake clock to simplify time keeping.
128 SimulatedClock clock(kStartTime);
129 uint32_t rtp = 0;
130 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
131 Optional(TimeDelta::Zero()));
132
133 rtp += kHalfRtp;
134 clock.AdvanceTime(kWrapAroundDelay);
135 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
136 Optional(TimeDelta::Zero()));
137 // 1st wrap around.
138 rtp += kHalfRtp + 1;
139 clock.AdvanceTime(kWrapAroundDelay + TimeDelta::Millis(1));
140 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
141 Optional(TimeDelta::Millis(1) - (1 / k90Khz)));
142
143 rtp += kHalfRtp;
144 clock.AdvanceTime(kWrapAroundDelay);
145 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
146 Optional(TimeDelta::Zero()));
147 // 2nd wrap arounds.
148 rtp += kHalfRtp + 1;
149 clock.AdvanceTime(kWrapAroundDelay - TimeDelta::Millis(1));
150 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
151 Optional(-TimeDelta::Millis(1) - (1 / k90Khz)));
152
153 // Ensure short delay (large RTP delay) between wrap-arounds has correct
154 // jitter.
155 rtp += kHalfRtp;
156 clock.AdvanceTime(TimeDelta::Millis(10));
157 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
158 Optional(-(kWrapAroundDelay - TimeDelta::Millis(10))));
159 // 3nd wrap arounds, this time with large RTP delay.
160 rtp += kHalfRtp + 1;
161 clock.AdvanceTime(TimeDelta::Millis(10));
162 EXPECT_THAT(
163 inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
164 Optional(-(kWrapAroundDelay - TimeDelta::Millis(10) + (1 / k90Khz))));
165 }
166
TEST(InterFrameDelayTest,NegativeWrapAroundAfterPositiveWrapAround)167 TEST(InterFrameDelayTest, NegativeWrapAroundAfterPositiveWrapAround) {
168 InterFrameDelay inter_frame_delay;
169 // Use a fake clock to simplify time keeping.
170 SimulatedClock clock(kStartTime);
171 uint32_t rtp = std::numeric_limits<uint32_t>::max() - 1500;
172 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
173 Optional(TimeDelta::Zero()));
174
175 // Rtp wraps around, now 1499.
176 rtp += kRtpTicksPerFrame;
177 // Frame delay should be as normal, in this case simulated as 1ms late.
178 clock.AdvanceTime(kFrameDelay);
179 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
180 Optional(TimeDelta::Zero()));
181
182 // Wrap back.
183 rtp -= kRtpTicksPerFrame;
184 // Frame delay should be as normal, in this case simulated as 1ms late.
185 clock.AdvanceTime(kFrameDelay);
186 EXPECT_THAT(inter_frame_delay.CalculateDelay(rtp, clock.CurrentTime()),
187 Eq(absl::nullopt));
188 }
189
190 } // namespace webrtc
191