Add write support for the RtpStreamId and RepairedRtpStreamId header extensions.

BUG=webrtc:7433

Review-Url: https://codereview.webrtc.org/2871813003
Cr-Commit-Position: refs/heads/master@{#18093}
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
index 13f488b..ba512ef 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
@@ -257,6 +257,13 @@
   return true;
 }
 
+bool RtpStreamId::Write(uint8_t* data, const StreamId& rsid) {
+  RTC_DCHECK_GE(rsid.size(), 1);
+  RTC_DCHECK_LE(rsid.size(), StreamId::kMaxSize);
+  memcpy(data, rsid.data(), rsid.size());
+  return true;
+}
+
 bool RtpStreamId::Parse(rtc::ArrayView<const uint8_t> data, std::string* rsid) {
   if (data.empty() || data[0] == 0)  // Valid rsid can't be empty.
     return false;
@@ -268,6 +275,13 @@
   return true;
 }
 
+bool RtpStreamId::Write(uint8_t* data, const std::string& rsid) {
+  RTC_DCHECK_GE(rsid.size(), 1);
+  RTC_DCHECK_LE(rsid.size(), StreamId::kMaxSize);
+  memcpy(data, rsid.data(), rsid.size());
+  return true;
+}
+
 // RepairedRtpStreamId.
 constexpr RTPExtensionType RepairedRtpStreamId::kId;
 constexpr uint8_t RepairedRtpStreamId::kValueSizeBytes;
@@ -279,9 +293,25 @@
   return RtpStreamId::Parse(data, rsid);
 }
 
+size_t RepairedRtpStreamId::ValueSize(const StreamId& rsid) {
+  return RtpStreamId::ValueSize(rsid);
+}
+
+bool RepairedRtpStreamId::Write(uint8_t* data, const StreamId& rsid) {
+  return RtpStreamId::Write(data, rsid);
+}
+
 bool RepairedRtpStreamId::Parse(rtc::ArrayView<const uint8_t> data,
                                 std::string* rsid) {
   return RtpStreamId::Parse(data, rsid);
 }
 
+size_t RepairedRtpStreamId::ValueSize(const std::string& rsid) {
+  return RtpStreamId::ValueSize(rsid);
+}
+
+bool RepairedRtpStreamId::Write(uint8_t* data, const std::string& rsid) {
+  return RtpStreamId::Write(data, rsid);
+}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
index c60f290..df68b21 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -28,6 +28,7 @@
       "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
 
   static bool Parse(rtc::ArrayView<const uint8_t> data, uint32_t* time_24bits);
+  static size_t ValueSize(int64_t time_ms) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, int64_t time_ms);
 
   static constexpr uint32_t MsTo24Bits(int64_t time_ms) {
@@ -45,6 +46,9 @@
   static bool Parse(rtc::ArrayView<const uint8_t> data,
                     bool* voice_activity,
                     uint8_t* audio_level);
+  static size_t ValueSize(bool voice_activity, uint8_t audio_level) {
+    return kValueSizeBytes;
+  }
   static bool Write(uint8_t* data, bool voice_activity, uint8_t audio_level);
 };
 
@@ -55,6 +59,7 @@
   static constexpr const char* kUri = "urn:ietf:params:rtp-hdrext:toffset";
 
   static bool Parse(rtc::ArrayView<const uint8_t> data, int32_t* rtp_time);
+  static size_t ValueSize(int32_t rtp_time) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, int32_t rtp_time);
 };
 
@@ -66,6 +71,7 @@
       "http://www.ietf.org/id/"
       "draft-holmer-rmcat-transport-wide-cc-extensions-01";
   static bool Parse(rtc::ArrayView<const uint8_t> data, uint16_t* value);
+  static size_t ValueSize(uint16_t value) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, uint16_t value);
 };
 
@@ -76,8 +82,10 @@
   static constexpr const char* kUri = "urn:3gpp:video-orientation";
 
   static bool Parse(rtc::ArrayView<const uint8_t> data, VideoRotation* value);
+  static size_t ValueSize(VideoRotation) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, VideoRotation value);
   static bool Parse(rtc::ArrayView<const uint8_t> data, uint8_t* value);
+  static size_t ValueSize(uint8_t value) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, uint8_t value);
 };
 
@@ -97,6 +105,9 @@
 
   static bool Parse(rtc::ArrayView<const uint8_t> data,
                     PlayoutDelay* playout_delay);
+  static size_t ValueSize(const PlayoutDelay&) {
+    return kValueSizeBytes;
+  }
   static bool Write(uint8_t* data, const PlayoutDelay& playout_delay);
 };
 
@@ -109,6 +120,9 @@
 
   static bool Parse(rtc::ArrayView<const uint8_t> data,
                     VideoContentType* content_type);
+  static size_t ValueSize(VideoContentType) {
+    return kValueSizeBytes;
+  }
   static bool Write(uint8_t* data, VideoContentType content_type);
 };
 
@@ -121,8 +135,13 @@
   static constexpr const char* kUri =
       "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
 
-  static bool Parse(rtc::ArrayView<const uint8_t> data, StreamId* rid);
-  static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* rid);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, StreamId* rsid);
+  static size_t ValueSize(const StreamId& rsid) { return rsid.size(); }
+  static bool Write(uint8_t* data, const StreamId& rsid);
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* rsid);
+  static size_t ValueSize(const std::string& rsid) { return rsid.size(); }
+  static bool Write(uint8_t* data, const std::string& rsid);
 };
 
 class RepairedRtpStreamId {
@@ -134,8 +153,13 @@
   static constexpr const char* kUri =
       "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id";
 
-  static bool Parse(rtc::ArrayView<const uint8_t> data, StreamId* rid);
-  static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* rid);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, StreamId* rsid);
+  static size_t ValueSize(const StreamId& rsid);
+  static bool Write(uint8_t* data, const StreamId& rsid);
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* rsid);
+  static size_t ValueSize(const std::string& rsid);
+  static bool Write(uint8_t* data, const std::string& rsid);
 };
 
 }  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet.h b/webrtc/modules/rtp_rtcp/source/rtp_packet.h
index ca189db..0901fc2 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_packet.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet.h
@@ -183,7 +183,10 @@
 
 template <typename Extension, typename... Values>
 bool Packet::SetExtension(Values... values) {
-  auto buffer = AllocateExtension(Extension::kId, Extension::kValueSizeBytes);
+  const size_t value_size = Extension::ValueSize(values...);
+  if (value_size == 0 || value_size > 16)
+    return false;
+  auto buffer = AllocateExtension(Extension::kId, value_size);
   if (buffer.empty())
     return false;
   return Extension::Write(buffer.data(), values...);
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
index bbe4080..001f06f 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
@@ -28,15 +28,18 @@
 constexpr uint32_t kTimestamp = 0x65431278;
 constexpr uint8_t kTransmissionOffsetExtensionId = 1;
 constexpr uint8_t kAudioLevelExtensionId = 9;
+constexpr uint8_t kRtpStreamIdExtensionId = 0xa;
 constexpr int32_t kTimeOffset = 0x56ce;
 constexpr bool kVoiceActive = true;
 constexpr uint8_t kAudioLevel = 0x5a;
+constexpr char kStreamId[] = "streamid";
 constexpr size_t kMaxPaddingSize = 224u;
 // clang-format off
 constexpr uint8_t kMinimumPacket[] = {
     0x80, kPayloadType, 0x00, kSeqNum,
     0x65, 0x43, 0x12, 0x78,
     0x12, 0x34, 0x56, 0x78};
+
 constexpr uint8_t kPacketWithTO[] = {
     0x90, kPayloadType, 0x00, kSeqNum,
     0x65, 0x43, 0x12, 0x78,
@@ -52,6 +55,15 @@
     0x12, 0x00, 0x56, 0xce,
     0x90, 0x80|kAudioLevel, 0x00, 0x00};
 
+constexpr uint8_t kPacketWithRsid[] = {
+    0x90, kPayloadType, 0x00, kSeqNum,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0xbe, 0xde, 0x00, 0x03,
+    0xa7, 's',  't',  'r',
+    'e',  'a',  'm',  'i',
+    'd' , 0x00, 0x00, 0x00};
+
 constexpr uint32_t kCsrcs[] = {0x34567890, 0x32435465};
 constexpr uint8_t kPayload[] = {'p', 'a', 'y', 'l', 'o', 'a', 'd'};
 constexpr uint8_t kPacketPaddingSize = 8;
@@ -117,6 +129,34 @@
               ElementsAreArray(packet.data(), packet.size()));
 }
 
+TEST(RtpPacketTest, CreateWithDynamicSizedExtensions) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  packet.SetExtension<RtpStreamId>(kStreamId);
+  EXPECT_THAT(kPacketWithRsid, ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, TryToCreateWithEmptyRsid) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  EXPECT_FALSE(packet.SetExtension<RtpStreamId>(""));
+}
+
+TEST(RtpPacketTest, TryToCreateWithLongRsid) {
+  RtpPacketToSend::ExtensionManager extensions;
+  constexpr char kLongStreamId[] = "LoooooooooongRsid";
+  ASSERT_EQ(strlen(kLongStreamId), 17u);
+  extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  EXPECT_FALSE(packet.SetExtension<RtpStreamId>(kLongStreamId));
+}
+
 TEST(RtpPacketTest, CreateWithExtensionsWithoutManager) {
   RtpPacketToSend packet(nullptr);
   packet.SetPayloadType(kPayloadType);