blob: 590cc7716d788e038aafc76e8880becccd7e8627 [file] [log] [blame]
Elad Alon10874b22019-02-21 16:25:40 +01001/*
2 * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "modules/video_coding/loss_notification_controller.h"
12
13#include <limits>
14#include <string>
15#include <tuple>
16#include <vector>
17
18#include "absl/types/optional.h"
19#include "test/gtest.h"
20
21namespace webrtc {
22namespace {
23VCMPacket CreatePacket(
24 bool first_in_frame,
25 bool last_in_frame,
26 uint16_t seq_num,
27 uint16_t frame_id,
28 bool is_key_frame,
29 std::vector<uint16_t> ref_frame_ids = std::vector<uint16_t>()) {
30 RtpGenericFrameDescriptor frame_descriptor;
31 frame_descriptor.SetFirstPacketInSubFrame(first_in_frame);
32 frame_descriptor.SetLastPacketInSubFrame(last_in_frame);
33 if (first_in_frame) {
34 frame_descriptor.SetFrameId(frame_id);
35 if (!is_key_frame) {
36 for (uint16_t ref_frame_id : ref_frame_ids) {
37 uint16_t fdiff = frame_id - ref_frame_id;
38 EXPECT_TRUE(frame_descriptor.AddFrameDependencyDiff(fdiff));
39 }
40 }
41 }
42
43 VCMPacket packet;
44 packet.seqNum = seq_num;
45 packet.generic_descriptor = frame_descriptor;
46 return packet;
47}
48
49class PacketStreamCreator final {
50 public:
51 PacketStreamCreator() : seq_num_(0), frame_id_(0), next_is_key_frame_(true) {}
52
53 VCMPacket NextPacket() {
54 std::vector<uint16_t> ref_frame_ids;
55 if (!next_is_key_frame_) {
56 ref_frame_ids.push_back(frame_id_ - 1);
57 }
58
59 VCMPacket packet = CreatePacket(true, true, seq_num_++, frame_id_++,
60 next_is_key_frame_, ref_frame_ids);
61
62 next_is_key_frame_ = false;
63
64 return packet;
65 }
66
67 private:
68 uint16_t seq_num_;
69 uint16_t frame_id_;
70 bool next_is_key_frame_;
71};
72} // namespace
73
74// Most of the logic for the tests is here. Subclasses allow parameterizing
75// the test, or adding some more specific logic.
76class LossNotificationControllerBaseTest : public ::testing::Test,
77 public KeyFrameRequestSender,
78 public LossNotificationSender {
79 protected:
80 LossNotificationControllerBaseTest()
81 : uut_(this, this), key_frame_requested_(false) {}
82
83 ~LossNotificationControllerBaseTest() override {
84 EXPECT_FALSE(LastKeyFrameRequest());
85 EXPECT_FALSE(LastLossNotification());
86 }
87
88 // KeyFrameRequestSender implementation.
89 void RequestKeyFrame() override {
90 EXPECT_FALSE(LastKeyFrameRequest());
91 EXPECT_FALSE(LastLossNotification());
92 key_frame_requested_ = true;
93 }
94
95 // LossNotificationSender implementation.
96 void SendLossNotification(uint16_t last_decoded_seq_num,
97 uint16_t last_received_seq_num,
Elad Alone86af2c2019-06-03 14:37:50 +020098 bool decodability_flag,
99 bool buffering_allowed) override {
100 EXPECT_TRUE(buffering_allowed); // (Flag useful elsewhere.)
Elad Alon10874b22019-02-21 16:25:40 +0100101 EXPECT_FALSE(LastKeyFrameRequest());
102 EXPECT_FALSE(LastLossNotification());
103 last_loss_notification_.emplace(last_decoded_seq_num, last_received_seq_num,
104 decodability_flag);
105 }
106
107 void OnReceivedPacket(const VCMPacket& packet) {
108 EXPECT_FALSE(LastKeyFrameRequest());
109 EXPECT_FALSE(LastLossNotification());
110
111 if (packet.generic_descriptor &&
112 packet.generic_descriptor->FirstPacketInSubFrame()) {
113 previous_first_packet_in_frame_ = packet;
114 }
115
116 uut_.OnReceivedPacket(packet);
117 }
118
119 void OnAssembledFrame(uint16_t first_seq_num,
120 uint16_t frame_id,
121 bool discardable) {
122 EXPECT_FALSE(LastKeyFrameRequest());
123 EXPECT_FALSE(LastLossNotification());
124
125 ASSERT_TRUE(previous_first_packet_in_frame_);
126 const RtpGenericFrameDescriptor& frame_descriptor =
127 previous_first_packet_in_frame_->generic_descriptor.value();
128
129 uut_.OnAssembledFrame(first_seq_num, frame_id, discardable,
130 frame_descriptor.FrameDependenciesDiffs());
131 }
132
133 void ExpectKeyFrameRequest() {
134 EXPECT_EQ(LastLossNotification(), absl::nullopt);
135 EXPECT_TRUE(LastKeyFrameRequest());
136 }
137
138 void ExpectLossNotification(uint16_t last_decoded_seq_num,
139 uint16_t last_received_seq_num,
140 bool decodability_flag) {
141 EXPECT_FALSE(LastKeyFrameRequest());
142 const auto last_ln = LastLossNotification();
143 ASSERT_TRUE(last_ln);
144 const LossNotification expected_ln(
145 last_decoded_seq_num, last_received_seq_num, decodability_flag);
146 EXPECT_EQ(expected_ln, *last_ln)
147 << "Expected loss notification (" << expected_ln.ToString()
148 << ") != received loss notification (" << last_ln->ToString() + ")";
149 }
150
151 struct LossNotification {
152 LossNotification(uint16_t last_decoded_seq_num,
153 uint16_t last_received_seq_num,
154 bool decodability_flag)
155 : last_decoded_seq_num(last_decoded_seq_num),
156 last_received_seq_num(last_received_seq_num),
157 decodability_flag(decodability_flag) {}
158
159 LossNotification& operator=(const LossNotification& other) = default;
160
161 bool operator==(const LossNotification& other) const {
162 return last_decoded_seq_num == other.last_decoded_seq_num &&
163 last_received_seq_num == other.last_received_seq_num &&
164 decodability_flag == other.decodability_flag;
165 }
166
167 std::string ToString() const {
168 return std::to_string(last_decoded_seq_num) + ", " +
169 std::to_string(last_received_seq_num) + ", " +
170 std::to_string(decodability_flag);
171 }
172
173 uint16_t last_decoded_seq_num;
174 uint16_t last_received_seq_num;
175 bool decodability_flag;
176 };
177
178 bool LastKeyFrameRequest() {
179 const bool result = key_frame_requested_;
180 key_frame_requested_ = false;
181 return result;
182 }
183
184 absl::optional<LossNotification> LastLossNotification() {
185 const absl::optional<LossNotification> result = last_loss_notification_;
186 last_loss_notification_ = absl::nullopt;
187 return result;
188 }
189
190 LossNotificationController uut_; // Unit under test.
191
192 bool key_frame_requested_;
193
194 absl::optional<LossNotification> last_loss_notification_;
195
196 // First packet of last frame. (Note that if a test skips the first packet
197 // of a subsequent frame, OnAssembledFrame is not called, and so this is
198 // note read. Therefore, it's not a problem if it is not cleared when
199 // the frame changes.)
200 absl::optional<VCMPacket> previous_first_packet_in_frame_;
201};
202
203class LossNotificationControllerTest
204 : public LossNotificationControllerBaseTest,
205 public ::testing::WithParamInterface<std::tuple<bool, bool, bool>> {
206 protected:
207 // Arbitrary parameterized values, to be used by the tests whenever they
208 // wish to either check some combinations, or wish to demonstrate that
209 // a particular arbitrary value is unimportant.
210 template <size_t N>
211 bool Bool() const {
212 return std::get<N>(GetParam());
213 }
214};
215
216INSTANTIATE_TEST_SUITE_P(_,
217 LossNotificationControllerTest,
218 ::testing::Combine(::testing::Bool(),
219 ::testing::Bool(),
220 ::testing::Bool()));
221
222// If the first frame, which is a key frame, is lost, then a new key frame
223// is requested.
224TEST_P(LossNotificationControllerTest,
225 PacketLossBeforeFirstFrameAssembledTriggersKeyFrameRequest) {
226 OnReceivedPacket(CreatePacket(true, false, 100, 0, true));
227 OnReceivedPacket(CreatePacket(Bool<0>(), Bool<1>(), 103, 1, false, {0}));
228 ExpectKeyFrameRequest();
229}
230
231// If packet loss occurs (but not of the first packet), then a loss notification
232// is issued.
233TEST_P(LossNotificationControllerTest,
234 PacketLossAfterFirstFrameAssembledTriggersLossNotification) {
235 OnReceivedPacket(CreatePacket(true, true, 100, 0, true));
236 OnAssembledFrame(100, 0, false);
237 const bool first = Bool<0>();
238 const bool last = Bool<1>();
239 OnReceivedPacket(CreatePacket(first, last, 103, 1, false, {0}));
240 const bool expected_decodability_flag = first;
241 ExpectLossNotification(100, 103, expected_decodability_flag);
242}
243
244// No key frame or loss notifications issued due to an innocuous wrap-around
245// of the sequence number.
246TEST_P(LossNotificationControllerTest, SeqNumWrapAround) {
247 uint16_t seq_num = std::numeric_limits<uint16_t>::max();
248 OnReceivedPacket(CreatePacket(true, true, seq_num, 0, true));
249 OnAssembledFrame(seq_num, 0, false);
250 const bool first = Bool<0>();
251 const bool last = Bool<1>();
252 OnReceivedPacket(CreatePacket(first, last, ++seq_num, 1, false, {0}));
253}
254
255// No key frame or loss notifications issued due to an innocuous wrap-around
256// of the frame ID.
257TEST_P(LossNotificationControllerTest, FrameIdWrapAround) {
258 uint16_t frame_id = std::numeric_limits<uint16_t>::max();
259 OnReceivedPacket(CreatePacket(true, true, 100, frame_id, true));
260 OnAssembledFrame(100, frame_id, false);
261 ++frame_id;
262 const bool first = Bool<0>();
263 const bool last = Bool<1>();
264 OnReceivedPacket(CreatePacket(first, last, 100, frame_id, false,
265 {static_cast<uint16_t>(frame_id - 1)}));
266}
267
268TEST_F(LossNotificationControllerTest,
269 KeyFrameAfterPacketLossProducesNoLossNotifications) {
270 OnReceivedPacket(CreatePacket(true, true, 100, 1, true));
271 OnAssembledFrame(100, 1, false);
272 OnReceivedPacket(CreatePacket(true, true, 108, 8, true));
273}
274
275TEST_P(LossNotificationControllerTest, LostReferenceProducesLossNotification) {
276 OnReceivedPacket(CreatePacket(true, true, 100, 0, true));
277 OnAssembledFrame(100, 0, false);
278 uint16_t last_decodable_non_discardable_seq_num = 100;
279
280 // RTP gap produces loss notification - not the focus of this test.
281 const bool first = Bool<0>();
282 const bool last = Bool<1>();
283 const bool discardable = Bool<2>();
284 const bool decodable = first; // Depends on assemblability.
285 OnReceivedPacket(CreatePacket(first, last, 107, 3, false, {0}));
286 ExpectLossNotification(100, 107, decodable);
287 OnAssembledFrame(107, 3, discardable);
288 if (!discardable) {
289 last_decodable_non_discardable_seq_num = 107;
290 }
291
292 // Test focus - a loss notification is produced because of the missing
293 // dependency (frame ID 2), despite the RTP sequence number being the
294 // next expected one.
295 OnReceivedPacket(CreatePacket(true, true, 108, 4, false, {2, 0}));
296 ExpectLossNotification(last_decodable_non_discardable_seq_num, 108, false);
297}
298
299// The difference between this test and the previous one, is that in this test,
300// although the reference frame was received, it was not decodable.
301TEST_P(LossNotificationControllerTest,
302 UndecodableReferenceProducesLossNotification) {
303 OnReceivedPacket(CreatePacket(true, true, 100, 0, true));
304 OnAssembledFrame(100, 0, false);
305 uint16_t last_decodable_non_discardable_seq_num = 100;
306
307 // RTP gap produces loss notification - not the focus of this test.
308 // Also, not decodable; this is important for later in the test.
309 OnReceivedPacket(CreatePacket(true, true, 107, 3, false, {2}));
310 ExpectLossNotification(100, 107, false);
311 const bool discardable = Bool<0>();
312 OnAssembledFrame(107, 3, discardable);
313
314 // Test focus - a loss notification is produced because of the undecodable
315 // dependency (frame ID 3, which depended on the missing frame ID 2).
316 OnReceivedPacket(CreatePacket(true, true, 108, 4, false, {3, 0}));
317 ExpectLossNotification(last_decodable_non_discardable_seq_num, 108, false);
318}
319
320TEST_P(LossNotificationControllerTest, RobustnessAgainstHighInitialRefFrameId) {
321 constexpr uint16_t max_uint16_t = std::numeric_limits<uint16_t>::max();
322 OnReceivedPacket(CreatePacket(true, true, 100, 0, true));
323 OnAssembledFrame(100, 0, false);
324 OnReceivedPacket(CreatePacket(true, true, 101, 1, false, {max_uint16_t}));
325 ExpectLossNotification(100, 101, false);
326 OnAssembledFrame(101, max_uint16_t, Bool<0>());
327}
328
329TEST_P(LossNotificationControllerTest, RepeatedPacketsAreIgnored) {
330 PacketStreamCreator packet_stream;
331
332 const auto key_frame_packet = packet_stream.NextPacket();
333 OnReceivedPacket(key_frame_packet);
334 OnAssembledFrame(key_frame_packet.seqNum,
335 key_frame_packet.generic_descriptor->FrameId(), false);
336
337 const bool gap = Bool<0>();
338
339 if (gap) {
340 // Lose one packet.
341 packet_stream.NextPacket();
342 }
343
344 auto repeated_packet = packet_stream.NextPacket();
345 OnReceivedPacket(repeated_packet);
346 if (gap) {
347 // Loss notification issued because of the gap. This is not the focus of
348 // the test.
349 ExpectLossNotification(key_frame_packet.seqNum, repeated_packet.seqNum,
350 false);
351 }
352 OnReceivedPacket(repeated_packet);
353}
354
355// Frames without the generic frame descriptor cannot be properly handled,
356// but must not induce a crash.
357TEST_F(LossNotificationControllerTest,
358 IgnoreFramesWithoutGenericFrameDescriptor) {
359 auto packet = CreatePacket(true, true, 1, 0, true);
360 packet.generic_descriptor.reset();
361 OnReceivedPacket(packet);
362}
363
364class LossNotificationControllerTestDecodabilityFlag
365 : public LossNotificationControllerBaseTest {
366 protected:
367 LossNotificationControllerTestDecodabilityFlag()
368 : key_frame_seq_num_(100),
369 key_frame_frame_id_(0),
370 never_received_frame_id_(key_frame_frame_id_ + 1),
371 seq_num_(0),
372 frame_id_(0) {}
373
374 void ReceiveKeyFrame() {
375 RTC_DCHECK_NE(key_frame_frame_id_, never_received_frame_id_);
376 OnReceivedPacket(CreatePacket(true, true, key_frame_seq_num_,
377 key_frame_frame_id_, true));
378 OnAssembledFrame(key_frame_seq_num_, key_frame_frame_id_, false);
379 seq_num_ = key_frame_seq_num_;
380 frame_id_ = key_frame_frame_id_;
381 }
382
383 void ReceivePacket(bool first_packet_in_frame,
384 bool last_packet_in_frame,
385 const std::vector<uint16_t>& ref_frame_ids) {
386 if (first_packet_in_frame) {
387 frame_id_ += 1;
388 }
389 RTC_DCHECK_NE(frame_id_, never_received_frame_id_);
390 constexpr bool is_key_frame = false;
391 OnReceivedPacket(CreatePacket(first_packet_in_frame, last_packet_in_frame,
392 ++seq_num_, frame_id_, is_key_frame,
393 ref_frame_ids));
394 }
395
396 void CreateGap() {
397 seq_num_ += 50;
398 frame_id_ += 10;
399 }
400
401 const uint16_t key_frame_seq_num_;
402 const uint16_t key_frame_frame_id_;
403
404 // The tests intentionally never receive this, and can therefore always
405 // use this as an unsatisfied dependency.
406 const uint16_t never_received_frame_id_ = 123;
407
408 uint16_t seq_num_;
409 uint16_t frame_id_;
410};
411
412TEST_F(LossNotificationControllerTestDecodabilityFlag,
413 SinglePacketFrameWithDecodableDependencies) {
414 ReceiveKeyFrame();
415 CreateGap();
416
417 const std::vector<uint16_t> ref_frame_ids = {key_frame_frame_id_};
418 ReceivePacket(true, true, ref_frame_ids);
419
420 const bool expected_decodability_flag = true;
421 ExpectLossNotification(key_frame_seq_num_, seq_num_,
422 expected_decodability_flag);
423}
424
425TEST_F(LossNotificationControllerTestDecodabilityFlag,
426 SinglePacketFrameWithUndecodableDependencies) {
427 ReceiveKeyFrame();
428 CreateGap();
429
430 const std::vector<uint16_t> ref_frame_ids = {never_received_frame_id_};
431 ReceivePacket(true, true, ref_frame_ids);
432
433 const bool expected_decodability_flag = false;
434 ExpectLossNotification(key_frame_seq_num_, seq_num_,
435 expected_decodability_flag);
436}
437
438TEST_F(LossNotificationControllerTestDecodabilityFlag,
439 FirstPacketOfMultiPacketFrameWithDecodableDependencies) {
440 ReceiveKeyFrame();
441 CreateGap();
442
443 const std::vector<uint16_t> ref_frame_ids = {key_frame_frame_id_};
444 ReceivePacket(true, false, ref_frame_ids);
445
446 const bool expected_decodability_flag = true;
447 ExpectLossNotification(key_frame_seq_num_, seq_num_,
448 expected_decodability_flag);
449}
450
451TEST_F(LossNotificationControllerTestDecodabilityFlag,
452 FirstPacketOfMultiPacketFrameWithUndecodableDependencies) {
453 ReceiveKeyFrame();
454 CreateGap();
455
456 const std::vector<uint16_t> ref_frame_ids = {never_received_frame_id_};
457 ReceivePacket(true, false, ref_frame_ids);
458
459 const bool expected_decodability_flag = false;
460 ExpectLossNotification(key_frame_seq_num_, seq_num_,
461 expected_decodability_flag);
462}
463
464TEST_F(LossNotificationControllerTestDecodabilityFlag,
465 MiddlePacketOfMultiPacketFrameWithDecodableDependenciesIfFirstMissed) {
466 ReceiveKeyFrame();
467 CreateGap();
468
469 const std::vector<uint16_t> ref_frame_ids = {key_frame_frame_id_};
470 ReceivePacket(false, false, ref_frame_ids);
471
472 const bool expected_decodability_flag = false;
473 ExpectLossNotification(key_frame_seq_num_, seq_num_,
474 expected_decodability_flag);
475}
476
477TEST_F(LossNotificationControllerTestDecodabilityFlag,
478 MiddlePacketOfMultiPacketFrameWithUndecodableDependenciesIfFirstMissed) {
479 ReceiveKeyFrame();
480 CreateGap();
481
482 const std::vector<uint16_t> ref_frame_ids = {never_received_frame_id_};
483 ReceivePacket(false, false, ref_frame_ids);
484
485 const bool expected_decodability_flag = false;
486 ExpectLossNotification(key_frame_seq_num_, seq_num_,
487 expected_decodability_flag);
488}
489
490TEST_F(LossNotificationControllerTestDecodabilityFlag,
491 MiddlePacketOfMultiPacketFrameWithDecodableDependenciesIfFirstReceived) {
492 ReceiveKeyFrame();
493 CreateGap();
494
495 // First packet in multi-packet frame. A loss notification is produced
496 // because of the gap in RTP sequence numbers.
497 const std::vector<uint16_t> ref_frame_ids = {key_frame_frame_id_};
498 ReceivePacket(true, false, ref_frame_ids);
499 const bool expected_decodability_flag_first = true;
500 ExpectLossNotification(key_frame_seq_num_, seq_num_,
501 expected_decodability_flag_first);
502
503 // Middle packet in multi-packet frame. No additional gap and the frame is
504 // still potentially decodable, so no additional loss indication.
505 ReceivePacket(false, false, ref_frame_ids);
506 EXPECT_FALSE(LastKeyFrameRequest());
507 EXPECT_FALSE(LastLossNotification());
508}
509
510TEST_F(
511 LossNotificationControllerTestDecodabilityFlag,
512 MiddlePacketOfMultiPacketFrameWithUndecodableDependenciesIfFirstReceived) {
513 ReceiveKeyFrame();
514 CreateGap();
515
516 // First packet in multi-packet frame. A loss notification is produced
517 // because of the gap in RTP sequence numbers. The frame is also recognized
518 // as having non-decodable dependencies.
519 const std::vector<uint16_t> ref_frame_ids = {never_received_frame_id_};
520 ReceivePacket(true, false, ref_frame_ids);
521 const bool expected_decodability_flag_first = false;
522 ExpectLossNotification(key_frame_seq_num_, seq_num_,
523 expected_decodability_flag_first);
524
525 // Middle packet in multi-packet frame. No additional gap, but the frame is
526 // known to be non-decodable, so we keep issuing loss indications.
527 ReceivePacket(false, false, ref_frame_ids);
528 const bool expected_decodability_flag_middle = false;
529 ExpectLossNotification(key_frame_seq_num_, seq_num_,
530 expected_decodability_flag_middle);
531}
532
533TEST_F(LossNotificationControllerTestDecodabilityFlag,
534 LastPacketOfMultiPacketFrameWithDecodableDependenciesIfAllPrevMissed) {
535 ReceiveKeyFrame();
536 CreateGap();
537
538 const std::vector<uint16_t> ref_frame_ids = {key_frame_frame_id_};
539 ReceivePacket(false, true, ref_frame_ids);
540
541 const bool expected_decodability_flag = false;
542 ExpectLossNotification(key_frame_seq_num_, seq_num_,
543 expected_decodability_flag);
544}
545
546TEST_F(LossNotificationControllerTestDecodabilityFlag,
547 LastPacketOfMultiPacketFrameWithUndecodableDependenciesIfAllPrevMissed) {
548 ReceiveKeyFrame();
549 CreateGap();
550
551 const std::vector<uint16_t> ref_frame_ids = {never_received_frame_id_};
552 ReceivePacket(false, true, ref_frame_ids);
553
554 const bool expected_decodability_flag = false;
555 ExpectLossNotification(key_frame_seq_num_, seq_num_,
556 expected_decodability_flag);
557}
558
559TEST_F(LossNotificationControllerTestDecodabilityFlag,
560 LastPacketOfMultiPacketFrameWithDecodableDependenciesIfAllPrevReceived) {
561 ReceiveKeyFrame();
562 CreateGap();
563
564 // First packet in multi-packet frame. A loss notification is produced
565 // because of the gap in RTP sequence numbers.
566 const std::vector<uint16_t> ref_frame_ids = {key_frame_frame_id_};
567 ReceivePacket(true, false, ref_frame_ids);
568 const bool expected_decodability_flag_first = true;
569 ExpectLossNotification(key_frame_seq_num_, seq_num_,
570 expected_decodability_flag_first);
571
572 // Last packet in multi-packet frame. No additional gap and the frame is
573 // still potentially decodable, so no additional loss indication.
574 ReceivePacket(false, true, ref_frame_ids);
575 EXPECT_FALSE(LastKeyFrameRequest());
576 EXPECT_FALSE(LastLossNotification());
577}
578
579TEST_F(
580 LossNotificationControllerTestDecodabilityFlag,
581 LastPacketOfMultiPacketFrameWithUndecodableDependenciesIfAllPrevReceived) {
582 ReceiveKeyFrame();
583 CreateGap();
584
585 // First packet in multi-packet frame. A loss notification is produced
586 // because of the gap in RTP sequence numbers. The frame is also recognized
587 // as having non-decodable dependencies.
588 const std::vector<uint16_t> ref_frame_ids = {never_received_frame_id_};
589 ReceivePacket(true, false, ref_frame_ids);
590 const bool expected_decodability_flag_first = false;
591 ExpectLossNotification(key_frame_seq_num_, seq_num_,
592 expected_decodability_flag_first);
593
594 // Last packet in multi-packet frame. No additional gap, but the frame is
595 // known to be non-decodable, so we keep issuing loss indications.
596 ReceivePacket(false, true, ref_frame_ids);
597 const bool expected_decodability_flag_last = false;
598 ExpectLossNotification(key_frame_seq_num_, seq_num_,
599 expected_decodability_flag_last);
600}
601
602} // namespace webrtc