Enable padding bit in TransportFeedback packets

Set padding bit if the TransportFeedback packet contains zero padding.
Also write number of padding elements at the last position of the packet.

Bug: webrtc:10263
Change-Id: I8d17bc0e889f658ac383dec64ddcb95d438c9702
Reviewed-on: https://webrtc-review.googlesource.com/c/122240
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Johannes Kron <kron@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26646}
diff --git a/modules/rtp_rtcp/source/rtcp_packet.cc b/modules/rtp_rtcp/source/rtcp_packet.cc
index 194b992..bac03e7 100644
--- a/modules/rtp_rtcp/source/rtcp_packet.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet.cc
@@ -52,7 +52,8 @@
 size_t RtcpPacket::HeaderLength() const {
   size_t length_in_bytes = BlockLength();
   RTC_DCHECK_GT(length_in_bytes, 0);
-  RTC_DCHECK_EQ(length_in_bytes % 4, 0) << "Padding not supported";
+  RTC_DCHECK_EQ(length_in_bytes % 4, 0)
+      << "Padding must be handled by each subclass.";
   // Length in 32-bit words without common header.
   return (length_in_bytes - kHeaderLength) / 4;
 }
@@ -71,12 +72,23 @@
     size_t length,
     uint8_t* buffer,
     size_t* pos) {
+  CreateHeader(count_or_format, packet_type, length, /*padding=*/false, buffer,
+               pos);
+}
+
+void RtcpPacket::CreateHeader(
+    size_t count_or_format,  // Depends on packet type.
+    uint8_t packet_type,
+    size_t length,
+    bool padding,
+    uint8_t* buffer,
+    size_t* pos) {
   RTC_DCHECK_LE(length, 0xffffU);
   RTC_DCHECK_LE(count_or_format, 0x1f);
   constexpr uint8_t kVersionBits = 2 << 6;
-  constexpr uint8_t kNoPaddingBit = 0 << 5;
+  uint8_t padding_bit = padding ? 1 << 5 : 0;
   buffer[*pos + 0] =
-      kVersionBits | kNoPaddingBit | static_cast<uint8_t>(count_or_format);
+      kVersionBits | padding_bit | static_cast<uint8_t>(count_or_format);
   buffer[*pos + 1] = packet_type;
   buffer[*pos + 2] = (length >> 8) & 0xff;
   buffer[*pos + 3] = length & 0xff;
diff --git a/modules/rtp_rtcp/source/rtcp_packet.h b/modules/rtp_rtcp/source/rtcp_packet.h
index 40e51e8..94bf9f0 100644
--- a/modules/rtp_rtcp/source/rtcp_packet.h
+++ b/modules/rtp_rtcp/source/rtcp_packet.h
@@ -87,6 +87,13 @@
                            uint8_t* buffer,
                            size_t* pos);
 
+  static void CreateHeader(size_t count_or_format,
+                           uint8_t packet_type,
+                           size_t block_length,  // Payload size in 32bit words.
+                           bool padding,  // True if there are padding bytes.
+                           uint8_t* buffer,
+                           size_t* pos);
+
   bool OnBufferFull(uint8_t* packet,
                     size_t* index,
                     PacketReadyCallback callback) const;
diff --git a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
index 2816559..81eda9e 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
@@ -521,6 +521,10 @@
   return (size_bytes_ + 3) & (~static_cast<size_t>(3));
 }
 
+size_t TransportFeedback::PaddingLength() const {
+  return BlockLength() - size_bytes_;
+}
+
 // Serialize packet.
 bool TransportFeedback::Create(uint8_t* packet,
                                size_t* position,
@@ -534,9 +538,10 @@
       return false;
   }
   const size_t position_end = *position + BlockLength();
-
-  CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
-               position);
+  const size_t padding_length = PaddingLength();
+  bool has_padding = padding_length > 0;
+  CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), has_padding,
+               packet, position);
   CreateCommonFeedback(packet + *position);
   *position += kCommonFeedbackLength;
 
@@ -571,9 +576,12 @@
     }
   }
 
-  while ((*position % 4) != 0)
-    packet[(*position)++] = 0;
-
+  if (padding_length > 0) {
+    for (size_t i = 0; i < padding_length - 1; ++i) {
+      packet[(*position)++] = 0;
+    }
+    packet[(*position)++] = padding_length;
+  }
   RTC_DCHECK_EQ(*position, position_end);
   return true;
 }
diff --git a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
index fbdc38e..b7bed9d 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
+++ b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
@@ -73,6 +73,7 @@
   bool IsConsistent() const;
 
   size_t BlockLength() const override;
+  size_t PaddingLength() const;
 
   bool Create(uint8_t* packet,
               size_t* position,
diff --git a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc
index 0496525..43eeeb9 100644
--- a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc
@@ -82,7 +82,7 @@
     feedback_ =
         TransportFeedback::ParseFrom(serialized_.data(), serialized_.size());
     ASSERT_TRUE(feedback_->IsConsistent());
-    ASSERT_NE(nullptr, feedback_.get());
+    ASSERT_NE(nullptr, feedback_);
     VerifyInternal();
   }
 
@@ -130,7 +130,7 @@
   rtc::Buffer serialized_;
 };
 
-TEST(RtcpPacketTest, TransportFeedback_OneBitVector) {
+TEST(RtcpPacketTest, TransportFeedbackOneBitVector) {
   const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13};
   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
   const size_t kExpectedSizeBytes =
@@ -142,7 +142,7 @@
   test.VerifyPacket();
 }
 
-TEST(RtcpPacketTest, TransportFeedback_FullOneBitVector) {
+TEST(RtcpPacketTest, TransportFeedbackFullOneBitVector) {
   const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13, 14};
   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
   const size_t kExpectedSizeBytes =
@@ -154,7 +154,7 @@
   test.VerifyPacket();
 }
 
-TEST(RtcpPacketTest, TransportFeedback_OneBitVector_WrapReceived) {
+TEST(RtcpPacketTest, TransportFeedbackOneBitVectorWrapReceived) {
   const uint16_t kMax = 0xFFFF;
   const uint16_t kReceived[] = {kMax - 2, kMax - 1, kMax, 0, 1, 2};
   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
@@ -167,7 +167,7 @@
   test.VerifyPacket();
 }
 
-TEST(RtcpPacketTest, TransportFeedback_OneBitVector_WrapMissing) {
+TEST(RtcpPacketTest, TransportFeedbackOneBitVectorWrapMissing) {
   const uint16_t kMax = 0xFFFF;
   const uint16_t kReceived[] = {kMax - 2, kMax - 1, 1, 2};
   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
@@ -180,7 +180,7 @@
   test.VerifyPacket();
 }
 
-TEST(RtcpPacketTest, TransportFeedback_TwoBitVector) {
+TEST(RtcpPacketTest, TransportFeedbackTwoBitVector) {
   const uint16_t kReceived[] = {1, 2, 6, 7};
   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
   const size_t kExpectedSizeBytes =
@@ -193,7 +193,7 @@
   test.VerifyPacket();
 }
 
-TEST(RtcpPacketTest, TransportFeedback_TwoBitVectorFull) {
+TEST(RtcpPacketTest, TransportFeedbackTwoBitVectorFull) {
   const uint16_t kReceived[] = {1, 2, 6, 7, 8};
   const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
   const size_t kExpectedSizeBytes =
@@ -206,7 +206,7 @@
   test.VerifyPacket();
 }
 
-TEST(RtcpPacketTest, TransportFeedback_LargeAndNegativeDeltas) {
+TEST(RtcpPacketTest, TransportFeedbackLargeAndNegativeDeltas) {
   const uint16_t kReceived[] = {1, 2, 6, 7, 8};
   const int64_t kReceiveTimes[] = {
       2000, 1000, 4000, 3000,
@@ -221,7 +221,7 @@
   test.VerifyPacket();
 }
 
-TEST(RtcpPacketTest, TransportFeedback_MaxRle) {
+TEST(RtcpPacketTest, TransportFeedbackMaxRle) {
   // Expected chunks created:
   // * 1-bit vector chunk (1xreceived + 13xdropped)
   // * RLE chunk of max length for dropped symbol
@@ -240,7 +240,7 @@
   test.VerifyPacket();
 }
 
-TEST(RtcpPacketTest, TransportFeedback_MinRle) {
+TEST(RtcpPacketTest, TransportFeedbackMinRle) {
   // Expected chunks created:
   // * 1-bit vector chunk (1xreceived + 13xdropped)
   // * RLE chunk of length 15 for dropped symbol
@@ -258,7 +258,7 @@
   test.VerifyPacket();
 }
 
-TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVector) {
+TEST(RtcpPacketTest, TransportFeedbackOneToTwoBitVector) {
   const size_t kTwoBitVectorCapacity = 7;
   const uint16_t kReceived[] = {0, kTwoBitVectorCapacity - 1};
   const int64_t kReceiveTimes[] = {
@@ -273,7 +273,7 @@
   test.VerifyPacket();
 }
 
-TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVectorSimpleSplit) {
+TEST(RtcpPacketTest, TransportFeedbackOneToTwoBitVectorSimpleSplit) {
   const size_t kTwoBitVectorCapacity = 7;
   const uint16_t kReceived[] = {0, kTwoBitVectorCapacity};
   const int64_t kReceiveTimes[] = {
@@ -288,7 +288,7 @@
   test.VerifyPacket();
 }
 
-TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVectorSplit) {
+TEST(RtcpPacketTest, TransportFeedbackOneToTwoBitVectorSplit) {
   // With received small delta = S, received large delta = L, use input
   // SSSSSSSSLSSSSSSSSSSSS. This will cause a 1:2 split at the L.
   // After split there will be two symbols in symbol_vec: SL.
@@ -316,7 +316,7 @@
   test.VerifyPacket();
 }
 
-TEST(RtcpPacketTest, TransportFeedback_Aliasing) {
+TEST(RtcpPacketTest, TransportFeedbackAliasing) {
   TransportFeedback feedback;
   feedback.SetBase(0, 0);
 
@@ -340,7 +340,7 @@
   }
 }
 
-TEST(RtcpPacketTest, TransportFeedback_Limits) {
+TEST(RtcpPacketTest, TransportFeedbackLimits) {
   // Sequence number wrap above 0x8000.
   std::unique_ptr<TransportFeedback> packet(new TransportFeedback());
   packet->SetBase(0, 0);
@@ -404,10 +404,12 @@
   // add back test for max size in bytes.
 }
 
-TEST(RtcpPacketTest, TransportFeedback_Padding) {
+TEST(RtcpPacketTest, TransportFeedbackPadding) {
   const size_t kExpectedSizeBytes =
       kHeaderSize + kStatusChunkSize + kSmallDeltaSize;
   const size_t kExpectedSizeWords = (kExpectedSizeBytes + 3) / 4;
+  const size_t kExpectedPaddingSizeBytes =
+      4 * kExpectedSizeWords - kExpectedSizeBytes;
 
   TransportFeedback feedback;
   feedback.SetBase(0, 0);
@@ -416,8 +418,10 @@
   rtc::Buffer packet = feedback.Build();
   EXPECT_EQ(kExpectedSizeWords * 4, packet.size());
   ASSERT_GT(kExpectedSizeWords * 4, kExpectedSizeBytes);
-  for (size_t i = kExpectedSizeBytes; i < kExpectedSizeWords * 4; ++i)
-    EXPECT_EQ(0u, packet.data()[i]);
+  for (size_t i = kExpectedSizeBytes; i < (kExpectedSizeWords * 4 - 1); ++i)
+    EXPECT_EQ(0u, packet[i]);
+
+  EXPECT_EQ(kExpectedPaddingSizeBytes, packet[kExpectedSizeWords * 4 - 1]);
 
   // Modify packet by adding 4 bytes of padding at the end. Not currently used
   // when we're sending, but need to be able to handle it when receiving.
@@ -428,7 +432,8 @@
   uint8_t mod_buffer[kExpectedSizeWithPadding];
   memcpy(mod_buffer, packet.data(), kExpectedSizeWords * 4);
   memset(&mod_buffer[kExpectedSizeWords * 4], 0, kPaddingBytes - 1);
-  mod_buffer[kExpectedSizeWithPadding - 1] = kPaddingBytes;
+  mod_buffer[kExpectedSizeWithPadding - 1] =
+      kPaddingBytes + kExpectedPaddingSizeBytes;
   const uint8_t padding_flag = 1 << 5;
   mod_buffer[0] |= padding_flag;
   ByteWriter<uint16_t>::WriteBigEndian(
@@ -437,11 +442,46 @@
 
   std::unique_ptr<TransportFeedback> parsed_packet(
       TransportFeedback::ParseFrom(mod_buffer, kExpectedSizeWithPadding));
-  ASSERT_TRUE(parsed_packet.get() != nullptr);
+  ASSERT_TRUE(parsed_packet != nullptr);
   EXPECT_EQ(kExpectedSizeWords * 4, packet.size());  // Padding not included.
 }
 
-TEST(RtcpPacketTest, TransportFeedback_CorrectlySplitsVectorChunks) {
+TEST(RtcpPacketTest, TransportFeedbackPaddingBackwardsCompatibility) {
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + kStatusChunkSize + kSmallDeltaSize;
+  const size_t kExpectedSizeWords = (kExpectedSizeBytes + 3) / 4;
+  const size_t kExpectedPaddingSizeBytes =
+      4 * kExpectedSizeWords - kExpectedSizeBytes;
+
+  TransportFeedback feedback;
+  feedback.SetBase(0, 0);
+  EXPECT_TRUE(feedback.AddReceivedPacket(0, 0));
+
+  rtc::Buffer packet = feedback.Build();
+  EXPECT_EQ(kExpectedSizeWords * 4, packet.size());
+  ASSERT_GT(kExpectedSizeWords * 4, kExpectedSizeBytes);
+  for (size_t i = kExpectedSizeBytes; i < (kExpectedSizeWords * 4 - 1); ++i)
+    EXPECT_EQ(0u, packet[i]);
+
+  EXPECT_GT(kExpectedPaddingSizeBytes, 0u);
+  EXPECT_EQ(kExpectedPaddingSizeBytes, packet[kExpectedSizeWords * 4 - 1]);
+
+  // Modify packet by removing padding bit and writing zero at the last padding
+  // byte to verify that we can parse packets from old clients, where zero
+  // padding of up to three bytes was used without the padding bit being set.
+  uint8_t mod_buffer[kExpectedSizeWords * 4];
+  memcpy(mod_buffer, packet.data(), kExpectedSizeWords * 4);
+  mod_buffer[kExpectedSizeWords * 4 - 1] = 0;
+  const uint8_t padding_flag = 1 << 5;
+  mod_buffer[0] &= ~padding_flag;  // Unset padding flag.
+
+  std::unique_ptr<TransportFeedback> parsed_packet(
+      TransportFeedback::ParseFrom(mod_buffer, kExpectedSizeWords * 4));
+  ASSERT_TRUE(parsed_packet != nullptr);
+  EXPECT_EQ(kExpectedSizeWords * 4, packet.size());
+}
+
+TEST(RtcpPacketTest, TransportFeedbackCorrectlySplitsVectorChunks) {
   const int kOneBitVectorCapacity = 14;
   const int64_t kLargeTimeDelta =
       TransportFeedback::kDeltaScaleFactor * (1 << 8);
@@ -460,11 +500,11 @@
     std::unique_ptr<TransportFeedback> deserialized_packet =
         TransportFeedback::ParseFrom(serialized_packet.data(),
                                      serialized_packet.size());
-    EXPECT_TRUE(deserialized_packet.get() != nullptr);
+    EXPECT_TRUE(deserialized_packet != nullptr);
   }
 }
 
-TEST(RtcpPacketTest, TransportFeedback_MoveConstructor) {
+TEST(RtcpPacketTest, TransportFeedbackMoveConstructor) {
   const int kSamples = 100;
   const int64_t kDelta = TransportFeedback::kDeltaScaleFactor;
   const uint16_t kBaseSeqNo = 7531;