1*d9f75844SAndroid Build Coastguard Worker /* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
2*d9f75844SAndroid Build Coastguard Worker *
3*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
4*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
5*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
6*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
7*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
8*d9f75844SAndroid Build Coastguard Worker */
9*d9f75844SAndroid Build Coastguard Worker
10*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/receiver.h"
11*d9f75844SAndroid Build Coastguard Worker
12*d9f75844SAndroid Build Coastguard Worker #include <string.h>
13*d9f75844SAndroid Build Coastguard Worker
14*d9f75844SAndroid Build Coastguard Worker #include <cstdint>
15*d9f75844SAndroid Build Coastguard Worker #include <memory>
16*d9f75844SAndroid Build Coastguard Worker #include <queue>
17*d9f75844SAndroid Build Coastguard Worker #include <vector>
18*d9f75844SAndroid Build Coastguard Worker
19*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/encoded_frame.h"
20*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/jitter_buffer_common.h"
21*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/packet.h"
22*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/test/stream_generator.h"
23*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/timing/timing.h"
24*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
25*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/clock.h"
26*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
27*d9f75844SAndroid Build Coastguard Worker #include "test/scoped_key_value_config.h"
28*d9f75844SAndroid Build Coastguard Worker
29*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
30*d9f75844SAndroid Build Coastguard Worker
31*d9f75844SAndroid Build Coastguard Worker class TestVCMReceiver : public ::testing::Test {
32*d9f75844SAndroid Build Coastguard Worker protected:
TestVCMReceiver()33*d9f75844SAndroid Build Coastguard Worker TestVCMReceiver()
34*d9f75844SAndroid Build Coastguard Worker : clock_(0),
35*d9f75844SAndroid Build Coastguard Worker timing_(&clock_, field_trials_),
36*d9f75844SAndroid Build Coastguard Worker receiver_(&timing_, &clock_, field_trials_),
37*d9f75844SAndroid Build Coastguard Worker stream_generator_(0, clock_.TimeInMilliseconds()) {}
38*d9f75844SAndroid Build Coastguard Worker
InsertPacket(int index)39*d9f75844SAndroid Build Coastguard Worker int32_t InsertPacket(int index) {
40*d9f75844SAndroid Build Coastguard Worker VCMPacket packet;
41*d9f75844SAndroid Build Coastguard Worker bool packet_available = stream_generator_.GetPacket(&packet, index);
42*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(packet_available);
43*d9f75844SAndroid Build Coastguard Worker if (!packet_available)
44*d9f75844SAndroid Build Coastguard Worker return kGeneralError; // Return here to avoid crashes below.
45*d9f75844SAndroid Build Coastguard Worker return receiver_.InsertPacket(packet);
46*d9f75844SAndroid Build Coastguard Worker }
47*d9f75844SAndroid Build Coastguard Worker
InsertPacketAndPop(int index)48*d9f75844SAndroid Build Coastguard Worker int32_t InsertPacketAndPop(int index) {
49*d9f75844SAndroid Build Coastguard Worker VCMPacket packet;
50*d9f75844SAndroid Build Coastguard Worker bool packet_available = stream_generator_.PopPacket(&packet, index);
51*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(packet_available);
52*d9f75844SAndroid Build Coastguard Worker if (!packet_available)
53*d9f75844SAndroid Build Coastguard Worker return kGeneralError; // Return here to avoid crashes below.
54*d9f75844SAndroid Build Coastguard Worker return receiver_.InsertPacket(packet);
55*d9f75844SAndroid Build Coastguard Worker }
56*d9f75844SAndroid Build Coastguard Worker
InsertFrame(VideoFrameType frame_type,bool complete)57*d9f75844SAndroid Build Coastguard Worker int32_t InsertFrame(VideoFrameType frame_type, bool complete) {
58*d9f75844SAndroid Build Coastguard Worker int num_of_packets = complete ? 1 : 2;
59*d9f75844SAndroid Build Coastguard Worker stream_generator_.GenerateFrame(
60*d9f75844SAndroid Build Coastguard Worker frame_type,
61*d9f75844SAndroid Build Coastguard Worker (frame_type != VideoFrameType::kEmptyFrame) ? num_of_packets : 0,
62*d9f75844SAndroid Build Coastguard Worker (frame_type == VideoFrameType::kEmptyFrame) ? 1 : 0,
63*d9f75844SAndroid Build Coastguard Worker clock_.TimeInMilliseconds());
64*d9f75844SAndroid Build Coastguard Worker int32_t ret = InsertPacketAndPop(0);
65*d9f75844SAndroid Build Coastguard Worker if (!complete) {
66*d9f75844SAndroid Build Coastguard Worker // Drop the second packet.
67*d9f75844SAndroid Build Coastguard Worker VCMPacket packet;
68*d9f75844SAndroid Build Coastguard Worker stream_generator_.PopPacket(&packet, 0);
69*d9f75844SAndroid Build Coastguard Worker }
70*d9f75844SAndroid Build Coastguard Worker clock_.AdvanceTimeMilliseconds(kDefaultFramePeriodMs);
71*d9f75844SAndroid Build Coastguard Worker return ret;
72*d9f75844SAndroid Build Coastguard Worker }
73*d9f75844SAndroid Build Coastguard Worker
DecodeNextFrame()74*d9f75844SAndroid Build Coastguard Worker bool DecodeNextFrame() {
75*d9f75844SAndroid Build Coastguard Worker VCMEncodedFrame* frame = receiver_.FrameForDecoding(0, false);
76*d9f75844SAndroid Build Coastguard Worker if (!frame)
77*d9f75844SAndroid Build Coastguard Worker return false;
78*d9f75844SAndroid Build Coastguard Worker receiver_.ReleaseFrame(frame);
79*d9f75844SAndroid Build Coastguard Worker return true;
80*d9f75844SAndroid Build Coastguard Worker }
81*d9f75844SAndroid Build Coastguard Worker
82*d9f75844SAndroid Build Coastguard Worker test::ScopedKeyValueConfig field_trials_;
83*d9f75844SAndroid Build Coastguard Worker SimulatedClock clock_;
84*d9f75844SAndroid Build Coastguard Worker VCMTiming timing_;
85*d9f75844SAndroid Build Coastguard Worker VCMReceiver receiver_;
86*d9f75844SAndroid Build Coastguard Worker StreamGenerator stream_generator_;
87*d9f75844SAndroid Build Coastguard Worker };
88*d9f75844SAndroid Build Coastguard Worker
TEST_F(TestVCMReceiver,NonDecodableDuration_Empty)89*d9f75844SAndroid Build Coastguard Worker TEST_F(TestVCMReceiver, NonDecodableDuration_Empty) {
90*d9f75844SAndroid Build Coastguard Worker const size_t kMaxNackListSize = 1000;
91*d9f75844SAndroid Build Coastguard Worker const int kMaxPacketAgeToNack = 1000;
92*d9f75844SAndroid Build Coastguard Worker const int kMaxNonDecodableDuration = 500;
93*d9f75844SAndroid Build Coastguard Worker const int kMinDelayMs = 500;
94*d9f75844SAndroid Build Coastguard Worker receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack,
95*d9f75844SAndroid Build Coastguard Worker kMaxNonDecodableDuration);
96*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameKey, true), kNoError);
97*d9f75844SAndroid Build Coastguard Worker // Advance time until it's time to decode the key frame.
98*d9f75844SAndroid Build Coastguard Worker clock_.AdvanceTimeMilliseconds(kMinDelayMs);
99*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(DecodeNextFrame());
100*d9f75844SAndroid Build Coastguard Worker bool request_key_frame = false;
101*d9f75844SAndroid Build Coastguard Worker std::vector<uint16_t> nack_list = receiver_.NackList(&request_key_frame);
102*d9f75844SAndroid Build Coastguard Worker EXPECT_FALSE(request_key_frame);
103*d9f75844SAndroid Build Coastguard Worker }
104*d9f75844SAndroid Build Coastguard Worker
TEST_F(TestVCMReceiver,NonDecodableDuration_NoKeyFrame)105*d9f75844SAndroid Build Coastguard Worker TEST_F(TestVCMReceiver, NonDecodableDuration_NoKeyFrame) {
106*d9f75844SAndroid Build Coastguard Worker const size_t kMaxNackListSize = 1000;
107*d9f75844SAndroid Build Coastguard Worker const int kMaxPacketAgeToNack = 1000;
108*d9f75844SAndroid Build Coastguard Worker const int kMaxNonDecodableDuration = 500;
109*d9f75844SAndroid Build Coastguard Worker receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack,
110*d9f75844SAndroid Build Coastguard Worker kMaxNonDecodableDuration);
111*d9f75844SAndroid Build Coastguard Worker const int kNumFrames = kDefaultFrameRate * kMaxNonDecodableDuration / 1000;
112*d9f75844SAndroid Build Coastguard Worker for (int i = 0; i < kNumFrames; ++i) {
113*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameDelta, true), kNoError);
114*d9f75844SAndroid Build Coastguard Worker }
115*d9f75844SAndroid Build Coastguard Worker bool request_key_frame = false;
116*d9f75844SAndroid Build Coastguard Worker std::vector<uint16_t> nack_list = receiver_.NackList(&request_key_frame);
117*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(request_key_frame);
118*d9f75844SAndroid Build Coastguard Worker }
119*d9f75844SAndroid Build Coastguard Worker
TEST_F(TestVCMReceiver,NonDecodableDuration_OneIncomplete)120*d9f75844SAndroid Build Coastguard Worker TEST_F(TestVCMReceiver, NonDecodableDuration_OneIncomplete) {
121*d9f75844SAndroid Build Coastguard Worker const size_t kMaxNackListSize = 1000;
122*d9f75844SAndroid Build Coastguard Worker const int kMaxPacketAgeToNack = 1000;
123*d9f75844SAndroid Build Coastguard Worker const int kMaxNonDecodableDuration = 500;
124*d9f75844SAndroid Build Coastguard Worker const int kMaxNonDecodableDurationFrames =
125*d9f75844SAndroid Build Coastguard Worker (kDefaultFrameRate * kMaxNonDecodableDuration + 500) / 1000;
126*d9f75844SAndroid Build Coastguard Worker const int kMinDelayMs = 500;
127*d9f75844SAndroid Build Coastguard Worker receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack,
128*d9f75844SAndroid Build Coastguard Worker kMaxNonDecodableDuration);
129*d9f75844SAndroid Build Coastguard Worker timing_.set_min_playout_delay(TimeDelta::Millis(kMinDelayMs));
130*d9f75844SAndroid Build Coastguard Worker int64_t key_frame_inserted = clock_.TimeInMilliseconds();
131*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameKey, true), kNoError);
132*d9f75844SAndroid Build Coastguard Worker // Insert an incomplete frame.
133*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameDelta, false), kNoError);
134*d9f75844SAndroid Build Coastguard Worker // Insert enough frames to have too long non-decodable sequence.
135*d9f75844SAndroid Build Coastguard Worker for (int i = 0; i < kMaxNonDecodableDurationFrames; ++i) {
136*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameDelta, true), kNoError);
137*d9f75844SAndroid Build Coastguard Worker }
138*d9f75844SAndroid Build Coastguard Worker // Advance time until it's time to decode the key frame.
139*d9f75844SAndroid Build Coastguard Worker clock_.AdvanceTimeMilliseconds(kMinDelayMs - clock_.TimeInMilliseconds() -
140*d9f75844SAndroid Build Coastguard Worker key_frame_inserted);
141*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(DecodeNextFrame());
142*d9f75844SAndroid Build Coastguard Worker // Make sure we get a key frame request.
143*d9f75844SAndroid Build Coastguard Worker bool request_key_frame = false;
144*d9f75844SAndroid Build Coastguard Worker std::vector<uint16_t> nack_list = receiver_.NackList(&request_key_frame);
145*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(request_key_frame);
146*d9f75844SAndroid Build Coastguard Worker }
147*d9f75844SAndroid Build Coastguard Worker
TEST_F(TestVCMReceiver,NonDecodableDuration_NoTrigger)148*d9f75844SAndroid Build Coastguard Worker TEST_F(TestVCMReceiver, NonDecodableDuration_NoTrigger) {
149*d9f75844SAndroid Build Coastguard Worker const size_t kMaxNackListSize = 1000;
150*d9f75844SAndroid Build Coastguard Worker const int kMaxPacketAgeToNack = 1000;
151*d9f75844SAndroid Build Coastguard Worker const int kMaxNonDecodableDuration = 500;
152*d9f75844SAndroid Build Coastguard Worker const int kMaxNonDecodableDurationFrames =
153*d9f75844SAndroid Build Coastguard Worker (kDefaultFrameRate * kMaxNonDecodableDuration + 500) / 1000;
154*d9f75844SAndroid Build Coastguard Worker const int kMinDelayMs = 500;
155*d9f75844SAndroid Build Coastguard Worker receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack,
156*d9f75844SAndroid Build Coastguard Worker kMaxNonDecodableDuration);
157*d9f75844SAndroid Build Coastguard Worker timing_.set_min_playout_delay(TimeDelta::Millis(kMinDelayMs));
158*d9f75844SAndroid Build Coastguard Worker int64_t key_frame_inserted = clock_.TimeInMilliseconds();
159*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameKey, true), kNoError);
160*d9f75844SAndroid Build Coastguard Worker // Insert an incomplete frame.
161*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameDelta, false), kNoError);
162*d9f75844SAndroid Build Coastguard Worker // Insert all but one frame to not trigger a key frame request due to
163*d9f75844SAndroid Build Coastguard Worker // too long duration of non-decodable frames.
164*d9f75844SAndroid Build Coastguard Worker for (int i = 0; i < kMaxNonDecodableDurationFrames - 1; ++i) {
165*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameDelta, true), kNoError);
166*d9f75844SAndroid Build Coastguard Worker }
167*d9f75844SAndroid Build Coastguard Worker // Advance time until it's time to decode the key frame.
168*d9f75844SAndroid Build Coastguard Worker clock_.AdvanceTimeMilliseconds(kMinDelayMs - clock_.TimeInMilliseconds() -
169*d9f75844SAndroid Build Coastguard Worker key_frame_inserted);
170*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(DecodeNextFrame());
171*d9f75844SAndroid Build Coastguard Worker // Make sure we don't get a key frame request since we haven't generated
172*d9f75844SAndroid Build Coastguard Worker // enough frames.
173*d9f75844SAndroid Build Coastguard Worker bool request_key_frame = false;
174*d9f75844SAndroid Build Coastguard Worker std::vector<uint16_t> nack_list = receiver_.NackList(&request_key_frame);
175*d9f75844SAndroid Build Coastguard Worker EXPECT_FALSE(request_key_frame);
176*d9f75844SAndroid Build Coastguard Worker }
177*d9f75844SAndroid Build Coastguard Worker
TEST_F(TestVCMReceiver,NonDecodableDuration_NoTrigger2)178*d9f75844SAndroid Build Coastguard Worker TEST_F(TestVCMReceiver, NonDecodableDuration_NoTrigger2) {
179*d9f75844SAndroid Build Coastguard Worker const size_t kMaxNackListSize = 1000;
180*d9f75844SAndroid Build Coastguard Worker const int kMaxPacketAgeToNack = 1000;
181*d9f75844SAndroid Build Coastguard Worker const int kMaxNonDecodableDuration = 500;
182*d9f75844SAndroid Build Coastguard Worker const int kMaxNonDecodableDurationFrames =
183*d9f75844SAndroid Build Coastguard Worker (kDefaultFrameRate * kMaxNonDecodableDuration + 500) / 1000;
184*d9f75844SAndroid Build Coastguard Worker const int kMinDelayMs = 500;
185*d9f75844SAndroid Build Coastguard Worker receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack,
186*d9f75844SAndroid Build Coastguard Worker kMaxNonDecodableDuration);
187*d9f75844SAndroid Build Coastguard Worker timing_.set_min_playout_delay(TimeDelta::Millis(kMinDelayMs));
188*d9f75844SAndroid Build Coastguard Worker int64_t key_frame_inserted = clock_.TimeInMilliseconds();
189*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameKey, true), kNoError);
190*d9f75844SAndroid Build Coastguard Worker // Insert enough frames to have too long non-decodable sequence, except that
191*d9f75844SAndroid Build Coastguard Worker // we don't have any losses.
192*d9f75844SAndroid Build Coastguard Worker for (int i = 0; i < kMaxNonDecodableDurationFrames; ++i) {
193*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameDelta, true), kNoError);
194*d9f75844SAndroid Build Coastguard Worker }
195*d9f75844SAndroid Build Coastguard Worker // Insert an incomplete frame.
196*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameDelta, false), kNoError);
197*d9f75844SAndroid Build Coastguard Worker // Advance time until it's time to decode the key frame.
198*d9f75844SAndroid Build Coastguard Worker clock_.AdvanceTimeMilliseconds(kMinDelayMs - clock_.TimeInMilliseconds() -
199*d9f75844SAndroid Build Coastguard Worker key_frame_inserted);
200*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(DecodeNextFrame());
201*d9f75844SAndroid Build Coastguard Worker // Make sure we don't get a key frame request since the non-decodable duration
202*d9f75844SAndroid Build Coastguard Worker // is only one frame.
203*d9f75844SAndroid Build Coastguard Worker bool request_key_frame = false;
204*d9f75844SAndroid Build Coastguard Worker std::vector<uint16_t> nack_list = receiver_.NackList(&request_key_frame);
205*d9f75844SAndroid Build Coastguard Worker EXPECT_FALSE(request_key_frame);
206*d9f75844SAndroid Build Coastguard Worker }
207*d9f75844SAndroid Build Coastguard Worker
TEST_F(TestVCMReceiver,NonDecodableDuration_KeyFrameAfterIncompleteFrames)208*d9f75844SAndroid Build Coastguard Worker TEST_F(TestVCMReceiver, NonDecodableDuration_KeyFrameAfterIncompleteFrames) {
209*d9f75844SAndroid Build Coastguard Worker const size_t kMaxNackListSize = 1000;
210*d9f75844SAndroid Build Coastguard Worker const int kMaxPacketAgeToNack = 1000;
211*d9f75844SAndroid Build Coastguard Worker const int kMaxNonDecodableDuration = 500;
212*d9f75844SAndroid Build Coastguard Worker const int kMaxNonDecodableDurationFrames =
213*d9f75844SAndroid Build Coastguard Worker (kDefaultFrameRate * kMaxNonDecodableDuration + 500) / 1000;
214*d9f75844SAndroid Build Coastguard Worker const int kMinDelayMs = 500;
215*d9f75844SAndroid Build Coastguard Worker receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack,
216*d9f75844SAndroid Build Coastguard Worker kMaxNonDecodableDuration);
217*d9f75844SAndroid Build Coastguard Worker timing_.set_min_playout_delay(TimeDelta::Millis(kMinDelayMs));
218*d9f75844SAndroid Build Coastguard Worker int64_t key_frame_inserted = clock_.TimeInMilliseconds();
219*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameKey, true), kNoError);
220*d9f75844SAndroid Build Coastguard Worker // Insert an incomplete frame.
221*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameDelta, false), kNoError);
222*d9f75844SAndroid Build Coastguard Worker // Insert enough frames to have too long non-decodable sequence.
223*d9f75844SAndroid Build Coastguard Worker for (int i = 0; i < kMaxNonDecodableDurationFrames; ++i) {
224*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameDelta, true), kNoError);
225*d9f75844SAndroid Build Coastguard Worker }
226*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(InsertFrame(VideoFrameType::kVideoFrameKey, true), kNoError);
227*d9f75844SAndroid Build Coastguard Worker // Advance time until it's time to decode the key frame.
228*d9f75844SAndroid Build Coastguard Worker clock_.AdvanceTimeMilliseconds(kMinDelayMs - clock_.TimeInMilliseconds() -
229*d9f75844SAndroid Build Coastguard Worker key_frame_inserted);
230*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(DecodeNextFrame());
231*d9f75844SAndroid Build Coastguard Worker // Make sure we don't get a key frame request since we have a key frame
232*d9f75844SAndroid Build Coastguard Worker // in the list.
233*d9f75844SAndroid Build Coastguard Worker bool request_key_frame = false;
234*d9f75844SAndroid Build Coastguard Worker std::vector<uint16_t> nack_list = receiver_.NackList(&request_key_frame);
235*d9f75844SAndroid Build Coastguard Worker EXPECT_FALSE(request_key_frame);
236*d9f75844SAndroid Build Coastguard Worker }
237*d9f75844SAndroid Build Coastguard Worker
238*d9f75844SAndroid Build Coastguard Worker // A simulated clock, when time elapses, will insert frames into the jitter
239*d9f75844SAndroid Build Coastguard Worker // buffer, based on initial settings.
240*d9f75844SAndroid Build Coastguard Worker class SimulatedClockWithFrames : public SimulatedClock {
241*d9f75844SAndroid Build Coastguard Worker public:
SimulatedClockWithFrames(StreamGenerator * stream_generator,VCMReceiver * receiver)242*d9f75844SAndroid Build Coastguard Worker SimulatedClockWithFrames(StreamGenerator* stream_generator,
243*d9f75844SAndroid Build Coastguard Worker VCMReceiver* receiver)
244*d9f75844SAndroid Build Coastguard Worker : SimulatedClock(0),
245*d9f75844SAndroid Build Coastguard Worker stream_generator_(stream_generator),
246*d9f75844SAndroid Build Coastguard Worker receiver_(receiver) {}
~SimulatedClockWithFrames()247*d9f75844SAndroid Build Coastguard Worker virtual ~SimulatedClockWithFrames() {}
248*d9f75844SAndroid Build Coastguard Worker
249*d9f75844SAndroid Build Coastguard Worker // If `stop_on_frame` is true and next frame arrives between now and
250*d9f75844SAndroid Build Coastguard Worker // now+`milliseconds`, the clock will be advanced to the arrival time of next
251*d9f75844SAndroid Build Coastguard Worker // frame.
252*d9f75844SAndroid Build Coastguard Worker // Otherwise, the clock will be advanced by `milliseconds`.
253*d9f75844SAndroid Build Coastguard Worker //
254*d9f75844SAndroid Build Coastguard Worker // For both cases, a frame will be inserted into the jitter buffer at the
255*d9f75844SAndroid Build Coastguard Worker // instant when the clock time is timestamps_.front().arrive_time.
256*d9f75844SAndroid Build Coastguard Worker //
257*d9f75844SAndroid Build Coastguard Worker // Return true if some frame arrives between now and now+`milliseconds`.
AdvanceTimeMilliseconds(int64_t milliseconds,bool stop_on_frame)258*d9f75844SAndroid Build Coastguard Worker bool AdvanceTimeMilliseconds(int64_t milliseconds, bool stop_on_frame) {
259*d9f75844SAndroid Build Coastguard Worker return AdvanceTimeMicroseconds(milliseconds * 1000, stop_on_frame);
260*d9f75844SAndroid Build Coastguard Worker }
261*d9f75844SAndroid Build Coastguard Worker
AdvanceTimeMicroseconds(int64_t microseconds,bool stop_on_frame)262*d9f75844SAndroid Build Coastguard Worker bool AdvanceTimeMicroseconds(int64_t microseconds, bool stop_on_frame) {
263*d9f75844SAndroid Build Coastguard Worker int64_t start_time = TimeInMicroseconds();
264*d9f75844SAndroid Build Coastguard Worker int64_t end_time = start_time + microseconds;
265*d9f75844SAndroid Build Coastguard Worker bool frame_injected = false;
266*d9f75844SAndroid Build Coastguard Worker while (!timestamps_.empty() &&
267*d9f75844SAndroid Build Coastguard Worker timestamps_.front().arrive_time <= end_time) {
268*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(timestamps_.front().arrive_time, start_time);
269*d9f75844SAndroid Build Coastguard Worker
270*d9f75844SAndroid Build Coastguard Worker SimulatedClock::AdvanceTimeMicroseconds(timestamps_.front().arrive_time -
271*d9f75844SAndroid Build Coastguard Worker TimeInMicroseconds());
272*d9f75844SAndroid Build Coastguard Worker GenerateAndInsertFrame((timestamps_.front().render_time + 500) / 1000);
273*d9f75844SAndroid Build Coastguard Worker timestamps_.pop();
274*d9f75844SAndroid Build Coastguard Worker frame_injected = true;
275*d9f75844SAndroid Build Coastguard Worker
276*d9f75844SAndroid Build Coastguard Worker if (stop_on_frame)
277*d9f75844SAndroid Build Coastguard Worker return frame_injected;
278*d9f75844SAndroid Build Coastguard Worker }
279*d9f75844SAndroid Build Coastguard Worker
280*d9f75844SAndroid Build Coastguard Worker if (TimeInMicroseconds() < end_time) {
281*d9f75844SAndroid Build Coastguard Worker SimulatedClock::AdvanceTimeMicroseconds(end_time - TimeInMicroseconds());
282*d9f75844SAndroid Build Coastguard Worker }
283*d9f75844SAndroid Build Coastguard Worker return frame_injected;
284*d9f75844SAndroid Build Coastguard Worker }
285*d9f75844SAndroid Build Coastguard Worker
286*d9f75844SAndroid Build Coastguard Worker // Input timestamps are in unit Milliseconds.
287*d9f75844SAndroid Build Coastguard Worker // And `arrive_timestamps` must be positive and in increasing order.
288*d9f75844SAndroid Build Coastguard Worker // `arrive_timestamps` determine when we are going to insert frames into the
289*d9f75844SAndroid Build Coastguard Worker // jitter buffer.
290*d9f75844SAndroid Build Coastguard Worker // `render_timestamps` are the timestamps on the frame.
SetFrames(const int64_t * arrive_timestamps,const int64_t * render_timestamps,size_t size)291*d9f75844SAndroid Build Coastguard Worker void SetFrames(const int64_t* arrive_timestamps,
292*d9f75844SAndroid Build Coastguard Worker const int64_t* render_timestamps,
293*d9f75844SAndroid Build Coastguard Worker size_t size) {
294*d9f75844SAndroid Build Coastguard Worker int64_t previous_arrive_timestamp = 0;
295*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < size; i++) {
296*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_GE(arrive_timestamps[i], previous_arrive_timestamp);
297*d9f75844SAndroid Build Coastguard Worker timestamps_.push(TimestampPair(arrive_timestamps[i] * 1000,
298*d9f75844SAndroid Build Coastguard Worker render_timestamps[i] * 1000));
299*d9f75844SAndroid Build Coastguard Worker previous_arrive_timestamp = arrive_timestamps[i];
300*d9f75844SAndroid Build Coastguard Worker }
301*d9f75844SAndroid Build Coastguard Worker }
302*d9f75844SAndroid Build Coastguard Worker
303*d9f75844SAndroid Build Coastguard Worker private:
304*d9f75844SAndroid Build Coastguard Worker struct TimestampPair {
TimestampPairwebrtc::SimulatedClockWithFrames::TimestampPair305*d9f75844SAndroid Build Coastguard Worker TimestampPair(int64_t arrive_timestamp, int64_t render_timestamp)
306*d9f75844SAndroid Build Coastguard Worker : arrive_time(arrive_timestamp), render_time(render_timestamp) {}
307*d9f75844SAndroid Build Coastguard Worker
308*d9f75844SAndroid Build Coastguard Worker int64_t arrive_time;
309*d9f75844SAndroid Build Coastguard Worker int64_t render_time;
310*d9f75844SAndroid Build Coastguard Worker };
311*d9f75844SAndroid Build Coastguard Worker
GenerateAndInsertFrame(int64_t render_timestamp_ms)312*d9f75844SAndroid Build Coastguard Worker void GenerateAndInsertFrame(int64_t render_timestamp_ms) {
313*d9f75844SAndroid Build Coastguard Worker VCMPacket packet;
314*d9f75844SAndroid Build Coastguard Worker stream_generator_->GenerateFrame(VideoFrameType::kVideoFrameKey,
315*d9f75844SAndroid Build Coastguard Worker 1, // media packets
316*d9f75844SAndroid Build Coastguard Worker 0, // empty packets
317*d9f75844SAndroid Build Coastguard Worker render_timestamp_ms);
318*d9f75844SAndroid Build Coastguard Worker
319*d9f75844SAndroid Build Coastguard Worker bool packet_available = stream_generator_->PopPacket(&packet, 0);
320*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(packet_available);
321*d9f75844SAndroid Build Coastguard Worker if (!packet_available)
322*d9f75844SAndroid Build Coastguard Worker return; // Return here to avoid crashes below.
323*d9f75844SAndroid Build Coastguard Worker receiver_->InsertPacket(packet);
324*d9f75844SAndroid Build Coastguard Worker }
325*d9f75844SAndroid Build Coastguard Worker
326*d9f75844SAndroid Build Coastguard Worker std::queue<TimestampPair> timestamps_;
327*d9f75844SAndroid Build Coastguard Worker StreamGenerator* stream_generator_;
328*d9f75844SAndroid Build Coastguard Worker VCMReceiver* receiver_;
329*d9f75844SAndroid Build Coastguard Worker };
330*d9f75844SAndroid Build Coastguard Worker
331*d9f75844SAndroid Build Coastguard Worker // Use a SimulatedClockWithFrames
332*d9f75844SAndroid Build Coastguard Worker // Wait call will do either of these:
333*d9f75844SAndroid Build Coastguard Worker // 1. If `stop_on_frame` is true, the clock will be turned to the exact instant
334*d9f75844SAndroid Build Coastguard Worker // that the first frame comes and the frame will be inserted into the jitter
335*d9f75844SAndroid Build Coastguard Worker // buffer, or the clock will be turned to now + `max_time` if no frame comes in
336*d9f75844SAndroid Build Coastguard Worker // the window.
337*d9f75844SAndroid Build Coastguard Worker // 2. If `stop_on_frame` is false, the clock will be turn to now + `max_time`,
338*d9f75844SAndroid Build Coastguard Worker // and all the frames arriving between now and now + `max_time` will be
339*d9f75844SAndroid Build Coastguard Worker // inserted into the jitter buffer.
340*d9f75844SAndroid Build Coastguard Worker //
341*d9f75844SAndroid Build Coastguard Worker // This is used to simulate the JitterBuffer getting packets from internet as
342*d9f75844SAndroid Build Coastguard Worker // time elapses.
343*d9f75844SAndroid Build Coastguard Worker
344*d9f75844SAndroid Build Coastguard Worker class FrameInjectEvent : public EventWrapper {
345*d9f75844SAndroid Build Coastguard Worker public:
FrameInjectEvent(SimulatedClockWithFrames * clock,bool stop_on_frame)346*d9f75844SAndroid Build Coastguard Worker FrameInjectEvent(SimulatedClockWithFrames* clock, bool stop_on_frame)
347*d9f75844SAndroid Build Coastguard Worker : clock_(clock), stop_on_frame_(stop_on_frame) {}
348*d9f75844SAndroid Build Coastguard Worker
Set()349*d9f75844SAndroid Build Coastguard Worker bool Set() override { return true; }
350*d9f75844SAndroid Build Coastguard Worker
Wait(int max_time_ms)351*d9f75844SAndroid Build Coastguard Worker EventTypeWrapper Wait(int max_time_ms) override {
352*d9f75844SAndroid Build Coastguard Worker if (clock_->AdvanceTimeMilliseconds(max_time_ms, stop_on_frame_) &&
353*d9f75844SAndroid Build Coastguard Worker stop_on_frame_) {
354*d9f75844SAndroid Build Coastguard Worker return EventTypeWrapper::kEventSignaled;
355*d9f75844SAndroid Build Coastguard Worker } else {
356*d9f75844SAndroid Build Coastguard Worker return EventTypeWrapper::kEventTimeout;
357*d9f75844SAndroid Build Coastguard Worker }
358*d9f75844SAndroid Build Coastguard Worker }
359*d9f75844SAndroid Build Coastguard Worker
360*d9f75844SAndroid Build Coastguard Worker private:
361*d9f75844SAndroid Build Coastguard Worker SimulatedClockWithFrames* clock_;
362*d9f75844SAndroid Build Coastguard Worker bool stop_on_frame_;
363*d9f75844SAndroid Build Coastguard Worker };
364*d9f75844SAndroid Build Coastguard Worker
365*d9f75844SAndroid Build Coastguard Worker class VCMReceiverTimingTest : public ::testing::Test {
366*d9f75844SAndroid Build Coastguard Worker protected:
VCMReceiverTimingTest()367*d9f75844SAndroid Build Coastguard Worker VCMReceiverTimingTest()
368*d9f75844SAndroid Build Coastguard Worker : clock_(&stream_generator_, &receiver_),
369*d9f75844SAndroid Build Coastguard Worker stream_generator_(0, clock_.TimeInMilliseconds()),
370*d9f75844SAndroid Build Coastguard Worker timing_(&clock_, field_trials_),
371*d9f75844SAndroid Build Coastguard Worker receiver_(
372*d9f75844SAndroid Build Coastguard Worker &timing_,
373*d9f75844SAndroid Build Coastguard Worker &clock_,
374*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<EventWrapper>(new FrameInjectEvent(&clock_, false)),
375*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<EventWrapper>(new FrameInjectEvent(&clock_, true)),
376*d9f75844SAndroid Build Coastguard Worker field_trials_) {}
377*d9f75844SAndroid Build Coastguard Worker
SetUp()378*d9f75844SAndroid Build Coastguard Worker virtual void SetUp() {}
379*d9f75844SAndroid Build Coastguard Worker
380*d9f75844SAndroid Build Coastguard Worker test::ScopedKeyValueConfig field_trials_;
381*d9f75844SAndroid Build Coastguard Worker SimulatedClockWithFrames clock_;
382*d9f75844SAndroid Build Coastguard Worker StreamGenerator stream_generator_;
383*d9f75844SAndroid Build Coastguard Worker VCMTiming timing_;
384*d9f75844SAndroid Build Coastguard Worker VCMReceiver receiver_;
385*d9f75844SAndroid Build Coastguard Worker };
386*d9f75844SAndroid Build Coastguard Worker
387*d9f75844SAndroid Build Coastguard Worker // Test whether VCMReceiver::FrameForDecoding handles parameter
388*d9f75844SAndroid Build Coastguard Worker // `max_wait_time_ms` correctly:
389*d9f75844SAndroid Build Coastguard Worker // 1. The function execution should never take more than `max_wait_time_ms`.
390*d9f75844SAndroid Build Coastguard Worker // 2. If the function exit before now + `max_wait_time_ms`, a frame must be
391*d9f75844SAndroid Build Coastguard Worker // returned.
TEST_F(VCMReceiverTimingTest,FrameForDecoding)392*d9f75844SAndroid Build Coastguard Worker TEST_F(VCMReceiverTimingTest, FrameForDecoding) {
393*d9f75844SAndroid Build Coastguard Worker const size_t kNumFrames = 100;
394*d9f75844SAndroid Build Coastguard Worker const int kFramePeriod = 40;
395*d9f75844SAndroid Build Coastguard Worker int64_t arrive_timestamps[kNumFrames];
396*d9f75844SAndroid Build Coastguard Worker int64_t render_timestamps[kNumFrames];
397*d9f75844SAndroid Build Coastguard Worker
398*d9f75844SAndroid Build Coastguard Worker // Construct test samples.
399*d9f75844SAndroid Build Coastguard Worker // render_timestamps are the timestamps stored in the Frame;
400*d9f75844SAndroid Build Coastguard Worker // arrive_timestamps controls when the Frame packet got received.
401*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < kNumFrames; i++) {
402*d9f75844SAndroid Build Coastguard Worker // Preset frame rate to 25Hz.
403*d9f75844SAndroid Build Coastguard Worker // But we add a reasonable deviation to arrive_timestamps to mimic Internet
404*d9f75844SAndroid Build Coastguard Worker // fluctuation.
405*d9f75844SAndroid Build Coastguard Worker arrive_timestamps[i] =
406*d9f75844SAndroid Build Coastguard Worker (i + 1) * kFramePeriod + (i % 10) * ((i % 2) ? 1 : -1);
407*d9f75844SAndroid Build Coastguard Worker render_timestamps[i] = (i + 1) * kFramePeriod;
408*d9f75844SAndroid Build Coastguard Worker }
409*d9f75844SAndroid Build Coastguard Worker
410*d9f75844SAndroid Build Coastguard Worker clock_.SetFrames(arrive_timestamps, render_timestamps, kNumFrames);
411*d9f75844SAndroid Build Coastguard Worker
412*d9f75844SAndroid Build Coastguard Worker // Record how many frames we finally get out of the receiver.
413*d9f75844SAndroid Build Coastguard Worker size_t num_frames_return = 0;
414*d9f75844SAndroid Build Coastguard Worker
415*d9f75844SAndroid Build Coastguard Worker const int64_t kMaxWaitTime = 30;
416*d9f75844SAndroid Build Coastguard Worker
417*d9f75844SAndroid Build Coastguard Worker // Ideally, we should get all frames that we input in InitializeFrames.
418*d9f75844SAndroid Build Coastguard Worker // In the case that FrameForDecoding kills frames by error, we rely on the
419*d9f75844SAndroid Build Coastguard Worker // build bot to kill the test.
420*d9f75844SAndroid Build Coastguard Worker while (num_frames_return < kNumFrames) {
421*d9f75844SAndroid Build Coastguard Worker int64_t start_time = clock_.TimeInMilliseconds();
422*d9f75844SAndroid Build Coastguard Worker VCMEncodedFrame* frame = receiver_.FrameForDecoding(kMaxWaitTime, false);
423*d9f75844SAndroid Build Coastguard Worker int64_t end_time = clock_.TimeInMilliseconds();
424*d9f75844SAndroid Build Coastguard Worker
425*d9f75844SAndroid Build Coastguard Worker // In any case the FrameForDecoding should not wait longer than
426*d9f75844SAndroid Build Coastguard Worker // max_wait_time.
427*d9f75844SAndroid Build Coastguard Worker // In the case that we did not get a frame, it should have been waiting for
428*d9f75844SAndroid Build Coastguard Worker // exactly max_wait_time. (By the testing samples we constructed above, we
429*d9f75844SAndroid Build Coastguard Worker // are sure there is no timing error, so the only case it returns with NULL
430*d9f75844SAndroid Build Coastguard Worker // is that it runs out of time.)
431*d9f75844SAndroid Build Coastguard Worker if (frame) {
432*d9f75844SAndroid Build Coastguard Worker receiver_.ReleaseFrame(frame);
433*d9f75844SAndroid Build Coastguard Worker ++num_frames_return;
434*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(kMaxWaitTime, end_time - start_time);
435*d9f75844SAndroid Build Coastguard Worker } else {
436*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(kMaxWaitTime, end_time - start_time);
437*d9f75844SAndroid Build Coastguard Worker }
438*d9f75844SAndroid Build Coastguard Worker }
439*d9f75844SAndroid Build Coastguard Worker }
440*d9f75844SAndroid Build Coastguard Worker
441*d9f75844SAndroid Build Coastguard Worker // Test whether VCMReceiver::FrameForDecoding handles parameter
442*d9f75844SAndroid Build Coastguard Worker // `prefer_late_decoding` and `max_wait_time_ms` correctly:
443*d9f75844SAndroid Build Coastguard Worker // 1. The function execution should never take more than `max_wait_time_ms`.
444*d9f75844SAndroid Build Coastguard Worker // 2. If the function exit before now + `max_wait_time_ms`, a frame must be
445*d9f75844SAndroid Build Coastguard Worker // returned and the end time must be equal to the render timestamp - delay
446*d9f75844SAndroid Build Coastguard Worker // for decoding and rendering.
TEST_F(VCMReceiverTimingTest,FrameForDecodingPreferLateDecoding)447*d9f75844SAndroid Build Coastguard Worker TEST_F(VCMReceiverTimingTest, FrameForDecodingPreferLateDecoding) {
448*d9f75844SAndroid Build Coastguard Worker const size_t kNumFrames = 100;
449*d9f75844SAndroid Build Coastguard Worker const int kFramePeriod = 40;
450*d9f75844SAndroid Build Coastguard Worker
451*d9f75844SAndroid Build Coastguard Worker int64_t arrive_timestamps[kNumFrames];
452*d9f75844SAndroid Build Coastguard Worker int64_t render_timestamps[kNumFrames];
453*d9f75844SAndroid Build Coastguard Worker
454*d9f75844SAndroid Build Coastguard Worker auto timings = timing_.GetTimings();
455*d9f75844SAndroid Build Coastguard Worker TimeDelta render_delay = timings.render_delay;
456*d9f75844SAndroid Build Coastguard Worker TimeDelta max_decode = timings.max_decode_duration;
457*d9f75844SAndroid Build Coastguard Worker
458*d9f75844SAndroid Build Coastguard Worker // Construct test samples.
459*d9f75844SAndroid Build Coastguard Worker // render_timestamps are the timestamps stored in the Frame;
460*d9f75844SAndroid Build Coastguard Worker // arrive_timestamps controls when the Frame packet got received.
461*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < kNumFrames; i++) {
462*d9f75844SAndroid Build Coastguard Worker // Preset frame rate to 25Hz.
463*d9f75844SAndroid Build Coastguard Worker // But we add a reasonable deviation to arrive_timestamps to mimic Internet
464*d9f75844SAndroid Build Coastguard Worker // fluctuation.
465*d9f75844SAndroid Build Coastguard Worker arrive_timestamps[i] =
466*d9f75844SAndroid Build Coastguard Worker (i + 1) * kFramePeriod + (i % 10) * ((i % 2) ? 1 : -1);
467*d9f75844SAndroid Build Coastguard Worker render_timestamps[i] = (i + 1) * kFramePeriod;
468*d9f75844SAndroid Build Coastguard Worker }
469*d9f75844SAndroid Build Coastguard Worker
470*d9f75844SAndroid Build Coastguard Worker clock_.SetFrames(arrive_timestamps, render_timestamps, kNumFrames);
471*d9f75844SAndroid Build Coastguard Worker
472*d9f75844SAndroid Build Coastguard Worker // Record how many frames we finally get out of the receiver.
473*d9f75844SAndroid Build Coastguard Worker size_t num_frames_return = 0;
474*d9f75844SAndroid Build Coastguard Worker const int64_t kMaxWaitTime = 30;
475*d9f75844SAndroid Build Coastguard Worker bool prefer_late_decoding = true;
476*d9f75844SAndroid Build Coastguard Worker while (num_frames_return < kNumFrames) {
477*d9f75844SAndroid Build Coastguard Worker int64_t start_time = clock_.TimeInMilliseconds();
478*d9f75844SAndroid Build Coastguard Worker
479*d9f75844SAndroid Build Coastguard Worker VCMEncodedFrame* frame =
480*d9f75844SAndroid Build Coastguard Worker receiver_.FrameForDecoding(kMaxWaitTime, prefer_late_decoding);
481*d9f75844SAndroid Build Coastguard Worker int64_t end_time = clock_.TimeInMilliseconds();
482*d9f75844SAndroid Build Coastguard Worker if (frame) {
483*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(frame->RenderTimeMs() - max_decode.ms() - render_delay.ms(),
484*d9f75844SAndroid Build Coastguard Worker end_time);
485*d9f75844SAndroid Build Coastguard Worker receiver_.ReleaseFrame(frame);
486*d9f75844SAndroid Build Coastguard Worker ++num_frames_return;
487*d9f75844SAndroid Build Coastguard Worker } else {
488*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(kMaxWaitTime, end_time - start_time);
489*d9f75844SAndroid Build Coastguard Worker }
490*d9f75844SAndroid Build Coastguard Worker }
491*d9f75844SAndroid Build Coastguard Worker }
492*d9f75844SAndroid Build Coastguard Worker
493*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
494