Cherry-pick WebRTC 235826 change
https://bugs.webkit.org/show_bug.cgi?id=235510
<rdar://87884184>

Reviewed by Eric Carlson.

Cherry-picking above fixing for compliance.

* Source/webrtc/media/engine/webrtc_media_engine.cc:
* Source/webrtc/media/engine/webrtc_media_engine.h:
* Source/webrtc/media/engine/webrtc_media_engine_unittest.cc:
* Source/webrtc/media/engine/webrtc_video_engine.cc:
* Source/webrtc/media/engine/webrtc_video_engine.h:
* Source/webrtc/media/engine/webrtc_voice_engine.cc:
* Source/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map.cc:
* Source/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@288464 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/ThirdParty/libwebrtc/ChangeLog b/Source/ThirdParty/libwebrtc/ChangeLog
index 203e3f1..627bce1 100644
--- a/Source/ThirdParty/libwebrtc/ChangeLog
+++ b/Source/ThirdParty/libwebrtc/ChangeLog
@@ -1,5 +1,24 @@
 2022-01-24  Youenn Fablet  <youenn@apple.com>
 
+        Cherry-pick WebRTC 235826 change
+        https://bugs.webkit.org/show_bug.cgi?id=235510
+        <rdar://87884184>
+
+        Reviewed by Eric Carlson.
+
+        Cherry-picking above fixing for compliance.
+
+        * Source/webrtc/media/engine/webrtc_media_engine.cc:
+        * Source/webrtc/media/engine/webrtc_media_engine.h:
+        * Source/webrtc/media/engine/webrtc_media_engine_unittest.cc:
+        * Source/webrtc/media/engine/webrtc_video_engine.cc:
+        * Source/webrtc/media/engine/webrtc_video_engine.h:
+        * Source/webrtc/media/engine/webrtc_voice_engine.cc:
+        * Source/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map.cc:
+        * Source/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc:
+
+2022-01-24  Youenn Fablet  <youenn@apple.com>
+
         Reject large number of WebRTC audio channels
         https://bugs.webkit.org/show_bug.cgi?id=235511
 
diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_media_engine.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_media_engine.cc
index 6ce52e4..f083b9c 100644
--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_media_engine.cc
+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_media_engine.cc
@@ -10,6 +10,7 @@
 
 #include "media/engine/webrtc_media_engine.h"
 
+#include <map>
 #include <memory>
 #include <utility>
 
@@ -74,7 +75,8 @@
 }  // namespace
 
 bool ValidateRtpExtensions(
-    const std::vector<webrtc::RtpExtension>& extensions) {
+    rtc::ArrayView<const webrtc::RtpExtension> extensions,
+    rtc::ArrayView<const webrtc::RtpExtension> old_extensions) {
   bool id_used[1 + webrtc::RtpExtension::kMaxId] = {false};
   for (const auto& extension : extensions) {
     if (extension.id < webrtc::RtpExtension::kMinId ||
@@ -89,6 +91,45 @@
     }
     id_used[extension.id] = true;
   }
+  // Validate the extension list against the already negotiated extensions.
+  // Re-registering is OK, re-mapping (either same URL at new ID or same
+  // ID used with new URL) is an illegal remap.
+
+  // This is required in order to avoid a crash when registering an
+  // extension. A better structure would use the registered extensions
+  // in the RTPSender. This requires spinning through:
+  //
+  // WebRtcVoiceMediaChannel::::WebRtcAudioSendStream::stream_ (pointer)
+  // AudioSendStream::rtp_rtcp_module_ (pointer)
+  // ModuleRtpRtcpImpl2::rtp_sender_ (pointer)
+  // RtpSenderContext::packet_generator (struct member)
+  // RTPSender::rtp_header_extension_map_ (class member)
+  //
+  // Getting at this seems like a hard slog.
+  if (!old_extensions.empty()) {
+    absl::string_view urimap[1 + webrtc::RtpExtension::kMaxId];
+    std::map<absl::string_view, int> idmap;
+    for (const auto& old_extension : old_extensions) {
+      urimap[old_extension.id] = old_extension.uri;
+      idmap[old_extension.uri] = old_extension.id;
+    }
+    for (const auto& extension : extensions) {
+      if (!urimap[extension.id].empty() &&
+          urimap[extension.id] != extension.uri) {
+        RTC_LOG(LS_ERROR) << "Extension negotiation failure: " << extension.id
+                          << " was mapped to " << urimap[extension.id]
+                          << " but is proposed changed to " << extension.uri;
+        return false;
+      }
+      const auto& it = idmap.find(extension.uri);
+      if (it != idmap.end() && it->second != extension.id) {
+        RTC_LOG(LS_ERROR) << "Extension negotation failure: " << extension.uri
+                          << " was identified by " << it->second
+                          << " but is proposed changed to " << extension.id;
+        return false;
+      }
+    }
+  }
   return true;
 }
 
@@ -97,7 +138,8 @@
     bool (*supported)(absl::string_view),
     bool filter_redundant_extensions,
     const webrtc::WebRtcKeyValueConfig& trials) {
-  RTC_DCHECK(ValidateRtpExtensions(extensions));
+  // Don't check against old parameters; this should have been done earlier.
+  RTC_DCHECK(ValidateRtpExtensions(extensions, {}));
   RTC_DCHECK(supported);
   std::vector<webrtc::RtpExtension> result;
 
diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_media_engine.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_media_engine.h
index 34ec4cd..ff97760 100644
--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_media_engine.h
+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_media_engine.h
@@ -63,8 +63,11 @@
     MediaEngineDependencies dependencies);
 
 // Verify that extension IDs are within 1-byte extension range and are not
-// overlapping.
-bool ValidateRtpExtensions(const std::vector<webrtc::RtpExtension>& extensions);
+// overlapping, and that they form a legal change from previously registerd
+// extensions (if any).
+bool ValidateRtpExtensions(
+    rtc::ArrayView<const webrtc::RtpExtension> extennsions,
+    rtc::ArrayView<const webrtc::RtpExtension> old_extensions);
 
 // Discard any extensions not validated by the 'supported' predicate. Duplicate
 // extensions are removed if 'filter_redundant_extensions' is set, and also any
diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_media_engine_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_media_engine_unittest.cc
index 78d13fc..81982fa 100644
--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_media_engine_unittest.cc
+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_media_engine_unittest.cc
@@ -66,41 +66,68 @@
 }
 }  // namespace
 
-TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_EmptyList) {
+TEST(WebRtcMediaEngineTest, ValidateRtpExtensionsEmptyList) {
   std::vector<RtpExtension> extensions;
-  EXPECT_TRUE(ValidateRtpExtensions(extensions));
+  EXPECT_TRUE(ValidateRtpExtensions(extensions, {}));
 }
 
-TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_AllGood) {
+TEST(WebRtcMediaEngineTest, ValidateRtpExtensionsAllGood) {
   std::vector<RtpExtension> extensions = MakeUniqueExtensions();
-  EXPECT_TRUE(ValidateRtpExtensions(extensions));
+  EXPECT_TRUE(ValidateRtpExtensions(extensions, {}));
 }
 
-TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_OutOfRangeId_Low) {
+TEST(WebRtcMediaEngineTest, ValidateRtpExtensionsOutOfRangeId_Low) {
   std::vector<RtpExtension> extensions = MakeUniqueExtensions();
   extensions.push_back(RtpExtension("foo", 0));
-  EXPECT_FALSE(ValidateRtpExtensions(extensions));
+  EXPECT_FALSE(ValidateRtpExtensions(extensions, {}));
 }
 
-TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_OutOfRangeId_High) {
+TEST(WebRtcMediaEngineTest, ValidateRtpExtensionsOutOfRangeIdHigh) {
   std::vector<RtpExtension> extensions = MakeUniqueExtensions();
   extensions.push_back(RtpExtension("foo", 256));
-  EXPECT_FALSE(ValidateRtpExtensions(extensions));
+  EXPECT_FALSE(ValidateRtpExtensions(extensions, {}));
 }
 
-TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_OverlappingIds_StartOfSet) {
+TEST(WebRtcMediaEngineTest, ValidateRtpExtensionsOverlappingIdsStartOfSet) {
   std::vector<RtpExtension> extensions = MakeUniqueExtensions();
   extensions.push_back(RtpExtension("foo", 1));
-  EXPECT_FALSE(ValidateRtpExtensions(extensions));
+  EXPECT_FALSE(ValidateRtpExtensions(extensions, {}));
 }
 
-TEST(WebRtcMediaEngineTest, ValidateRtpExtensions_OverlappingIds_EndOfSet) {
+TEST(WebRtcMediaEngineTest, ValidateRtpExtensionsOverlappingIdsEndOfSet) {
   std::vector<RtpExtension> extensions = MakeUniqueExtensions();
   extensions.push_back(RtpExtension("foo", 255));
-  EXPECT_FALSE(ValidateRtpExtensions(extensions));
+  EXPECT_FALSE(ValidateRtpExtensions(extensions, {}));
 }
 
-TEST(WebRtcMediaEngineTest, FilterRtpExtensions_EmptyList) {
+TEST(WebRtcMediaEngineTest, ValidateRtpExtensionsEmptyToEmpty) {
+  std::vector<RtpExtension> extensions;
+  EXPECT_TRUE(ValidateRtpExtensions(extensions, extensions));
+}
+
+TEST(WebRtcMediaEngineTest, ValidateRtpExtensionsNoChange) {
+  std::vector<RtpExtension> extensions = MakeUniqueExtensions();
+  EXPECT_TRUE(ValidateRtpExtensions(extensions, extensions));
+}
+
+TEST(WebRtcMediaEngineTest, ValidateRtpExtensionsChangeIdNotUrl) {
+  std::vector<RtpExtension> old_extensions = MakeUniqueExtensions();
+  std::vector<RtpExtension> new_extensions = old_extensions;
+  std::swap(new_extensions[0].id, new_extensions[1].id);
+
+  EXPECT_FALSE(ValidateRtpExtensions(new_extensions, old_extensions));
+}
+
+TEST(WebRtcMediaEngineTest, ValidateRtpExtensionsChangeIdForUrl) {
+  std::vector<RtpExtension> old_extensions = MakeUniqueExtensions();
+  std::vector<RtpExtension> new_extensions = old_extensions;
+  // Change first extension to something not generated by MakeUniqueExtensions
+  new_extensions[0].id = 123;
+
+  EXPECT_FALSE(ValidateRtpExtensions(new_extensions, old_extensions));
+}
+
+TEST(WebRtcMediaEngineTest, FilterRtpExtensionsEmptyList) {
   std::vector<RtpExtension> extensions;
   webrtc::FieldTrialBasedConfig trials;
   std::vector<webrtc::RtpExtension> filtered =
@@ -108,7 +135,7 @@
   EXPECT_EQ(0u, filtered.size());
 }
 
-TEST(WebRtcMediaEngineTest, FilterRtpExtensions_IncludeOnlySupported) {
+TEST(WebRtcMediaEngineTest, FilterRtpExtensionsIncludeOnlySupported) {
   std::vector<RtpExtension> extensions = MakeUniqueExtensions();
   webrtc::FieldTrialBasedConfig trials;
   std::vector<webrtc::RtpExtension> filtered =
@@ -118,7 +145,7 @@
   EXPECT_EQ("i", filtered[1].uri);
 }
 
-TEST(WebRtcMediaEngineTest, FilterRtpExtensions_SortedByName_1) {
+TEST(WebRtcMediaEngineTest, FilterRtpExtensionsSortedByName1) {
   std::vector<RtpExtension> extensions = MakeUniqueExtensions();
   webrtc::FieldTrialBasedConfig trials;
   std::vector<webrtc::RtpExtension> filtered =
@@ -127,7 +154,7 @@
   EXPECT_TRUE(IsSorted(filtered));
 }
 
-TEST(WebRtcMediaEngineTest, FilterRtpExtensions_SortedByName_2) {
+TEST(WebRtcMediaEngineTest, FilterRtpExtensionsSortedByName2) {
   std::vector<RtpExtension> extensions = MakeUniqueExtensions();
   webrtc::FieldTrialBasedConfig trials;
   std::vector<webrtc::RtpExtension> filtered =
@@ -136,7 +163,7 @@
   EXPECT_TRUE(IsSorted(filtered));
 }
 
-TEST(WebRtcMediaEngineTest, FilterRtpExtensions_DontRemoveRedundant) {
+TEST(WebRtcMediaEngineTest, FilterRtpExtensionsDontRemoveRedundant) {
   std::vector<RtpExtension> extensions = MakeRedundantExtensions();
   webrtc::FieldTrialBasedConfig trials;
   std::vector<webrtc::RtpExtension> filtered =
@@ -146,7 +173,7 @@
   EXPECT_EQ(filtered[0].uri, filtered[1].uri);
 }
 
-TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundant) {
+TEST(WebRtcMediaEngineTest, FilterRtpExtensionsRemoveRedundant) {
   std::vector<RtpExtension> extensions = MakeRedundantExtensions();
   webrtc::FieldTrialBasedConfig trials;
   std::vector<webrtc::RtpExtension> filtered =
@@ -156,7 +183,7 @@
   EXPECT_NE(filtered[0].uri, filtered[1].uri);
 }
 
-TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantEncrypted_1) {
+TEST(WebRtcMediaEngineTest, FilterRtpExtensionsRemoveRedundantEncrypted1) {
   std::vector<RtpExtension> extensions;
   extensions.push_back(webrtc::RtpExtension("b", 1));
   extensions.push_back(webrtc::RtpExtension("b", 2, true));
@@ -173,7 +200,7 @@
   EXPECT_NE(filtered[1].uri, filtered[2].uri);
 }
 
-TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantEncrypted_2) {
+TEST(WebRtcMediaEngineTest, FilterRtpExtensionsRemoveRedundantEncrypted2) {
   std::vector<RtpExtension> extensions;
   extensions.push_back(webrtc::RtpExtension("b", 1, true));
   extensions.push_back(webrtc::RtpExtension("b", 2));
@@ -190,7 +217,7 @@
   EXPECT_NE(filtered[1].uri, filtered[2].uri);
 }
 
-TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantBwe_1) {
+TEST(WebRtcMediaEngineTest, FilterRtpExtensionsRemoveRedundantBwe1) {
   webrtc::test::ScopedFieldTrials override_field_trials_(
       "WebRTC-FilterAbsSendTimeExtension/Enabled/");
   webrtc::FieldTrialBasedConfig trials;
@@ -209,7 +236,7 @@
 }
 
 TEST(WebRtcMediaEngineTest,
-     FilterRtpExtensions_RemoveRedundantBwe_1_KeepAbsSendTime) {
+     FilterRtpExtensionsRemoveRedundantBwe1KeepAbsSendTime) {
   std::vector<RtpExtension> extensions;
   extensions.push_back(
       RtpExtension(RtpExtension::kTransportSequenceNumberUri, 3));
@@ -226,7 +253,7 @@
   EXPECT_EQ(RtpExtension::kAbsSendTimeUri, filtered[1].uri);
 }
 
-TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantBweEncrypted_1) {
+TEST(WebRtcMediaEngineTest, FilterRtpExtensionsRemoveRedundantBweEncrypted1) {
   webrtc::test::ScopedFieldTrials override_field_trials_(
       "WebRTC-FilterAbsSendTimeExtension/Enabled/");
   webrtc::FieldTrialBasedConfig trials;
@@ -251,7 +278,7 @@
 }
 
 TEST(WebRtcMediaEngineTest,
-     FilterRtpExtensions_RemoveRedundantBweEncrypted_1_KeepAbsSendTime) {
+     FilterRtpExtensionsRemoveRedundantBweEncrypted1KeepAbsSendTime) {
   std::vector<RtpExtension> extensions;
   extensions.push_back(
       RtpExtension(RtpExtension::kTransportSequenceNumberUri, 3));
@@ -274,7 +301,7 @@
   EXPECT_NE(filtered[0].encrypt, filtered[1].encrypt);
 }
 
-TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantBwe_2) {
+TEST(WebRtcMediaEngineTest, FilterRtpExtensionsRemoveRedundantBwe2) {
   std::vector<RtpExtension> extensions;
   extensions.push_back(RtpExtension(RtpExtension::kTimestampOffsetUri, 1));
   extensions.push_back(RtpExtension(RtpExtension::kAbsSendTimeUri, 14));
@@ -286,7 +313,7 @@
   EXPECT_EQ(RtpExtension::kAbsSendTimeUri, filtered[0].uri);
 }
 
-TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantBwe_3) {
+TEST(WebRtcMediaEngineTest, FilterRtpExtensionsRemoveRedundantBwe3) {
   std::vector<RtpExtension> extensions;
   extensions.push_back(RtpExtension(RtpExtension::kTimestampOffsetUri, 2));
   extensions.push_back(RtpExtension(RtpExtension::kTimestampOffsetUri, 14));
diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_video_engine.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_video_engine.cc
index ea2298b..39e3cc5 100644
--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_video_engine.cc
+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_video_engine.cc
@@ -808,7 +808,7 @@
     const VideoSendParameters& params,
     ChangedSendParameters* changed_params) const {
   if (!ValidateCodecFormats(params.codecs) ||
-      !ValidateRtpExtensions(params.extensions)) {
+      !ValidateRtpExtensions(params.extensions, send_rtp_extensions_)) {
     return false;
   }
 
@@ -843,7 +843,7 @@
   std::vector<webrtc::RtpExtension> filtered_extensions = FilterRtpExtensions(
       params.extensions, webrtc::RtpExtension::IsSupportedForVideo, true,
       call_->trials());
-  if (!send_rtp_extensions_ || (*send_rtp_extensions_ != filtered_extensions)) {
+  if (send_rtp_extensions_ != filtered_extensions) {
     changed_params->rtp_header_extensions =
         absl::optional<std::vector<webrtc::RtpExtension>>(filtered_extensions);
   }
@@ -990,7 +990,7 @@
     SetExtmapAllowMixed(*changed_params.extmap_allow_mixed);
   }
   if (changed_params.rtp_header_extensions) {
-    send_rtp_extensions_ = changed_params.rtp_header_extensions;
+    send_rtp_extensions_ = *changed_params.rtp_header_extensions;
   }
 
   if (changed_params.send_codec || changed_params.max_bandwidth_bps) {
@@ -1167,7 +1167,7 @@
     const VideoRecvParameters& params,
     ChangedRecvParameters* changed_params) const {
   if (!ValidateCodecFormats(params.codecs) ||
-      !ValidateRtpExtensions(params.extensions)) {
+      !ValidateRtpExtensions(params.extensions, recv_rtp_extensions_)) {
     return false;
   }
 
diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_video_engine.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_video_engine.h
index 9b8ba0b..6602319 100644
--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_video_engine.h
+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_video_engine.h
@@ -601,7 +601,7 @@
   std::vector<VideoCodecSettings> negotiated_codecs_
       RTC_GUARDED_BY(thread_checker_);
 
-  absl::optional<std::vector<webrtc::RtpExtension>> send_rtp_extensions_
+  std::vector<webrtc::RtpExtension> send_rtp_extensions_
       RTC_GUARDED_BY(thread_checker_);
 
   webrtc::VideoEncoderFactory* const encoder_factory_
diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_voice_engine.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_voice_engine.cc
index 448ad35..7ce5063 100644
--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_voice_engine.cc
+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtc_voice_engine.cc
@@ -1384,7 +1384,7 @@
     return false;
   }
 
-  if (!ValidateRtpExtensions(params.extensions)) {
+  if (!ValidateRtpExtensions(params.extensions, send_rtp_extensions_)) {
     return false;
   }
 
@@ -1430,7 +1430,7 @@
     return false;
   }
 
-  if (!ValidateRtpExtensions(params.extensions)) {
+  if (!ValidateRtpExtensions(params.extensions, recv_rtp_extensions_)) {
     return false;
   }
   std::vector<webrtc::RtpExtension> filtered_extensions = FilterRtpExtensions(
diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map.cc
index 541e570..0584823 100644
--- a/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map.cc
+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map.cc
@@ -161,7 +161,12 @@
                         << static_cast<int>(registered_type);
     return false;
   }
-  RTC_DCHECK(!IsRegistered(type));
+  if (IsRegistered(type)) {
+    RTC_LOG(LS_WARNING) << "Illegal reregistration for uri: " << uri
+                        << " is previously registered with id " << GetId(type)
+                        << " and cannot be reregistered with id " << id;
+    return false;
+  }
 
   // There is a run-time check above id fits into uint8_t.
   ids_[type] = static_cast<uint8_t>(id);
diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc
index 91bb252..0326b45 100644
--- a/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc
+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc
@@ -106,4 +106,10 @@
   EXPECT_EQ(3, map.GetId(TransmissionOffset::kId));
 }
 
+TEST(RtpHeaderExtensionTest, RemapFails) {
+  RtpHeaderExtensionMap map;
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+  EXPECT_FALSE(map.Register<TransmissionOffset>(4));
+}
+
 }  // namespace webrtc