Bug 1193437: Use config structs in NrIceCtx, and centralize pref lookups some. r=mjf
authorByron Campen [:bwc] <docfaraday@gmail.com>
Tue, 07 Jul 2020 17:14:38 +0000
changeset 539169 e1841978b15a9978cfdd2abcb11f8d569879575e
parent 539168 fb2b08c6bc8c320127586fcedb2626e496bf3dcf
child 539170 2af48ca6f91a68a6a4833be4114d779d140cdf86
push id120974
push userbcampen@mozilla.com
push dateTue, 07 Jul 2020 18:03:34 +0000
treeherderautoland@e1841978b15a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmjf
bugs1193437
milestone80.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1193437: Use config structs in NrIceCtx, and centralize pref lookups some. r=mjf Differential Revision: https://phabricator.services.mozilla.com/D82549
media/mtransport/nricectx.cpp
media/mtransport/nricectx.h
media/mtransport/test/ice_unittest.cpp
media/mtransport/test/multi_tcp_socket_unittest.cpp
media/mtransport/test/test_nr_socket_ice_unittest.cpp
media/mtransport/test/transport_unittests.cpp
media/mtransport/test/turn_unittest.cpp
media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -260,40 +260,36 @@ nsresult NrIceTurnServer::ToNicerTurnStr
   if (r) {
     RFREE(server->username);
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
-NrIceCtx::NrIceCtx(const std::string& name, Policy policy)
+NrIceCtx::NrIceCtx(const std::string& name, const Config& aConfig)
     : connection_state_(ICE_CTX_INIT),
       gathering_state_(ICE_CTX_GATHER_INIT),
       name_(name),
       ice_controlling_set_(false),
       streams_(),
       ctx_(nullptr),
       peer_(nullptr),
       ice_handler_vtbl_(nullptr),
       ice_handler_(nullptr),
       trickle_(true),
-      policy_(policy),
+      config_(aConfig),
       nat_(nullptr),
       proxy_config_(nullptr),
       obfuscate_host_addresses_(false) {}
 
 /* static */
-RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name, bool allow_loopback,
-                                  bool tcp_enabled, bool allow_link_local,
-                                  Policy policy) {
-  // InitializeGlobals only executes once
-  NrIceCtx::InitializeGlobals(allow_loopback, tcp_enabled, allow_link_local);
-
-  RefPtr<NrIceCtx> ctx = new NrIceCtx(name, policy);
+RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& aName,
+                                  const Config& aConfig) {
+  RefPtr<NrIceCtx> ctx = new NrIceCtx(aName, aConfig);
 
   if (!ctx->Initialize()) {
     return nullptr;
   }
 
   return ctx;
 }
 
@@ -452,18 +448,17 @@ void NrIceCtx::trickle_cb(void* arg, nr_
   if (r) return;
 
   MOZ_MTLOG(ML_INFO, "NrIceCtx(" << ctx->name_ << "): trickling candidate "
                                  << candidate_str);
 
   s->SignalCandidate(s, candidate_str, stream->ufrag, mdns_addr, actual_addr);
 }
 
-void NrIceCtx::InitializeGlobals(bool allow_loopback, bool tcp_enabled,
-                                 bool allow_link_local) {
+void NrIceCtx::InitializeGlobals(const GlobalConfig& aConfig) {
   RLogConnector::CreateInstance();
   // Initialize the crypto callbacks and logging stuff
   if (!initialized) {
     NR_reg_init(NR_REG_MODE_LOCAL);
     nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
     initialized = true;
 
     // Set the priorites for candidate type preferences.
@@ -471,67 +466,37 @@ void NrIceCtx::InitializeGlobals(bool al
     NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_SRV_RFLX, 100);
     NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_PEER_RFLX, 110);
     NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_HOST, 126);
     NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_RELAYED, 5);
     NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_SRV_RFLX_TCP, 99);
     NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_PEER_RFLX_TCP, 109);
     NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_HOST_TCP, 125);
     NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_RELAYED_TCP, 0);
-
-    int32_t stun_client_maximum_transmits = 7;
-    int32_t ice_trickle_grace_period = 5000;
-    int32_t ice_tcp_so_sock_count = 3;
-    int32_t ice_tcp_listen_backlog = 10;
-    nsAutoCString force_net_interface;
-    nsresult res;
-    nsCOMPtr<nsIPrefService> prefs =
-        do_GetService("@mozilla.org/preferences-service;1", &res);
+    NR_reg_set_uint4((char*)"stun.client.maximum_transmits",
+                     aConfig.mStunClientMaxTransmits);
+    NR_reg_set_uint4((char*)NR_ICE_REG_TRICKLE_GRACE_PERIOD,
+                     aConfig.mTrickleIceGracePeriod);
+    NR_reg_set_int4((char*)NR_ICE_REG_ICE_TCP_SO_SOCK_COUNT,
+                    aConfig.mIceTcpSoSockCount);
+    NR_reg_set_int4((char*)NR_ICE_REG_ICE_TCP_LISTEN_BACKLOG,
+                    aConfig.mIceTcpListenBacklog);
 
-    if (NS_SUCCEEDED(res)) {
-      nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
-      if (branch) {
-        branch->GetIntPref(
-            "media.peerconnection.ice.stun_client_maximum_transmits",
-            &stun_client_maximum_transmits);
-        branch->GetIntPref("media.peerconnection.ice.trickle_grace_period",
-                           &ice_trickle_grace_period);
-        branch->GetIntPref("media.peerconnection.ice.tcp_so_sock_count",
-                           &ice_tcp_so_sock_count);
-        branch->GetIntPref("media.peerconnection.ice.tcp_listen_backlog",
-                           &ice_tcp_listen_backlog);
-        branch->GetCharPref("media.peerconnection.ice.force_interface",
-                            force_net_interface);
-      }
-    }
+    NR_reg_set_char((char*)NR_ICE_REG_ICE_TCP_DISABLE, !aConfig.mTcpEnabled);
 
-    NR_reg_set_uint4((char*)"stun.client.maximum_transmits",
-                     stun_client_maximum_transmits);
-    NR_reg_set_uint4((char*)NR_ICE_REG_TRICKLE_GRACE_PERIOD,
-                     ice_trickle_grace_period);
-    NR_reg_set_int4((char*)NR_ICE_REG_ICE_TCP_SO_SOCK_COUNT,
-                    ice_tcp_so_sock_count);
-    NR_reg_set_int4((char*)NR_ICE_REG_ICE_TCP_LISTEN_BACKLOG,
-                    ice_tcp_listen_backlog);
-
-    NR_reg_set_char((char*)NR_ICE_REG_ICE_TCP_DISABLE, !tcp_enabled);
-
-    if (allow_loopback) {
+    if (aConfig.mAllowLoopback) {
       NR_reg_set_char((char*)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, 1);
     }
 
-    if (allow_link_local) {
+    if (aConfig.mAllowLinkLocal) {
       NR_reg_set_char((char*)NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS, 1);
     }
-    if (force_net_interface.Length() > 0) {
-      // Stupid cast.... but needed
-      const nsCString& flat =
-          PromiseFlatCString(static_cast<nsACString&>(force_net_interface));
+    if (!aConfig.mForceNetInterface.Length()) {
       NR_reg_set_string((char*)NR_ICE_REG_PREF_FORCE_INTERFACE_NAME,
-                        const_cast<char*>(flat.get()));
+                        const_cast<char*>(aConfig.mForceNetInterface.get()));
     }
   }
 }
 
 void NrIceCtx::SetTargetForDefaultLocalAddressLookup(
     const std::string& target_ip, uint16_t target_port) {
   nr_ice_set_target_for_default_local_address_lookup(ctx_, target_ip.c_str(),
                                                      target_port);
@@ -578,17 +543,17 @@ void NrIceCtx::SetStunAddrs(const nsTArr
   delete[] local_addrs;
 }
 
 bool NrIceCtx::Initialize() {
   // Create the ICE context
   int r;
 
   UINT4 flags = NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
-  switch (policy_) {
+  switch (config_.mPolicy) {
     case ICE_POLICY_RELAY:
       flags |= NR_ICE_CTX_FLAGS_RELAY_ONLY;
       break;
     case ICE_POLICY_NO_HOST:
       flags |= NR_ICE_CTX_FLAGS_HIDE_HOST_CANDIDATES;
       break;
     case ICE_POLICY_ALL:
       break;
@@ -627,48 +592,24 @@ bool NrIceCtx::Initialize() {
   if (generating_trickle()) {
     r = nr_ice_ctx_set_trickle_cb(ctx_, &NrIceCtx::trickle_cb, this);
     if (r) {
       MOZ_MTLOG(ML_ERROR, "Couldn't set trickle cb for '" << name_ << "'");
       return false;
     }
   }
 
-  nsAutoCString mapping_type;
-  nsAutoCString filtering_type;
-  bool block_udp = false;
-  bool block_tcp = false;
-
-  nsresult rv;
-  nsCOMPtr<nsIPrefService> pref_service =
-      do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
-
-  if (NS_SUCCEEDED(rv)) {
-    nsCOMPtr<nsIPrefBranch> pref_branch;
-    rv = pref_service->GetBranch(nullptr, getter_AddRefs(pref_branch));
-    if (NS_SUCCEEDED(rv)) {
-      Unused << pref_branch->GetCharPref(
-          "media.peerconnection.nat_simulator.mapping_type", mapping_type);
-      Unused << pref_branch->GetCharPref(
-          "media.peerconnection.nat_simulator.filtering_type", filtering_type);
-      Unused << pref_branch->GetBoolPref(
-          "media.peerconnection.nat_simulator.block_udp", &block_udp);
-      Unused << pref_branch->GetBoolPref(
-          "media.peerconnection.nat_simulator.block_tcp", &block_tcp);
-    }
-  }
-
-  if (!mapping_type.IsEmpty() && !filtering_type.IsEmpty()) {
-    MOZ_MTLOG(ML_DEBUG, "NAT filtering type: " << filtering_type.get());
-    MOZ_MTLOG(ML_DEBUG, "NAT mapping type: " << mapping_type.get());
+  if (config_.mNatSimulatorConfig.isSome()) {
     TestNat* test_nat = new TestNat;
-    test_nat->filtering_type_ = TestNat::ToNatBehavior(filtering_type.get());
-    test_nat->mapping_type_ = TestNat::ToNatBehavior(mapping_type.get());
-    test_nat->block_udp_ = block_udp;
-    test_nat->block_tcp_ = block_tcp;
+    test_nat->filtering_type_ = TestNat::ToNatBehavior(
+        config_.mNatSimulatorConfig->mFilteringType.get());
+    test_nat->mapping_type_ =
+        TestNat::ToNatBehavior(config_.mNatSimulatorConfig->mMappingType.get());
+    test_nat->block_udp_ = config_.mNatSimulatorConfig->mBlockUdp;
+    test_nat->block_tcp_ = config_.mNatSimulatorConfig->mBlockTcp;
     test_nat->enabled_ = true;
     SetNat(test_nat);
   }
 
   // Create the handler objects
   ice_handler_vtbl_ = new nr_ice_handler_vtbl();
   ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair;
   ice_handler_vtbl_->stream_ready = &NrIceCtx::stream_ready;
@@ -687,16 +628,17 @@ bool NrIceCtx::Initialize() {
   std::string peer_name = name_ + ":default";
   r = nr_ice_peer_ctx_create(ctx_, ice_handler_,
                              const_cast<char*>(peer_name.c_str()), &peer_);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't create ICE peer ctx for '" << name_ << "'");
     return false;
   }
 
+  nsresult rv;
   sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
 
   if (!NS_SUCCEEDED(rv)) return false;
 
   return true;
 }
 
 int NrIceCtx::SetNat(const RefPtr<TestNat>& aNat) {
@@ -779,21 +721,16 @@ nsresult NrIceCtx::SetControlling(Contro
   }
   return NS_OK;
 }
 
 NrIceCtx::Controlling NrIceCtx::GetControlling() {
   return (peer_->controlling) ? ICE_CONTROLLING : ICE_CONTROLLED;
 }
 
-nsresult NrIceCtx::SetPolicy(Policy policy) {
-  policy_ = policy;
-  return NS_OK;
-}
-
 nsresult NrIceCtx::SetStunServers(
     const std::vector<NrIceStunServer>& stun_servers) {
   if (stun_servers.empty()) return NS_OK;
 
   auto servers = MakeUnique<nr_ice_stun_server[]>(stun_servers.size());
 
   for (size_t i = 0; i < stun_servers.size(); ++i) {
     nsresult rv = stun_servers[i].ToNicerStunStruct(&servers[i]);
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -58,16 +58,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #include "sigslot.h"
 
 #include "prnetdb.h"
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "nsIEventTarget.h"
 #include "nsTArray.h"
+#include "mozilla/Maybe.h"
 
 #include "m_cpp_utils.h"
 #include "nricestunaddr.h"
 #include "nricemediastream.h"
 
 typedef struct nr_ice_ctx_ nr_ice_ctx;
 typedef struct nr_ice_peer_ctx_ nr_ice_peer_ctx;
 typedef struct nr_ice_media_stream_ nr_ice_media_stream;
@@ -196,30 +197,49 @@ class NrIceCtx {
     ICE_CTX_GATHER_STARTED,
     ICE_CTX_GATHER_COMPLETE
   };
 
   enum Controlling { ICE_CONTROLLING, ICE_CONTROLLED };
 
   enum Policy { ICE_POLICY_RELAY, ICE_POLICY_NO_HOST, ICE_POLICY_ALL };
 
-  static RefPtr<NrIceCtx> Create(
-      const std::string& name, bool allow_loopback = false,
-      bool tcp_enabled = true, bool allow_link_local = false,
-      NrIceCtx::Policy policy = NrIceCtx::ICE_POLICY_ALL);
+  struct NatSimulatorConfig {
+    bool mBlockTcp = false;
+    bool mBlockUdp = false;
+    nsCString mMappingType = "ENDPOINT_INDEPENDENT"_ns;
+    nsCString mFilteringType = "ENDPOINT_INDEPENDENT"_ns;
+  };
+
+  struct Config {
+    NrIceCtx::Policy mPolicy = NrIceCtx::ICE_POLICY_ALL;
+    Maybe<NatSimulatorConfig> mNatSimulatorConfig;
+  };
+
+  static RefPtr<NrIceCtx> Create(const std::string& aName,
+                                 const Config& aConfig);
 
   RefPtr<NrIceMediaStream> CreateStream(const std::string& id,
                                         const std::string& name,
                                         int components);
   void DestroyStream(const std::string& id);
 
+  struct GlobalConfig {
+    bool mAllowLinkLocal = false;
+    bool mAllowLoopback = false;
+    bool mTcpEnabled = true;
+    int mStunClientMaxTransmits = 7;
+    int mTrickleIceGracePeriod = 5000;
+    int mIceTcpSoSockCount = 3;
+    int mIceTcpListenBacklog = 10;
+    nsCString mForceNetInterface;
+  };
+
   // initialize ICE globals, crypto, and logging
-  static void InitializeGlobals(bool allow_loopback = false,
-                                bool tcp_enabled = true,
-                                bool allow_link_local = false);
+  static void InitializeGlobals(const GlobalConfig& aConfig);
 
   void SetTargetForDefaultLocalAddressLookup(const std::string& target_ip,
                                              uint16_t target_port);
 
   // static GetStunAddrs for use in parent process to support
   // sandboxing restrictions
   static nsTArray<NrIceStunAddr> GetStunAddrs();
   void SetStunAddrs(const nsTArray<NrIceStunAddr>& addrs);
@@ -273,22 +293,16 @@ class NrIceCtx {
   // Set the other side's global attributes
   nsresult ParseGlobalAttributes(std::vector<std::string> attrs);
 
   // Set whether we are controlling or not.
   nsresult SetControlling(Controlling controlling);
 
   Controlling GetControlling();
 
-  // Set whether we're allowed to produce none, relay or all candidates.
-  // TODO(jib@mozilla.com): Work out what change means mid-connection (1181768)
-  nsresult SetPolicy(Policy policy);
-
-  Policy policy() const { return policy_; }
-
   // Set the STUN servers. Must be called before StartGathering
   // (if at all).
   nsresult SetStunServers(const std::vector<NrIceStunServer>& stun_servers);
 
   // Set the TURN servers. Must be called before StartGathering
   // (if at all).
   nsresult SetTurnServers(const std::vector<NrIceTurnServer>& turn_servers);
 
@@ -334,17 +348,17 @@ class NrIceCtx {
       SignalConnectionStateChange;
 
   // The thread to direct method calls to
   nsCOMPtr<nsIEventTarget> thread() { return sts_target_; }
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceCtx)
 
  private:
-  NrIceCtx(const std::string& name, Policy policy);
+  NrIceCtx(const std::string& name, const Config& aConfig);
 
   virtual ~NrIceCtx();
 
   DISALLOW_COPY_ASSIGN(NrIceCtx);
 
   // Callbacks for nICEr
   static void gather_cb(NR_SOCKET s, int h, void* arg);  // ICE gather complete
 
@@ -383,17 +397,17 @@ class NrIceCtx {
   bool ice_controlling_set_;
   std::map<std::string, RefPtr<NrIceMediaStream>> streams_;
   nr_ice_ctx* ctx_;
   nr_ice_peer_ctx* peer_;
   nr_ice_handler_vtbl* ice_handler_vtbl_;  // Must be pointer
   nr_ice_handler* ice_handler_;            // Must be pointer
   bool trickle_;
   nsCOMPtr<nsIEventTarget> sts_target_;  // The thread to run on
-  Policy policy_;
+  Config config_;
   RefPtr<TestNat> nat_;
   std::shared_ptr<NrSocketProxyConfig> proxy_config_;
   bool obfuscate_host_addresses_;
   std::map<std::string, std::string> obfuscated_host_addresses_;
 };
 
 }  // namespace mozilla
 #endif
--- a/media/mtransport/test/ice_unittest.cpp
+++ b/media/mtransport/test/ice_unittest.cpp
@@ -169,21 +169,16 @@ class StunTest : public MtransportTest {
     MtransportTest::TearDown();
   }
 };
 
 enum TrickleMode { TRICKLE_NONE, TRICKLE_SIMULATE, TRICKLE_REAL };
 
 enum ConsentStatus { CONSENT_FRESH, CONSENT_STALE, CONSENT_EXPIRED };
 
-const unsigned int ICE_TEST_PEER_OFFERER = (1 << 0);
-const unsigned int ICE_TEST_PEER_ALLOW_LOOPBACK = (1 << 1);
-const unsigned int ICE_TEST_PEER_ENABLED_TCP = (1 << 2);
-const unsigned int ICE_TEST_PEER_ALLOW_LINK_LOCAL = (1 << 3);
-
 typedef std::string (*CandidateFilter)(const std::string& candidate);
 
 std::vector<std::string> split(const std::string& s, char delim) {
   std::vector<std::string> elems;
   std::stringstream ss(s);
   std::string item;
   while (std::getline(ss, item, delim)) {
     elems.push_back(item);
@@ -356,25 +351,20 @@ class SchedulableTrickleCandidate {
   void* timer_handle_;
   MtransportTestUtils* test_utils_;
 
   DISALLOW_COPY_ASSIGN(SchedulableTrickleCandidate);
 };
 
 class IceTestPeer : public sigslot::has_slots<> {
  public:
-  // TODO(ekr@rtfm.com): Convert to flags when NrIceCtx::Create() does.
-  // Bug 1193437.
   IceTestPeer(const std::string& name, MtransportTestUtils* utils, bool offerer,
-              bool allow_loopback = false, bool enable_tcp = true,
-              bool allow_link_local = false,
-              NrIceCtx::Policy ice_policy = NrIceCtx::ICE_POLICY_ALL)
+              const NrIceCtx::Config& config)
       : name_(name),
-        ice_ctx_(NrIceCtx::Create(name, allow_loopback, enable_tcp,
-                                  allow_link_local, ice_policy)),
+        ice_ctx_(NrIceCtx::Create(name, config)),
         offerer_(offerer),
         candidates_(),
         stream_counter_(0),
         shutting_down_(false),
         gathering_complete_(false),
         ready_ct_(0),
         ice_connected_(false),
         ice_failed_(false),
@@ -1416,23 +1406,20 @@ class WebRtcIceGatherTest : public StunT
     }
   }
 
   void TearDown() override {
     peer_ = nullptr;
     StunTest::TearDown();
   }
 
-  void EnsurePeer(const unsigned int flags = ICE_TEST_PEER_OFFERER) {
+  void EnsurePeer() {
     if (!peer_) {
-      peer_ = MakeUnique<IceTestPeer>("P1", test_utils_,
-                                      flags & ICE_TEST_PEER_OFFERER,
-                                      flags & ICE_TEST_PEER_ALLOW_LOOPBACK,
-                                      flags & ICE_TEST_PEER_ENABLED_TCP,
-                                      flags & ICE_TEST_PEER_ALLOW_LINK_LOCAL);
+      peer_ =
+          MakeUnique<IceTestPeer>("P1", test_utils_, true, NrIceCtx::Config());
       peer_->AddStream(1);
     }
   }
 
   void Gather(unsigned int waitTime = kDefaultTimeout) {
     EnsurePeer();
     peer_->Gather();
 
@@ -1488,27 +1475,27 @@ class WebRtcIceGatherTest : public StunT
     std::vector<NrIceStunServer> stun_servers;
     AddStunServerWithResponse(fake_addr, fake_port, fqdn, "udp", &stun_servers);
     peer_->SetStunServers(stun_servers);
   }
 
   void UseFakeStunTcpServerWithResponse(
       const std::string& fake_addr, uint16_t fake_port,
       const std::string& fqdn = std::string()) {
-    EnsurePeer(ICE_TEST_PEER_OFFERER | ICE_TEST_PEER_ENABLED_TCP);
+    EnsurePeer();
     std::vector<NrIceStunServer> stun_servers;
     AddStunServerWithResponse(fake_addr, fake_port, fqdn, "tcp", &stun_servers);
     peer_->SetStunServers(stun_servers);
   }
 
   void UseFakeStunUdpTcpServersWithResponse(const std::string& fake_udp_addr,
                                             uint16_t fake_udp_port,
                                             const std::string& fake_tcp_addr,
                                             uint16_t fake_tcp_port) {
-    EnsurePeer(ICE_TEST_PEER_OFFERER | ICE_TEST_PEER_ENABLED_TCP);
+    EnsurePeer();
     std::vector<NrIceStunServer> stun_servers;
     AddStunServerWithResponse(fake_udp_addr, fake_udp_port,
                               "",  // no fqdn
                               "udp", &stun_servers);
     AddStunServerWithResponse(fake_tcp_addr, fake_tcp_port,
                               "",  // no fqdn
                               "tcp", &stun_servers);
 
@@ -1572,37 +1559,36 @@ class WebRtcIceConnectTest : public Stun
   void TearDown() override {
     p1_ = nullptr;
     p2_ = nullptr;
 
     StunTest::TearDown();
   }
 
   void AddStream(int components) {
-    Init(false, false);
+    Init();
     p1_->AddStream(components);
     p2_->AddStream(components);
   }
 
   void RemoveStream(size_t index) {
     p1_->RemoveStream(index);
     p2_->RemoveStream(index);
   }
 
-  void Init(bool allow_loopback, bool enable_tcp,
-            bool setup_stun_servers = true,
+  void Init(bool setup_stun_servers = true,
             NrIceCtx::Policy ice_policy = NrIceCtx::ICE_POLICY_ALL) {
     if (initted_) {
       return;
     }
 
-    p1_ = MakeUnique<IceTestPeer>("P1", test_utils_, true, allow_loopback,
-                                  enable_tcp, false, ice_policy);
-    p2_ = MakeUnique<IceTestPeer>("P2", test_utils_, false, allow_loopback,
-                                  enable_tcp, false, ice_policy);
+    p1_ = MakeUnique<IceTestPeer>("P1", test_utils_, true,
+                                  NrIceCtx::Config({.mPolicy = ice_policy}));
+    p2_ = MakeUnique<IceTestPeer>("P2", test_utils_, false,
+                                  NrIceCtx::Config({.mPolicy = ice_policy}));
     InitPeer(p1_.get(), setup_stun_servers);
     InitPeer(p2_.get(), setup_stun_servers);
 
     initted_ = true;
   }
 
   void InitPeer(IceTestPeer* peer, bool setup_stun_servers = true) {
     if (use_nat_) {
@@ -1627,17 +1613,17 @@ class WebRtcIceConnectTest : public Stun
           stun_server_address_, kDefaultStunServerPort, kNrIceTransportTcp));
 
       peer->SetStunServers(stun_servers);
     }
   }
 
   bool Gather(unsigned int waitTime = kDefaultTimeout,
               bool default_route_only = false) {
-    Init(false, false);
+    Init();
 
     return GatherCallerAndCallee(p1_.get(), p2_.get(), waitTime,
                                  default_route_only);
   }
 
   bool GatherCallerAndCallee(IceTestPeer* caller, IceTestPeer* callee,
                              unsigned int waitTime = kDefaultTimeout,
                              bool default_route_only = false) {
@@ -1936,18 +1922,20 @@ class WebRtcIcePrioritizerTest : public 
 
 class WebRtcIcePacketFilterTest : public StunTest {
  public:
   WebRtcIcePacketFilterTest() : udp_filter_(nullptr), tcp_filter_(nullptr) {}
 
   void SetUp() {
     StunTest::SetUp();
 
+    NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig());
+
     // Set up enough of the ICE ctx to allow the packet filter to work
-    ice_ctx_ = NrIceCtx::Create("test", true);
+    ice_ctx_ = NrIceCtx::Create("test", NrIceCtx::Config());
 
     nsCOMPtr<nsISocketFilterHandler> udp_handler =
         do_GetService(NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID);
     ASSERT_TRUE(udp_handler);
     udp_handler->NewFilter(getter_AddRefs(udp_filter_));
 
     nsCOMPtr<nsISocketFilterHandler> tcp_handler =
         do_GetService(NS_STUN_TCP_SOCKET_FILTER_HANDLER_CONTRACTID);
@@ -2048,121 +2036,137 @@ class WebRtcIcePacketFilterTest : public
 };
 }  // end namespace
 
 TEST_F(WebRtcIceGatherTest, TestGatherFakeStunServerHostnameNoResolver) {
   if (stun_server_hostname_.empty()) {
     return;
   }
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   peer_->SetStunServer(stun_server_hostname_, kDefaultStunServerPort);
   Gather();
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherFakeStunServerTcpHostnameNoResolver) {
   if (stun_server_hostname_.empty()) {
     return;
   }
 
-  EnsurePeer(ICE_TEST_PEER_OFFERER | ICE_TEST_PEER_ENABLED_TCP);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
+  EnsurePeer();
   peer_->SetStunServer(stun_server_hostname_, kDefaultStunServerPort,
                        kNrIceTransportTcp);
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " TCP "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherFakeStunServerIpAddress) {
   if (stun_server_address_.empty()) {
     return;
   }
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   peer_->SetStunServer(stun_server_address_, kDefaultStunServerPort);
   peer_->SetFakeResolver(stun_server_address_, stun_server_hostname_);
   Gather();
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherStunServerIpAddressNoHost) {
   if (stun_server_address_.empty()) {
     return;
   }
 
-  peer_ = MakeUnique<IceTestPeer>("P1", test_utils_, true, false, false, false,
-                                  NrIceCtx::ICE_POLICY_NO_HOST);
+  {
+    NrIceCtx::GlobalConfig config;
+    config.mTcpEnabled = false;
+    NrIceCtx::InitializeGlobals(config);
+  }
+
+  NrIceCtx::Config config;
+  config.mPolicy = NrIceCtx::ICE_POLICY_NO_HOST;
+  peer_ = MakeUnique<IceTestPeer>("P1", test_utils_, true, config);
   peer_->AddStream(1);
   peer_->SetStunServer(stun_server_address_, kDefaultStunServerPort);
   peer_->SetFakeResolver(stun_server_address_, stun_server_hostname_);
   Gather();
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " host "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherFakeStunServerHostname) {
   if (stun_server_hostname_.empty()) {
     return;
   }
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   peer_->SetStunServer(stun_server_hostname_, kDefaultStunServerPort);
   peer_->SetFakeResolver(stun_server_address_, stun_server_hostname_);
   Gather();
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherFakeStunBogusHostname) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort);
   peer_->SetFakeResolver(stun_server_address_, stun_server_hostname_);
   Gather();
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherDNSStunServerIpAddress) {
   if (stun_server_address_.empty()) {
     return;
   }
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   peer_->SetStunServer(stun_server_address_, kDefaultStunServerPort);
   peer_->SetDNSResolver();
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " UDP "));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "typ srflx raddr"));
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherDNSStunServerIpAddressTcp) {
   if (stun_server_address_.empty()) {
     return;
   }
 
-  EnsurePeer(ICE_TEST_PEER_OFFERER | ICE_TEST_PEER_ENABLED_TCP);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
+  EnsurePeer();
   peer_->SetStunServer(stun_server_address_, kDefaultStunServerPort,
                        kNrIceTransportTcp);
   peer_->SetDNSResolver();
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "tcptype passive"));
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "tcptype passive", " 9 "));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "tcptype so"));
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "tcptype so", " 9 "));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "tcptype active", " 9 "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherDNSStunServerHostname) {
   if (stun_server_hostname_.empty()) {
     return;
   }
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   peer_->SetStunServer(stun_server_hostname_, kDefaultStunServerPort);
   peer_->SetDNSResolver();
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " UDP "));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "typ srflx raddr"));
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherDNSStunServerHostnameTcp) {
-  EnsurePeer(ICE_TEST_PEER_OFFERER | ICE_TEST_PEER_ENABLED_TCP);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
+  EnsurePeer();
   peer_->SetStunServer(stun_server_hostname_, kDefaultStunServerPort,
                        kNrIceTransportTcp);
   peer_->SetDNSResolver();
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "tcptype passive"));
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "tcptype passive", " 9 "));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "tcptype so"));
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "tcptype so", " 9 "));
@@ -2171,17 +2175,18 @@ TEST_F(WebRtcIceGatherTest, TestGatherDN
 
 TEST_F(WebRtcIceGatherTest, TestGatherDNSStunServerHostnameBothUdpTcp) {
   if (stun_server_hostname_.empty()) {
     return;
   }
 
   std::vector<NrIceStunServer> stun_servers;
 
-  EnsurePeer(ICE_TEST_PEER_OFFERER | ICE_TEST_PEER_ENABLED_TCP);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
+  EnsurePeer();
   stun_servers.push_back(*NrIceStunServer::Create(
       stun_server_hostname_, kDefaultStunServerPort, kNrIceTransportUdp));
   stun_servers.push_back(*NrIceStunServer::Create(
       stun_server_hostname_, kDefaultStunServerPort, kNrIceTransportTcp));
   peer_->SetStunServers(stun_servers);
   peer_->SetDNSResolver();
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " UDP "));
@@ -2190,308 +2195,353 @@ TEST_F(WebRtcIceGatherTest, TestGatherDN
 
 TEST_F(WebRtcIceGatherTest, TestGatherDNSStunServerIpAddressBothUdpTcp) {
   if (stun_server_address_.empty()) {
     return;
   }
 
   std::vector<NrIceStunServer> stun_servers;
 
-  EnsurePeer(ICE_TEST_PEER_OFFERER | ICE_TEST_PEER_ENABLED_TCP);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
+  EnsurePeer();
   stun_servers.push_back(*NrIceStunServer::Create(
       stun_server_address_, kDefaultStunServerPort, kNrIceTransportUdp));
   stun_servers.push_back(*NrIceStunServer::Create(
       stun_server_address_, kDefaultStunServerPort, kNrIceTransportTcp));
   peer_->SetStunServers(stun_servers);
   peer_->SetDNSResolver();
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " UDP "));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " TCP "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherDNSStunBogusHostname) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort);
   peer_->SetDNSResolver();
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " UDP "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherDNSStunBogusHostnameTcp) {
-  EnsurePeer(ICE_TEST_PEER_OFFERER | ICE_TEST_PEER_ENABLED_TCP);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
+  EnsurePeer();
   peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort,
                        kNrIceTransportTcp);
   peer_->SetDNSResolver();
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " TCP "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestDefaultCandidate) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   peer_->SetStunServer(stun_server_hostname_, kDefaultStunServerPort);
   Gather();
   NrIceCandidate default_candidate;
   ASSERT_TRUE(NS_SUCCEEDED(peer_->GetDefaultCandidate(0, &default_candidate)));
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherTurn) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   if (turn_server_.empty()) return;
   peer_->SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                        turn_password_, kNrIceTransportUdp);
   Gather();
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherTurnTcp) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   if (turn_server_.empty()) return;
   peer_->SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                        turn_password_, kNrIceTransportTcp);
   Gather();
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherDisableComponent) {
   if (stun_server_hostname_.empty()) {
     return;
   }
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   peer_->SetStunServer(stun_server_hostname_, kDefaultStunServerPort);
   peer_->AddStream(2);
   peer_->DisableComponent(1, 2);
   Gather();
   std::vector<std::string> attributes = peer_->GetAttributes(1);
 
   for (auto& attribute : attributes) {
     if (attribute.find("candidate:") != std::string::npos) {
       size_t sp1 = attribute.find(' ');
       ASSERT_EQ(0, attribute.compare(sp1 + 1, 1, "1", 1));
     }
   }
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherVerifyNoLoopback) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   Gather();
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "127.0.0.1"));
 }
 
 TEST_F(WebRtcIceGatherTest, TestGatherAllowLoopback) {
+  NrIceCtx::GlobalConfig config({.mTcpEnabled = false});
+  config.mAllowLoopback = true;
+  NrIceCtx::InitializeGlobals(config);
+
   // Set up peer with loopback allowed.
-  peer_ = MakeUnique<IceTestPeer>("P1", test_utils_, true, true);
+  peer_ = MakeUnique<IceTestPeer>("P1", test_utils_, true, NrIceCtx::Config());
   peer_->AddStream(1);
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "127.0.0.1"));
 }
 
-TEST_F(WebRtcIceGatherTest, TestGatherTcpDisabled) {
-  // Set up peer with tcp disabled.
-  peer_ = MakeUnique<IceTestPeer>("P1", test_utils_, true, false, false);
-  peer_->AddStream(1);
+TEST_F(WebRtcIceGatherTest, TestGatherTcpDisabledNoStun) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
+  EnsurePeer();
   Gather();
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " TCP "));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " UDP "));
 }
 
 TEST_F(WebRtcIceGatherTest, VerifyTestStunServer) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseFakeStunUdpServerWithResponse("192.0.2.133", 3333);
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.133 3333 "));
 }
 
 TEST_F(WebRtcIceGatherTest, VerifyTestStunTcpServer) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
   UseFakeStunTcpServerWithResponse("192.0.2.233", 3333);
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.233 3333 typ srflx",
                                          " tcptype "));
 }
 
 TEST_F(WebRtcIceGatherTest, VerifyTestStunServerV6) {
   if (!TestStunServer::GetInstance(AF_INET6)) {
     // No V6 addresses
     return;
   }
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseFakeStunUdpServerWithResponse("beef::", 3333);
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " beef:: 3333 "));
 }
 
 TEST_F(WebRtcIceGatherTest, VerifyTestStunServerFQDN) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseFakeStunUdpServerWithResponse("192.0.2.133", 3333, "stun.example.com");
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.133 3333 "));
 }
 
 TEST_F(WebRtcIceGatherTest, VerifyTestStunServerV6FQDN) {
   if (!TestStunServer::GetInstance(AF_INET6)) {
     // No V6 addresses
     return;
   }
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseFakeStunUdpServerWithResponse("beef::", 3333, "stun.example.com");
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " beef:: 3333 "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestStunServerReturnsWildcardAddr) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseFakeStunUdpServerWithResponse("0.0.0.0", 3333);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 0.0.0.0 "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestStunServerReturnsWildcardAddrV6) {
   if (!TestStunServer::GetInstance(AF_INET6)) {
     // No V6 addresses
     return;
   }
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseFakeStunUdpServerWithResponse("::", 3333);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " :: "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestStunServerReturnsPort0) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseFakeStunUdpServerWithResponse("192.0.2.133", 0);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.2.133 0 "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestStunServerReturnsLoopbackAddr) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseFakeStunUdpServerWithResponse("127.0.0.133", 3333);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 127.0.0.133 "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestStunServerReturnsLoopbackAddrV6) {
   if (!TestStunServer::GetInstance(AF_INET6)) {
     // No V6 addresses
     return;
   }
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseFakeStunUdpServerWithResponse("::1", 3333);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " ::1 "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestStunServerTrickle) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseFakeStunUdpServerWithResponse("192.0.2.1", 3333);
   TestStunServer::GetInstance(AF_INET)->SetDropInitialPackets(3);
   Gather(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1"));
   WaitForGather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1"));
 }
 
 // Test no host with our fake STUN server and apparently NATted.
 TEST_F(WebRtcIceGatherTest, TestFakeStunServerNatedNoHost) {
-  peer_ = MakeUnique<IceTestPeer>("P1", test_utils_, true, false, false, false,
-                                  NrIceCtx::ICE_POLICY_NO_HOST);
+  {
+    NrIceCtx::GlobalConfig config;
+    config.mTcpEnabled = false;
+    NrIceCtx::InitializeGlobals(config);
+  }
+
+  NrIceCtx::Config config;
+  config.mPolicy = NrIceCtx::ICE_POLICY_NO_HOST;
+  peer_ = MakeUnique<IceTestPeer>("P1", test_utils_, true, config);
   peer_->AddStream(1);
   UseFakeStunUdpServerWithResponse("192.0.2.1", 3333);
   Gather(0);
   WaitForGather();
   DumpAttributes(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "host"));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "srflx"));
   NrIceCandidate default_candidate;
   nsresult rv = peer_->GetDefaultCandidate(0, &default_candidate);
   if (NS_SUCCEEDED(rv)) {
     ASSERT_NE(NrIceCandidate::ICE_HOST, default_candidate.type);
   }
 }
 
 // Test no host with our fake STUN server and apparently non-NATted.
 TEST_F(WebRtcIceGatherTest, TestFakeStunServerNoNatNoHost) {
-  peer_ = MakeUnique<IceTestPeer>("P1", test_utils_, true, false, false, false,
-                                  NrIceCtx::ICE_POLICY_NO_HOST);
+  {
+    NrIceCtx::GlobalConfig config;
+    config.mTcpEnabled = false;
+    NrIceCtx::InitializeGlobals(config);
+  }
+
+  NrIceCtx::Config config;
+  config.mPolicy = NrIceCtx::ICE_POLICY_NO_HOST;
+  peer_ = MakeUnique<IceTestPeer>("P1", test_utils_, true, config);
   peer_->AddStream(1);
   UseTestStunServer();
   Gather(0);
   WaitForGather();
   DumpAttributes(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "host"));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "srflx"));
 }
 
 TEST_F(WebRtcIceGatherTest, TestStunTcpServerTrickle) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
   UseFakeStunTcpServerWithResponse("192.0.3.1", 3333);
   TestStunTcpServer::GetInstance(AF_INET)->SetDelay(500);
   Gather(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
   WaitForGather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestStunTcpAndUdpServerTrickle) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
   UseFakeStunUdpTcpServersWithResponse("192.0.2.1", 3333, "192.0.3.1", 3333);
   TestStunServer::GetInstance(AF_INET)->SetDropInitialPackets(3);
   TestStunTcpServer::GetInstance(AF_INET)->SetDelay(500);
   Gather(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
   WaitForGather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
 }
 
 TEST_F(WebRtcIceGatherTest, TestSetIceControlling) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   peer_->SetControlling(NrIceCtx::ICE_CONTROLLING);
   NrIceCtx::Controlling controlling = peer_->GetControlling();
   ASSERT_EQ(NrIceCtx::ICE_CONTROLLING, controlling);
   // SetControlling should only allow setting this once
   peer_->SetControlling(NrIceCtx::ICE_CONTROLLED);
   controlling = peer_->GetControlling();
   ASSERT_EQ(NrIceCtx::ICE_CONTROLLING, controlling);
 }
 
 TEST_F(WebRtcIceGatherTest, TestSetIceControlled) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   EnsurePeer();
   peer_->SetControlling(NrIceCtx::ICE_CONTROLLED);
   NrIceCtx::Controlling controlling = peer_->GetControlling();
   ASSERT_EQ(NrIceCtx::ICE_CONTROLLED, controlling);
   // SetControlling should only allow setting this once
   peer_->SetControlling(NrIceCtx::ICE_CONTROLLING);
   controlling = peer_->GetControlling();
   ASSERT_EQ(NrIceCtx::ICE_CONTROLLED, controlling);
 }
 
 TEST_F(WebRtcIceConnectTest, TestGather) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
 }
 
 TEST_F(WebRtcIceConnectTest, TestGatherTcp) {
-  Init(false, true);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
+  Init();
   AddStream(1);
   ASSERT_TRUE(Gather());
 }
 
 TEST_F(WebRtcIceConnectTest, TestGatherAutoPrioritize) {
-  Init(false, false);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
+  Init();
   AddStream(1);
   ASSERT_TRUE(Gather());
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnect) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectRestartIce) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   Connect();
   SendReceive(p1_.get(), p2_.get());
 
   p2_->RestartIce();
   ASSERT_FALSE(p2_->gathering_complete());
 
   // verify p1 and p2 streams are still connected after restarting ice on p2
   SendReceive(p1_.get(), p2_.get());
 
   mozilla::UniquePtr<IceTestPeer> p3_;
-  p3_ = MakeUnique<IceTestPeer>("P3", test_utils_, true, false, false, false);
+  p3_ = MakeUnique<IceTestPeer>("P3", test_utils_, true, NrIceCtx::Config());
   InitPeer(p3_.get());
   p3_->AddStream(1);
 
   ASSERT_TRUE(GatherCallerAndCallee(p2_.get(), p3_.get()));
   std::cout << "-------------------------------------------------" << std::endl;
   ConnectCallerAndCallee(p3_.get(), p2_.get(), TRICKLE_SIMULATE);
   SendReceive(p1_.get(), p2_.get());  // p1 and p2 are still connected
   SendReceive(p3_.get(), p2_.get(), true, true);  // p3 and p2 not yet connected
@@ -2499,41 +2549,43 @@ TEST_F(WebRtcIceConnectTest, TestConnect
   p3_->SimulateTrickle(0);
   SendReceive(p1_.get(), p2_.get(), false, true);  // p1 and p2 not connected
   SendReceive(p3_.get(), p2_.get());  // p3 and p2 are now connected
 
   p3_ = nullptr;
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectRestartIceThenAbort) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   Connect();
   SendReceive(p1_.get(), p2_.get());
 
   p2_->RestartIce();
   ASSERT_FALSE(p2_->gathering_complete());
 
   // verify p1 and p2 streams are still connected after restarting ice on p2
   SendReceive(p1_.get(), p2_.get());
 
   mozilla::UniquePtr<IceTestPeer> p3_;
-  p3_ = MakeUnique<IceTestPeer>("P3", test_utils_, true, false, false, false);
+  p3_ = MakeUnique<IceTestPeer>("P3", test_utils_, true, NrIceCtx::Config());
   InitPeer(p3_.get());
   p3_->AddStream(1);
 
   ASSERT_TRUE(GatherCallerAndCallee(p2_.get(), p3_.get()));
   std::cout << "-------------------------------------------------" << std::endl;
   p2_->RollbackIceRestart();
   p2_->Connect(p1_.get(), TRICKLE_NONE);
   SendReceive(p1_.get(), p2_.get());
   p3_ = nullptr;
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectIceRestartRoleConflict) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   // Just for fun lets do this with switched rolls
   p1_->SetControlling(NrIceCtx::ICE_CONTROLLED);
   p2_->SetControlling(NrIceCtx::ICE_CONTROLLING);
   Connect();
   SendReceive(p1_.get(), p2_.get());
   // Set rolls should not switch by connecting
@@ -2542,17 +2594,17 @@ TEST_F(WebRtcIceConnectTest, TestConnect
 
   p2_->RestartIce();
   ASSERT_FALSE(p2_->gathering_complete());
   p2_->SetControlling(NrIceCtx::ICE_CONTROLLED);
   ASSERT_EQ(NrIceCtx::ICE_CONTROLLING, p2_->GetControlling())
       << "ICE restart should not allow role to change, unless ice-lite happens";
 
   mozilla::UniquePtr<IceTestPeer> p3_;
-  p3_ = MakeUnique<IceTestPeer>("P3", test_utils_, true, false, false, false);
+  p3_ = MakeUnique<IceTestPeer>("P3", test_utils_, true, NrIceCtx::Config());
   InitPeer(p3_.get());
   p3_->AddStream(1);
   // Set control role for p3 accordingly (with role conflict)
   p3_->SetControlling(NrIceCtx::ICE_CONTROLLING);
   ASSERT_EQ(NrIceCtx::ICE_CONTROLLING, p3_->GetControlling());
 
   ASSERT_TRUE(GatherCallerAndCallee(p2_.get(), p3_.get()));
   std::cout << "-------------------------------------------------" << std::endl;
@@ -2581,16 +2633,17 @@ TEST_F(WebRtcIceConnectTest,
   wifi_addr.interface.type = NR_INTERFACE_TYPE_WIFI;
   wifi_addr.interface.estimated_speed = 1000;
 
   int r = nr_str_port_to_transport_addr(FAKE_WIFI_ADDR, 0, IPPROTO_UDP,
                                         &(wifi_addr.addr));
   ASSERT_EQ(0, r);
   strncpy(wifi_addr.addr.ifname, FAKE_WIFI_IF_NAME, MAXIFNAME);
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   // setup initial ICE connection between p1_ and p2_
   UseNat();
   AddStream(1);
   SetExpectedTypes(NrIceCandidate::Type::ICE_SERVER_REFLEXIVE,
                    NrIceCandidate::Type::ICE_SERVER_REFLEXIVE);
   ASSERT_TRUE(Gather(kDefaultTimeout, true));
   Connect();
 
@@ -2612,250 +2665,281 @@ TEST_F(WebRtcIceConnectTest,
   ASSERT_FALSE(p2_->gathering_complete());
 
   // verify that we can successfully gather candidates
   p2_->Gather();
   EXPECT_TRUE_WAIT(p2_->gathering_complete(), kDefaultTimeout);
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTcp) {
-  Init(false, true);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
+  Init();
   AddStream(1);
   ASSERT_TRUE(Gather());
   SetCandidateFilter(IsTcpCandidate);
   SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
                    NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
   Connect();
 }
 
 // TCP SO tests works on localhost only with delay applied:
 //  tc qdisc add dev lo root netem delay 10ms
 TEST_F(WebRtcIceConnectTest, DISABLED_TestConnectTcpSo) {
-  Init(false, true);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
+  Init();
   AddStream(1);
   ASSERT_TRUE(Gather());
   SetCandidateFilter(IsTcpSoCandidate);
   SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
                    NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
   Connect();
 }
 
 // Disabled because this breaks with hairpinning.
 TEST_F(WebRtcIceConnectTest, DISABLED_TestConnectNoHost) {
-  Init(false, false, false, NrIceCtx::ICE_POLICY_NO_HOST);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
+  Init(false, NrIceCtx::ICE_POLICY_NO_HOST);
   AddStream(1);
   ASSERT_TRUE(Gather());
   SetExpectedTypes(NrIceCandidate::Type::ICE_SERVER_REFLEXIVE,
                    NrIceCandidate::Type::ICE_SERVER_REFLEXIVE,
                    kNrIceTransportTcp);
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestLoopbackOnlySortOf) {
-  Init(true, false, false);
+  NrIceCtx::GlobalConfig config({.mTcpEnabled = false});
+  config.mAllowLoopback = true;
+  NrIceCtx::InitializeGlobals(config);
+  Init(false);
   AddStream(1);
   SetCandidateFilter(IsLoopbackCandidate);
   ASSERT_TRUE(Gather());
   SetExpectedRemoteCandidateAddr("127.0.0.1");
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectBothControllingP1Wins) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   p1_->SetTiebreaker(1);
   p2_->SetTiebreaker(0);
   ASSERT_TRUE(Gather());
   p1_->SetControlling(NrIceCtx::ICE_CONTROLLING);
   p2_->SetControlling(NrIceCtx::ICE_CONTROLLING);
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectBothControllingP2Wins) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   p1_->SetTiebreaker(0);
   p2_->SetTiebreaker(1);
   ASSERT_TRUE(Gather());
   p1_->SetControlling(NrIceCtx::ICE_CONTROLLING);
   p2_->SetControlling(NrIceCtx::ICE_CONTROLLING);
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectIceLiteOfferer) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   p1_->SimulateIceLite();
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestTrickleBothControllingP1Wins) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   p1_->SetTiebreaker(1);
   p2_->SetTiebreaker(0);
   ASSERT_TRUE(Gather());
   p1_->SetControlling(NrIceCtx::ICE_CONTROLLING);
   p2_->SetControlling(NrIceCtx::ICE_CONTROLLING);
   ConnectTrickle();
   SimulateTrickle(0);
   WaitForConnected(1000);
   AssertCheckingReached();
 }
 
 TEST_F(WebRtcIceConnectTest, TestTrickleBothControllingP2Wins) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   p1_->SetTiebreaker(0);
   p2_->SetTiebreaker(1);
   ASSERT_TRUE(Gather());
   p1_->SetControlling(NrIceCtx::ICE_CONTROLLING);
   p2_->SetControlling(NrIceCtx::ICE_CONTROLLING);
   ConnectTrickle();
   SimulateTrickle(0);
   WaitForConnected(1000);
   AssertCheckingReached();
 }
 
 TEST_F(WebRtcIceConnectTest, TestTrickleIceLiteOfferer) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   p1_->SimulateIceLite();
   ConnectTrickle();
   SimulateTrickle(0);
   WaitForConnected(1000);
   AssertCheckingReached();
 }
 
 TEST_F(WebRtcIceConnectTest, TestGatherFullCone) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseNat();
   AddStream(1);
   ASSERT_TRUE(Gather());
 }
 
 TEST_F(WebRtcIceConnectTest, TestGatherFullConeAutoPrioritize) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseNat();
-  Init(true, false);
+  Init();
   AddStream(1);
   ASSERT_TRUE(Gather());
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectFullCone) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseNat();
   AddStream(1);
   SetExpectedTypes(NrIceCandidate::Type::ICE_SERVER_REFLEXIVE,
                    NrIceCandidate::Type::ICE_SERVER_REFLEXIVE);
   ASSERT_TRUE(Gather());
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectNoNatNoHost) {
-  Init(false, false, false, NrIceCtx::ICE_POLICY_NO_HOST);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
+  Init(false, NrIceCtx::ICE_POLICY_NO_HOST);
   AddStream(1);
   UseTestStunServer();
   // Because we are connecting from our host candidate to the
   // other side's apparent srflx (which is also their host)
   // we see a host/srflx pair.
   SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
                    NrIceCandidate::Type::ICE_SERVER_REFLEXIVE);
   ASSERT_TRUE(Gather());
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectFullConeNoHost) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseNat();
-  Init(false, false, false, NrIceCtx::ICE_POLICY_NO_HOST);
+  Init(false, NrIceCtx::ICE_POLICY_NO_HOST);
   AddStream(1);
   UseTestStunServer();
   SetExpectedTypes(NrIceCandidate::Type::ICE_SERVER_REFLEXIVE,
                    NrIceCandidate::Type::ICE_SERVER_REFLEXIVE);
   ASSERT_TRUE(Gather());
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestGatherAddressRestrictedCone) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseNat();
   SetFilteringType(TestNat::ADDRESS_DEPENDENT);
   SetMappingType(TestNat::ENDPOINT_INDEPENDENT);
   AddStream(1);
   ASSERT_TRUE(Gather());
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectAddressRestrictedCone) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseNat();
   SetFilteringType(TestNat::ADDRESS_DEPENDENT);
   SetMappingType(TestNat::ENDPOINT_INDEPENDENT);
   AddStream(1);
   SetExpectedTypes(NrIceCandidate::Type::ICE_SERVER_REFLEXIVE,
                    NrIceCandidate::Type::ICE_SERVER_REFLEXIVE);
   ASSERT_TRUE(Gather());
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestGatherPortRestrictedCone) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseNat();
   SetFilteringType(TestNat::PORT_DEPENDENT);
   SetMappingType(TestNat::ENDPOINT_INDEPENDENT);
   AddStream(1);
   ASSERT_TRUE(Gather());
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectPortRestrictedCone) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseNat();
   SetFilteringType(TestNat::PORT_DEPENDENT);
   SetMappingType(TestNat::ENDPOINT_INDEPENDENT);
   AddStream(1);
   SetExpectedTypes(NrIceCandidate::Type::ICE_SERVER_REFLEXIVE,
                    NrIceCandidate::Type::ICE_SERVER_REFLEXIVE);
   ASSERT_TRUE(Gather());
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestGatherSymmetricNat) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseNat();
   SetFilteringType(TestNat::PORT_DEPENDENT);
   SetMappingType(TestNat::PORT_DEPENDENT);
   AddStream(1);
   ASSERT_TRUE(Gather());
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectSymmetricNat) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseNat();
   SetFilteringType(TestNat::PORT_DEPENDENT);
   SetMappingType(TestNat::PORT_DEPENDENT);
   AddStream(1);
   p1_->SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
                         NrIceCandidate::Type::ICE_RELAYED);
   p2_->SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
                         NrIceCandidate::Type::ICE_RELAYED);
   SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                 turn_password_);
   ASSERT_TRUE(Gather());
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectSymmetricNatAndNoNat) {
-  p1_ = MakeUnique<IceTestPeer>("P1", test_utils_, true, false, false);
+  {
+    NrIceCtx::GlobalConfig config;
+    config.mTcpEnabled = true;
+    NrIceCtx::InitializeGlobals(config);
+  }
+
+  NrIceCtx::Config config;
+  p1_ = MakeUnique<IceTestPeer>("P1", test_utils_, true, config);
   p1_->UseNat();
   p1_->SetFilteringType(TestNat::PORT_DEPENDENT);
   p1_->SetMappingType(TestNat::PORT_DEPENDENT);
 
-  p2_ = MakeUnique<IceTestPeer>("P2", test_utils_, false, false, false);
+  p2_ = MakeUnique<IceTestPeer>("P2", test_utils_, false, config);
   initted_ = true;
 
   AddStream(1);
   p1_->SetExpectedTypes(NrIceCandidate::Type::ICE_PEER_REFLEXIVE,
                         NrIceCandidate::Type::ICE_HOST);
   p2_->SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
                         NrIceCandidate::Type::ICE_PEER_REFLEXIVE);
   ASSERT_TRUE(Gather());
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestGatherNatBlocksUDP) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseNat();
   BlockUdp();
   AddStream(1);
   std::vector<NrIceTurnServer> turn_servers;
   std::vector<unsigned char> password_vec(turn_password_.begin(),
                                           turn_password_.end());
   turn_servers.push_back(
       *NrIceTurnServer::Create(turn_server_, kDefaultStunServerPort, turn_user_,
@@ -2866,16 +2950,17 @@ TEST_F(WebRtcIceConnectTest, TestGatherN
   SetTurnServers(turn_servers);
   // We have to wait for the UDP-based stuff to time out.
   ASSERT_TRUE(Gather(kDefaultTimeout * 3));
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectNatBlocksUDP) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   UseNat();
   BlockUdp();
   AddStream(1);
   std::vector<NrIceTurnServer> turn_servers;
   std::vector<unsigned char> password_vec(turn_password_.begin(),
                                           turn_password_.end());
   turn_servers.push_back(
       *NrIceTurnServer::Create(turn_server_, kDefaultStunServerPort, turn_user_,
@@ -2888,80 +2973,88 @@ TEST_F(WebRtcIceConnectTest, TestConnect
                         NrIceCandidate::Type::ICE_RELAYED, kNrIceTransportTcp);
   p2_->SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
                         NrIceCandidate::Type::ICE_RELAYED, kNrIceTransportTcp);
   ASSERT_TRUE(Gather(kDefaultTimeout * 3));
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTwoComponents) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(2);
   ASSERT_TRUE(Gather());
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTwoComponentsDisableSecond) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(2);
   ASSERT_TRUE(Gather());
   p1_->DisableComponent(0, 2);
   p2_->DisableComponent(0, 2);
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectP2ThenP1) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectP2();
   PR_Sleep(1000);
   ConnectP1();
   WaitForConnectedStreams();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectP2ThenP1Trickle) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectP2();
   PR_Sleep(1000);
   ConnectP1(TRICKLE_SIMULATE);
   SimulateTrickleP1(0);
   WaitForConnectedStreams();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectP2ThenP1TrickleTwoComponents) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   AddStream(2);
   ASSERT_TRUE(Gather());
   ConnectP2();
   PR_Sleep(1000);
   ConnectP1(TRICKLE_SIMULATE);
   SimulateTrickleP1(0);
   std::cerr << "Sleeping between trickle streams" << std::endl;
   PR_Sleep(1000);  // Give this some time to settle but not complete
                    // all of ICE.
   SimulateTrickleP1(1);
   WaitForConnectedStreams(2);
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectAutoPrioritize) {
-  Init(false, false);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
+  Init();
   AddStream(1);
   ASSERT_TRUE(Gather());
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTrickleOneStreamOneComponent) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   SimulateTrickle(0);
   WaitForConnected(1000);
   AssertCheckingReached();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTrickleTwoStreamsOneComponent) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   SimulateTrickle(0);
   SimulateTrickle(1);
   WaitForConnected(1000);
   AssertCheckingReached();
@@ -3033,79 +3126,85 @@ void AddNonPairableCandidates(
     (*i)->Schedule(0);
   }
 }
 
 void DropTrickleCandidates(
     std::vector<SchedulableTrickleCandidate*>& candidates) {}
 
 TEST_F(WebRtcIceConnectTest, TestConnectTrickleAddStreamDuringICE) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   RealisticTrickleDelay(p1_->ControlTrickle(0));
   RealisticTrickleDelay(p2_->ControlTrickle(0));
   AddStream(1);
   RealisticTrickleDelay(p1_->ControlTrickle(1));
   RealisticTrickleDelay(p2_->ControlTrickle(1));
   WaitForConnected(1000);
   AssertCheckingReached();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTrickleAddStreamAfterICE) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   RealisticTrickleDelay(p1_->ControlTrickle(0));
   RealisticTrickleDelay(p2_->ControlTrickle(0));
   WaitForConnected(1000);
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   RealisticTrickleDelay(p1_->ControlTrickle(1));
   RealisticTrickleDelay(p2_->ControlTrickle(1));
   WaitForConnected(1000);
   AssertCheckingReached();
 }
 
 TEST_F(WebRtcIceConnectTest, RemoveStream) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   RealisticTrickleDelay(p1_->ControlTrickle(0));
   RealisticTrickleDelay(p2_->ControlTrickle(0));
   RealisticTrickleDelay(p1_->ControlTrickle(1));
   RealisticTrickleDelay(p2_->ControlTrickle(1));
   WaitForConnected(1000);
 
   RemoveStream(0);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
 }
 
 TEST_F(WebRtcIceConnectTest, P1NoTrickle) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   DropTrickleCandidates(p1_->ControlTrickle(0));
   RealisticTrickleDelay(p2_->ControlTrickle(0));
   WaitForConnected(1000);
 }
 
 TEST_F(WebRtcIceConnectTest, P2NoTrickle) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   RealisticTrickleDelay(p1_->ControlTrickle(0));
   DropTrickleCandidates(p2_->ControlTrickle(0));
   WaitForConnected(1000);
 }
 
 TEST_F(WebRtcIceConnectTest, RemoveAndAddStream) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   RealisticTrickleDelay(p1_->ControlTrickle(0));
   RealisticTrickleDelay(p2_->ControlTrickle(0));
   RealisticTrickleDelay(p1_->ControlTrickle(1));
   RealisticTrickleDelay(p2_->ControlTrickle(1));
@@ -3116,113 +3215,123 @@ TEST_F(WebRtcIceConnectTest, RemoveAndAd
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   RealisticTrickleDelay(p1_->ControlTrickle(2));
   RealisticTrickleDelay(p2_->ControlTrickle(2));
   WaitForConnected(1000);
 }
 
 TEST_F(WebRtcIceConnectTest, RemoveStreamBeforeGather) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   AddStream(1);
   ASSERT_TRUE(Gather(0));
   RemoveStream(0);
   WaitForGather();
   ConnectTrickle();
   RealisticTrickleDelay(p1_->ControlTrickle(1));
   RealisticTrickleDelay(p2_->ControlTrickle(1));
   WaitForConnected(1000);
 }
 
 TEST_F(WebRtcIceConnectTest, RemoveStreamDuringGather) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   AddStream(1);
   RemoveStream(0);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   RealisticTrickleDelay(p1_->ControlTrickle(1));
   RealisticTrickleDelay(p2_->ControlTrickle(1));
   WaitForConnected(1000);
 }
 
 TEST_F(WebRtcIceConnectTest, RemoveStreamDuringConnect) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   RealisticTrickleDelay(p1_->ControlTrickle(0));
   RealisticTrickleDelay(p2_->ControlTrickle(0));
   RealisticTrickleDelay(p1_->ControlTrickle(1));
   RealisticTrickleDelay(p2_->ControlTrickle(1));
   RemoveStream(0);
   WaitForConnected(1000);
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectRealTrickleOneStreamOneComponent) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   AddStream(1);
   ASSERT_TRUE(Gather(0));
   ConnectTrickle(TRICKLE_REAL);
   WaitForConnected();
   WaitForGather();  // ICE can complete before we finish gathering.
   AssertCheckingReached();
 }
 
 TEST_F(WebRtcIceConnectTest, TestSendReceive) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   Connect();
   SendReceive();
 }
 
 TEST_F(WebRtcIceConnectTest, TestSendReceiveTcp) {
-  Init(false, true);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
+  Init();
   AddStream(1);
   ASSERT_TRUE(Gather());
   SetCandidateFilter(IsTcpCandidate);
   SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
                    NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
   Connect();
   SendReceive();
 }
 
 // TCP SO tests works on localhost only with delay applied:
 //  tc qdisc add dev lo root netem delay 10ms
 TEST_F(WebRtcIceConnectTest, DISABLED_TestSendReceiveTcpSo) {
-  Init(false, true);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
+  Init();
   AddStream(1);
   ASSERT_TRUE(Gather());
   SetCandidateFilter(IsTcpSoCandidate);
   SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
                    NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
   Connect();
   SendReceive();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConsent) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetupAndCheckConsent();
   PR_Sleep(1500);
   AssertConsentRefresh();
   SendReceive();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConsentTcp) {
-  Init(false, true);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = true}));
+  Init();
   AddStream(1);
   SetCandidateFilter(IsTcpCandidate);
   SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
                    NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
   SetupAndCheckConsent();
   PR_Sleep(1500);
   AssertConsentRefresh();
   SendReceive();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConsentIntermittent) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetupAndCheckConsent();
   p1_->SetBlockStun(true);
   p2_->SetBlockStun(true);
   WaitForDisconnected();
   AssertConsentRefresh(CONSENT_STALE);
   SendReceive();
   p1_->SetBlockStun(false);
@@ -3237,70 +3346,76 @@ TEST_F(WebRtcIceConnectTest, TestConsent
   SendReceive();
   p1_->SetBlockStun(false);
   p2_->SetBlockStun(false);
   WaitForConnected();
   AssertConsentRefresh();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConsentTimeout) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetupAndCheckConsent();
   p1_->SetBlockStun(true);
   p2_->SetBlockStun(true);
   WaitForDisconnected();
   AssertConsentRefresh(CONSENT_STALE);
   SendReceive();
   WaitForFailed();
   AssertConsentRefresh(CONSENT_EXPIRED);
   SendFailure();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConsentDelayed) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetupAndCheckConsent();
   /* Note: We don't have a list of STUN transaction IDs of the previously timed
            out consent requests. Thus responses after sending the next consent
            request are ignored. */
   p1_->SetStunResponseDelay(200);
   p2_->SetStunResponseDelay(200);
   PR_Sleep(1000);
   AssertConsentRefresh();
   SendReceive();
 }
 
 TEST_F(WebRtcIceConnectTest, TestNetworkForcedOfflineAndRecovery) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetupAndCheckConsent();
   p1_->ChangeNetworkStateToOffline();
   ASSERT_TRUE_WAIT(p1_->ice_connected() == 0, kDefaultTimeout);
   // Next round of consent check should switch it back to online
   ASSERT_TRUE_WAIT(p1_->ice_connected(), kDefaultTimeout);
 }
 
 TEST_F(WebRtcIceConnectTest, TestNetworkForcedOfflineTwice) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetupAndCheckConsent();
   p2_->ChangeNetworkStateToOffline();
   ASSERT_TRUE_WAIT(p2_->ice_connected() == 0, kDefaultTimeout);
   p2_->ChangeNetworkStateToOffline();
   ASSERT_TRUE_WAIT(p2_->ice_connected() == 0, kDefaultTimeout);
 }
 
 TEST_F(WebRtcIceConnectTest, TestNetworkOnlineDoesntChangeState) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetupAndCheckConsent();
   p2_->ChangeNetworkStateToOnline();
   ASSERT_TRUE(p2_->ice_connected());
   PR_Sleep(1500);
   p2_->ChangeNetworkStateToOnline();
   ASSERT_TRUE(p2_->ice_connected());
 }
 
 TEST_F(WebRtcIceConnectTest, TestNetworkOnlineTriggersConsent) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   // Let's emulate audio + video w/o rtcp-mux
   AddStream(2);
   AddStream(2);
   SetupAndCheckConsent();
   p1_->ChangeNetworkStateToOffline();
   p1_->SetBlockStun(true);
   ASSERT_TRUE_WAIT(p1_->ice_connected() == 0, kDefaultTimeout);
   PR_Sleep(1500);
@@ -3308,71 +3423,76 @@ TEST_F(WebRtcIceConnectTest, TestNetwork
   p1_->SetBlockStun(false);
   p1_->ChangeNetworkStateToOnline();
   ASSERT_TRUE_WAIT(p1_->ice_connected(), 500);
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTurn) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                 turn_password_);
   ASSERT_TRUE(Gather());
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTurnWithDelay) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                 turn_password_);
   SetCandidateFilter(SabotageHostCandidateAndDropReflexive);
   p1_->Gather();
   PR_Sleep(500);
   p2_->Gather();
   ConnectTrickle(TRICKLE_REAL);
   WaitForGather();
   WaitForConnectedStreams();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTurnWithNormalTrickleDelay) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                 turn_password_);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   RealisticTrickleDelay(p1_->ControlTrickle(0));
   RealisticTrickleDelay(p2_->ControlTrickle(0));
 
   WaitForConnected();
   AssertCheckingReached();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTurnWithNormalTrickleDelayOneSided) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                 turn_password_);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   RealisticTrickleDelay(p1_->ControlTrickle(0));
   p2_->SimulateTrickle(0);
 
   WaitForConnected();
   AssertCheckingReached();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTurnWithLargeTrickleDelay) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                 turn_password_);
   SetCandidateFilter(SabotageHostCandidateAndDropReflexive);
   ASSERT_TRUE(Gather());
   ConnectTrickle();
   // Trickle host candidates immediately, but delay relay candidates
   DelayRelayCandidates(p1_->ControlTrickle(0), 3700);
@@ -3380,80 +3500,86 @@ TEST_F(WebRtcIceConnectTest, TestConnect
 
   WaitForConnected();
   AssertCheckingReached();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTurnTcp) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                 turn_password_, kNrIceTransportTcp);
   ASSERT_TRUE(Gather());
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTurnOnly) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                 turn_password_);
   ASSERT_TRUE(Gather());
   SetCandidateFilter(IsRelayCandidate);
   SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
                    NrIceCandidate::Type::ICE_RELAYED);
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectTurnTcpOnly) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                 turn_password_, kNrIceTransportTcp);
   ASSERT_TRUE(Gather());
   SetCandidateFilter(IsRelayCandidate);
   SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
                    NrIceCandidate::Type::ICE_RELAYED, kNrIceTransportTcp);
   Connect();
 }
 
 TEST_F(WebRtcIceConnectTest, TestSendReceiveTurnOnly) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                 turn_password_);
   ASSERT_TRUE(Gather());
   SetCandidateFilter(IsRelayCandidate);
   SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
                    NrIceCandidate::Type::ICE_RELAYED);
   Connect();
   SendReceive();
 }
 
 TEST_F(WebRtcIceConnectTest, TestSendReceiveTurnTcpOnly) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   SetTurnServer(turn_server_, kDefaultStunServerPort, turn_user_,
                 turn_password_, kNrIceTransportTcp);
   ASSERT_TRUE(Gather());
   SetCandidateFilter(IsRelayCandidate);
   SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
                    NrIceCandidate::Type::ICE_RELAYED, kNrIceTransportTcp);
   Connect();
   SendReceive();
 }
 
 TEST_F(WebRtcIceConnectTest, TestSendReceiveTurnBothOnly) {
   if (turn_server_.empty()) return;
 
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   std::vector<NrIceTurnServer> turn_servers;
   std::vector<unsigned char> password_vec(turn_password_.begin(),
                                           turn_password_.end());
   turn_servers.push_back(
       *NrIceTurnServer::Create(turn_server_, kDefaultStunServerPort, turn_user_,
                                password_vec, kNrIceTransportTcp));
   turn_servers.push_back(
@@ -3465,37 +3591,40 @@ TEST_F(WebRtcIceConnectTest, TestSendRec
   // UDP is preferred.
   SetExpectedTypes(NrIceCandidate::Type::ICE_RELAYED,
                    NrIceCandidate::Type::ICE_RELAYED, kNrIceTransportUdp);
   Connect();
   SendReceive();
 }
 
 TEST_F(WebRtcIceConnectTest, TestConnectShutdownOneSide) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   ConnectThenDelete();
 }
 
 TEST_F(WebRtcIceConnectTest, TestPollCandPairsBeforeConnect) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
 
   std::vector<NrIceCandidatePair> pairs;
   nsresult res = p1_->GetCandidatePairs(0, &pairs);
   // There should be no candidate pairs prior to calling Connect()
   ASSERT_EQ(NS_OK, res);
   ASSERT_EQ(0U, pairs.size());
 
   res = p2_->GetCandidatePairs(0, &pairs);
   ASSERT_EQ(NS_OK, res);
   ASSERT_EQ(0U, pairs.size());
 }
 
 TEST_F(WebRtcIceConnectTest, TestPollCandPairsAfterConnect) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
   Connect();
 
   std::vector<NrIceCandidatePair> pairs;
   nsresult r = p1_->GetCandidatePairs(0, &pairs);
   ASSERT_EQ(NS_OK, r);
   // How detailed of a check do we want to do here? If the turn server is
@@ -3511,17 +3640,18 @@ TEST_F(WebRtcIceConnectTest, TestPollCan
   ASSERT_NE(0U, pairs.size());
   ASSERT_TRUE(p2_->CandidatePairsPriorityDescending(pairs));
   ASSERT_TRUE(ContainsSucceededPair(pairs));
 }
 
 // TODO Bug 1259842 - disabled until we find a better way to handle two
 // candidates from different RFC1918 ranges
 TEST_F(WebRtcIceConnectTest, DISABLED_TestHostCandPairingFilter) {
-  Init(false, false, false);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
+  Init(false);
   AddStream(1);
   ASSERT_TRUE(Gather());
   SetCandidateFilter(IsIpv4Candidate);
 
   int host_net = p1_->GetCandidatesPrivateIpv4Range(0);
   if (host_net <= 0) {
     // TODO bug 1226838: make this work with multiple private IPs
     FAIL() << "This test needs exactly one private IPv4 host candidate to work"
@@ -3550,17 +3680,18 @@ TEST_F(WebRtcIceConnectTest, DISABLED_Te
 }
 
 // TODO Bug 1226838 - See Comment 2 - this test can't work as written
 TEST_F(WebRtcIceConnectTest, DISABLED_TestSrflxCandPairingFilter) {
   if (stun_server_address_.empty()) {
     return;
   }
 
-  Init(false, false, false);
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
+  Init(false);
   AddStream(1);
   ASSERT_TRUE(Gather());
   SetCandidateFilter(IsSrflxCandidate);
 
   if (p1_->GetCandidatesPrivateIpv4Range(0) <= 0) {
     // TODO bug 1226838: make this work with public IP addresses
     std::cerr << "Don't run this test at IETF meetings!" << std::endl;
     FAIL() << "This test needs one private IPv4 host candidate to work"
@@ -3594,16 +3725,17 @@ TEST_F(WebRtcIceConnectTest, DISABLED_Te
     ASSERT_TRUE(nr_transport_addr_get_private_addr_range(&addr) != 0);
     nr_str_port_to_transport_addr(p.remote.cand_addr.host.c_str(), 0,
                                   IPPROTO_UDP, &addr);
     ASSERT_TRUE(nr_transport_addr_get_private_addr_range(&addr) == 0);
   }
 }
 
 TEST_F(WebRtcIceConnectTest, TestPollCandPairsDuringConnect) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
 
   p2_->Connect(p1_.get(), TRICKLE_NONE, false);
   p1_->Connect(p2_.get(), TRICKLE_NONE, false);
 
   std::vector<NrIceCandidatePair> pairs1;
   std::vector<NrIceCandidatePair> pairs2;
@@ -3619,16 +3751,17 @@ TEST_F(WebRtcIceConnectTest, TestPollCan
   WaitForConnectedStreams();
   p1_->UpdateAndValidateCandidatePairs(0, &pairs1);
   p2_->UpdateAndValidateCandidatePairs(0, &pairs2);
   ASSERT_TRUE(ContainsSucceededPair(pairs1));
   ASSERT_TRUE(ContainsSucceededPair(pairs2));
 }
 
 TEST_F(WebRtcIceConnectTest, TestRLogConnector) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   ASSERT_TRUE(Gather());
 
   p2_->Connect(p1_.get(), TRICKLE_NONE, false);
   p1_->Connect(p2_.get(), TRICKLE_NONE, false);
 
   std::vector<NrIceCandidatePair> pairs1;
   std::vector<NrIceCandidatePair> pairs2;
@@ -3662,41 +3795,44 @@ TEST_F(WebRtcIceConnectTest, TestRLogCon
     RLogConnector::GetInstance()->Filter(substring, 0, &logs);
     ASSERT_NE(0U, logs.size());
   }
 }
 
 // Verify that a bogus candidate doesn't cause crashes on the
 // main thread. See bug 856433.
 TEST_F(WebRtcIceConnectTest, TestBogusCandidate) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   Gather();
   ConnectTrickle();
   p1_->ParseCandidate(0, kBogusIceCandidate, "");
 
   std::vector<NrIceCandidatePair> pairs;
   nsresult res = p1_->GetCandidatePairs(0, &pairs);
   ASSERT_EQ(NS_OK, res);
   ASSERT_EQ(0U, pairs.size());
 }
 
 TEST_F(WebRtcIceConnectTest, TestNonMDNSCandidate) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   Gather();
   ConnectTrickle();
   p1_->ParseCandidate(0, kUnreachableHostIceCandidate, "");
 
   std::vector<NrIceCandidatePair> pairs;
   nsresult res = p1_->GetCandidatePairs(0, &pairs);
   ASSERT_EQ(NS_OK, res);
   ASSERT_EQ(1U, pairs.size());
   ASSERT_EQ(pairs[0].remote.mdns_addr, "");
 }
 
 TEST_F(WebRtcIceConnectTest, TestMDNSCandidate) {
+  NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig({.mTcpEnabled = false}));
   AddStream(1);
   Gather();
   ConnectTrickle();
   p1_->ParseCandidate(0, kUnreachableHostIceCandidate, "host.local");
 
   std::vector<NrIceCandidatePair> pairs;
   nsresult res = p1_->GetCandidatePairs(0, &pairs);
   ASSERT_EQ(NS_OK, res);
--- a/media/mtransport/test/multi_tcp_socket_unittest.cpp
+++ b/media/mtransport/test/multi_tcp_socket_unittest.cpp
@@ -38,17 +38,18 @@ namespace {
 class MultiTcpSocketTest : public MtransportTest {
  public:
   MultiTcpSocketTest()
       : MtransportTest(), socks(3, nullptr), readable(false), ice_ctx_() {}
 
   void SetUp() {
     MtransportTest::SetUp();
 
-    ice_ctx_ = NrIceCtx::Create("stun", true);
+    NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig());
+    ice_ctx_ = NrIceCtx::Create("stun", NrIceCtx::Config());
 
     test_utils_->sts_target()->Dispatch(
         WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET),
         NS_DISPATCH_SYNC);
     test_utils_->sts_target()->Dispatch(
         WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET6),
         NS_DISPATCH_SYNC);
   }
--- a/media/mtransport/test/test_nr_socket_ice_unittest.cpp
+++ b/media/mtransport/test/test_nr_socket_ice_unittest.cpp
@@ -302,17 +302,17 @@ class TestNrSocketIceUnitTest : public :
  public:
   void SetUp() override {
     NSS_NoDB_Init(nullptr);
     NSS_SetDomesticPolicy();
 
     test_utils_ = new MtransportTestUtils();
     test_utils2_ = new MtransportTestUtils();
 
-    NrIceCtx::InitializeGlobals(false, false, false);
+    NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig());
   }
 
   void TearDown() override {
     delete test_utils_;
     delete test_utils2_;
   }
 
   MtransportTestUtils* test_utils_;
--- a/media/mtransport/test/transport_unittests.cpp
+++ b/media/mtransport/test/transport_unittests.cpp
@@ -437,24 +437,26 @@ class TransportTestPeer : public sigslot
         received_packets_(0),
         received_bytes_(0),
         flow_(new TransportFlow(name)),
         loopback_(new TransportLayerLoopback()),
         logging_(new TransportLayerLogging()),
         lossy_(new TransportLayerLossy()),
         dtls_(new TransportLayerDtls()),
         identity_(DtlsIdentity::Generate()),
-        ice_ctx_(NrIceCtx::Create(name)),
+        ice_ctx_(),
         streams_(),
         peer_(nullptr),
         gathering_complete_(false),
         digest_("sha-1"),
         enabled_cipersuites_(),
         disabled_cipersuites_(),
         test_utils_(utils) {
+    NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig());
+    ice_ctx_ = NrIceCtx::Create(name, NrIceCtx::Config());
     std::vector<NrIceStunServer> stun_servers;
     UniquePtr<NrIceStunServer> server(NrIceStunServer::Create(
         std::string((char*)"stun.services.mozilla.com"), 3478));
     stun_servers.push_back(*server);
     EXPECT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(stun_servers)));
 
     dtls_->SetIdentity(identity_);
     dtls_->SetRole(offerer_ ? TransportLayerDtls::SERVER
--- a/media/mtransport/test/turn_unittest.cpp
+++ b/media/mtransport/test/turn_unittest.cpp
@@ -91,17 +91,17 @@ class TurnClient : public MtransportTest
         turn_ctx_(nullptr),
         allocated_(false),
         received_(0),
         protocol_(IPPROTO_UDP) {}
 
   ~TurnClient() = default;
 
   static void SetUpTestCase() {
-    NrIceCtx::InitializeGlobals(false, false, false);
+    NrIceCtx::InitializeGlobals(NrIceCtx::GlobalConfig());
   }
 
   void SetTcp() { protocol_ = IPPROTO_TCP; }
 
   void Init_s() {
     int r;
     nr_transport_addr addr;
     r = nr_ip4_port_to_transport_addr(0, 0, protocol_, &addr);
--- a/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp
+++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp
@@ -154,18 +154,18 @@ class MediaTransportHandlerSTS : public 
                    dom::RTCStatsCollection* aStats) const;
 
   virtual ~MediaTransportHandlerSTS() = default;
   nsCOMPtr<nsISerialEventTarget> mStsThread;
   RefPtr<NrIceCtx> mIceCtx;
   RefPtr<NrIceResolver> mDNSResolver;
   std::map<std::string, Transport> mTransports;
   bool mObfuscateHostAddresses = false;
-  uint32_t minDtlsVersion = 0;
-  uint32_t maxDtlsVersion = 0;
+  uint32_t mMinDtlsVersion = 0;
+  uint32_t mMaxDtlsVersion = 0;
 
   std::set<std::string> mSignaledAddresses;
 
   // Init can only be done on main, but we want this to be usable on any thread
   typedef MozPromise<bool, std::string, false> InitPromise;
   RefPtr<InitPromise> mInitPromise;
 };
 
@@ -335,16 +335,66 @@ nsresult MediaTransportHandler::ConvertI
         return rv;
       }
     }
   }
 
   return NS_OK;
 }
 
+static NrIceCtx::GlobalConfig GetGlobalConfig() {
+  NrIceCtx::GlobalConfig config;
+  config.mAllowLinkLocal =
+      Preferences::GetBool("media.peerconnection.ice.link_local", false);
+  config.mAllowLoopback =
+      Preferences::GetBool("media.peerconnection.ice.loopback", false);
+  config.mTcpEnabled =
+      Preferences::GetBool("media.peerconnection.ice.tcp", false);
+  config.mStunClientMaxTransmits = Preferences::GetInt(
+      "media.peerconnection.ice.stun_client_maximum_transmits",
+      config.mStunClientMaxTransmits);
+  config.mTrickleIceGracePeriod =
+      Preferences::GetInt("media.peerconnection.ice.trickle_grace_period",
+                          config.mTrickleIceGracePeriod);
+  config.mIceTcpSoSockCount = Preferences::GetInt(
+      "media.peerconnection.ice.tcp_so_sock_count", config.mIceTcpSoSockCount);
+  config.mIceTcpListenBacklog =
+      Preferences::GetInt("media.peerconnection.ice.tcp_listen_backlog",
+                          config.mIceTcpListenBacklog);
+  (void)Preferences::GetCString("media.peerconnection.ice.force_interface",
+                                config.mForceNetInterface);
+  return config;
+}
+
+static Maybe<NrIceCtx::NatSimulatorConfig> GetNatConfig() {
+  bool block_tcp = Preferences::GetBool(
+      "media.peerconnection.nat_simulator.block_tcp", false);
+  bool block_udp = Preferences::GetBool(
+      "media.peerconnection.nat_simulator.block_udp", false);
+  nsAutoCString mapping_type;
+  (void)Preferences::GetCString(
+      "media.peerconnection.nat_simulator.mapping_type", mapping_type);
+  nsAutoCString filtering_type;
+  (void)Preferences::GetCString(
+      "media.peerconnection.nat_simulator.filtering_type", filtering_type);
+
+  if (block_udp || block_tcp || !mapping_type.IsEmpty() ||
+      !filtering_type.IsEmpty()) {
+    CSFLogDebug(LOGTAG, "NAT filtering type: %s", filtering_type.get());
+    CSFLogDebug(LOGTAG, "NAT mapping type: %s", mapping_type.get());
+    NrIceCtx::NatSimulatorConfig natConfig;
+    natConfig.mBlockUdp = block_udp;
+    natConfig.mBlockTcp = block_tcp;
+    natConfig.mFilteringType = filtering_type;
+    natConfig.mMappingType = mapping_type;
+    return Some(natConfig);
+  }
+  return Nothing();
+}
+
 nsresult MediaTransportHandlerSTS::CreateIceCtx(
     const std::string& aName, const nsTArray<dom::RTCIceServer>& aIceServers,
     dom::RTCIceTransportPolicy aIcePolicy) {
   // We rely on getting an error when this happens, so do it up front.
   std::vector<NrIceStunServer> stunServers;
   std::vector<NrIceTurnServer> turnServers;
   nsresult rv = ConvertIceServers(aIceServers, &stunServers, &turnServers);
   if (NS_FAILED(rv)) {
@@ -366,82 +416,90 @@ nsresult MediaTransportHandlerSTS::Creat
             MOZ_CRASH();
             return InitPromise::CreateAndReject("InitializeCipherSuite failed",
                                                 __func__);
           }
 
           mozilla::psm::DisableMD5();
         }
 
-        // This stuff will probably live on the other side of IPC; errors down
-        // here will either need to be ignored, or plumbed back in some way
-        // other than the return.
-        bool allowLoopback =
-            Preferences::GetBool("media.peerconnection.ice.loopback", false);
-        bool tcpEnabled =
-            Preferences::GetBool("media.peerconnection.ice.tcp", false);
-        bool allowLinkLocal =
-            Preferences::GetBool("media.peerconnection.ice.link_local", false);
-
-        mIceCtx = NrIceCtx::Create(aName, allowLoopback, tcpEnabled,
-                                   allowLinkLocal, toNrIcePolicy(aIcePolicy));
-        if (!mIceCtx) {
-          return InitPromise::CreateAndReject("NrIceCtx::Create failed",
-                                              __func__);
+        static bool globalInitDone = false;
+        if (!globalInitDone) {
+          mStsThread->Dispatch(
+              WrapRunnableNM(&NrIceCtx::InitializeGlobals, GetGlobalConfig()),
+              NS_DISPATCH_NORMAL);
+          globalInitDone = true;
         }
 
-        mIceCtx->SignalGatheringStateChange.connect(
-            this, &MediaTransportHandlerSTS::OnGatheringStateChange);
-        mIceCtx->SignalConnectionStateChange.connect(
-            this, &MediaTransportHandlerSTS::OnConnectionStateChange);
-
-        nsresult rv;
-
-        if (NS_FAILED(rv = mIceCtx->SetStunServers(stunServers))) {
-          CSFLogError(LOGTAG, "%s: Failed to set stun servers", __FUNCTION__);
-          return InitPromise::CreateAndReject("Failed to set stun servers",
-                                              __func__);
-        }
         // Give us a way to globally turn off TURN support
-        bool disabled =
+        bool turnDisabled =
             Preferences::GetBool("media.peerconnection.turn.disable", false);
-        if (!disabled) {
-          if (NS_FAILED(rv = mIceCtx->SetTurnServers(turnServers))) {
-            CSFLogError(LOGTAG, "%s: Failed to set turn servers", __FUNCTION__);
-            return InitPromise::CreateAndReject("Failed to set turn servers",
-                                                __func__);
-          }
-        } else if (!turnServers.empty()) {
-          CSFLogError(LOGTAG, "%s: Setting turn servers disabled",
-                      __FUNCTION__);
-        }
-
-        mDNSResolver = new NrIceResolver;
-        if (NS_FAILED(rv = mDNSResolver->Init())) {
-          CSFLogError(LOGTAG, "%s: Failed to initialize dns resolver",
-                      __FUNCTION__);
-          return InitPromise::CreateAndReject(
-              "Failed to initialize dns resolver", __func__);
-        }
-        if (NS_FAILED(
-                rv = mIceCtx->SetResolver(mDNSResolver->AllocateResolver()))) {
-          CSFLogError(LOGTAG, "%s: Failed to get dns resolver", __FUNCTION__);
-          return InitPromise::CreateAndReject("Failed to get dns resolver",
-                                              __func__);
-        }
-
         // We are reading these here, because when we setup the DTLS transport
         // we are on the wrong thread to read prefs
-        minDtlsVersion =
+        mMinDtlsVersion =
             Preferences::GetUint("media.peerconnection.dtls.version.min");
-        maxDtlsVersion =
+        mMaxDtlsVersion =
             Preferences::GetUint("media.peerconnection.dtls.version.max");
 
-        CSFLogDebug(LOGTAG, "%s done", __func__);
-        return InitPromise::CreateAndResolve(true, __func__);
+        NrIceCtx::Config config;
+        config.mPolicy = toNrIcePolicy(aIcePolicy);
+        config.mNatSimulatorConfig = GetNatConfig();
+
+        return InvokeAsync(
+            mStsThread, __func__,
+            [=, self = RefPtr<MediaTransportHandlerSTS>(this)]() {
+              mIceCtx = NrIceCtx::Create(aName, config);
+              if (!mIceCtx) {
+                return InitPromise::CreateAndReject("NrIceCtx::Create failed",
+                                                    __func__);
+              }
+
+              mIceCtx->SignalGatheringStateChange.connect(
+                  this, &MediaTransportHandlerSTS::OnGatheringStateChange);
+              mIceCtx->SignalConnectionStateChange.connect(
+                  this, &MediaTransportHandlerSTS::OnConnectionStateChange);
+
+              nsresult rv;
+
+              if (NS_FAILED(rv = mIceCtx->SetStunServers(stunServers))) {
+                CSFLogError(LOGTAG, "%s: Failed to set stun servers",
+                            __FUNCTION__);
+                return InitPromise::CreateAndReject(
+                    "Failed to set stun servers", __func__);
+              }
+              if (!turnDisabled) {
+                if (NS_FAILED(rv = mIceCtx->SetTurnServers(turnServers))) {
+                  CSFLogError(LOGTAG, "%s: Failed to set turn servers",
+                              __FUNCTION__);
+                  return InitPromise::CreateAndReject(
+                      "Failed to set turn servers", __func__);
+                }
+              } else if (!turnServers.empty()) {
+                CSFLogError(LOGTAG, "%s: Setting turn servers disabled",
+                            __FUNCTION__);
+              }
+
+              mDNSResolver = new NrIceResolver;
+              if (NS_FAILED(rv = mDNSResolver->Init())) {
+                CSFLogError(LOGTAG, "%s: Failed to initialize dns resolver",
+                            __FUNCTION__);
+                return InitPromise::CreateAndReject(
+                    "Failed to initialize dns resolver", __func__);
+              }
+              if (NS_FAILED(rv = mIceCtx->SetResolver(
+                                mDNSResolver->AllocateResolver()))) {
+                CSFLogError(LOGTAG, "%s: Failed to get dns resolver",
+                            __FUNCTION__);
+                return InitPromise::CreateAndReject(
+                    "Failed to get dns resolver", __func__);
+              }
+
+              CSFLogDebug(LOGTAG, "%s done", __func__);
+              return InitPromise::CreateAndResolve(true, __func__);
+            });
       });
   return NS_OK;
 }
 
 void MediaTransportHandlerSTS::Destroy() {
   if (!mInitPromise) {
     return;
   }
@@ -1188,18 +1246,18 @@ RefPtr<TransportFlow> MediaTransportHand
   auto dtls = MakeUnique<TransportLayerDtls>();
   auto srtp = MakeUnique<TransportLayerSrtp>(*dtls);
   dtls->SetRole(aDtlsClient ? TransportLayerDtls::CLIENT
                             : TransportLayerDtls::SERVER);
 
   dtls->SetIdentity(aDtlsIdentity);
 
   dtls->SetMinMaxVersion(
-      static_cast<TransportLayerDtls::Version>(minDtlsVersion),
-      static_cast<TransportLayerDtls::Version>(maxDtlsVersion));
+      static_cast<TransportLayerDtls::Version>(mMinDtlsVersion),
+      static_cast<TransportLayerDtls::Version>(mMaxDtlsVersion));
 
   for (const auto& digest : aDigests) {
     rv = dtls->SetVerificationDigest(digest);
     if (NS_FAILED(rv)) {
       CSFLogError(LOGTAG, "Could not set fingerprint");
       return nullptr;
     }
   }