Add signaling to support ICE renomination.
By default, this will tell the remote side that I am supporting ICE renomination.
It does not use ICE renomination yet even if the remote side supports it.

R=deadbeef@webrtc.org, pthatcher@webrtc.org, skvlad@webrtc.org

Review URL: https://codereview.webrtc.org/2224563004 .

Cr-Commit-Position: refs/heads/master@{#13998}
diff --git a/webrtc/api/peerconnection.cc b/webrtc/api/peerconnection.cc
index b13113a..bdd33d7 100644
--- a/webrtc/api/peerconnection.cc
+++ b/webrtc/api/peerconnection.cc
@@ -633,6 +633,8 @@
 
   stats_.reset(new StatsCollector(this));
 
+  enable_ice_renomination_ = configuration.enable_ice_renomination;
+
   // Initialize the WebRtcSession. It creates transport channels etc.
   if (!session_->Initialize(factory_->options(), std::move(cert_generator),
                             configuration)) {
@@ -1262,6 +1264,8 @@
 
   // TODO(deadbeef): Shouldn't have to hop to the worker thread twice...
   session_->SetIceConfig(session_->ParseIceConfig(configuration));
+
+  enable_ice_renomination_ = configuration.enable_ice_renomination;
   return true;
 }
 
@@ -1615,6 +1619,8 @@
           cricket::TransportOptions();
     }
   }
+  session_options->enable_ice_renomination = enable_ice_renomination_;
+
   if (!ExtractMediaSessionOptions(rtc_options, true, session_options)) {
     return false;
   }
@@ -1651,6 +1657,13 @@
   return true;
 }
 
+void PeerConnection::InitializeOptionsForAnswer(
+    cricket::MediaSessionOptions* session_options) {
+  session_options->recv_audio = false;
+  session_options->recv_video = false;
+  session_options->enable_ice_renomination = enable_ice_renomination_;
+}
+
 void PeerConnection::FinishOptionsForAnswer(
     cricket::MediaSessionOptions* session_options) {
   // TODO(deadbeef): Once we have transceivers, enumerate them here instead of
@@ -1685,8 +1698,7 @@
 bool PeerConnection::GetOptionsForAnswer(
     const MediaConstraintsInterface* constraints,
     cricket::MediaSessionOptions* session_options) {
-  session_options->recv_audio = false;
-  session_options->recv_video = false;
+  InitializeOptionsForAnswer(session_options);
   if (!ParseConstraintsForAnswer(constraints, session_options)) {
     return false;
   }
@@ -1699,8 +1711,7 @@
 bool PeerConnection::GetOptionsForAnswer(
     const RTCOfferAnswerOptions& options,
     cricket::MediaSessionOptions* session_options) {
-  session_options->recv_audio = false;
-  session_options->recv_video = false;
+  InitializeOptionsForAnswer(session_options);
   if (!ExtractMediaSessionOptions(options, false, session_options)) {
     return false;
   }
diff --git a/webrtc/api/peerconnection.h b/webrtc/api/peerconnection.h
index c4a9a60..042e7f1 100644
--- a/webrtc/api/peerconnection.h
+++ b/webrtc/api/peerconnection.h
@@ -239,6 +239,9 @@
       const RTCOfferAnswerOptions& options,
       cricket::MediaSessionOptions* session_options);
 
+  void InitializeOptionsForAnswer(
+      cricket::MediaSessionOptions* session_options);
+
   // Helper function for options processing.
   // Deprecated.
   virtual void FinishOptionsForAnswer(
@@ -414,6 +417,8 @@
 
   bool remote_peer_supports_msid_ = false;
 
+  bool enable_ice_renomination_ = false;
+
   std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
       senders_;
   std::vector<
diff --git a/webrtc/api/peerconnection_unittest.cc b/webrtc/api/peerconnection_unittest.cc
index 33b7b2f..fb3c188 100644
--- a/webrtc/api/peerconnection_unittest.cc
+++ b/webrtc/api/peerconnection_unittest.cc
@@ -393,6 +393,15 @@
 
   bool ExpectIceRestart() const { return expect_ice_restart_; }
 
+  void SetExpectIceRenomination(bool expect_renomination) {
+    expect_ice_renomination_ = expect_renomination;
+  }
+  void SetExpectRemoteIceRenomination(bool expect_renomination) {
+    expect_remote_ice_renomination_ = expect_renomination;
+  }
+  bool ExpectIceRenomination() { return expect_ice_renomination_; }
+  bool ExpectRemoteIceRenomination() { return expect_remote_ice_renomination_; }
+
   void SetReceiveAudioVideo(bool audio, bool video) {
     SetReceiveAudio(audio);
     SetReceiveVideo(video);
@@ -670,6 +679,42 @@
     }
   }
 
+  void VerifyLocalIceRenomination() {
+    ASSERT_TRUE(peer_connection_->local_description() != nullptr);
+    const cricket::SessionDescription* desc =
+        peer_connection_->local_description()->description();
+    const cricket::ContentInfos& contents = desc->contents();
+
+    for (auto content : contents) {
+      if (content.rejected)
+        continue;
+      const cricket::TransportDescription* transport_desc =
+          desc->GetTransportDescriptionByName(content.name);
+      const auto& options = transport_desc->transport_options;
+      auto iter = std::find(options.begin(), options.end(),
+                            cricket::ICE_RENOMINATION_STR);
+      EXPECT_EQ(ExpectIceRenomination(), iter != options.end());
+    }
+  }
+
+  void VerifyRemoteIceRenomination() {
+    ASSERT_TRUE(peer_connection_->remote_description() != nullptr);
+    const cricket::SessionDescription* desc =
+        peer_connection_->remote_description()->description();
+    const cricket::ContentInfos& contents = desc->contents();
+
+    for (auto content : contents) {
+      if (content.rejected)
+        continue;
+      const cricket::TransportDescription* transport_desc =
+          desc->GetTransportDescriptionByName(content.name);
+      const auto& options = transport_desc->transport_options;
+      auto iter = std::find(options.begin(), options.end(),
+                            cricket::ICE_RENOMINATION_STR);
+      EXPECT_EQ(ExpectRemoteIceRenomination(), iter != options.end());
+    }
+  }
+
   int GetAudioOutputLevelStats(webrtc::MediaStreamTrackInterface* track) {
     rtc::scoped_refptr<MockStatsObserver>
         observer(new rtc::RefCountedObject<MockStatsObserver>());
@@ -1030,6 +1075,8 @@
   typedef std::pair<std::string, std::string> IceUfragPwdPair;
   std::map<int, IceUfragPwdPair> ice_ufrag_pwd_;
   bool expect_ice_restart_ = false;
+  bool expect_ice_renomination_ = false;
+  bool expect_remote_ice_renomination_ = false;
 
   // Needed to keep track of number of frames sent.
   rtc::scoped_refptr<FakeAudioCaptureModule> fake_audio_capture_module_;
@@ -2128,6 +2175,32 @@
   EXPECT_NE(receiver_candidate, receiver_candidate_restart);
 }
 
+TEST_F(P2PTestConductor, IceRenominationDisabled) {
+  config()->enable_ice_renomination = false;
+  ASSERT_TRUE(CreateTestClients());
+  LocalP2PTest();
+
+  initializing_client()->VerifyLocalIceRenomination();
+  receiving_client()->VerifyLocalIceRenomination();
+  initializing_client()->VerifyRemoteIceRenomination();
+  receiving_client()->VerifyRemoteIceRenomination();
+}
+
+TEST_F(P2PTestConductor, IceRenominationEnabled) {
+  config()->enable_ice_renomination = true;
+  ASSERT_TRUE(CreateTestClients());
+  initializing_client()->SetExpectIceRenomination(true);
+  initializing_client()->SetExpectRemoteIceRenomination(true);
+  receiving_client()->SetExpectIceRenomination(true);
+  receiving_client()->SetExpectRemoteIceRenomination(true);
+  LocalP2PTest();
+
+  initializing_client()->VerifyLocalIceRenomination();
+  receiving_client()->VerifyLocalIceRenomination();
+  initializing_client()->VerifyRemoteIceRenomination();
+  receiving_client()->VerifyRemoteIceRenomination();
+}
+
 // This test sets up a call between two parties with audio, and video.
 // It then renegotiates setting the video m-line to "port 0", then later
 // renegotiates again, enabling video.
diff --git a/webrtc/api/peerconnectioninterface.h b/webrtc/api/peerconnectioninterface.h
index 1dba14c..624c67f 100644
--- a/webrtc/api/peerconnectioninterface.h
+++ b/webrtc/api/peerconnectioninterface.h
@@ -317,6 +317,9 @@
     // If set to true, this means the ICE transport should presume TURN-to-TURN
     // candidate pairs will succeed, even before a binding response is received.
     bool presume_writable_when_fully_relayed = false;
+    // If true, "renomination" will be added to the ice options in the transport
+    // description.
+    bool enable_ice_renomination = false;
     // If true, ICE role is redetermined when peerconnection sets a local
     // transport description that indicates an ICE restart.
     bool redetermine_role_on_ice_restart = true;
@@ -329,18 +332,13 @@
     // The default value for constraint offerToReceiveX:true.
     static const int kOfferToReceiveMediaTrue = 1;
 
-    int offer_to_receive_video;
-    int offer_to_receive_audio;
-    bool voice_activity_detection;
-    bool ice_restart;
-    bool use_rtp_mux;
+    int offer_to_receive_video = kUndefined;
+    int offer_to_receive_audio = kUndefined;
+    bool voice_activity_detection = true;
+    bool ice_restart = false;
+    bool use_rtp_mux = true;
 
-    RTCOfferAnswerOptions()
-        : offer_to_receive_video(kUndefined),
-          offer_to_receive_audio(kUndefined),
-          voice_activity_detection(true),
-          ice_restart(false),
-          use_rtp_mux(true) {}
+    RTCOfferAnswerOptions() = default;
 
     RTCOfferAnswerOptions(int offer_to_receive_video,
                           int offer_to_receive_audio,
diff --git a/webrtc/p2p/base/dtlstransportchannel.h b/webrtc/p2p/base/dtlstransportchannel.h
index 9f6c563..19823f8 100644
--- a/webrtc/p2p/base/dtlstransportchannel.h
+++ b/webrtc/p2p/base/dtlstransportchannel.h
@@ -163,13 +163,11 @@
   void SetIceTiebreaker(uint64_t tiebreaker) override {
     channel_->SetIceTiebreaker(tiebreaker);
   }
-  void SetIceCredentials(const std::string& ice_ufrag,
-                         const std::string& ice_pwd) override {
-    channel_->SetIceCredentials(ice_ufrag, ice_pwd);
+  void SetIceParameters(const IceParameters& ice_params) override {
+    channel_->SetIceParameters(ice_params);
   }
-  void SetRemoteIceCredentials(const std::string& ice_ufrag,
-                               const std::string& ice_pwd) override {
-    channel_->SetRemoteIceCredentials(ice_ufrag, ice_pwd);
+  void SetRemoteIceParameters(const IceParameters& ice_params) override {
+    channel_->SetRemoteIceParameters(ice_params);
   }
   void SetRemoteIceMode(IceMode mode) override {
     channel_->SetRemoteIceMode(mode);
diff --git a/webrtc/p2p/base/faketransportcontroller.h b/webrtc/p2p/base/faketransportcontroller.h
index d795254..153aa56 100644
--- a/webrtc/p2p/base/faketransportcontroller.h
+++ b/webrtc/p2p/base/faketransportcontroller.h
@@ -88,15 +88,13 @@
   void SetIceTiebreaker(uint64_t tiebreaker) override {
     tiebreaker_ = tiebreaker;
   }
-  void SetIceCredentials(const std::string& ice_ufrag,
-                         const std::string& ice_pwd) override {
-    ice_ufrag_ = ice_ufrag;
-    ice_pwd_ = ice_pwd;
+  void SetIceParameters(const IceParameters& ice_params) override {
+    ice_ufrag_ = ice_params.ufrag;
+    ice_pwd_ = ice_params.pwd;
   }
-  void SetRemoteIceCredentials(const std::string& ice_ufrag,
-                               const std::string& ice_pwd) override {
-    remote_ice_ufrag_ = ice_ufrag;
-    remote_ice_pwd_ = ice_pwd;
+  void SetRemoteIceParameters(const IceParameters& params) override {
+    remote_ice_ufrag_ = params.ufrag;
+    remote_ice_pwd_ = params.pwd;
   }
 
   void SetRemoteIceMode(IceMode mode) override { remote_ice_mode_ = mode; }
diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc
index 03b0ed4..f5f8a66 100644
--- a/webrtc/p2p/base/p2ptransportchannel.cc
+++ b/webrtc/p2p/base/p2ptransportchannel.cc
@@ -308,38 +308,37 @@
   return TransportChannelState::STATE_COMPLETED;
 }
 
-void P2PTransportChannel::SetIceCredentials(const std::string& ice_ufrag,
-                                            const std::string& ice_pwd) {
+void P2PTransportChannel::SetIceParameters(const IceParameters& ice_params) {
   ASSERT(worker_thread_ == rtc::Thread::Current());
-  ice_ufrag_ = ice_ufrag;
-  ice_pwd_ = ice_pwd;
+  ice_parameters_ = ice_params;
   // Note: Candidate gathering will restart when MaybeStartGathering is next
   // called.
 }
 
-void P2PTransportChannel::SetRemoteIceCredentials(const std::string& ice_ufrag,
-                                                  const std::string& ice_pwd) {
+void P2PTransportChannel::SetRemoteIceParameters(
+    const IceParameters& ice_params) {
   ASSERT(worker_thread_ == rtc::Thread::Current());
+  LOG(LS_INFO) << "Remote supports ICE renomination ? "
+               << ice_params.renomination;
   IceParameters* current_ice = remote_ice();
-  IceParameters new_ice(ice_ufrag, ice_pwd);
-  if (!current_ice || *current_ice != new_ice) {
+  if (!current_ice || *current_ice != ice_params) {
     // Keep the ICE credentials so that newer connections
     // are prioritized over the older ones.
-    remote_ice_parameters_.push_back(new_ice);
+    remote_ice_parameters_.push_back(ice_params);
   }
 
   // Update the pwd of remote candidate if needed.
   for (RemoteCandidate& candidate : remote_candidates_) {
-    if (candidate.username() == ice_ufrag && candidate.password().empty()) {
-      candidate.set_password(ice_pwd);
+    if (candidate.username() == ice_params.ufrag &&
+        candidate.password().empty()) {
+      candidate.set_password(ice_params.pwd);
     }
   }
   // We need to update the credentials and generation for any peer reflexive
   // candidates.
   for (Connection* conn : connections_) {
-    conn->MaybeSetRemoteIceCredentialsAndGeneration(
-        ice_ufrag, ice_pwd,
-        static_cast<int>(remote_ice_parameters_.size() - 1));
+    conn->MaybeSetRemoteIceParametersAndGeneration(
+        ice_params, static_cast<int>(remote_ice_parameters_.size() - 1));
   }
   // Updating the remote ICE candidate generation could change the sort order.
   RequestSortAndStateUpdate();
@@ -434,22 +433,23 @@
 }
 
 void P2PTransportChannel::MaybeStartGathering() {
-  if (ice_ufrag_.empty() || ice_pwd_.empty()) {
+  if (ice_parameters_.ufrag.empty() || ice_parameters_.pwd.empty()) {
     return;
   }
   // Start gathering if we never started before, or if an ICE restart occurred.
   if (allocator_sessions_.empty() ||
       IceCredentialsChanged(allocator_sessions_.back()->ice_ufrag(),
-                            allocator_sessions_.back()->ice_pwd(), ice_ufrag_,
-                            ice_pwd_)) {
+                            allocator_sessions_.back()->ice_pwd(),
+                            ice_parameters_.ufrag, ice_parameters_.pwd)) {
     if (gathering_state_ != kIceGatheringGathering) {
       gathering_state_ = kIceGatheringGathering;
       SignalGatheringState(this);
     }
     // Time for a new allocator.
     std::unique_ptr<PortAllocatorSession> pooled_session =
-        allocator_->TakePooledSession(transport_name(), component(), ice_ufrag_,
-                                      ice_pwd_);
+        allocator_->TakePooledSession(transport_name(), component(),
+                                      ice_parameters_.ufrag,
+                                      ice_parameters_.pwd);
     if (pooled_session) {
       AddAllocatorSession(std::move(pooled_session));
       PortAllocatorSession* raw_pooled_session =
@@ -465,7 +465,8 @@
       }
     } else {
       AddAllocatorSession(allocator_->CreateSession(
-          transport_name(), component(), ice_ufrag_, ice_pwd_));
+          transport_name(), component(), ice_parameters_.ufrag,
+          ice_parameters_.pwd));
       LOG(LS_INFO) << "Start getting ports";
       allocator_sessions_.back()->StartGettingPorts();
     }
@@ -1625,7 +1626,10 @@
   bool use_candidate_attr = false;
   uint32_t nomination = 0;
   if (ice_role_ == ICEROLE_CONTROLLING) {
-    if (remote_supports_renomination_) {
+    bool renomination_supported = ice_parameters_.renomination &&
+                                  !remote_ice_parameters_.empty() &&
+                                  remote_ice_parameters_.back().renomination;
+    if (renomination_supported) {
       nomination = GetNominationAttr(conn);
     } else {
       use_candidate_attr =
diff --git a/webrtc/p2p/base/p2ptransportchannel.h b/webrtc/p2p/base/p2ptransportchannel.h
index 25510c2..a6dfd88 100644
--- a/webrtc/p2p/base/p2ptransportchannel.h
+++ b/webrtc/p2p/base/p2ptransportchannel.h
@@ -43,18 +43,6 @@
 extern const int STABLE_WRITABLE_CONNECTION_PING_INTERVAL;
 static const int MIN_PINGS_AT_WEAK_PING_INTERVAL = 3;
 
-struct IceParameters {
-  std::string ufrag;
-  std::string pwd;
-  IceParameters(const std::string& ice_ufrag, const std::string& ice_pwd)
-      : ufrag(ice_ufrag), pwd(ice_pwd) {}
-
-  bool operator==(const IceParameters& other) {
-    return ufrag == other.ufrag && pwd == other.pwd;
-  }
-  bool operator!=(const IceParameters& other) { return !(*this == other); }
-};
-
 // Adds the port on which the candidate originated.
 class RemoteCandidate : public Candidate {
  public:
@@ -88,10 +76,8 @@
   void SetIceRole(IceRole role) override;
   IceRole GetIceRole() const override { return ice_role_; }
   void SetIceTiebreaker(uint64_t tiebreaker) override;
-  void SetIceCredentials(const std::string& ice_ufrag,
-                         const std::string& ice_pwd) override;
-  void SetRemoteIceCredentials(const std::string& ice_ufrag,
-                               const std::string& ice_pwd) override;
+  void SetIceParameters(const IceParameters& ice_params) override;
+  void SetRemoteIceParameters(const IceParameters& ice_params) override;
   void SetRemoteIceMode(IceMode mode) override;
   // TODO(deadbeef): Deprecated. Remove when Chromium's
   // IceTransportChannel does not depend on this.
@@ -209,11 +195,6 @@
     return remote_candidates_;
   }
 
-  // Public for unit tests.
-  void set_remote_supports_renomination(bool remote_supports_renomination) {
-    remote_supports_renomination_ = remote_supports_renomination;
-  }
-
  private:
   rtc::Thread* thread() const { return worker_thread_; }
   bool IsGettingPorts() { return allocator_session()->IsGettingPorts(); }
@@ -395,8 +376,7 @@
   bool had_connection_ = false;  // if connections_ has ever been nonempty
   typedef std::map<rtc::Socket::Option, int> OptionMap;
   OptionMap options_;
-  std::string ice_ufrag_;
-  std::string ice_pwd_;
+  IceParameters ice_parameters_;
   std::vector<IceParameters> remote_ice_parameters_;
   IceMode remote_ice_mode_;
   IceRole ice_role_;
@@ -410,10 +390,6 @@
   IceConfig config_;
   int last_sent_packet_id_ = -1;  // -1 indicates no packet was sent before.
   bool started_pinging_ = false;
-  // TODO(honghaiz): Put this and ICE role inside ICEParameters and rename this
-  // as renomination. Set its value in subsequent CLs based on signaling
-  // exchange.
-  bool remote_supports_renomination_ = false;
   // The value put in the "nomination" attribute for the next nominated
   // connection. A zero-value indicates the connection will not be nominated.
   uint32_t nomination_ = 0;
diff --git a/webrtc/p2p/base/p2ptransportchannel_unittest.cc b/webrtc/p2p/base/p2ptransportchannel_unittest.cc
index 26db621..d7e8773 100644
--- a/webrtc/p2p/base/p2ptransportchannel_unittest.cc
+++ b/webrtc/p2p/base/p2ptransportchannel_unittest.cc
@@ -92,16 +92,19 @@
 static const cricket::RelayCredentials kRelayCredentials("test", "test");
 
 // Based on ICE_UFRAG_LENGTH
-static const char* kIceUfrag[4] = {"UF00", "UF01",
-                                   "UF02", "UF03"};
+const char* kIceUfrag[4] = {"UF00", "UF01", "UF02", "UF03"};
 // Based on ICE_PWD_LENGTH
-static const char* kIcePwd[4] = {"TESTICEPWD00000000000000",
-                                 "TESTICEPWD00000000000001",
-                                 "TESTICEPWD00000000000002",
-                                 "TESTICEPWD00000000000003"};
+const char* kIcePwd[4] = {
+    "TESTICEPWD00000000000000", "TESTICEPWD00000000000001",
+    "TESTICEPWD00000000000002", "TESTICEPWD00000000000003"};
+const cricket::IceParameters kIceParams[4] = {
+    {kIceUfrag[0], kIcePwd[0], false},
+    {kIceUfrag[1], kIcePwd[1], false},
+    {kIceUfrag[2], kIcePwd[2], false},
+    {kIceUfrag[3], kIcePwd[3], false}};
 
-static const uint64_t kLowTiebreaker = 11111;
-static const uint64_t kHighTiebreaker = 22222;
+const uint64_t kLowTiebreaker = 11111;
+const uint64_t kHighTiebreaker = 22222;
 
 enum { MSG_ADD_CANDIDATES, MSG_REMOVE_CANDIDATES };
 
@@ -131,7 +134,7 @@
   return c;
 }
 
-}  // namespace {
+}  // namespace
 
 namespace cricket {
 
@@ -305,34 +308,38 @@
       return ep2_.GetChannelData(channel);
   }
 
+  IceParameters IceParamsWithRenomination(const IceParameters& ice,
+                                          bool renomination) {
+    IceParameters new_ice = ice;
+    new_ice.renomination = renomination;
+    return new_ice;
+  }
+
   void CreateChannels(int num,
                       const IceConfig& ep1_config,
-                      const IceConfig& ep2_config) {
-    std::string ice_ufrag_ep1_cd1_ch = kIceUfrag[0];
-    std::string ice_pwd_ep1_cd1_ch = kIcePwd[0];
-    std::string ice_ufrag_ep2_cd1_ch = kIceUfrag[1];
-    std::string ice_pwd_ep2_cd1_ch = kIcePwd[1];
-    ep1_.cd1_.ch_.reset(CreateChannel(
-        0, ICE_CANDIDATE_COMPONENT_DEFAULT, ice_ufrag_ep1_cd1_ch,
-        ice_pwd_ep1_cd1_ch, ice_ufrag_ep2_cd1_ch, ice_pwd_ep2_cd1_ch));
-    ep2_.cd1_.ch_.reset(CreateChannel(
-        1, ICE_CANDIDATE_COMPONENT_DEFAULT, ice_ufrag_ep2_cd1_ch,
-        ice_pwd_ep2_cd1_ch, ice_ufrag_ep1_cd1_ch, ice_pwd_ep1_cd1_ch));
+                      const IceConfig& ep2_config,
+                      bool renomination = false) {
+    IceParameters ice_ep1_cd1_ch =
+        IceParamsWithRenomination(kIceParams[0], renomination);
+    IceParameters ice_ep2_cd1_ch =
+        IceParamsWithRenomination(kIceParams[1], renomination);
+    ep1_.cd1_.ch_.reset(CreateChannel(0, ICE_CANDIDATE_COMPONENT_DEFAULT,
+                                      ice_ep1_cd1_ch, ice_ep2_cd1_ch));
+    ep2_.cd1_.ch_.reset(CreateChannel(1, ICE_CANDIDATE_COMPONENT_DEFAULT,
+                                      ice_ep2_cd1_ch, ice_ep1_cd1_ch));
     ep1_.cd1_.ch_->SetIceConfig(ep1_config);
     ep2_.cd1_.ch_->SetIceConfig(ep2_config);
     ep1_.cd1_.ch_->MaybeStartGathering();
     ep2_.cd1_.ch_->MaybeStartGathering();
     if (num == 2) {
-      std::string ice_ufrag_ep1_cd2_ch = kIceUfrag[2];
-      std::string ice_pwd_ep1_cd2_ch = kIcePwd[2];
-      std::string ice_ufrag_ep2_cd2_ch = kIceUfrag[3];
-      std::string ice_pwd_ep2_cd2_ch = kIcePwd[3];
-      ep1_.cd2_.ch_.reset(CreateChannel(
-          0, ICE_CANDIDATE_COMPONENT_DEFAULT, ice_ufrag_ep1_cd2_ch,
-          ice_pwd_ep1_cd2_ch, ice_ufrag_ep2_cd2_ch, ice_pwd_ep2_cd2_ch));
-      ep2_.cd2_.ch_.reset(CreateChannel(
-          1, ICE_CANDIDATE_COMPONENT_DEFAULT, ice_ufrag_ep2_cd2_ch,
-          ice_pwd_ep2_cd2_ch, ice_ufrag_ep1_cd2_ch, ice_pwd_ep1_cd2_ch));
+      IceParameters ice_ep1_cd2_ch =
+          IceParamsWithRenomination(kIceParams[2], renomination);
+      IceParameters ice_ep2_cd2_ch =
+          IceParamsWithRenomination(kIceParams[3], renomination);
+      ep1_.cd2_.ch_.reset(CreateChannel(0, ICE_CANDIDATE_COMPONENT_DEFAULT,
+                                        ice_ep1_cd2_ch, ice_ep2_cd2_ch));
+      ep2_.cd2_.ch_.reset(CreateChannel(1, ICE_CANDIDATE_COMPONENT_DEFAULT,
+                                        ice_ep2_cd2_ch, ice_ep1_cd2_ch));
       ep1_.cd2_.ch_->SetIceConfig(ep1_config);
       ep2_.cd2_.ch_->SetIceConfig(ep2_config);
       ep1_.cd2_.ch_->MaybeStartGathering();
@@ -342,15 +349,13 @@
 
   void CreateChannels(int num) {
     IceConfig default_config;
-    CreateChannels(num, default_config, default_config);
+    CreateChannels(num, default_config, default_config, false);
   }
 
   P2PTransportChannel* CreateChannel(int endpoint,
                                      int component,
-                                     const std::string& local_ice_ufrag,
-                                     const std::string& local_ice_pwd,
-                                     const std::string& remote_ice_ufrag,
-                                     const std::string& remote_ice_pwd) {
+                                     const IceParameters& local_ice,
+                                     const IceParameters& remote_ice) {
     P2PTransportChannel* channel = new P2PTransportChannel(
         "test content name", component, GetAllocator(endpoint));
     channel->SignalReadyToSend.connect(
@@ -365,9 +370,9 @@
         this, &P2PTransportChannelTestBase::OnRoleConflict);
     channel->SignalSelectedCandidatePairChanged.connect(
         this, &P2PTransportChannelTestBase::OnSelectedCandidatePairChanged);
-    channel->SetIceCredentials(local_ice_ufrag, local_ice_pwd);
-    if (remote_ice_credential_source_ == FROM_SETICECREDENTIALS) {
-      channel->SetRemoteIceCredentials(remote_ice_ufrag, remote_ice_pwd);
+    channel->SetIceParameters(local_ice);
+    if (remote_ice_parameter_source_ == FROM_SETICEPARAMETERS) {
+      channel->SetRemoteIceParameters(remote_ice);
     }
     channel->SetIceRole(GetEndpoint(endpoint)->ice_role());
     channel->SetIceTiebreaker(GetEndpoint(endpoint)->GetIceTiebreaker());
@@ -598,13 +603,13 @@
   }
 
   // This test waits for the transport to become receiving and writable on both
-  // end points. Once they are, the end points set new local ice credentials and
+  // end points. Once they are, the end points set new local ice parameters and
   // restart the ice gathering. Finally it waits for the transport to select a
   // new connection using the newly generated ice candidates.
   // Before calling this function the end points must be configured.
   void TestHandleIceUfragPasswordChanged() {
-    ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[1], kIcePwd[1]);
-    ep2_ch1()->SetRemoteIceCredentials(kIceUfrag[0], kIcePwd[0]);
+    ep1_ch1()->SetRemoteIceParameters(kIceParams[1]);
+    ep2_ch1()->SetRemoteIceParameters(kIceParams[0]);
     EXPECT_TRUE_WAIT_MARGIN(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
                             ep2_ch1()->receiving() && ep2_ch1()->writable(),
                             1000, 1000);
@@ -614,11 +619,12 @@
     const Candidate* old_remote_candidate1 = RemoteCandidate(ep1_ch1());
     const Candidate* old_remote_candidate2 = RemoteCandidate(ep2_ch1());
 
-    ep1_ch1()->SetIceCredentials(kIceUfrag[2], kIcePwd[2]);
-    ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[3], kIcePwd[3]);
+    ep1_ch1()->SetIceParameters(kIceParams[2]);
+    ep1_ch1()->SetRemoteIceParameters(kIceParams[3]);
     ep1_ch1()->MaybeStartGathering();
-    ep2_ch1()->SetIceCredentials(kIceUfrag[3], kIcePwd[3]);
-    ep2_ch1()->SetRemoteIceCredentials(kIceUfrag[2], kIcePwd[2]);
+    ep2_ch1()->SetIceParameters(kIceParams[3]);
+
+    ep2_ch1()->SetRemoteIceParameters(kIceParams[2]);
     ep2_ch1()->MaybeStartGathering();
 
     EXPECT_TRUE_WAIT_MARGIN(LocalCandidate(ep1_ch1())->generation() !=
@@ -745,7 +751,7 @@
           return;
         }
         for (auto& c : data->candidates) {
-          if (remote_ice_credential_source_ != FROM_CANDIDATE) {
+          if (remote_ice_parameter_source_ != FROM_CANDIDATE) {
             c.set_username("");
             c.set_password("");
           }
@@ -830,13 +836,13 @@
     return GetChannelData(ch)->ch_packets_;
   }
 
-  enum RemoteIceCredentialSource { FROM_CANDIDATE, FROM_SETICECREDENTIALS };
+  enum RemoteIceParameterSource { FROM_CANDIDATE, FROM_SETICEPARAMETERS };
 
-  // How does the test pass ICE credentials to the P2PTransportChannel?
-  // On the candidate itself, or through SetIceCredentials?
+  // How does the test pass ICE parameters to the P2PTransportChannel?
+  // On the candidate itself, or through SetRemoteIceParameters?
   // Goes through the candidate itself by default.
-  void set_remote_ice_credential_source(RemoteIceCredentialSource source) {
-    remote_ice_credential_source_ = source;
+  void set_remote_ice_parameter_source(RemoteIceParameterSource source) {
+    remote_ice_parameter_source_ = source;
   }
 
   void set_force_relay(bool relay) {
@@ -865,7 +871,7 @@
   rtc::SocksProxyServer socks_server2_;
   Endpoint ep1_;
   Endpoint ep2_;
-  RemoteIceCredentialSource remote_ice_credential_source_ = FROM_CANDIDATE;
+  RemoteIceParameterSource remote_ice_parameter_source_ = FROM_CANDIDATE;
   bool force_relay_;
   int selected_candidate_pair_switches_ = 0;
 
@@ -991,7 +997,7 @@
     SetAllocatorFlags(1, allocator_flags2);
     SetAllocationStepDelay(1, delay);
 
-    set_remote_ice_credential_source(FROM_SETICECREDENTIALS);
+    set_remote_ice_parameter_source(FROM_SETICEPARAMETERS);
   }
   void ConfigureEndpoint(int endpoint, Config config) {
     switch (config) {
@@ -1202,11 +1208,11 @@
 TEST_F(P2PTransportChannelTest, PeerReflexiveCandidateBeforeSignaling) {
   ConfigureEndpoints(OPEN, OPEN, kDefaultPortAllocatorFlags,
                      kDefaultPortAllocatorFlags);
-  // Emulate no remote credentials coming in.
-  set_remote_ice_credential_source(FROM_CANDIDATE);
+  // Emulate no remote parameters coming in.
+  set_remote_ice_parameter_source(FROM_CANDIDATE);
   CreateChannels(1);
-  // Only have remote credentials come in for ep2, not ep1.
-  ep2_ch1()->SetRemoteIceCredentials(kIceUfrag[0], kIcePwd[0]);
+  // Only have remote parameters come in for ep2, not ep1.
+  ep2_ch1()->SetRemoteIceParameters(kIceParams[0]);
 
   // Pause sending ep2's candidates to ep1 until ep1 receives the peer reflexive
   // candidate.
@@ -1217,8 +1223,8 @@
   ASSERT_TRUE_WAIT(ep2_ch1()->selected_connection() != nullptr, 3000);
   // Add two sets of remote ICE credentials, so that the ones used by the
   // candidate will be generation 1 instead of 0.
-  ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[3], kIcePwd[3]);
-  ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[1], kIcePwd[1]);
+  ep1_ch1()->SetRemoteIceParameters(kIceParams[3]);
+  ep1_ch1()->SetRemoteIceParameters(kIceParams[1]);
   // The caller should have the selected connection connected to the peer
   // reflexive candidate.
   const Connection* selected_connection = nullptr;
@@ -1244,11 +1250,11 @@
 TEST_F(P2PTransportChannelTest, PeerReflexiveCandidateBeforeSignalingWithNAT) {
   ConfigureEndpoints(OPEN, NAT_SYMMETRIC, kDefaultPortAllocatorFlags,
                      kDefaultPortAllocatorFlags);
-  // Emulate no remote credentials coming in.
-  set_remote_ice_credential_source(FROM_CANDIDATE);
+  // Emulate no remote parameters coming in.
+  set_remote_ice_parameter_source(FROM_CANDIDATE);
   CreateChannels(1);
-  // Only have remote credentials come in for ep2, not ep1.
-  ep2_ch1()->SetRemoteIceCredentials(kIceUfrag[0], kIcePwd[0]);
+  // Only have remote parameters come in for ep2, not ep1.
+  ep2_ch1()->SetRemoteIceParameters(kIceParams[0]);
   // Pause sending ep2's candidates to ep1 until ep1 receives the peer reflexive
   // candidate.
   PauseCandidates(1);
@@ -1258,8 +1264,8 @@
   ASSERT_TRUE_WAIT(ep2_ch1()->selected_connection() != nullptr, 3000);
   // Add two sets of remote ICE credentials, so that the ones used by the
   // candidate will be generation 1 instead of 0.
-  ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[3], kIcePwd[3]);
-  ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[1], kIcePwd[1]);
+  ep1_ch1()->SetRemoteIceParameters(kIceParams[3]);
+  ep1_ch1()->SetRemoteIceParameters(kIceParams[1]);
 
   // The caller's selected connection should be connected to the peer reflexive
   // candidate.
@@ -1298,21 +1304,22 @@
   // it's prioritized above the current candidate pair.
   GetEndpoint(0)->allocator_->set_candidate_filter(CF_RELAY);
   GetEndpoint(1)->allocator_->set_candidate_filter(CF_RELAY);
-  // Setting this allows us to control when SetRemoteIceCredentials is called.
-  set_remote_ice_credential_source(FROM_CANDIDATE);
+  // Setting this allows us to control when SetRemoteIceParameters is called.
+  set_remote_ice_parameter_source(FROM_CANDIDATE);
   CreateChannels(1);
   // Wait for the initial connection to be made.
-  ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[1], kIcePwd[1]);
-  ep2_ch1()->SetRemoteIceCredentials(kIceUfrag[0], kIcePwd[0]);
+  ep1_ch1()->SetRemoteIceParameters(kIceParams[1]);
+  ep2_ch1()->SetRemoteIceParameters(kIceParams[0]);
   EXPECT_TRUE_WAIT(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
                        ep2_ch1()->receiving() && ep2_ch1()->writable(),
                    kDefaultTimeout);
 
   // Simulate an ICE restart on ep2, but don't signal the candidate or new
-  // ICE credentials until after a prflx connection has been made.
+  // ICE parameters until after a prflx connection has been made.
   PauseCandidates(1);
-  ep2_ch1()->SetIceCredentials(kIceUfrag[3], kIcePwd[3]);
-  ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[3], kIcePwd[3]);
+  ep2_ch1()->SetIceParameters(kIceParams[3]);
+
+  ep1_ch1()->SetRemoteIceParameters(kIceParams[3]);
   ep2_ch1()->MaybeStartGathering();
 
   // The caller should have the selected connection connected to the peer
@@ -1324,8 +1331,9 @@
       ep1_ch1()->selected_connection();
 
   // Now simulate the ICE restart on ep1.
-  ep1_ch1()->SetIceCredentials(kIceUfrag[2], kIcePwd[2]);
-  ep2_ch1()->SetRemoteIceCredentials(kIceUfrag[2], kIcePwd[2]);
+  ep1_ch1()->SetIceParameters(kIceParams[2]);
+
+  ep2_ch1()->SetRemoteIceParameters(kIceParams[2]);
   ep1_ch1()->MaybeStartGathering();
 
   // Finally send the candidates from ep2's ICE restart and verify that ep1 uses
@@ -1341,7 +1349,7 @@
 
 // Test that if remote candidates don't have ufrag and pwd, we still work.
 TEST_F(P2PTransportChannelTest, RemoteCandidatesWithoutUfragPwd) {
-  set_remote_ice_credential_source(FROM_SETICECREDENTIALS);
+  set_remote_ice_parameter_source(FROM_SETICEPARAMETERS);
   ConfigureEndpoints(OPEN, OPEN, kDefaultPortAllocatorFlags,
                      kDefaultPortAllocatorFlags);
   CreateChannels(1);
@@ -1410,10 +1418,10 @@
   SetAllowTcpListen(0, true);   // actpass.
   SetAllowTcpListen(1, false);  // active.
 
-  // We want SetRemoteIceCredentials to be called as it normally would.
-  // Otherwise we won't know what credentials to use for the expected
+  // We want SetRemoteIceParameters to be called as it normally would.
+  // Otherwise we won't know what parameters to use for the expected
   // prflx TCP candidates.
-  set_remote_ice_credential_source(FROM_SETICECREDENTIALS);
+  set_remote_ice_parameter_source(FROM_SETICEPARAMETERS);
 
   // Pause candidate so we could verify the candidate properties.
   PauseCandidates(0);
@@ -1700,9 +1708,8 @@
                      kDefaultPortAllocatorFlags);
   // Only configure one channel so we can control when the remote candidate
   // is added.
-  GetEndpoint(0)->cd1_.ch_.reset(
-      CreateChannel(0, ICE_CANDIDATE_COMPONENT_DEFAULT, kIceUfrag[0],
-                    kIcePwd[0], kIceUfrag[1], kIcePwd[1]));
+  GetEndpoint(0)->cd1_.ch_.reset(CreateChannel(
+      0, ICE_CANDIDATE_COMPONENT_DEFAULT, kIceParams[0], kIceParams[1]));
   IceConfig config;
   config.presume_writable_when_fully_relayed = true;
   ep1_ch1()->SetIceConfig(config);
@@ -1748,12 +1755,10 @@
   test_turn_server()->set_enable_permission_checks(false);
   IceConfig config;
   config.presume_writable_when_fully_relayed = true;
-  GetEndpoint(0)->cd1_.ch_.reset(
-      CreateChannel(0, ICE_CANDIDATE_COMPONENT_DEFAULT, kIceUfrag[0],
-                    kIcePwd[0], kIceUfrag[1], kIcePwd[1]));
-  GetEndpoint(1)->cd1_.ch_.reset(
-      CreateChannel(1, ICE_CANDIDATE_COMPONENT_DEFAULT, kIceUfrag[1],
-                    kIcePwd[1], kIceUfrag[0], kIcePwd[0]));
+  GetEndpoint(0)->cd1_.ch_.reset(CreateChannel(
+      0, ICE_CANDIDATE_COMPONENT_DEFAULT, kIceParams[0], kIceParams[1]));
+  GetEndpoint(1)->cd1_.ch_.reset(CreateChannel(
+      1, ICE_CANDIDATE_COMPONENT_DEFAULT, kIceParams[1], kIceParams[0]));
   ep1_ch1()->SetIceConfig(config);
   ep2_ch1()->SetIceConfig(config);
   // Don't signal candidates from channel 2, so that channel 1 sees the TURN
@@ -1789,12 +1794,10 @@
                      kDefaultPortAllocatorFlags);
   IceConfig config;
   config.presume_writable_when_fully_relayed = true;
-  GetEndpoint(0)->cd1_.ch_.reset(
-      CreateChannel(0, ICE_CANDIDATE_COMPONENT_DEFAULT, kIceUfrag[0],
-                    kIcePwd[0], kIceUfrag[1], kIcePwd[1]));
-  GetEndpoint(1)->cd1_.ch_.reset(
-      CreateChannel(1, ICE_CANDIDATE_COMPONENT_DEFAULT, kIceUfrag[1],
-                    kIcePwd[1], kIceUfrag[0], kIcePwd[0]));
+  GetEndpoint(0)->cd1_.ch_.reset(CreateChannel(
+      0, ICE_CANDIDATE_COMPONENT_DEFAULT, kIceParams[0], kIceParams[1]));
+  GetEndpoint(1)->cd1_.ch_.reset(CreateChannel(
+      1, ICE_CANDIDATE_COMPONENT_DEFAULT, kIceParams[1], kIceParams[0]));
   ep1_ch1()->SetIceConfig(config);
   ep2_ch1()->SetIceConfig(config);
   ep1_ch1()->MaybeStartGathering();
@@ -1837,7 +1840,7 @@
             static_cast<rtc::NATType>(nat_type - NAT_FULL_CONE));
     ConfigureEndpoint(outer_nat, 0, config1);
     ConfigureEndpoint(outer_nat, 1, config2);
-    set_remote_ice_credential_source(FROM_SETICECREDENTIALS);
+    set_remote_ice_parameter_source(FROM_SETICEPARAMETERS);
   }
   void ConfigureEndpoint(rtc::NATSocketServer::Translator* nat,
                          int endpoint, Config config) {
@@ -2027,11 +2030,12 @@
   SetAllocatorFlags(0, kOnlyLocalPorts);
   SetAllocatorFlags(1, kOnlyLocalPorts);
 
+  // We want it to set the remote ICE parameters when creating channels.
+  set_remote_ice_parameter_source(FROM_SETICEPARAMETERS);
   // Make the receiving timeout shorter for testing.
   IceConfig config = CreateIceConfig(1000, GATHER_ONCE);
-  // Create channels and let them go writable, as usual.
-  CreateChannels(1, config, config);
-  ep1_ch1()->set_remote_supports_renomination(true);
+  // Create channels with ICE renomination and let them go writable as usual.
+  CreateChannels(1, config, config, true);
   EXPECT_TRUE_SIMULATED_WAIT(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
                                  ep2_ch1()->receiving() &&
                                  ep2_ch1()->writable(),
@@ -2601,8 +2605,8 @@
  protected:
   void PrepareChannel(P2PTransportChannel* ch) {
     ch->SetIceRole(ICEROLE_CONTROLLING);
-    ch->SetIceCredentials(kIceUfrag[0], kIcePwd[0]);
-    ch->SetRemoteIceCredentials(kIceUfrag[1], kIcePwd[1]);
+    ch->SetIceParameters(kIceParams[0]);
+    ch->SetRemoteIceParameters(kIceParams[1]);
     ch->SignalSelectedCandidatePairChanged.connect(
         this, &P2PTransportChannelPingTest::OnSelectedCandidatePairChanged);
     ch->SignalReadyToSend.connect(this,
@@ -2881,20 +2885,20 @@
 }
 
 // Test that we start pinging as soon as we have a connection and remote ICE
-// credentials.
+// parameters.
 TEST_F(P2PTransportChannelPingTest, PingingStartedAsSoonAsPossible) {
   rtc::ScopedFakeClock clock;
 
   FakePortAllocator pa(rtc::Thread::Current(), nullptr);
   P2PTransportChannel ch("TestChannel", 1, &pa);
   ch.SetIceRole(ICEROLE_CONTROLLING);
-  ch.SetIceCredentials(kIceUfrag[0], kIcePwd[0]);
+  ch.SetIceParameters(kIceParams[0]);
   ch.MaybeStartGathering();
   EXPECT_EQ_WAIT(IceGatheringState::kIceGatheringComplete, ch.gathering_state(),
                  kDefaultTimeout);
 
   // Simulate a binding request being received, creating a peer reflexive
-  // candidate pair while we still don't have remote ICE credentials.
+  // candidate pair while we still don't have remote ICE parameters.
   IceMessage request;
   request.SetType(STUN_BINDING_REQUEST);
   request.AddAttribute(
@@ -2910,14 +2914,14 @@
   ASSERT_NE(nullptr, conn);
 
   // Simulate waiting for a second (and change) and verify that no pings were
-  // sent, since we don't yet have remote ICE credentials.
+  // sent, since we don't yet have remote ICE parameters.
   SIMULATED_WAIT(conn->num_pings_sent() > 0, 1025, clock);
   EXPECT_EQ(0, conn->num_pings_sent());
 
-  // Set remote ICE credentials. Now we should be able to ping. Ensure that
+  // Set remote ICE parameters. Now we should be able to ping. Ensure that
   // the first ping is sent as soon as possible, within one simulated clock
   // tick.
-  ch.SetRemoteIceCredentials(kIceUfrag[1], kIcePwd[1]);
+  ch.SetRemoteIceParameters(kIceParams[1]);
   EXPECT_TRUE_SIMULATED_WAIT(conn->num_pings_sent() > 0, 1, clock);
 }
 
@@ -2981,7 +2985,7 @@
 // is added with an old ufrag, it will be discarded. If it is added with a
 // ufrag that was not seen before, it will be used to create connections
 // although the ICE pwd in the remote candidate will be set when the ICE
-// credentials arrive. If a remote candidate is added with the current ICE
+// parameters arrive. If a remote candidate is added with the current ICE
 // ufrag, its pwd and generation will be set properly.
 TEST_F(P2PTransportChannelPingTest, TestAddRemoteCandidateWithVariousUfrags) {
   FakePortAllocator pa(rtc::Thread::Current(), nullptr);
@@ -2998,10 +3002,10 @@
   EXPECT_TRUE(candidate.password().empty());
   EXPECT_TRUE(FindNextPingableConnectionAndPingIt(&ch) == nullptr);
 
-  // Set the remote credentials with the "future" ufrag.
+  // Set the remote ICE parameters with the "future" ufrag.
   // This should set the ICE pwd in the remote candidate of |conn1|, making
   // it pingable.
-  ch.SetRemoteIceCredentials(kIceUfrag[2], kIcePwd[2]);
+  ch.SetRemoteIceParameters(kIceParams[2]);
   EXPECT_EQ(kIceUfrag[2], candidate.username());
   EXPECT_EQ(kIcePwd[2], candidate.password());
   EXPECT_EQ(conn1, FindNextPingableConnectionAndPingIt(&ch));
@@ -3261,8 +3265,8 @@
   // Test that the request from an unknown address contains a ufrag from an old
   // generation.
   port->set_sent_binding_response(false);
-  ch.SetRemoteIceCredentials(kIceUfrag[2], kIcePwd[2]);
-  ch.SetRemoteIceCredentials(kIceUfrag[3], kIcePwd[3]);
+  ch.SetRemoteIceParameters(kIceParams[2]);
+  ch.SetRemoteIceParameters(kIceParams[3]);
   port->SignalUnknownAddress(port, rtc::SocketAddress("5.5.5.5", 5), PROTO_UDP,
                              &request, kIceUfrag[2], false);
   Connection* conn5 = WaitForConnectionTo(&ch, "5.5.5.5", 5);
@@ -3732,7 +3736,7 @@
   // Start a new session. Even though conn1, which belongs to an older
   // session, becomes unwritable and writable again, it should not stop the
   // current session.
-  ch.SetIceCredentials(kIceUfrag[1], kIcePwd[1]);
+  ch.SetIceParameters(kIceParams[1]);
   ch.MaybeStartGathering();
   conn1->Prune();
   conn1->ReceivedPingResponse(LOW_RTT, "id");
@@ -3788,7 +3792,7 @@
 
   // Do an ICE restart, change the role, and expect the old port to have its
   // role updated.
-  ch.SetIceCredentials(kIceUfrag[1], kIcePwd[1]);
+  ch.SetIceParameters(kIceParams[1]);
   ch.MaybeStartGathering();
   ch.SetIceRole(ICEROLE_CONTROLLED);
   EXPECT_EQ(ICEROLE_CONTROLLED, conn->port()->GetIceRole());
diff --git a/webrtc/p2p/base/port.cc b/webrtc/p2p/base/port.cc
index c648450..2f487dc 100644
--- a/webrtc/p2p/base/port.cc
+++ b/webrtc/p2p/base/port.cc
@@ -1423,19 +1423,18 @@
   port_->SignalRoleConflict(port_);
 }
 
-void Connection::MaybeSetRemoteIceCredentialsAndGeneration(
-    const std::string& ice_ufrag,
-    const std::string& ice_pwd,
+void Connection::MaybeSetRemoteIceParametersAndGeneration(
+    const IceParameters& ice_params,
     int generation) {
-  if (remote_candidate_.username() == ice_ufrag &&
+  if (remote_candidate_.username() == ice_params.ufrag &&
       remote_candidate_.password().empty()) {
-    remote_candidate_.set_password(ice_pwd);
+    remote_candidate_.set_password(ice_params.pwd);
   }
   // TODO(deadbeef): A value of '0' for the generation is used for both
   // generation 0 and "generation unknown". It should be changed to an
   // rtc::Optional to fix this.
-  if (remote_candidate_.username() == ice_ufrag &&
-      remote_candidate_.password() == ice_pwd &&
+  if (remote_candidate_.username() == ice_params.ufrag &&
+      remote_candidate_.password() == ice_params.pwd &&
       remote_candidate_.generation() == 0) {
     remote_candidate_.set_generation(generation);
   }
diff --git a/webrtc/p2p/base/port.h b/webrtc/p2p/base/port.h
index 2dc9dea..2acea42 100644
--- a/webrtc/p2p/base/port.h
+++ b/webrtc/p2p/base/port.h
@@ -590,14 +590,11 @@
 
   uint32_t ComputeNetworkCost() const;
 
-  // Update the ICE password and/or generation of the remote candidate if a
-  // ufrag in |remote_ice_parameters| matches the candidate's ufrag, and the
+  // Update the ICE password and/or generation of the remote candidate if the
+  // ufrag in |params| matches the candidate's ufrag, and the
   // candidate's password and/or ufrag has not been set.
-  // |remote_ice_parameters| should be a list of known ICE parameters ordered
-  // by generation.
-  void MaybeSetRemoteIceCredentialsAndGeneration(const std::string& ice_ufrag,
-                                                 const std::string& ice_pwd,
-                                                 int generation);
+  void MaybeSetRemoteIceParametersAndGeneration(const IceParameters& params,
+                                                int generation);
 
   // If |remote_candidate_| is peer reflexive and is equivalent to
   // |new_candidate| except the type, update |remote_candidate_| to
diff --git a/webrtc/p2p/base/transport.cc b/webrtc/p2p/base/transport.cc
index 9fbe952..7bd14c4 100644
--- a/webrtc/p2p/base/transport.cc
+++ b/webrtc/p2p/base/transport.cc
@@ -321,15 +321,13 @@
 
 bool Transport::ApplyLocalTransportDescription(TransportChannelImpl* ch,
                                                std::string* error_desc) {
-  ch->SetIceCredentials(local_description_->ice_ufrag,
-                        local_description_->ice_pwd);
+  ch->SetIceParameters(local_description_->GetIceParameters());
   return true;
 }
 
 bool Transport::ApplyRemoteTransportDescription(TransportChannelImpl* ch,
                                                 std::string* error_desc) {
-  ch->SetRemoteIceCredentials(remote_description_->ice_ufrag,
-                              remote_description_->ice_pwd);
+  ch->SetRemoteIceParameters(remote_description_->GetIceParameters());
   return true;
 }
 
diff --git a/webrtc/p2p/base/transportchannelimpl.h b/webrtc/p2p/base/transportchannelimpl.h
index 910ec31..0c7fa50 100644
--- a/webrtc/p2p/base/transportchannelimpl.h
+++ b/webrtc/p2p/base/transportchannelimpl.h
@@ -44,15 +44,26 @@
   // TODO(pthatcher): Remove this once it's no longer called in
   // remoting/protocol/libjingle_transport_factory.cc
   virtual void SetIceProtocolType(IceProtocolType type) {}
-  // SetIceCredentials only need to be implemented by the ICE
-  // transport channels. Non-ICE transport channels can just ignore.
-  // The ufrag and pwd must be set before candidate gathering can start.
+  // TODO(honghaiz): Remove this once the call in chromoting is removed.
   virtual void SetIceCredentials(const std::string& ice_ufrag,
-                                 const std::string& ice_pwd)  = 0;
-  // SetRemoteIceCredentials only need to be implemented by the ICE
-  // transport channels. Non-ICE transport channels can just ignore.
+                                 const std::string& ice_pwd) {
+    SetIceParameters(IceParameters(ice_ufrag, ice_pwd, false));
+  }
+  // TODO(honghaiz): Remove this once the call in chromoting is removed.
   virtual void SetRemoteIceCredentials(const std::string& ice_ufrag,
-                                       const std::string& ice_pwd) = 0;
+                                       const std::string& ice_pwd) {
+    SetRemoteIceParameters(IceParameters(ice_ufrag, ice_pwd, false));
+  }
+
+  // SetIceParameters only needs to be implemented by the ICE transport
+  // channels. Non-ICE transport channels should pass them down to the inner
+  // ICE transport channel. The ufrag and pwd in |ice_params| must be set
+  // before candidate gathering can start.
+  virtual void SetIceParameters(const IceParameters& ice_params) = 0;
+  // SetRemoteIceParameters only needs to be implemented by the ICE transport
+  // channels. Non-ICE transport channels should pass them down to the inner
+  // ICE transport channel.
+  virtual void SetRemoteIceParameters(const IceParameters& ice_params) = 0;
 
   // SetRemoteIceMode must be implemented only by the ICE transport channels.
   virtual void SetRemoteIceMode(IceMode mode) = 0;
diff --git a/webrtc/p2p/base/transportdescription.h b/webrtc/p2p/base/transportdescription.h
index 42e45a6..df8ee92 100644
--- a/webrtc/p2p/base/transportdescription.h
+++ b/webrtc/p2p/base/transportdescription.h
@@ -60,11 +60,33 @@
   CONNECTIONROLE_HOLDCONN,
 };
 
+struct IceParameters {
+  // TODO(honghaiz): Include ICE mode in this structure to match the ORTC
+  // struct:
+  // http://ortc.org/wp-content/uploads/2016/03/ortc.html#idl-def-RTCIceParameters
+  std::string ufrag;
+  std::string pwd;
+  bool renomination = false;
+  IceParameters() = default;
+  IceParameters(const std::string& ice_ufrag,
+                const std::string& ice_pwd,
+                bool ice_renomination)
+      : ufrag(ice_ufrag), pwd(ice_pwd), renomination(ice_renomination) {}
+
+  bool operator==(const IceParameters& other) {
+    return ufrag == other.ufrag && pwd == other.pwd &&
+           renomination == other.renomination;
+  }
+  bool operator!=(const IceParameters& other) { return !(*this == other); }
+};
+
 extern const char CONNECTIONROLE_ACTIVE_STR[];
 extern const char CONNECTIONROLE_PASSIVE_STR[];
 extern const char CONNECTIONROLE_ACTPASS_STR[];
 extern const char CONNECTIONROLE_HOLDCONN_STR[];
 
+constexpr auto ICE_RENOMINATION_STR = "renomination";
+
 bool StringToConnectionRole(const std::string& role_str, ConnectionRole* role);
 bool ConnectionRoleToString(const ConnectionRole& role, std::string* role_str);
 
@@ -125,6 +147,10 @@
   }
   bool secure() const { return identity_fingerprint != NULL; }
 
+  IceParameters GetIceParameters() {
+    return IceParameters(ice_ufrag, ice_pwd, HasOption(ICE_RENOMINATION_STR));
+  }
+
   static rtc::SSLFingerprint* CopyFingerprint(
       const rtc::SSLFingerprint* from) {
     if (!from)
diff --git a/webrtc/p2p/base/transportdescriptionfactory.cc b/webrtc/p2p/base/transportdescriptionfactory.cc
index e57b7e3..61e2a9f 100644
--- a/webrtc/p2p/base/transportdescriptionfactory.cc
+++ b/webrtc/p2p/base/transportdescriptionfactory.cc
@@ -37,6 +37,9 @@
     desc->ice_ufrag = current_description->ice_ufrag;
     desc->ice_pwd = current_description->ice_pwd;
   }
+  if (options.enable_ice_renomination) {
+    desc->AddOption(ICE_RENOMINATION_STR);
+  }
 
   // If we are trying to establish a secure transport, add a fingerprint.
   if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) {
@@ -71,6 +74,9 @@
     desc->ice_ufrag = current_description->ice_ufrag;
     desc->ice_pwd = current_description->ice_pwd;
   }
+  if (options.enable_ice_renomination) {
+    desc->AddOption(ICE_RENOMINATION_STR);
+  }
 
   // Negotiate security params.
   if (offer && offer->identity_fingerprint.get()) {
diff --git a/webrtc/p2p/base/transportdescriptionfactory.h b/webrtc/p2p/base/transportdescriptionfactory.h
index 828aa6d22..2dde5b1 100644
--- a/webrtc/p2p/base/transportdescriptionfactory.h
+++ b/webrtc/p2p/base/transportdescriptionfactory.h
@@ -21,9 +21,11 @@
 namespace cricket {
 
 struct TransportOptions {
-  TransportOptions() : ice_restart(false), prefer_passive_role(false) {}
-  bool ice_restart;
-  bool prefer_passive_role;
+  bool ice_restart = false;
+  bool prefer_passive_role = false;
+  // If true, ICE renomination is supported and will be used if it is also
+  // supported by the remote side.
+  bool enable_ice_renomination = false;
 };
 
 // Creates transport descriptions according to the supplied configuration.
diff --git a/webrtc/p2p/base/transportdescriptionfactory_unittest.cc b/webrtc/p2p/base/transportdescriptionfactory_unittest.cc
index 38675ba..14be338 100644
--- a/webrtc/p2p/base/transportdescriptionfactory_unittest.cc
+++ b/webrtc/p2p/base/transportdescriptionfactory_unittest.cc
@@ -59,16 +59,7 @@
   // in the offer and answer is changed.
   // If |dtls| is true, the test verifies that the finger print is not changed.
   void TestIceRestart(bool dtls) {
-    if (dtls) {
-      f1_.set_secure(cricket::SEC_ENABLED);
-      f2_.set_secure(cricket::SEC_ENABLED);
-      f1_.set_certificate(cert1_);
-      f2_.set_certificate(cert2_);
-    } else {
-      f1_.set_secure(cricket::SEC_DISABLED);
-      f2_.set_secure(cricket::SEC_DISABLED);
-    }
-
+    SetDtls(dtls);
     cricket::TransportOptions options;
     // The initial offer / answer exchange.
     std::unique_ptr<TransportDescription> offer(f1_.CreateOffer(options, NULL));
@@ -109,7 +100,50 @@
     }
   }
 
+  void TestIceRenomination(bool dtls) {
+    SetDtls(dtls);
+
+    cricket::TransportOptions options;
+    // The initial offer / answer exchange.
+    std::unique_ptr<TransportDescription> offer(
+        f1_.CreateOffer(options, nullptr));
+    std::unique_ptr<TransportDescription> answer(
+        f2_.CreateAnswer(offer.get(), options, nullptr));
+    VerifyRenomination(offer.get(), false);
+    VerifyRenomination(answer.get(), false);
+
+    options.enable_ice_renomination = true;
+    std::unique_ptr<TransportDescription> renomination_offer(
+        f1_.CreateOffer(options, offer.get()));
+    VerifyRenomination(renomination_offer.get(), true);
+
+    std::unique_ptr<TransportDescription> renomination_answer(
+        f2_.CreateAnswer(renomination_offer.get(), options, answer.get()));
+    VerifyRenomination(renomination_answer.get(), true);
+  }
+
  protected:
+  void VerifyRenomination(TransportDescription* desc,
+                          bool renomination_expected) {
+    ASSERT_TRUE(desc != nullptr);
+    std::vector<std::string>& options = desc->transport_options;
+    auto iter = std::find(options.begin(), options.end(),
+                          cricket::ICE_RENOMINATION_STR);
+    EXPECT_EQ(renomination_expected, iter != options.end());
+  }
+
+  void SetDtls(bool dtls) {
+    if (dtls) {
+      f1_.set_secure(cricket::SEC_ENABLED);
+      f2_.set_secure(cricket::SEC_ENABLED);
+      f1_.set_certificate(cert1_);
+      f2_.set_certificate(cert2_);
+    } else {
+      f1_.set_secure(cricket::SEC_DISABLED);
+      f2_.set_secure(cricket::SEC_DISABLED);
+    }
+  }
+
   TransportDescriptionFactory f1_;
   TransportDescriptionFactory f2_;
 
@@ -256,3 +290,16 @@
 TEST_F(TransportDescriptionFactoryTest, TestIceRestartWithDtls) {
   TestIceRestart(true);
 }
+
+// Test that ice renomination is set in an updated offer and answer
+// if |TransportDescriptionOptions::enable_ice_renomination| is true.
+TEST_F(TransportDescriptionFactoryTest, TestIceRenomination) {
+  TestIceRenomination(false);
+}
+
+// Test that ice renomination is set in an updated offer and answer
+// if |TransportDescriptionOptions::enable_ice_renomination| is true and DTLS
+// is enabled.
+TEST_F(TransportDescriptionFactoryTest, TestIceRenominationWithDtls) {
+  TestIceRenomination(true);
+}
diff --git a/webrtc/p2p/quic/quictransportchannel.h b/webrtc/p2p/quic/quictransportchannel.h
index eec82be..22b69b7 100644
--- a/webrtc/p2p/quic/quictransportchannel.h
+++ b/webrtc/p2p/quic/quictransportchannel.h
@@ -142,13 +142,11 @@
   void SetIceTiebreaker(uint64_t tiebreaker) override {
     channel_->SetIceTiebreaker(tiebreaker);
   }
-  void SetIceCredentials(const std::string& ice_ufrag,
-                         const std::string& ice_pwd) override {
-    channel_->SetIceCredentials(ice_ufrag, ice_pwd);
+  void SetIceParameters(const IceParameters& ice_params) override {
+    channel_->SetIceParameters(ice_params);
   }
-  void SetRemoteIceCredentials(const std::string& ice_ufrag,
-                               const std::string& ice_pwd) override {
-    channel_->SetRemoteIceCredentials(ice_ufrag, ice_pwd);
+  void SetRemoteIceParameters(const IceParameters& ice_params) override {
+    channel_->SetRemoteIceParameters(ice_params);
   }
   void SetRemoteIceMode(IceMode mode) override {
     channel_->SetRemoteIceMode(mode);
diff --git a/webrtc/p2p/quic/quictransportchannel_unittest.cc b/webrtc/p2p/quic/quictransportchannel_unittest.cc
index 49ca29c..c973f2d 100644
--- a/webrtc/p2p/quic/quictransportchannel_unittest.cc
+++ b/webrtc/p2p/quic/quictransportchannel_unittest.cc
@@ -134,9 +134,8 @@
         std::vector<std::string>(), kIceUfrag, kIcePwd, cricket::ICEMODE_FULL,
         remote_connection_role, remote_fingerprint);
 
-    quic_channel_.SetIceCredentials(local_desc.ice_ufrag, local_desc.ice_pwd);
-    quic_channel_.SetRemoteIceCredentials(remote_desc.ice_ufrag,
-                                          remote_desc.ice_pwd);
+    quic_channel_.SetIceParameters(local_desc.GetIceParameters());
+    quic_channel_.SetRemoteIceParameters(remote_desc.GetIceParameters());
   }
 
   // Creates fingerprint from certificate.
diff --git a/webrtc/pc/mediasession.cc b/webrtc/pc/mediasession.cc
index 65fe363..bfb5692 100644
--- a/webrtc/pc/mediasession.cc
+++ b/webrtc/pc/mediasession.cc
@@ -686,11 +686,13 @@
 
 static TransportOptions GetTransportOptions(const MediaSessionOptions& options,
                                             const std::string& content_name) {
+  TransportOptions transport_options;
   auto it = options.transport_options.find(content_name);
-  if (it == options.transport_options.end()) {
-    return TransportOptions();
+  if (it != options.transport_options.end()) {
+    transport_options = it->second;
   }
-  return it->second;
+  transport_options.enable_ice_renomination = options.enable_ice_renomination;
+  return transport_options;
 }
 
 // Create a media content to be offered in a session-initiate,
diff --git a/webrtc/pc/mediasession.h b/webrtc/pc/mediasession.h
index b39a8e5..289bc35 100644
--- a/webrtc/pc/mediasession.h
+++ b/webrtc/pc/mediasession.h
@@ -160,6 +160,7 @@
   // bps. -1 == auto.
   int video_bandwidth;
   int data_bandwidth;
+  bool enable_ice_renomination = false;
   // content name ("mid") => options.
   std::map<std::string, TransportOptions> transport_options;
   std::string rtcp_cname;
diff --git a/webrtc/pc/mediasession_unittest.cc b/webrtc/pc/mediasession_unittest.cc
index 281d306..6125d5f 100644
--- a/webrtc/pc/mediasession_unittest.cc
+++ b/webrtc/pc/mediasession_unittest.cc
@@ -267,6 +267,16 @@
     return true;
   }
 
+  // Returns true if the transport info contains "renomination" as an
+  // ICE option.
+  bool GetIceRenomination(const TransportInfo* transport_info) {
+    const std::vector<std::string>& ice_options =
+        transport_info->description.transport_options;
+    auto iter = std::find(ice_options.begin(), ice_options.end(),
+                          cricket::ICE_RENOMINATION_STR);
+    return iter != ice_options.end();
+  }
+
   void TestTransportInfo(bool offer, const MediaSessionOptions& options,
                          bool has_current_desc) {
     const std::string current_audio_ufrag = "current_audio_ufrag";
@@ -312,6 +322,7 @@
         EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
                   ti_audio->description.ice_pwd.size());
       }
+      EXPECT_EQ(options.enable_ice_renomination, GetIceRenomination(ti_audio));
 
     } else {
       EXPECT_TRUE(ti_audio == NULL);
@@ -335,6 +346,7 @@
                     ti_video->description.ice_pwd.size());
         }
       }
+      EXPECT_EQ(options.enable_ice_renomination, GetIceRenomination(ti_video));
     } else {
       EXPECT_TRUE(ti_video == NULL);
     }
@@ -357,6 +369,8 @@
                     ti_data->description.ice_pwd.size());
         }
       }
+      EXPECT_EQ(options.enable_ice_renomination, GetIceRenomination(ti_data));
+
     } else {
       EXPECT_TRUE(ti_video == NULL);
     }
@@ -2140,6 +2154,13 @@
   TestTransportInfo(true, options, false);
 }
 
+TEST_F(MediaSessionDescriptionFactoryTest,
+       TestTransportInfoOfferIceRenomination) {
+  MediaSessionOptions options;
+  options.enable_ice_renomination = true;
+  TestTransportInfo(true, options, false);
+}
+
 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
   MediaSessionOptions options;
   options.recv_audio = true;
@@ -2189,7 +2210,14 @@
 }
 
 TEST_F(MediaSessionDescriptionFactoryTest,
-    TestTransportInfoAnswerAudioCurrent) {
+       TestTransportInfoAnswerIceRenomination) {
+  MediaSessionOptions options;
+  options.enable_ice_renomination = true;
+  TestTransportInfo(false, options, false);
+}
+
+TEST_F(MediaSessionDescriptionFactoryTest,
+       TestTransportInfoAnswerAudioCurrent) {
   MediaSessionOptions options;
   options.recv_audio = true;
   TestTransportInfo(false, options, true);