blob: 81d63029a99e1d0d2bed80153f4fb19069525750 [file] [log] [blame]
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +01001/*
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 "video/decode_synchronizer.h"
12
13#include <stddef.h>
14
15#include <memory>
16#include <utility>
17
18#include "api/metronome/test/fake_metronome.h"
19#include "api/units/time_delta.h"
20#include "test/gmock.h"
21#include "test/gtest.h"
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +010022#include "test/time_controller/simulated_time_controller.h"
23#include "video/frame_decode_scheduler.h"
24#include "video/frame_decode_timing.h"
25
26using ::testing::_;
27using ::testing::Eq;
28
29namespace webrtc {
30
31class DecodeSynchronizerTest : public ::testing::Test {
32 public:
33 static constexpr TimeDelta kTickPeriod = TimeDelta::Millis(33);
34
35 DecodeSynchronizerTest()
36 : time_controller_(Timestamp::Millis(1337)),
37 clock_(time_controller_.GetClock()),
38 metronome_(kTickPeriod),
Evan Shrubsole7cbd8de2022-08-16 08:08:53 +000039 decode_synchronizer_(clock_,
40 &metronome_,
41 time_controller_.GetMainThread()) {}
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +010042
43 protected:
44 GlobalSimulatedTimeController time_controller_;
45 Clock* clock_;
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +010046 test::ForcedTickMetronome metronome_;
47 DecodeSynchronizer decode_synchronizer_;
48};
49
50TEST_F(DecodeSynchronizerTest, AllFramesReadyBeforeNextTickDecoded) {
51 ::testing::MockFunction<void(uint32_t, Timestamp)> mock_callback1;
52 auto scheduler1 = decode_synchronizer_.CreateSynchronizedFrameScheduler();
53
54 testing::MockFunction<void(unsigned int, Timestamp)> mock_callback2;
55 auto scheduler2 = decode_synchronizer_.CreateSynchronizedFrameScheduler();
56
57 {
58 uint32_t frame_rtp = 90000;
59 FrameDecodeTiming::FrameSchedule frame_sched{
60 .latest_decode_time =
61 clock_->CurrentTime() + kTickPeriod - TimeDelta::Millis(3),
62 .render_time = clock_->CurrentTime() + TimeDelta::Millis(60)};
63 scheduler1->ScheduleFrame(frame_rtp, frame_sched,
64 mock_callback1.AsStdFunction());
65 EXPECT_CALL(mock_callback1,
66 Call(Eq(frame_rtp), Eq(frame_sched.render_time)));
67 }
68 {
69 uint32_t frame_rtp = 123456;
70 FrameDecodeTiming::FrameSchedule frame_sched{
71 .latest_decode_time =
72 clock_->CurrentTime() + kTickPeriod - TimeDelta::Millis(2),
73 .render_time = clock_->CurrentTime() + TimeDelta::Millis(70)};
74 scheduler2->ScheduleFrame(frame_rtp, frame_sched,
75 mock_callback2.AsStdFunction());
76 EXPECT_CALL(mock_callback2,
77 Call(Eq(frame_rtp), Eq(frame_sched.render_time)));
78 }
79 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53 +000080 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +010081
82 // Cleanup
83 scheduler1->Stop();
84 scheduler2->Stop();
85}
86
87TEST_F(DecodeSynchronizerTest, FramesNotDecodedIfDecodeTimeIsInNextInterval) {
88 ::testing::MockFunction<void(unsigned int, Timestamp)> mock_callback;
89 auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
90
91 uint32_t frame_rtp = 90000;
92 FrameDecodeTiming::FrameSchedule frame_sched{
93 .latest_decode_time =
94 clock_->CurrentTime() + kTickPeriod + TimeDelta::Millis(10),
95 .render_time =
96 clock_->CurrentTime() + kTickPeriod + TimeDelta::Millis(30)};
97 scheduler->ScheduleFrame(frame_rtp, frame_sched,
98 mock_callback.AsStdFunction());
99
100 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53 +0000101 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +0100102 // No decodes should have happened in this tick.
103 ::testing::Mock::VerifyAndClearExpectations(&mock_callback);
104
105 // Decode should happen on next tick.
106 EXPECT_CALL(mock_callback, Call(Eq(frame_rtp), Eq(frame_sched.render_time)));
107 time_controller_.AdvanceTime(kTickPeriod);
108 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53 +0000109 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +0100110
111 // Cleanup
112 scheduler->Stop();
113}
114
115TEST_F(DecodeSynchronizerTest, FrameDecodedOnce) {
116 ::testing::MockFunction<void(unsigned int, Timestamp)> mock_callback;
117 auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
118
119 uint32_t frame_rtp = 90000;
120 FrameDecodeTiming::FrameSchedule frame_sched{
121 .latest_decode_time = clock_->CurrentTime() + TimeDelta::Millis(30),
122 .render_time = clock_->CurrentTime() + TimeDelta::Millis(60)};
123 scheduler->ScheduleFrame(frame_rtp, frame_sched,
124 mock_callback.AsStdFunction());
125 EXPECT_CALL(mock_callback, Call(_, _)).Times(1);
126 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53 +0000127 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +0100128 ::testing::Mock::VerifyAndClearExpectations(&mock_callback);
129
130 // Trigger tick again. No frame should be decoded now.
131 time_controller_.AdvanceTime(kTickPeriod);
132 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53 +0000133 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +0100134
135 // Cleanup
136 scheduler->Stop();
137}
138
139TEST_F(DecodeSynchronizerTest, FrameWithDecodeTimeInPastDecodedImmediately) {
140 ::testing::MockFunction<void(unsigned int, Timestamp)> mock_callback;
141 auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
142
143 uint32_t frame_rtp = 90000;
144 FrameDecodeTiming::FrameSchedule frame_sched{
145 .latest_decode_time = clock_->CurrentTime() - TimeDelta::Millis(5),
146 .render_time = clock_->CurrentTime() + TimeDelta::Millis(30)};
147 EXPECT_CALL(mock_callback, Call(Eq(90000u), _)).Times(1);
148 scheduler->ScheduleFrame(frame_rtp, frame_sched,
149 mock_callback.AsStdFunction());
150 // Verify the callback was invoked already.
151 ::testing::Mock::VerifyAndClearExpectations(&mock_callback);
152
153 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53 +0000154 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +0100155
156 // Cleanup
157 scheduler->Stop();
158}
159
160TEST_F(DecodeSynchronizerTest,
161 FrameWithDecodeTimeFarBeforeNextTickDecodedImmediately) {
162 ::testing::MockFunction<void(unsigned int, Timestamp)> mock_callback;
163 auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
164
165 // Frame which would be behind by more than kMaxAllowedFrameDelay after
166 // the next tick.
167 FrameDecodeTiming::FrameSchedule frame_sched{
168 .latest_decode_time = clock_->CurrentTime() + kTickPeriod -
169 FrameDecodeTiming::kMaxAllowedFrameDelay -
170 TimeDelta::Millis(1),
171 .render_time = clock_->CurrentTime() + TimeDelta::Millis(30)};
172 EXPECT_CALL(mock_callback, Call(Eq(90000u), _)).Times(1);
173 scheduler->ScheduleFrame(90000, frame_sched, mock_callback.AsStdFunction());
174 // Verify the callback was invoked already.
175 ::testing::Mock::VerifyAndClearExpectations(&mock_callback);
176
177 time_controller_.AdvanceTime(kTickPeriod);
178 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53 +0000179 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +0100180
181 // A frame that would be behind by exactly kMaxAllowedFrameDelay after next
182 // tick should decode at the next tick.
183 FrameDecodeTiming::FrameSchedule queued_frame{
184 .latest_decode_time = clock_->CurrentTime() + kTickPeriod -
185 FrameDecodeTiming::kMaxAllowedFrameDelay,
186 .render_time = clock_->CurrentTime() + TimeDelta::Millis(30)};
187 scheduler->ScheduleFrame(180000, queued_frame, mock_callback.AsStdFunction());
188 // Verify the callback was invoked already.
189 ::testing::Mock::VerifyAndClearExpectations(&mock_callback);
190
191 EXPECT_CALL(mock_callback, Call(Eq(180000u), _)).Times(1);
192 time_controller_.AdvanceTime(kTickPeriod);
193 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53 +0000194 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +0100195
196 // Cleanup
197 scheduler->Stop();
198}
199
200TEST_F(DecodeSynchronizerTest, FramesNotReleasedAfterStop) {
201 ::testing::MockFunction<void(unsigned int, Timestamp)> mock_callback;
202 auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
203
204 uint32_t frame_rtp = 90000;
205 FrameDecodeTiming::FrameSchedule frame_sched{
206 .latest_decode_time = clock_->CurrentTime() + TimeDelta::Millis(30),
207 .render_time = clock_->CurrentTime() + TimeDelta::Millis(60)};
208 scheduler->ScheduleFrame(frame_rtp, frame_sched,
209 mock_callback.AsStdFunction());
210 // Cleanup
211 scheduler->Stop();
212
213 // No callback should occur on this tick since Stop() was called before.
214 metronome_.Tick();
Evan Shrubsole7cbd8de2022-08-16 08:08:53 +0000215 time_controller_.AdvanceTime(TimeDelta::Zero());
Evan Shrubsole6cd6d8e2022-02-11 15:30:26 +0100216}
217
218TEST_F(DecodeSynchronizerTest, MetronomeNotListenedWhenNoStreamsAreActive) {
219 EXPECT_EQ(0u, metronome_.NumListeners());
220
221 auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
222 EXPECT_EQ(1u, metronome_.NumListeners());
223 auto scheduler2 = decode_synchronizer_.CreateSynchronizedFrameScheduler();
224 EXPECT_EQ(1u, metronome_.NumListeners());
225
226 scheduler->Stop();
227 EXPECT_EQ(1u, metronome_.NumListeners());
228 scheduler2->Stop();
229 EXPECT_EQ(0u, metronome_.NumListeners());
230}
231
232} // namespace webrtc