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