Add RtpSequenceNumberMap::InsertFrame()

This will make code using RtpSequenceNumberMap simpler.

Bug: webrtc:10501
Change-Id: I74b11f3562d5962efb42b5bb7662489d7d411388
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/131386
Commit-Queue: Elad Alon <eladalon@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27485}
diff --git a/modules/rtp_rtcp/source/rtp_sequence_number_map.cc b/modules/rtp_rtcp/source/rtp_sequence_number_map.cc
index 95eafce..28ae9c8 100644
--- a/modules/rtp_rtcp/source/rtp_sequence_number_map.cc
+++ b/modules/rtp_rtcp/source/rtp_sequence_number_map.cc
@@ -12,6 +12,7 @@
 
 #include <algorithm>
 #include <iterator>
+#include <limits>
 
 #include "absl/algorithm/container.h"
 #include "rtc_base/checks.h"
@@ -28,7 +29,7 @@
 
 RtpSequenceNumberMap::~RtpSequenceNumberMap() = default;
 
-void RtpSequenceNumberMap::Insert(uint16_t sequence_number, Info info) {
+void RtpSequenceNumberMap::InsertPacket(uint16_t sequence_number, Info info) {
   RTC_DCHECK(associations_.size() < 2 ||
              AheadOf(associations_.back().sequence_number,
                      associations_.front().sequence_number));
@@ -79,6 +80,20 @@
                      associations_.front().sequence_number));
 }
 
+void RtpSequenceNumberMap::InsertFrame(uint16_t first_sequence_number,
+                                       size_t packet_count,
+                                       uint32_t timestamp) {
+  RTC_DCHECK_GT(packet_count, 0);
+  RTC_DCHECK_LE(packet_count, std::numeric_limits<size_t>::max());
+
+  for (size_t i = 0; i < packet_count; ++i) {
+    const bool is_first = (i == 0);
+    const bool is_last = (i == packet_count - 1);
+    InsertPacket(static_cast<uint16_t>(first_sequence_number + i),
+                 Info(timestamp, is_first, is_last));
+  }
+}
+
 absl::optional<RtpSequenceNumberMap::Info> RtpSequenceNumberMap::Get(
     uint16_t sequence_number) const {
   // To make the binary search easier to understand, we use the fact that
diff --git a/modules/rtp_rtcp/source/rtp_sequence_number_map.h b/modules/rtp_rtcp/source/rtp_sequence_number_map.h
index 1f6a304..68fcc63 100644
--- a/modules/rtp_rtcp/source/rtp_sequence_number_map.h
+++ b/modules/rtp_rtcp/source/rtp_sequence_number_map.h
@@ -53,7 +53,10 @@
   RtpSequenceNumberMap& operator=(const RtpSequenceNumberMap& other) = delete;
   ~RtpSequenceNumberMap();
 
-  void Insert(uint16_t sequence_number, Info info);
+  void InsertPacket(uint16_t sequence_number, Info info);
+  void InsertFrame(uint16_t first_sequence_number,
+                   size_t packet_count,
+                   uint32_t timestamp);
 
   absl::optional<Info> Get(uint16_t sequence_number) const;
 
diff --git a/modules/rtp_rtcp/source/rtp_sequence_number_map_unittest.cc b/modules/rtp_rtcp/source/rtp_sequence_number_map_unittest.cc
index 5cb9d73..e371a3e 100644
--- a/modules/rtp_rtcp/source/rtp_sequence_number_map_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_sequence_number_map_unittest.cc
@@ -147,7 +147,7 @@
 
   constexpr uint16_t kKnownSequenceNumber = 10;
   constexpr uint32_t kArbitrary = 987;
-  uut.Insert(kKnownSequenceNumber, {kArbitrary, false, false});
+  uut.InsertPacket(kKnownSequenceNumber, {kArbitrary, false, false});
 
   constexpr uint16_t kUnknownSequenceNumber = kKnownSequenceNumber + 1;
   EXPECT_FALSE(uut.Get(kUnknownSequenceNumber));
@@ -161,7 +161,7 @@
   const std::vector<Association> setup = {CreateAssociation(1000, 500),  //
                                           CreateAssociation(1020, 501)};
   for (const Association& association : setup) {
-    uut.Insert(association.sequence_number, association.info);
+    uut.InsertPacket(association.sequence_number, association.info);
   }
 
   EXPECT_FALSE(uut.Get(1001));
@@ -179,12 +179,57 @@
                                        /*allow_obsoletion=*/false);
 
   for (const Association& association : associations) {
-    uut.Insert(association.sequence_number, association.info);
+    uut.InsertPacket(association.sequence_number, association.info);
   }
 
   VerifyAssociations(uut, associations);
 }
 
+TEST_F(RtpSequenceNumberMapTest, InsertFrameOnSinglePacketFrame) {
+  RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
+
+  constexpr uint16_t kSequenceNumber = 888;
+  constexpr uint32_t kTimestamp = 98765;
+  uut.InsertFrame(kSequenceNumber, 1, kTimestamp);
+
+  EXPECT_EQ(uut.Get(kSequenceNumber), Info(kTimestamp, true, true));
+}
+
+TEST_F(RtpSequenceNumberMapTest, InsertFrameOnMultiPacketFrameNoWrapAround) {
+  RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
+
+  constexpr uint16_t kFirstSequenceNumber = 0;
+  constexpr uint32_t kTimestamp = 98765;
+  uut.InsertFrame(kFirstSequenceNumber, 3, kTimestamp);
+
+  EXPECT_EQ(uut.Get(kFirstSequenceNumber + 0), Info(kTimestamp, true, false));
+  EXPECT_EQ(uut.Get(kFirstSequenceNumber + 1), Info(kTimestamp, false, false));
+  EXPECT_EQ(uut.Get(kFirstSequenceNumber + 2), Info(kTimestamp, false, true));
+}
+
+TEST_F(RtpSequenceNumberMapTest, InsertFrameOnMultiPacketFrameWithWrapAround) {
+  RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
+
+  constexpr uint16_t kFirstSequenceNumber = kUint16Max;
+  constexpr uint32_t kTimestamp = 98765;
+  uut.InsertFrame(kFirstSequenceNumber, 3, kTimestamp);
+
+// Suppress "truncation of constant value" warning; wrap-around is intended.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4309)
+#endif
+  EXPECT_EQ(uut.Get(static_cast<uint16_t>(kFirstSequenceNumber + 0u)),
+            Info(kTimestamp, true, false));
+  EXPECT_EQ(uut.Get(static_cast<uint16_t>(kFirstSequenceNumber + 1u)),
+            Info(kTimestamp, false, false));
+  EXPECT_EQ(uut.Get(static_cast<uint16_t>(kFirstSequenceNumber + 2u)),
+            Info(kTimestamp, false, true));
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+}
+
 TEST_F(RtpSequenceNumberMapTest,
        GetObsoleteSequenceNumberReturnsNullOptSingleValueObsoleted) {
   RtpSequenceNumberMap uut(kMaxPossibleMaxEntries);
@@ -194,18 +239,18 @@
       CreateAssociation(0x8000, 20),  //
       CreateAssociation(0x8001u, 30)};
 
-  uut.Insert(associations[0].sequence_number, associations[0].info);
+  uut.InsertPacket(associations[0].sequence_number, associations[0].info);
 
   // First association not yet obsolete, and therefore remembered.
   RTC_DCHECK(AheadOf(associations[1].sequence_number,
                      associations[0].sequence_number));
-  uut.Insert(associations[1].sequence_number, associations[1].info);
+  uut.InsertPacket(associations[1].sequence_number, associations[1].info);
   VerifyAssociations(uut, {associations[0], associations[1]});
 
   // Test focus - new entry obsoletes first entry.
   RTC_DCHECK(!AheadOf(associations[2].sequence_number,
                       associations[0].sequence_number));
-  uut.Insert(associations[2].sequence_number, associations[2].info);
+  uut.InsertPacket(associations[2].sequence_number, associations[2].info);
   VerifyAssociations(uut, {associations[1], associations[2]});
 }
 
@@ -231,7 +276,7 @@
   }
 
   for (auto association : associations) {
-    uut.Insert(association.sequence_number, association.info);
+    uut.InsertPacket(association.sequence_number, association.info);
   }
   VerifyAssociations(uut, associations);
 
@@ -261,7 +306,7 @@
   // Record the new association.
   const Association new_association =
       CreateAssociation(new_sequence_number, 60);
-  uut.Insert(new_association.sequence_number, new_association.info);
+  uut.InsertPacket(new_association.sequence_number, new_association.info);
 
   // Make sure all obsoleted elements were removed.
   const size_t obsoleted_count =
@@ -320,12 +365,12 @@
                                           CreateAssociation(102, 502)};
   RTC_DCHECK_LT(index_of_repeated, setup.size());
   for (const Association& association : setup) {
-    uut.Insert(association.sequence_number, association.info);
+    uut.InsertPacket(association.sequence_number, association.info);
   }
 
   const Association new_association =
       CreateAssociation(setup[index_of_repeated].sequence_number, 503);
-  uut.Insert(new_association.sequence_number, new_association.info);
+  uut.InsertPacket(new_association.sequence_number, new_association.info);
 
   // All entries from setup invalidated.
   // New entry valid and mapped to new value.
@@ -361,11 +406,11 @@
                                           CreateAssociation(1020, 501),  //
                                           CreateAssociation(1030, 502)};
   for (const Association& association : setup) {
-    uut.Insert(association.sequence_number, association.info);
+    uut.InsertPacket(association.sequence_number, association.info);
   }
 
   const Association new_association = CreateAssociation(1010, 503);
-  uut.Insert(new_association.sequence_number, new_association.info);
+  uut.InsertPacket(new_association.sequence_number, new_association.info);
 
   // All entries from setup invalidated.
   // New entry valid and mapped to new value.
@@ -384,13 +429,13 @@
   uint32_t timestamp = 789;
   for (size_t i = 0; i < kMaxEntries; ++i) {
     associations.push_back(CreateAssociation(i, ++timestamp));
-    uut.Insert(associations[i].sequence_number, associations[i].info);
+    uut.InsertPacket(associations[i].sequence_number, associations[i].info);
   }
   VerifyAssociations(uut, associations);  // Sanity.
 
   const Association new_association =
       CreateAssociation(kMaxEntries, ++timestamp);
-  uut.Insert(new_association.sequence_number, new_association.info);
+  uut.InsertPacket(new_association.sequence_number, new_association.info);
   associations.push_back(new_association);
 
   // The +1 is for |new_association|.
@@ -410,7 +455,7 @@
   uint32_t timestamp = 789;
   for (size_t i = 0; i < max_entries; ++i) {
     associations.push_back(CreateAssociation(i, ++timestamp));
-    uut.Insert(associations[i].sequence_number, associations[i].info);
+    uut.InsertPacket(associations[i].sequence_number, associations[i].info);
   }
   VerifyAssociations(uut, associations);  // Sanity.
 
@@ -418,7 +463,7 @@
       static_cast<uint16_t>(obsoleted_count) + (1 << 15);
   const Association new_association =
       CreateAssociation(new_association_sequence_number, ++timestamp);
-  uut.Insert(new_association.sequence_number, new_association.info);
+  uut.InsertPacket(new_association.sequence_number, new_association.info);
   associations.push_back(new_association);
 
   // The +1 is for |new_association|.