tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

loss_notification_controller_unittest.cc (22251B)


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