Reland of Simplify and extend RtpHeaderExtensionMap (patchset #1 id:1 of https://codereview.webrtc.org/2484863007/ )

Reason for revert:
dependent project adjusted

Original issue's description:
> Revert of Simplify and extend RtpHeaderExtensionMap (patchset #12 id:260001 of https://codereview.webrtc.org/2452293004/ )
>
> Reason for revert:
> breaks downstream project
>
> Original issue's description:
> > Simplify and extend RtpHeaderExtensionMap
> > Add register functions for various codepaths.
> > Add initialize-list constructor to create usable const RtpHeaderExtensionMap
> > Optimize implementation for GetId/GetType.
> >
> > BUG=webrtc:1994
> >
> > Committed: https://crrev.com/d1d26fbeb37a69471a34004c6ac2d3fafde5d404
> > Cr-Commit-Position: refs/heads/master@{#14986}
>
> TBR=sprang@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:1994
>
> Committed: https://crrev.com/bc38b4d450a80bf45efbe5b0a452e0374cdae1e6
> Cr-Commit-Position: refs/heads/master@{#14988}

TBR=sprang@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=webrtc:1994

Review-Url: https://codereview.webrtc.org/2492443002
Cr-Commit-Position: refs/heads/master@{#15000}
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
index 7fdff34..b7c7306 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
@@ -8,148 +8,143 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include <assert.h>
-
-#include "webrtc/base/checks.h"
-#include "webrtc/common_types.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
+
+#include "webrtc/base/arraysize.h"
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
 
 namespace webrtc {
+namespace {
 
+using RtpUtility::Word32Align;
+
+struct ExtensionInfo {
+  RTPExtensionType type;
+  size_t value_size;
+  const char* uri;
+};
+
+template <typename Extension>
+constexpr ExtensionInfo CreateExtensionInfo() {
+  return {Extension::kId, Extension::kValueSizeBytes, Extension::kUri};
+}
+
+constexpr ExtensionInfo kExtensions[] = {
+    CreateExtensionInfo<TransmissionOffset>(),
+    CreateExtensionInfo<AudioLevel>(),
+    CreateExtensionInfo<AbsoluteSendTime>(),
+    CreateExtensionInfo<VideoOrientation>(),
+    CreateExtensionInfo<TransportSequenceNumber>(),
+    CreateExtensionInfo<PlayoutDelayLimits>(),
+};
+
+// Because of kRtpExtensionNone, NumberOfExtension is 1 bigger than the actual
+// number of known extensions.
+static_assert(arraysize(kExtensions) ==
+                  static_cast<int>(kRtpExtensionNumberOfExtensions) - 1,
+              "kExtensions expect to list all known extensions");
+
+size_t ValueSize(RTPExtensionType type) {
+  for (const ExtensionInfo& extension : kExtensions)
+    if (type == extension.type)
+      return extension.value_size;
+
+  RTC_NOTREACHED();
+  return 0;
+}
+
+}  // namespace
+
+constexpr RTPExtensionType RtpHeaderExtensionMap::kInvalidType;
 constexpr uint8_t RtpHeaderExtensionMap::kInvalidId;
+constexpr uint8_t RtpHeaderExtensionMap::kMinId;
+constexpr uint8_t RtpHeaderExtensionMap::kMaxId;
 
 RtpHeaderExtensionMap::RtpHeaderExtensionMap() {
+  total_values_size_bytes_ = 0;
+  for (auto& type : types_)
+    type = kInvalidType;
+  for (auto& id : ids_)
+    id = kInvalidId;
 }
 
-RtpHeaderExtensionMap::~RtpHeaderExtensionMap() {
-  Erase();
+RtpHeaderExtensionMap::RtpHeaderExtensionMap(
+    std::initializer_list<RtpExtension> extensions)
+    : RtpHeaderExtensionMap() {
+  for (const RtpExtension& extension : extensions)
+    RegisterByUri(extension.id, extension.uri);
 }
 
-void RtpHeaderExtensionMap::Erase() {
-  while (!extensionMap_.empty()) {
-    std::map<uint8_t, HeaderExtension*>::iterator it =
-        extensionMap_.begin();
-    delete it->second;
-    extensionMap_.erase(it);
-  }
-}
-
-int32_t RtpHeaderExtensionMap::Register(RTPExtensionType type, uint8_t id) {
-  if (id < 1 || id > 14) {
-    return -1;
-  }
-  std::map<uint8_t, HeaderExtension*>::iterator it =
-      extensionMap_.find(id);
-  if (it != extensionMap_.end()) {
-    if (it->second->type != type) {
-      // An extension is already registered with the same id
-      // but a different type, so return failure.
-      return -1;
-    }
-    // This extension type is already registered with this id,
-    // so return success.
-    return 0;
-  }
-  RTC_DCHECK_EQ(kInvalidId, GetId(type));
-  extensionMap_[id] = new HeaderExtension(type);
-  return 0;
-}
-
-int32_t RtpHeaderExtensionMap::Deregister(const RTPExtensionType type) {
-  uint8_t id;
-  if (GetId(type, &id) != 0) {
-    return 0;
-  }
-  std::map<uint8_t, HeaderExtension*>::iterator it =
-      extensionMap_.find(id);
-  assert(it != extensionMap_.end());
-  delete it->second;
-  extensionMap_.erase(it);
-  return 0;
-}
-
-bool RtpHeaderExtensionMap::IsRegistered(RTPExtensionType type) const {
-  std::map<uint8_t, HeaderExtension*>::const_iterator it =
-    extensionMap_.begin();
-  for (; it != extensionMap_.end(); ++it) {
-    if (it->second->type == type)
-      return true;
-  }
+bool RtpHeaderExtensionMap::RegisterByType(uint8_t id, RTPExtensionType type) {
+  for (const ExtensionInfo& extension : kExtensions)
+    if (type == extension.type)
+      return Register(id, extension.type, extension.value_size, extension.uri);
+  RTC_NOTREACHED();
   return false;
 }
 
-int32_t RtpHeaderExtensionMap::GetType(const uint8_t id,
-                                       RTPExtensionType* type) const {
-  assert(type);
-  std::map<uint8_t, HeaderExtension*>::const_iterator it =
-      extensionMap_.find(id);
-  if (it == extensionMap_.end()) {
-    return -1;
-  }
-  HeaderExtension* extension = it->second;
-  *type = extension->type;
-  return 0;
-}
-
-RTPExtensionType RtpHeaderExtensionMap::GetType(uint8_t id) const {
-  auto it = extensionMap_.find(id);
-  if (it == extensionMap_.end()) {
-    return kInvalidType;
-  }
-  return it->second->type;
-}
-
-int32_t RtpHeaderExtensionMap::GetId(const RTPExtensionType type,
-                                     uint8_t* id) const {
-  assert(id);
-  std::map<uint8_t, HeaderExtension*>::const_iterator it =
-      extensionMap_.begin();
-
-  while (it != extensionMap_.end()) {
-    HeaderExtension* extension = it->second;
-    if (extension->type == type) {
-      *id = it->first;
-      return 0;
-    }
-    it++;
-  }
-  return -1;
-}
-
-uint8_t RtpHeaderExtensionMap::GetId(RTPExtensionType type) const {
-  for (auto kv : extensionMap_) {
-    if (kv.second->type == type)
-      return kv.first;
-  }
-  return kInvalidId;
+bool RtpHeaderExtensionMap::RegisterByUri(uint8_t id, const std::string& uri) {
+  for (const ExtensionInfo& extension : kExtensions)
+    if (uri == extension.uri)
+      return Register(id, extension.type, extension.value_size, extension.uri);
+  LOG(LS_WARNING) << "Unknown extension uri:'" << uri
+                  << "', id: " << static_cast<int>(id) << '.';
+  return false;
 }
 
 size_t RtpHeaderExtensionMap::GetTotalLengthInBytes() const {
-  // Get length for each extension block.
-  size_t length = 0;
-  for (const auto& kv : extensionMap_)
-    length += kv.second->length;
-  // Add RTP extension header length.
-  if (length > 0)
-    length += kRtpOneByteHeaderLength;
-  // Pad up to nearest 32bit word.
-  length = RtpUtility::Word32Align(length);
-  return length;
+  if (total_values_size_bytes_ == 0)
+    return 0;
+  return Word32Align(kRtpOneByteHeaderLength + total_values_size_bytes_);
 }
 
-int32_t RtpHeaderExtensionMap::Size() const {
-  return extensionMap_.size();
-}
-
-void RtpHeaderExtensionMap::GetCopy(RtpHeaderExtensionMap* map) const {
-  assert(map);
-  std::map<uint8_t, HeaderExtension*>::const_iterator it =
-      extensionMap_.begin();
-  while (it != extensionMap_.end()) {
-    HeaderExtension* extension = it->second;
-    map->Register(extension->type, it->first);
-    it++;
+int32_t RtpHeaderExtensionMap::Deregister(RTPExtensionType type) {
+  if (IsRegistered(type)) {
+    uint8_t id = GetId(type);
+    total_values_size_bytes_ -= (ValueSize(type) + 1);
+    types_[id] = kInvalidType;
+    ids_[type] = kInvalidId;
   }
+  return 0;
 }
+
+bool RtpHeaderExtensionMap::Register(uint8_t id,
+                                     RTPExtensionType type,
+                                     size_t value_size,
+                                     const char* uri) {
+  RTC_DCHECK_GT(type, kRtpExtensionNone);
+  RTC_DCHECK_LT(type, kRtpExtensionNumberOfExtensions);
+  RTC_DCHECK_GE(value_size, 1U);
+  RTC_DCHECK_LE(value_size, 16U);
+
+  if (id < kMinId || id > kMaxId) {
+    LOG(LS_WARNING) << "Failed to register extension uri:'" << uri
+                    << "' with invalid id:" << static_cast<int>(id) << ".";
+    return false;
+  }
+
+  if (GetType(id) == type) {  // Same type/id pair already registered.
+    LOG(LS_VERBOSE) << "Reregistering extension uri:'" << uri
+                    << "', id:" << static_cast<int>(id);
+    return true;
+  }
+
+  if (GetType(id) != kInvalidType) {  // |id| used by another extension type.
+    LOG(LS_WARNING) << "Failed to register extension uri:'" << uri
+                    << "', id:" << static_cast<int>(id)
+                    << ". Id already in use by extension type "
+                    << static_cast<int>(GetType(id));
+    return false;
+  }
+  RTC_DCHECK(!IsRegistered(type));
+
+  types_[id] = type;
+  ids_[type] = id;
+  total_values_size_bytes_ += (value_size + 1);
+  return true;
+}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
index b053f7f..a8591c7 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
@@ -11,10 +11,13 @@
 #ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSION_H_
 #define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSION_H_
 
-#include <map>
+#include <initializer_list>
+#include <string>
 
+#include "webrtc/base/basictypes.h"
+#include "webrtc/base/checks.h"
+#include "webrtc/config.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "webrtc/typedefs.h"
 
 namespace webrtc {
 
@@ -35,74 +38,63 @@
 // Maximum playout delay value in milliseconds.
 const int kPlayoutDelayMaxMs = 40950;
 
-struct HeaderExtension {
-  explicit HeaderExtension(RTPExtensionType extension_type)
-      : type(extension_type), length(0) {
-    Init();
-  }
-
-  void Init() {
-    // TODO(solenberg): Create handler classes for header extensions so we can
-    // get rid of switches like these as well as handling code spread out all
-    // over.
-    switch (type) {
-      case kRtpExtensionTransmissionTimeOffset:
-        length = kTransmissionTimeOffsetLength;
-        break;
-      case kRtpExtensionAudioLevel:
-        length = kAudioLevelLength;
-        break;
-      case kRtpExtensionAbsoluteSendTime:
-        length = kAbsoluteSendTimeLength;
-        break;
-      case kRtpExtensionVideoRotation:
-        length = kVideoRotationLength;
-        break;
-      case kRtpExtensionTransportSequenceNumber:
-        length = kTransportSequenceNumberLength;
-        break;
-      case kRtpExtensionPlayoutDelay:
-        length = kPlayoutDelayLength;
-        break;
-      default:
-        assert(false);
-    }
-  }
-
-  const RTPExtensionType type;
-  uint8_t length;
-};
-
 class RtpHeaderExtensionMap {
  public:
   static constexpr RTPExtensionType kInvalidType = kRtpExtensionNone;
   static constexpr uint8_t kInvalidId = 0;
+
   RtpHeaderExtensionMap();
-  ~RtpHeaderExtensionMap();
+  RtpHeaderExtensionMap(std::initializer_list<RtpExtension>);
 
-  void Erase();
+  template <typename Extension>
+  bool Register(uint8_t id) {
+    return Register(id, Extension::kId, Extension::kValueSizeBytes,
+                    Extension::kUri);
+  }
+  bool RegisterByType(uint8_t id, RTPExtensionType type);
+  bool RegisterByUri(uint8_t id, const std::string& uri);
 
-  int32_t Register(RTPExtensionType type, uint8_t id);
-
-  int32_t Deregister(RTPExtensionType type);
-
-  bool IsRegistered(RTPExtensionType type) const;
-
-  int32_t GetType(uint8_t id, RTPExtensionType* type) const;
+  bool IsRegistered(RTPExtensionType type) const {
+    return GetId(type) != kInvalidId;
+  }
   // Return kInvalidType if not found.
-  RTPExtensionType GetType(uint8_t id) const;
-
-  int32_t GetId(const RTPExtensionType type, uint8_t* id) const;
+  RTPExtensionType GetType(uint8_t id) const {
+    RTC_DCHECK_GE(id, kMinId);
+    RTC_DCHECK_LE(id, kMaxId);
+    return types_[id];
+  }
   // Return kInvalidId if not found.
-  uint8_t GetId(RTPExtensionType type) const;
+  uint8_t GetId(RTPExtensionType type) const {
+    RTC_DCHECK_GT(type, kRtpExtensionNone);
+    RTC_DCHECK_LT(type, kRtpExtensionNumberOfExtensions);
+    return ids_[type];
+  }
+
   size_t GetTotalLengthInBytes() const;
 
-  void GetCopy(RtpHeaderExtensionMap* map) const;
-
-  int32_t Size() const;
+  // TODO(danilchap): Remove use of the functions below.
+  void Erase() { *this = RtpHeaderExtensionMap(); }
+  int32_t Register(RTPExtensionType type, uint8_t id) {
+    return RegisterByType(id, type) ? 0 : -1;
+  }
+  int32_t Deregister(RTPExtensionType type);
+  int32_t GetType(uint8_t id, RTPExtensionType* type) const {
+    *type = GetType(id);
+    return *type == kInvalidType ? -1 : 0;
+  }
+  void GetCopy(RtpHeaderExtensionMap* copy) const { *copy = *this; }
 
  private:
-  std::map<uint8_t, HeaderExtension*> extensionMap_;
+  static constexpr uint8_t kMinId = 1;
+  static constexpr uint8_t kMaxId = 14;
+  bool Register(uint8_t id,
+                RTPExtensionType type,
+                size_t value_size,
+                const char* uri);
+
+  size_t total_values_size_bytes_ = 0;
+  RTPExtensionType types_[kMaxId + 1];
+  uint8_t ids_[kRtpExtensionNumberOfExtensions];
 };
 }  // namespace webrtc
 
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extension_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_header_extension_unittest.cc
index 50a913e..3794e83 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_header_extension_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extension_unittest.cc
@@ -10,87 +10,99 @@
 
 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "webrtc/test/gtest.h"
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
 
-class RtpHeaderExtensionTest : public ::testing::Test {
- protected:
-  RtpHeaderExtensionTest() {}
-  ~RtpHeaderExtensionTest() {}
+TEST(RtpHeaderExtensionTest, RegisterByType) {
+  RtpHeaderExtensionMap map;
+  EXPECT_FALSE(map.IsRegistered(TransmissionOffset::kId));
 
-  RtpHeaderExtensionMap map_;
-  static const uint8_t kId;
-};
+  EXPECT_TRUE(map.RegisterByType(3, TransmissionOffset::kId));
 
-const uint8_t RtpHeaderExtensionTest::kId = 3;
-
-TEST_F(RtpHeaderExtensionTest, Register) {
-  EXPECT_EQ(0, map_.Size());
-  EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
-  EXPECT_TRUE(map_.IsRegistered(kRtpExtensionTransmissionTimeOffset));
-  EXPECT_EQ(1, map_.Size());
-  EXPECT_EQ(0, map_.Deregister(kRtpExtensionTransmissionTimeOffset));
-  EXPECT_EQ(0, map_.Size());
+  EXPECT_TRUE(map.IsRegistered(TransmissionOffset::kId));
+  EXPECT_EQ(3, map.GetId(TransmissionOffset::kId));
+  EXPECT_EQ(TransmissionOffset::kId, map.GetType(3));
 }
 
-TEST_F(RtpHeaderExtensionTest, RegisterIllegalArg) {
+TEST(RtpHeaderExtensionTest, RegisterByUri) {
+  RtpHeaderExtensionMap map;
+
+  EXPECT_TRUE(map.RegisterByUri(3, TransmissionOffset::kUri));
+
+  EXPECT_TRUE(map.IsRegistered(TransmissionOffset::kId));
+  EXPECT_EQ(3, map.GetId(TransmissionOffset::kId));
+  EXPECT_EQ(TransmissionOffset::kId, map.GetType(3));
+}
+
+TEST(RtpHeaderExtensionTest, RegisterWithTrait) {
+  RtpHeaderExtensionMap map;
+
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+
+  EXPECT_TRUE(map.IsRegistered(TransmissionOffset::kId));
+  EXPECT_EQ(3, map.GetId(TransmissionOffset::kId));
+  EXPECT_EQ(TransmissionOffset::kId, map.GetType(3));
+}
+
+TEST(RtpHeaderExtensionTest, RegisterDuringContruction) {
+  const RtpHeaderExtensionMap map = {{TransmissionOffset::kUri, 1},
+                                     {AbsoluteSendTime::kUri, 3}};
+
+  EXPECT_EQ(1, map.GetId(TransmissionOffset::kId));
+  EXPECT_EQ(3, map.GetId(AbsoluteSendTime::kId));
+}
+
+TEST(RtpHeaderExtensionTest, RegisterIllegalArg) {
+  RtpHeaderExtensionMap map;
   // Valid range for id: [1-14].
-  EXPECT_EQ(-1, map_.Register(kRtpExtensionTransmissionTimeOffset, 0));
-  EXPECT_EQ(-1, map_.Register(kRtpExtensionTransmissionTimeOffset, 15));
+  EXPECT_FALSE(map.Register<TransmissionOffset>(0));
+  EXPECT_FALSE(map.Register<TransmissionOffset>(15));
 }
 
-TEST_F(RtpHeaderExtensionTest, Idempotent) {
-  EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
-  EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
-  EXPECT_EQ(0, map_.Deregister(kRtpExtensionTransmissionTimeOffset));
-  EXPECT_EQ(0, map_.Deregister(kRtpExtensionTransmissionTimeOffset));
+TEST(RtpHeaderExtensionTest, Idempotent) {
+  RtpHeaderExtensionMap map;
+
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+
+  map.Deregister(TransmissionOffset::kId);
+  map.Deregister(TransmissionOffset::kId);
 }
 
-TEST_F(RtpHeaderExtensionTest, NonUniqueId) {
-  EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
-  EXPECT_EQ(-1, map_.Register(kRtpExtensionAudioLevel, kId));
+TEST(RtpHeaderExtensionTest, NonUniqueId) {
+  RtpHeaderExtensionMap map;
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+
+  EXPECT_FALSE(map.Register<AudioLevel>(3));
+  EXPECT_TRUE(map.Register<AudioLevel>(4));
 }
 
-TEST_F(RtpHeaderExtensionTest, GetTotalLength) {
-  EXPECT_EQ(0u, map_.GetTotalLengthInBytes());
-  EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
-  EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength,
-            map_.GetTotalLengthInBytes());
+TEST(RtpHeaderExtensionTest, GetTotalLength) {
+  RtpHeaderExtensionMap map;
+  EXPECT_EQ(0u, map.GetTotalLengthInBytes());
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+  EXPECT_EQ(kRtpOneByteHeaderLength + (TransmissionOffset::kValueSizeBytes + 1),
+            map.GetTotalLengthInBytes());
 }
 
-TEST_F(RtpHeaderExtensionTest, GetType) {
-  RTPExtensionType typeOut;
-  EXPECT_EQ(-1, map_.GetType(kId, &typeOut));
+TEST(RtpHeaderExtensionTest, GetType) {
+  RtpHeaderExtensionMap map;
+  EXPECT_EQ(RtpHeaderExtensionMap::kInvalidType, map.GetType(3));
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
 
-  EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
-  EXPECT_EQ(0, map_.GetType(kId, &typeOut));
-  EXPECT_EQ(kRtpExtensionTransmissionTimeOffset, typeOut);
+  EXPECT_EQ(TransmissionOffset::kId, map.GetType(3));
 }
 
-TEST_F(RtpHeaderExtensionTest, GetId) {
-  uint8_t idOut;
-  EXPECT_EQ(-1, map_.GetId(kRtpExtensionTransmissionTimeOffset, &idOut));
+TEST(RtpHeaderExtensionTest, GetId) {
+  RtpHeaderExtensionMap map;
+  EXPECT_EQ(RtpHeaderExtensionMap::kInvalidId,
+            map.GetId(TransmissionOffset::kId));
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
 
-  EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
-  EXPECT_EQ(0, map_.GetId(kRtpExtensionTransmissionTimeOffset, &idOut));
-  EXPECT_EQ(kId, idOut);
+  EXPECT_EQ(3, map.GetId(TransmissionOffset::kId));
 }
 
-TEST_F(RtpHeaderExtensionTest, GetCopy) {
-  EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
-
-  RtpHeaderExtensionMap mapOut;
-  map_.GetCopy(&mapOut);
-  EXPECT_EQ(1, mapOut.Size());
-  EXPECT_EQ(kId, mapOut.GetId(kRtpExtensionTransmissionTimeOffset));
-}
-
-TEST_F(RtpHeaderExtensionTest, Erase) {
-  EXPECT_EQ(0, map_.Register(kRtpExtensionTransmissionTimeOffset, kId));
-  EXPECT_EQ(1, map_.Size());
-  map_.Erase();
-  EXPECT_EQ(0, map_.Size());
-}
 }  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
index 1356069..167f29e 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
@@ -33,8 +33,7 @@
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType AbsoluteSendTime::kId;
 constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
-const char* const AbsoluteSendTime::kUri =
-    "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
+constexpr const char* AbsoluteSendTime::kUri;
 
 bool AbsoluteSendTime::Parse(const uint8_t* data, uint32_t* time_24bits) {
   *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data);
@@ -60,8 +59,7 @@
 //
 constexpr RTPExtensionType AudioLevel::kId;
 constexpr uint8_t AudioLevel::kValueSizeBytes;
-const char* const AudioLevel::kUri =
-    "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
+constexpr const char* AudioLevel::kUri;
 
 bool AudioLevel::Parse(const uint8_t* data,
                        bool* voice_activity,
@@ -97,8 +95,7 @@
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType TransmissionOffset::kId;
 constexpr uint8_t TransmissionOffset::kValueSizeBytes;
-const char* const TransmissionOffset::kUri =
-    "urn:ietf:params:rtp-hdrext:toffset";
+constexpr const char* TransmissionOffset::kUri;
 
 bool TransmissionOffset::Parse(const uint8_t* data, int32_t* rtp_time) {
   *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data);
@@ -118,8 +115,7 @@
 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType TransportSequenceNumber::kId;
 constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
-const char* const TransportSequenceNumber::kUri =
-    "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions";
+constexpr const char* TransportSequenceNumber::kUri;
 
 bool TransportSequenceNumber::Parse(const uint8_t* data, uint16_t* value) {
   *value = ByteReader<uint16_t>::ReadBigEndian(data);
@@ -144,7 +140,7 @@
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType VideoOrientation::kId;
 constexpr uint8_t VideoOrientation::kValueSizeBytes;
-const char* const VideoOrientation::kUri = "urn:3gpp:video-orientation";
+constexpr const char* VideoOrientation::kUri;
 
 bool VideoOrientation::Parse(const uint8_t* data, VideoRotation* rotation) {
   *rotation = ConvertCVOByteToVideoRotation(data[0]);
@@ -173,8 +169,7 @@
 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType PlayoutDelayLimits::kId;
 constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
-const char* const PlayoutDelayLimits::kUri =
-    "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay";
+constexpr const char* PlayoutDelayLimits::kUri;
 
 bool PlayoutDelayLimits::Parse(const uint8_t* data,
                                PlayoutDelay* playout_delay) {
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
index b685023..afe47e5 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -20,7 +20,8 @@
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionAbsoluteSendTime;
   static constexpr uint8_t kValueSizeBytes = 3;
-  static const char* const kUri;
+  static constexpr const char* kUri =
+      "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
 
   static bool Parse(const uint8_t* data, uint32_t* time_24bits);
   static bool Write(uint8_t* data, int64_t time_ms);
@@ -34,7 +35,8 @@
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionAudioLevel;
   static constexpr uint8_t kValueSizeBytes = 1;
-  static const char* const kUri;
+  static constexpr const char* kUri =
+      "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
 
   static bool Parse(const uint8_t* data,
                     bool* voice_activity,
@@ -46,7 +48,7 @@
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionTransmissionTimeOffset;
   static constexpr uint8_t kValueSizeBytes = 3;
-  static const char* const kUri;
+  static constexpr const char* kUri = "urn:ietf:params:rtp-hdrext:toffset";
 
   static bool Parse(const uint8_t* data, int32_t* rtp_time);
   static bool Write(uint8_t* data, int32_t rtp_time);
@@ -56,8 +58,9 @@
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionTransportSequenceNumber;
   static constexpr uint8_t kValueSizeBytes = 2;
-  static const char* const kUri;
-
+  static constexpr const char* kUri =
+      "http://www.ietf.org/id/"
+      "draft-holmer-rmcat-transport-wide-cc-extensions-01";
   static bool Parse(const uint8_t* data, uint16_t* value);
   static bool Write(uint8_t* data, uint16_t value);
 };
@@ -66,7 +69,7 @@
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionVideoRotation;
   static constexpr uint8_t kValueSizeBytes = 1;
-  static const char* const kUri;
+  static constexpr const char* kUri = "urn:3gpp:video-orientation";
 
   static bool Parse(const uint8_t* data, VideoRotation* value);
   static bool Write(uint8_t* data, VideoRotation value);
@@ -78,7 +81,8 @@
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionPlayoutDelay;
   static constexpr uint8_t kValueSizeBytes = 3;
-  static const char* const kUri;
+  static constexpr const char* kUri =
+      "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay";
 
   // Playout delay in milliseconds. A playout delay limit (min or max)
   // has 12 bits allocated. This allows a range of 0-4095 values which