xref: /aosp_15_r20/external/webrtc/modules/video_coding/receiver_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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