Update connection states to match spec changes.

These changes simplify the code, and also fix the issue where the peerconnectionstate would sometimes return to "new" during connection setup.

Bug: webrtc:9308
Change-Id: I895cd2f94a2b9688c821cca64d1a077317b99d44
Reviewed-on: https://webrtc-review.googlesource.com/c/111964
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Jonas Olsson <jonasolsson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25942}
diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn
index 8611a65..ce390bc 100644
--- a/p2p/BUILD.gn
+++ b/p2p/BUILD.gn
@@ -149,6 +149,7 @@
       "../rtc_base/third_party/sigslot",
       "../test:test_support",
       "//third_party/abseil-cpp/absl/memory",
+      "//third_party/abseil-cpp/absl/types:optional",
     ]
   }
 
diff --git a/p2p/base/fakeicetransport.h b/p2p/base/fakeicetransport.h
index 88afc38..c36dd7f 100644
--- a/p2p/base/fakeicetransport.h
+++ b/p2p/base/fakeicetransport.h
@@ -15,6 +15,7 @@
 #include <string>
 #include <utility>
 
+#include "absl/types/optional.h"
 #include "p2p/base/icetransportinternal.h"
 #include "rtc_base/asyncinvoker.h"
 #include "rtc_base/copyonwritebuffer.h"
@@ -69,6 +70,13 @@
     }
   }
 
+  void SetTransportState(webrtc::IceTransportState state,
+                         IceTransportState legacy_state) {
+    transport_state_ = state;
+    legacy_transport_state_ = legacy_state;
+    SignalIceTransportStateChanged(this);
+  }
+
   void SetConnectionCount(size_t connection_count) {
     size_t old_connection_count = connection_count_;
     connection_count_ = connection_count;
@@ -107,6 +115,10 @@
   const std::string& remote_ice_pwd() const { return remote_ice_pwd_; }
 
   IceTransportState GetState() const override {
+    if (legacy_transport_state_) {
+      return *legacy_transport_state_;
+    }
+
     if (connection_count_ == 0) {
       return had_connection_ ? IceTransportState::STATE_FAILED
                              : IceTransportState::STATE_INIT;
@@ -120,6 +132,10 @@
   }
 
   webrtc::IceTransportState GetIceTransportState() const override {
+    if (transport_state_) {
+      return *transport_state_;
+    }
+
     if (connection_count_ == 0) {
       return had_connection_ ? webrtc::IceTransportState::kFailed
                              : webrtc::IceTransportState::kNew;
@@ -293,6 +309,8 @@
   std::string remote_ice_pwd_;
   IceMode remote_ice_mode_ = ICEMODE_FULL;
   size_t connection_count_ = 0;
+  absl::optional<webrtc::IceTransportState> transport_state_;
+  absl::optional<IceTransportState> legacy_transport_state_;
   IceGatheringState gathering_state_ = kIceGatheringNew;
   bool had_connection_ = false;
   bool writable_ = false;
diff --git a/pc/jseptransportcontroller.cc b/pc/jseptransportcontroller.cc
index 03899c3..ea2451d 100644
--- a/pc/jseptransportcontroller.cc
+++ b/pc/jseptransportcontroller.cc
@@ -1368,36 +1368,30 @@
   int total_ice = dtls_transports.size();
 
   if (total_ice_failed > 0) {
-    // Any of the RTCIceTransports are in the "failed" state.
+    // Any RTCIceTransports are in the "failed" state.
     new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
   } else if (total_ice_disconnected > 0) {
-    // Any of the RTCIceTransports are in the "disconnected" state and none of
-    // them are in the "failed" state.
+    // None of the previous states apply and any RTCIceTransports are in the
+    // "disconnected" state.
     new_ice_connection_state =
         PeerConnectionInterface::kIceConnectionDisconnected;
-  } else if (total_ice_checking > 0) {
-    // Any of the RTCIceTransports are in the "checking" state and none of them
-    // are in the "disconnected" or "failed" state.
+  } else if (total_ice_new + total_ice_closed == total_ice) {
+    // None of the previous states apply and all RTCIceTransports are in the
+    // "new" or "closed" state, or there are no transports.
+    new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
+  } else if (total_ice_new + total_ice_checking > 0) {
+    // None of the previous states apply and any RTCIceTransports are in the
+    // "new" or "checking" state.
     new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
-  } else if (total_ice_completed + total_ice_closed == total_ice &&
-             total_ice_completed > 0) {
-    // All RTCIceTransports are in the "completed" or "closed" state and at
-    // least one of them is in the "completed" state.
+  } else if (total_ice_completed + total_ice_closed == total_ice) {
+    // None of the previous states apply and all RTCIceTransports are in the
+    // "completed" or "closed" state.
     new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
   } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
-                 total_ice &&
-             total_ice_connected > 0) {
-    // All RTCIceTransports are in the "connected", "completed" or "closed"
-    // state and at least one of them is in the "connected" state.
+             total_ice) {
+    // None of the previous states apply and all RTCIceTransports are in the
+    // "connected", "completed" or "closed" state.
     new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
-  } else if ((total_ice_new > 0 &&
-              total_ice_checking + total_ice_disconnected + total_ice_failed ==
-                  0) ||
-             total_ice == total_ice_closed) {
-    // Any of the RTCIceTransports are in the "new" state and none of them are
-    // in the "checking", "disconnected" or "failed" state, or all
-    // RTCIceTransports are in the "closed" state, or there are no transports.
-    new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
   } else {
     RTC_NOTREACHED();
   }
@@ -1431,38 +1425,27 @@
   if (total_failed > 0) {
     // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
     new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
-  } else if (total_ice_disconnected > 0 &&
-             total_dtls_connecting + total_ice_checking == 0) {
-    // Any of the RTCIceTransports or RTCDtlsTransports are in the
-    // "disconnected" state and none of them are in the "failed" or "connecting"
-    // or "checking" state.
+  } else if (total_ice_disconnected > 0) {
+    // None of the previous states apply and any RTCIceTransports or
+    // RTCDtlsTransports are in the "disconnected" state.
     new_combined_state =
         PeerConnectionInterface::PeerConnectionState::kDisconnected;
-  } else if (total_dtls_connecting + total_ice_checking > 0) {
-    // Any of the RTCIceTransports or RTCDtlsTransports are in the "connecting"
-    // or "checking" state and none of them is in the "failed" state.
+  } else if (total_new + total_closed == total_transports) {
+    // None of the previous states apply and all RTCIceTransports and
+    // RTCDtlsTransports are in the "new" or "closed" state, or there are no
+    // transports.
+    new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
+  } else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
+    // None of the previous states apply and all RTCIceTransports or
+    // RTCDtlsTransports are in the "new", "connecting" or "checking" state.
     new_combined_state =
         PeerConnectionInterface::PeerConnectionState::kConnecting;
   } else if (total_connected + total_ice_completed + total_closed ==
-                 total_transports &&
-             total_connected + total_ice_completed > 0) {
-    // All RTCIceTransports and RTCDtlsTransports are in the "connected",
-    // "completed" or "closed" state and at least one of them is in the
-    // "connected" or "completed" state.
+             total_transports) {
+    // None of the previous states apply and all RTCIceTransports and
+    // RTCDtlsTransports are in the "connected", "completed" or "closed" state.
     new_combined_state =
         PeerConnectionInterface::PeerConnectionState::kConnected;
-  } else if ((total_new > 0 && total_dtls_connecting + total_ice_checking +
-                                       total_failed + total_ice_disconnected ==
-                                   0) ||
-             total_transports == total_closed) {
-    // Any of the RTCIceTransports or RTCDtlsTransports are in the "new" state
-    // and none of the transports are in the "connecting", "checking", "failed"
-    // or "disconnected" state, or all transports are in the "closed" state, or
-    // there are no transports.
-    //
-    // Note that if none of the other conditions hold this is guaranteed to be
-    // true.
-    new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
   } else {
     RTC_NOTREACHED();
   }
diff --git a/pc/jseptransportcontroller_unittest.cc b/pc/jseptransportcontroller_unittest.cc
index fd8a779..3031b8d 100644
--- a/pc/jseptransportcontroller_unittest.cc
+++ b/pc/jseptransportcontroller_unittest.cc
@@ -273,6 +273,8 @@
 
   void OnCombinedConnectionState(
       PeerConnectionInterface::PeerConnectionState state) {
+    RTC_LOG(LS_INFO) << "OnCombinedConnectionState: "
+                     << static_cast<int>(state);
     if (!signaling_thread_->IsCurrent()) {
       signaled_on_non_signaling_thread_ = true;
     }
@@ -783,10 +785,10 @@
   EXPECT_EQ(1, connection_state_signal_count_);
   EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
                  ice_connection_state_, kTimeout);
-  EXPECT_EQ(1, ice_connection_state_signal_count_);
+  EXPECT_EQ(2, ice_connection_state_signal_count_);
   EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
                  combined_connection_state_, kTimeout);
-  EXPECT_EQ(1, combined_connection_state_signal_count_);
+  EXPECT_EQ(2, combined_connection_state_signal_count_);
 
   fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
   fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
@@ -798,10 +800,10 @@
   EXPECT_EQ(2, connection_state_signal_count_);
   EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
                  ice_connection_state_, kTimeout);
-  EXPECT_EQ(2, ice_connection_state_signal_count_);
+  EXPECT_EQ(3, ice_connection_state_signal_count_);
   EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
                  combined_connection_state_, kTimeout);
-  EXPECT_EQ(2, combined_connection_state_signal_count_);
+  EXPECT_EQ(3, combined_connection_state_signal_count_);
 }
 
 TEST_F(JsepTransportControllerTest,
@@ -906,37 +908,48 @@
   // First, have one transport connect, and another fail, to ensure that
   // the first transport connecting didn't trigger a "connected" state signal.
   // We should only get a signal when all are connected.
-  fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
+  fake_audio_dtls->fake_ice_transport()->SetTransportState(
+      IceTransportState::kCompleted,
+      cricket::IceTransportState::STATE_COMPLETED);
   fake_audio_dtls->SetWritable(true);
   fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
-  // Decrease the number of the connection to trigger the signal.
-  fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
-  fake_video_dtls->fake_ice_transport()->SetConnectionCount(0);
+
+  EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
+                 ice_connection_state_, kTimeout);
+  EXPECT_EQ(1, ice_connection_state_signal_count_);
+  EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnecting,
+                 combined_connection_state_, kTimeout);
+  EXPECT_EQ(1, combined_connection_state_signal_count_);
+
+  fake_video_dtls->fake_ice_transport()->SetTransportState(
+      IceTransportState::kFailed, cricket::IceTransportState::STATE_FAILED);
   fake_video_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
 
   EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
   EXPECT_EQ(1, connection_state_signal_count_);
   EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
                  ice_connection_state_, kTimeout);
-  EXPECT_EQ(1, ice_connection_state_signal_count_);
+  EXPECT_EQ(2, ice_connection_state_signal_count_);
   EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kFailed,
                  combined_connection_state_, kTimeout);
-  EXPECT_EQ(1, combined_connection_state_signal_count_);
+  EXPECT_EQ(2, combined_connection_state_signal_count_);
 
   fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
   fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
   // Set the connection count to be 1 and the cricket::FakeIceTransport will set
   // the transport state to be STATE_COMPLETED.
-  fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
+  fake_video_dtls->fake_ice_transport()->SetTransportState(
+      IceTransportState::kCompleted,
+      cricket::IceTransportState::STATE_COMPLETED);
   fake_video_dtls->SetWritable(true);
   EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
   EXPECT_EQ(2, connection_state_signal_count_);
   EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
                  ice_connection_state_, kTimeout);
-  EXPECT_EQ(2, ice_connection_state_signal_count_);
+  EXPECT_EQ(3, ice_connection_state_signal_count_);
   EXPECT_EQ_WAIT(PeerConnectionInterface::PeerConnectionState::kConnected,
                  combined_connection_state_, kTimeout);
-  EXPECT_EQ(2, combined_connection_state_signal_count_);
+  EXPECT_EQ(3, combined_connection_state_signal_count_);
 }
 
 TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
diff --git a/pc/peerconnection_integrationtest.cc b/pc/peerconnection_integrationtest.cc
index f0184f1..fda34fe 100644
--- a/pc/peerconnection_integrationtest.cc
+++ b/pc/peerconnection_integrationtest.cc
@@ -3883,8 +3883,6 @@
   EXPECT_THAT(
       caller()->peer_connection_state_history(),
       ElementsAre(PeerConnectionInterface::PeerConnectionState::kConnecting,
-                  PeerConnectionInterface::PeerConnectionState::kNew,
-                  PeerConnectionInterface::PeerConnectionState::kConnecting,
                   PeerConnectionInterface::PeerConnectionState::kConnected));
   EXPECT_THAT(caller()->ice_gathering_state_history(),
               ElementsAre(PeerConnectionInterface::kIceGatheringGathering,
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java
index 2063199..5855322 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java
@@ -836,8 +836,6 @@
 
     offeringExpectations.expectIceConnectionChange(IceConnectionState.CHECKING);
     offeringExpectations.expectIceConnectionChange(IceConnectionState.CONNECTED);
-    offeringExpectations.expectConnectionChange(PeerConnectionState.NEW);
-    offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTING);
     offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTED);
     // TODO(bemasc): uncomment once delivery of ICECompleted is reliable
     // (https://code.google.com/p/webrtc/issues/detail?id=3021).
@@ -1071,8 +1069,6 @@
 
     offeringExpectations.expectIceConnectionChange(IceConnectionState.CHECKING);
     offeringExpectations.expectIceConnectionChange(IceConnectionState.CONNECTED);
-    offeringExpectations.expectConnectionChange(PeerConnectionState.NEW);
-    offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTING);
     offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTED);
     // TODO(bemasc): uncomment once delivery of ICECompleted is reliable
     // (https://code.google.com/p/webrtc/issues/detail?id=3021).
@@ -1255,8 +1251,6 @@
 
     offeringExpectations.expectIceConnectionChange(IceConnectionState.CHECKING);
     offeringExpectations.expectIceConnectionChange(IceConnectionState.CONNECTED);
-    offeringExpectations.expectConnectionChange(PeerConnectionState.NEW);
-    offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTING);
     offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTED);
     // TODO(bemasc): uncomment once delivery of ICECompleted is reliable
     // (https://code.google.com/p/webrtc/issues/detail?id=3021).