Bug 935723. Part 1. Decouple ICE state with ICE gathering state r=ekr,abr,jesup
authorByron Campen [:bwc] <docfaraday@gmail.com>
Wed, 13 Nov 2013 14:53:30 -0800
changeset 173271 df21e1d3eaa28000b8539d85ddf7891ed1101ff6
parent 173270 765f15f432c8f973cf03bd0fb7d2aa65858c0036
child 173272 1fb0d84b5210790fc8dadd82d0e0c69e7d84dd6c
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersekr, abr, jesup
bugs935723
milestone28.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 935723. Part 1. Decouple ICE state with ICE gathering state r=ekr,abr,jesup
CLOBBER
dom/media/PeerConnection.js
dom/webidl/PeerConnectionImpl.webidl
dom/webidl/PeerConnectionImplEnums.webidl
dom/webidl/PeerConnectionObserverEnums.webidl
media/mtransport/nricectx.cpp
media/mtransport/nricectx.h
media/mtransport/test/ice_unittest.cpp
media/mtransport/test/transport_unittests.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
media/webrtc/signaling/test/signaling_unittests.cpp
--- a/CLOBBER
+++ b/CLOBBER
@@ -13,10 +13,9 @@
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
-WebIDL dictionary modification requires clobber on Windows (bug 928195), part of
-bug 906990.
+Another Windows WebIDL clobber needed due to bug 928195
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -1011,31 +1011,18 @@ PeerConnectionObserver.prototype = {
             candidate: candidate,
             sdpMid: mid,
             sdpMLineIndex: level - 1
         }
     ));
   },
 
 
-  // This method is primarily responsible for updating two attributes:
-  // iceGatheringState and iceConnectionState. These states are defined
-  // in the WebRTC specification as follows:
-  //
-  // iceGatheringState:
-  // ------------------
-  //   new        The object was just created, and no networking has occurred
-  //              yet.
-  //
-  //   gathering  The ICE engine is in the process of gathering candidates for
-  //              this RTCPeerConnection.
-  //
-  //   complete   The ICE engine has completed gathering. Events such as adding
-  //              a new interface or a new TURN server will cause the state to
-  //              go back to gathering.
+  // This method is primarily responsible for updating iceConnectionState.
+  // This state is defined in the WebRTC specification as follows:
   //
   // iceConnectionState:
   // -------------------
   //   new           The ICE Agent is gathering addresses and/or waiting for
   //                 remote candidates to be supplied.
   //
   //   checking      The ICE Agent has received remote candidates on at least
   //                 one component, and is checking candidate pairs but has not
@@ -1059,46 +1046,48 @@ PeerConnectionObserver.prototype = {
   //   disconnected  Liveness checks have failed for one or more components.
   //                 This is more aggressive than failed, and may trigger
   //                 intermittently (and resolve itself without action) on a
   //                 flaky network.
   //
   //   closed        The ICE Agent has shut down and is no longer responding to
   //                 STUN requests.
 
-  handleIceStateChanges: function(iceState) {
+  handleIceConnectionStateChange: function(iceState) {
     var histogram = Services.telemetry.getHistogramById("WEBRTC_ICE_SUCCESS_RATE");
 
-    const STATE_MAP = {
-      IceGathering:
-        { gathering: "gathering" },
-      IceWaiting:
-        { connection: "new",  gathering: "complete" },
-      IceChecking:
-        { connection: "checking" },
-      IceConnected:
-        { connection: "connected", success: true },
-      IceFailed:
-        { connection: "failed", success: false }
-    };
-    // These are all the allowed inputs.
+    if (iceState === 'failed') {
+      histogram.add(false);
+    }
+    if (this._dompc.iceConnectionState === 'checking' &&
+        (iceState === 'completed' || iceState === 'connected')) {
+          histogram.add(true);
+    }
+    this._dompc.changeIceConnectionState(iceState);
+  },
 
-    let transitions = STATE_MAP[iceState];
+  // This method is responsible for updating iceGatheringState. This
+  // state is defined in the WebRTC specification as follows:
+  //
+  // iceGatheringState:
+  // ------------------
+  //   new        The object was just created, and no networking has occurred
+  //              yet.
+  //
+  //   gathering  The ICE engine is in the process of gathering candidates for
+  //              this RTCPeerConnection.
+  //
+  //   complete   The ICE engine has completed gathering. Events such as adding
+  //              a new interface or a new TURN server will cause the state to
+  //              go back to gathering.
+  //
+  handleIceGatheringStateChange: function(gatheringState) {
+    this._dompc.changeIceGatheringState(gatheringState);
 
-    if ("connection" in transitions) {
-        this._dompc.changeIceConnectionState(transitions.connection);
-    }
-    if ("gathering" in transitions) {
-      this._dompc.changeIceGatheringState(transitions.gathering);
-    }
-    if ("success" in transitions) {
-      histogram.add(transitions.success);
-    }
-
-    if (iceState == "IceWaiting") {
+    if (gatheringState === "complete") {
       if (!this._dompc._trickleIce) {
         // If we are not trickling, then the queue is in a pending state
         // waiting for ICE gathering and executeNext frees it
         this._dompc._executeNext();
       }
       else if (this._dompc.localDescription) {
         // If we are trickling but we have already done setLocal,
         // then we need to send a final foundIceCandidate(null) to indicate
@@ -1110,18 +1099,22 @@ PeerConnectionObserver.prototype = {
 
   onStateChange: function(state) {
     switch (state) {
       case "SignalingState":
         this.callCB(this._dompc.onsignalingstatechange,
                     this._dompc.signalingState);
         break;
 
-      case "IceState":
-        this.handleIceStateChanges(this._dompc._pc.iceState);
+      case "IceConnectionState":
+        this.handleIceConnectionStateChange(this._dompc._pc.iceState);
+        break;
+
+      case "IceGatheringState":
+        this.handleIceGatheringStateChange(this._dompc._pc.iceGatheringState);
         break;
 
       case "SdpState":
         // No-op
         break;
 
       case "ReadyState":
         // No-op
--- a/dom/webidl/PeerConnectionImpl.webidl
+++ b/dom/webidl/PeerConnectionImpl.webidl
@@ -65,17 +65,18 @@ interface PeerConnectionImpl  {
 
   /* Puts the SIPCC engine back to 'kIdle', shuts down threads, deletes state */
   void close();
 
   /* Attributes */
   readonly attribute DOMString localDescription;
   readonly attribute DOMString remoteDescription;
 
-  readonly attribute PCImplIceState iceState;
+  readonly attribute PCImplIceConnectionState iceConnectionState;
+  readonly attribute PCImplIceGatheringState iceGatheringState;
   readonly attribute PCImplReadyState readyState;
   readonly attribute PCImplSignalingState signalingState;
   readonly attribute PCImplSipccState sipccState;
 
   /* Data channels */
   [Throws]
   DataChannel createDataChannel(DOMString label, DOMString protocol,
     unsigned short type, boolean outOfOrderAllowed,
--- a/dom/webidl/PeerConnectionImplEnums.webidl
+++ b/dom/webidl/PeerConnectionImplEnums.webidl
@@ -26,16 +26,25 @@ enum PCImplSignalingState {
 };
 
 enum PCImplSipccState {
   "Idle",
   "Starting",
   "Started"
 };
 
-// TODO(ekr@rtfm.com): make this conform to the specifications
-enum PCImplIceState {
-  "IceGathering",
-  "IceWaiting",
-  "IceChecking",
-  "IceConnected",
-  "IceFailed"
+enum PCImplIceConnectionState {
+    "new",
+    "checking",
+    "connected",
+    "completed",
+    "failed",
+    "disconnected",
+    "closed"
 };
+
+// Deliberately identical to the values specified in webrtc
+enum PCImplIceGatheringState {
+  "new",
+  "gathering",
+  "complete"
+};
+
--- a/dom/webidl/PeerConnectionObserverEnums.webidl
+++ b/dom/webidl/PeerConnectionObserverEnums.webidl
@@ -4,13 +4,14 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * This is in a separate file so it can be shared with unittests.
  */
 
 enum PCObserverStateType {
     "None",
     "ReadyState",
-    "IceState",
+    "IceConnectionState",
+    "IceGatheringState",
     "SdpState",
     "SipccState",
     "SignalingState"
 };
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -271,28 +271,28 @@ int NrIceCtx::stream_failed(void *obj, n
 
   // Get the ICE ctx
   NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
   RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
 
   // Streams which do not exist should never fail.
   MOZ_ASSERT(s);
 
-  ctx->SetState(ICE_CTX_FAILED);
+  ctx->SetConnectionState(ICE_CTX_FAILED);
   s -> SignalFailed(s);
   return 0;
 }
 
 int NrIceCtx::ice_completed(void *obj, nr_ice_peer_ctx *pctx) {
   MOZ_MTLOG(ML_DEBUG, "ice_completed called");
 
   // Get the ICE ctx
   NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
 
-  ctx->SetState(ICE_CTX_OPEN);
+  ctx->SetConnectionState(ICE_CTX_OPEN);
 
   return 0;
 }
 
 int NrIceCtx::msg_recvd(void *obj, nr_ice_peer_ctx *pctx,
                         nr_ice_media_stream *stream, int component_id,
                         UCHAR *msg, int len) {
   // Get the ICE ctx
@@ -546,31 +546,31 @@ nsresult NrIceCtx::SetResolver(nr_resolv
   return NS_OK;
 }
 
 nsresult NrIceCtx::StartGathering() {
   MOZ_ASSERT(ctx_->state == ICE_CTX_INIT);
   if (ctx_->state != ICE_CTX_INIT) {
     MOZ_MTLOG(ML_ERROR, "ICE ctx in the wrong state for gathering: '"
               << name_ << "'");
-    SetState(ICE_CTX_FAILED);
+    SetConnectionState(ICE_CTX_FAILED);
     return NS_ERROR_FAILURE;
   }
 
   int r = nr_ice_initialize(ctx_, &NrIceCtx::initialized_cb,
                             this);
 
   if (r && r != R_WOULDBLOCK) {
       MOZ_MTLOG(ML_ERROR, "Couldn't gather ICE candidates for '"
                 << name_ << "'");
-      SetState(ICE_CTX_FAILED);
+      SetConnectionState(ICE_CTX_FAILED);
       return NS_ERROR_FAILURE;
   }
 
-  SetState(ICE_CTX_GATHERING);
+  SetGatheringState(ICE_CTX_GATHER_STARTED);
 
   return NS_OK;
 }
 
 RefPtr<NrIceMediaStream> NrIceCtx::FindStream(
     nr_ice_media_stream *stream) {
   for (size_t i=0; i<streams_.size(); ++i) {
     if (streams_[i]->stream() == stream) {
@@ -625,78 +625,77 @@ nsresult NrIceCtx::ParseGlobalAttributes
 
 nsresult NrIceCtx::StartChecks() {
   int r;
 
   r=nr_ice_peer_ctx_pair_candidates(peer_);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't pair candidates on "
               << name_ << "'");
-    SetState(ICE_CTX_FAILED);
+    SetConnectionState(ICE_CTX_FAILED);
     return NS_ERROR_FAILURE;
   }
 
   r = nr_ice_peer_ctx_start_checks2(peer_,1);
   if (r) {
     if (r == R_NOT_FOUND) {
       MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks on "
                 << name_ << "' assuming trickle ICE");
     } else {
       MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks on "
                 << name_ << "'");
-      SetState(ICE_CTX_FAILED);
+      SetConnectionState(ICE_CTX_FAILED);
       return NS_ERROR_FAILURE;
     }
   } else {
-    SetState(ICE_CTX_CHECKING);
+    SetConnectionState(ICE_CTX_CHECKING);
   }
 
   return NS_OK;
 }
 
 
 void NrIceCtx::initialized_cb(NR_SOCKET s, int h, void *arg) {
   NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
 
-  ctx->SetState(ICE_CTX_GATHERED);
+  ctx->SetGatheringState(ICE_CTX_GATHER_COMPLETE);
 }
 
 nsresult NrIceCtx::Finalize() {
   int r = nr_ice_ctx_finalize(ctx_, peer_);
 
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't finalize "
          << name_ << "'");
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
-void NrIceCtx::SetState(State state) {
-  if (state == state_)
+void NrIceCtx::SetConnectionState(ConnectionState state) {
+  if (state == connection_state_)
     return;
 
   MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): state " <<
-            state_ << "->" << state);
-  state_ = state;
+            connection_state_ << "->" << state);
+  connection_state_ = state;
+
+  SignalConnectionStateChange(this, state);
+}
 
-  switch(state_) {
-    case ICE_CTX_GATHERED:
-      SignalGatheringCompleted(this);
-      break;
-    case ICE_CTX_OPEN:
-      SignalCompleted(this);
-      break;
-    case ICE_CTX_FAILED:
-      SignalFailed(this);
-      break;
-    default:
-      break;
-  }
+void NrIceCtx::SetGatheringState(GatheringState state) {
+  if (state == gathering_state_)
+    return;
+
+  MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << name_ << "): gathering state " <<
+            gathering_state_ << "->" << state);
+  gathering_state_ = state;
+
+  SignalGatheringStateChange(this, state);
 }
 
 }  // close namespace
 
 
 extern "C" {
 int nr_bin2hex(UCHAR *in,int len,UCHAR *out);
 }
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -158,22 +158,25 @@ class NrIceTurnServer : public NrIceStun
       username_(username), password_(password) {}
 
   std::string username_;
   std::vector<unsigned char> password_;
 };
 
 class NrIceCtx {
  public:
-  enum State { ICE_CTX_INIT,
-               ICE_CTX_GATHERING,
-               ICE_CTX_GATHERED,
-               ICE_CTX_CHECKING,
-               ICE_CTX_OPEN,
-               ICE_CTX_FAILED
+  enum ConnectionState { ICE_CTX_INIT,
+                         ICE_CTX_CHECKING,
+                         ICE_CTX_OPEN,
+                         ICE_CTX_FAILED
+  };
+
+  enum GatheringState { ICE_CTX_GATHER_INIT,
+                        ICE_CTX_GATHER_STARTED,
+                        ICE_CTX_GATHER_COMPLETE
   };
 
   enum Controlling { ICE_CONTROLLING,
                      ICE_CONTROLLED
   };
 
   static RefPtr<NrIceCtx> Create(const std::string& name,
                                  bool offerer,
@@ -189,17 +192,24 @@ class NrIceCtx {
   // Create a media stream
   RefPtr<NrIceMediaStream> CreateStream(const std::string& name,
                                                  int components);
 
   // The name of the ctx
   const std::string& name() const { return name_; }
 
   // Current state
-  State state() const { return state_; }
+  ConnectionState connection_state() const {
+    return connection_state_;
+  }
+
+  // Current state
+  GatheringState gathering_state() const {
+    return gathering_state_;
+  }
 
   // Get the global attributes
   std::vector<std::string> GetGlobalAttributes();
 
   // Set the other side's global attributes
   nsresult ParseGlobalAttributes(std::vector<std::string> attrs);
 
   // Set whether we are controlling or not.
@@ -227,31 +237,31 @@ class NrIceCtx {
   // more forking.
   nsresult Finalize();
 
   // Are we trickling?
   bool generating_trickle() const { return trickle_; }
 
   // Signals to indicate events. API users can (and should)
   // register for these.
-  // TODO(ekr@rtfm.com): refactor this to be state change instead
-  // so we don't need to keep adding signals?
-  sigslot::signal1<NrIceCtx *> SignalGatheringCompleted;  // Done gathering
-  sigslot::signal1<NrIceCtx *> SignalCompleted;  // Done handshaking
-  sigslot::signal1<NrIceCtx *> SignalFailed;  // Failure.
+  sigslot::signal2<NrIceCtx*, NrIceCtx::GatheringState>
+    SignalGatheringStateChange;
+  sigslot::signal2<NrIceCtx*, NrIceCtx::ConnectionState>
+    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,
            bool offerer)
-  : state_(ICE_CTX_INIT),
+  : connection_state_(ICE_CTX_INIT),
+    gathering_state_(ICE_CTX_GATHER_INIT),
     name_(name),
     offerer_(offerer),
     streams_(),
     ctx_(nullptr),
     peer_(nullptr),
     ice_handler_vtbl_(nullptr),
     ice_handler_(nullptr),
     trickle_(true) {
@@ -276,19 +286,23 @@ class NrIceCtx {
                        unsigned char *msg, int len);
   static void trickle_cb(void *arg, nr_ice_ctx *ctx, nr_ice_media_stream *stream,
                          int component_id, nr_ice_candidate *candidate);
 
   // Find a media stream by stream ptr. Gross
   RefPtr<NrIceMediaStream> FindStream(nr_ice_media_stream *stream);
 
   // Set the state
-  void SetState(State state);
+  void SetConnectionState(ConnectionState state);
 
-  State state_;
+  // Set the state
+  void SetGatheringState(GatheringState state);
+
+  ConnectionState connection_state_;
+  GatheringState gathering_state_;
   const std::string name_;
   bool offerer_;
   std::vector<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_;
--- a/media/mtransport/test/ice_unittest.cpp
+++ b/media/mtransport/test/ice_unittest.cpp
@@ -138,19 +138,22 @@ class IceTestPeer : public sigslot::has_
       fake_resolver_(),
       dns_resolver_(new NrIceResolver()),
       remote_(nullptr),
       candidate_filter_(nullptr),
       expected_local_type_(NrIceCandidate::ICE_HOST),
       expected_remote_type_(NrIceCandidate::ICE_HOST),
       trickle_mode_(TRICKLE_NONE),
       trickled_(0) {
-    ice_ctx_->SignalGatheringCompleted.connect(this,
-                                               &IceTestPeer::GatheringComplete);
-    ice_ctx_->SignalCompleted.connect(this, &IceTestPeer::IceCompleted);
+    ice_ctx_->SignalGatheringStateChange.connect(
+        this,
+        &IceTestPeer::GatheringStateChange);
+    ice_ctx_->SignalConnectionStateChange.connect(
+        this,
+        &IceTestPeer::ConnectionStateChange);
   }
 
   ~IceTestPeer() {
     test_utils->sts_target()->Dispatch(WrapRunnable(this,
                                                     &IceTestPeer::Shutdown),
         NS_DISPATCH_SYNC);
 
     // Give the ICE destruction callback time to fire before
@@ -421,17 +424,23 @@ class IceTestPeer : public sigslot::has_
     // Now start checks
     test_utils->sts_target()->Dispatch(
         WrapRunnableRet(ice_ctx_, &NrIceCtx::StartChecks, &res),
         NS_DISPATCH_SYNC);
     ASSERT_TRUE(NS_SUCCEEDED(res));
   }
 
   // Handle events
-  void GatheringComplete(NrIceCtx *ctx) {
+  void GatheringStateChange(NrIceCtx* ctx,
+                            NrIceCtx::GatheringState state) {
+    (void)ctx;
+    if (state != NrIceCtx::ICE_CTX_GATHER_COMPLETE) {
+      return;
+    }
+
     std::cerr << "Gathering complete for " <<  name_ << std::endl;
     gathering_complete_ = true;
 
     std::cerr << "CANDIDATES:" << std::endl;
     for (size_t i=0; i<streams_.size(); ++i) {
       std::cerr << "Stream " << name_ << std::endl;
       std::vector<std::string> candidates =
           streams_[i]->GetCandidates();
@@ -593,17 +602,22 @@ class IceTestPeer : public sigslot::has_
     std::cerr << "Stream ready " << stream->name() << " ct=" << ready_ct_ << std::endl;
     DumpCandidatePairs(stream);
   }
   void StreamFailed(NrIceMediaStream *stream) {
     std::cerr << "Stream failed " << stream->name() << " ct=" << ready_ct_ << std::endl;
     DumpCandidatePairs(stream);
   }
 
-  void IceCompleted(NrIceCtx *ctx) {
+  void ConnectionStateChange(NrIceCtx* ctx,
+                             NrIceCtx::ConnectionState state) {
+    (void)ctx;
+    if (state != NrIceCtx::ICE_CTX_OPEN) {
+      return;
+    }
     std::cerr << "ICE completed " << name_ << std::endl;
     ice_complete_ = true;
   }
 
   void PacketReceived(NrIceMediaStream *stream, int component, const unsigned char *data,
                       int len) {
     std::cerr << "Received " << len << " bytes" << std::endl;
     ++received_;
--- a/media/mtransport/test/transport_unittests.cpp
+++ b/media/mtransport/test/transport_unittests.cpp
@@ -232,18 +232,18 @@ class TransportTestPeer : public sigslot
                                peer),
                   NS_DISPATCH_SYNC);
   }
 
   void InitIce() {
     nsresult res;
 
     // Attach our slots
-    ice_ctx_->SignalGatheringCompleted.
-        connect(this, &TransportTestPeer::GatheringComplete);
+    ice_ctx_->SignalGatheringStateChange.
+        connect(this, &TransportTestPeer::GatheringStateChange);
 
     char name[100];
     snprintf(name, sizeof(name), "%s:stream%d", name_.c_str(),
              (int)streams_.size());
 
     // Create the media stream
     mozilla::RefPtr<NrIceMediaStream> stream =
         ice_ctx_->CreateStream(static_cast<char *>(name), 1);
@@ -280,28 +280,36 @@ class TransportTestPeer : public sigslot
     ASSERT_TRUE(NS_SUCCEEDED(res));
   }
 
   void ConnectIce(TransportTestPeer *peer) {
     peer_ = peer;
 
     // If gathering is already complete, push the candidates over
     if (gathering_complete_)
-      GatheringComplete(ice_ctx_);
+      GatheringComplete();
   }
 
   // New candidate
   void GotCandidate(NrIceMediaStream *stream, const std::string &candidate) {
     std::cerr << "Got candidate " << candidate << std::endl;
     candidates_[stream->name()].push_back(candidate);
   }
 
+  void GatheringStateChange(NrIceCtx* ctx,
+                            NrIceCtx::GatheringState state) {
+    (void)ctx;
+    if (state == NrIceCtx::ICE_CTX_GATHER_COMPLETE) {
+      GatheringComplete();
+    }
+  }
+
   // Gathering complete, so send our candidates and start
   // connecting on the other peer.
-  void GatheringComplete(NrIceCtx *ctx) {
+  void GatheringComplete() {
     nsresult res;
 
     // Don't send to the other side
     if (!peer_) {
       gathering_complete_ = true;
       return;
     }
 
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -451,17 +451,18 @@ struct PeerConnectionImpl::Internal {
 };
 
 PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
 : mTimeCard(PR_LOG_TEST(signalingLogInfo(),PR_LOG_ERROR) ?
             create_timecard() : nullptr)
   , mInternal(new Internal())
   , mReadyState(PCImplReadyState::New)
   , mSignalingState(PCImplSignalingState::SignalingStable)
-  , mIceState(PCImplIceState::IceGathering)
+  , mIceConnectionState(PCImplIceConnectionState::New)
+  , mIceGatheringState(PCImplIceGatheringState::New)
   , mWindow(nullptr)
   , mIdentity(nullptr)
   , mSTSThread(nullptr)
   , mMedia(nullptr)
   , mNumAudioStreams(0)
   , mNumVideoStreams(0)
   , mHaveDataStream(false)
   , mTrickle(true) // TODO(ekr@rtfm.com): Use pref
@@ -748,19 +749,22 @@ PeerConnectionImpl::Initialize(PeerConne
       return res;
     }
     aConfiguration = &converted;
   }
 
   mMedia = new PeerConnectionMedia(this);
 
   // Connect ICE slots.
-  mMedia->SignalIceGatheringCompleted.connect(this, &PeerConnectionImpl::IceGatheringCompleted);
-  mMedia->SignalIceCompleted.connect(this, &PeerConnectionImpl::IceCompleted);
-  mMedia->SignalIceFailed.connect(this, &PeerConnectionImpl::IceFailed);
+  mMedia->SignalIceGatheringStateChange.connect(
+      this,
+      &PeerConnectionImpl::IceGatheringStateChange);
+  mMedia->SignalIceConnectionStateChange.connect(
+      this,
+      &PeerConnectionImpl::IceConnectionStateChange);
 
   // Initialize the media object.
   res = mMedia->Init(aConfiguration->getStunServers(),
                      aConfiguration->getTurnServers());
   if (NS_FAILED(res)) {
     CSFLogError(logTag, "%s: Couldn't initialize media object", __FUNCTION__);
     return res;
   }
@@ -1413,31 +1417,41 @@ PeerConnectionImpl::SipccState(PCImplSip
     *aState = pcctx->sipcc_state();
   } else {
     *aState = PCImplSipccState::Idle;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PeerConnectionImpl::IceState(PCImplIceState* aState)
+PeerConnectionImpl::IceConnectionState(PCImplIceConnectionState* aState)
 {
   PC_AUTO_ENTER_API_CALL_NO_CHECK();
   MOZ_ASSERT(aState);
 
-  *aState = mIceState;
+  *aState = mIceConnectionState;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PeerConnectionImpl::IceGatheringState(PCImplIceGatheringState* aState)
+{
+  PC_AUTO_ENTER_API_CALL_NO_CHECK();
+  MOZ_ASSERT(aState);
+
+  *aState = mIceGatheringState;
   return NS_OK;
 }
 
 nsresult
 PeerConnectionImpl::CheckApiState(bool assert_ice_ready) const
 {
   PC_AUTO_ENTER_API_CALL_NO_CHECK();
   MOZ_ASSERT(mTrickle || !assert_ice_ready ||
-             (mIceState != PCImplIceState::IceGathering));
+             (mIceGatheringState == PCImplIceGatheringState::Complete));
 
   if (mReadyState == PCImplReadyState::Closed)
     return NS_ERROR_FAILURE;
   if (!mMedia)
     return NS_ERROR_FAILURE;
   return NS_OK;
 }
 
@@ -1625,93 +1639,155 @@ PeerConnectionWrapper::PeerConnectionWra
 
 const std::string&
 PeerConnectionImpl::GetHandle()
 {
   PC_AUTO_ENTER_API_CALL_NO_CHECK();
   return mHandle;
 }
 
+static mozilla::dom::PCImplIceConnectionState
+toDomIceConnectionState(NrIceCtx::ConnectionState state) {
+  switch (state) {
+    case NrIceCtx::ICE_CTX_INIT:
+      return PCImplIceConnectionState::New;
+    case NrIceCtx::ICE_CTX_CHECKING:
+      return PCImplIceConnectionState::Checking;
+    case NrIceCtx::ICE_CTX_OPEN:
+      return PCImplIceConnectionState::Connected;
+    case NrIceCtx::ICE_CTX_FAILED:
+      return PCImplIceConnectionState::Failed;
+  }
+  MOZ_CRASH();
+}
+
+static mozilla::dom::PCImplIceGatheringState
+toDomIceGatheringState(NrIceCtx::GatheringState state) {
+  switch (state) {
+    case NrIceCtx::ICE_CTX_GATHER_INIT:
+      return PCImplIceGatheringState::New;
+    case NrIceCtx::ICE_CTX_GATHER_STARTED:
+      return PCImplIceGatheringState::Gathering;
+    case NrIceCtx::ICE_CTX_GATHER_COMPLETE:
+      return PCImplIceGatheringState::Complete;
+  }
+  MOZ_CRASH();
+}
+
 // This is called from the STS thread and so we need to thunk
 // to the main thread.
-void
-PeerConnectionImpl::IceGatheringCompleted(NrIceCtx *aCtx)
-{
-  (void) aCtx;
+void PeerConnectionImpl::IceConnectionStateChange(
+    NrIceCtx* ctx,
+    NrIceCtx::ConnectionState state) {
+  (void)ctx;
   // Do an async call here to unwind the stack. refptr keeps the PC alive.
   nsRefPtr<PeerConnectionImpl> pc(this);
   RUN_ON_THREAD(mThread,
                 WrapRunnable(pc,
-                             &PeerConnectionImpl::IceStateChange_m,
-                             PCImplIceState::IceWaiting),
+                             &PeerConnectionImpl::IceConnectionStateChange_m,
+                             toDomIceConnectionState(state)),
                 NS_DISPATCH_NORMAL);
 }
 
 void
-PeerConnectionImpl::IceCompleted(NrIceCtx *aCtx)
+PeerConnectionImpl::IceGatheringStateChange(
+    NrIceCtx* ctx,
+    NrIceCtx::GatheringState state)
 {
-  (void) aCtx;
+  (void)ctx;
   // Do an async call here to unwind the stack. refptr keeps the PC alive.
   nsRefPtr<PeerConnectionImpl> pc(this);
   RUN_ON_THREAD(mThread,
                 WrapRunnable(pc,
-                             &PeerConnectionImpl::IceStateChange_m,
-                             PCImplIceState::IceConnected),
-                NS_DISPATCH_NORMAL);
-}
-
-void
-PeerConnectionImpl::IceFailed(NrIceCtx *aCtx)
-{
-  (void) aCtx;
-  // Do an async call here to unwind the stack. refptr keeps the PC alive.
-  nsRefPtr<PeerConnectionImpl> pc(this);
-  RUN_ON_THREAD(mThread,
-                WrapRunnable(pc,
-                             &PeerConnectionImpl::IceStateChange_m,
-                             PCImplIceState::IceFailed),
+                             &PeerConnectionImpl::IceGatheringStateChange_m,
+                             toDomIceGatheringState(state)),
                 NS_DISPATCH_NORMAL);
 }
 
 nsresult
-PeerConnectionImpl::IceStateChange_m(PCImplIceState aState)
+PeerConnectionImpl::IceConnectionStateChange_m(PCImplIceConnectionState aState)
 {
   PC_AUTO_ENTER_API_CALL(false);
 
   CSFLogDebug(logTag, "%s", __FUNCTION__);
 
-  mIceState = aState;
+  mIceConnectionState = aState;
 
-  switch (mIceState) {
-    case PCImplIceState::IceGathering:
-      STAMP_TIMECARD(mTimeCard, "Ice state: gathering");
+  // Would be nice if we had a means of converting one of these dom enums
+  // to a string that wasn't almost as much text as this switch statement...
+  switch (mIceConnectionState) {
+    case PCImplIceConnectionState::New:
+      STAMP_TIMECARD(mTimeCard, "Ice state: new");
       break;
-    case PCImplIceState::IceWaiting:
-      STAMP_TIMECARD(mTimeCard, "Ice state: waiting");
-      break;
-    case PCImplIceState::IceChecking:
+    case PCImplIceConnectionState::Checking:
       STAMP_TIMECARD(mTimeCard, "Ice state: checking");
       break;
-    case PCImplIceState::IceConnected:
+    case PCImplIceConnectionState::Connected:
       STAMP_TIMECARD(mTimeCard, "Ice state: connected");
       break;
-    case PCImplIceState::IceFailed:
+    case PCImplIceConnectionState::Completed:
+      STAMP_TIMECARD(mTimeCard, "Ice state: completed");
+      break;
+    case PCImplIceConnectionState::Failed:
       STAMP_TIMECARD(mTimeCard, "Ice state: failed");
       break;
+    case PCImplIceConnectionState::Disconnected:
+      STAMP_TIMECARD(mTimeCard, "Ice state: disconnected");
+      break;
+    case PCImplIceConnectionState::Closed:
+      STAMP_TIMECARD(mTimeCard, "Ice state: closed");
+      break;
   }
 
   nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
   if (!pco) {
     return NS_OK;
   }
   WrappableJSErrorResult rv;
   RUN_ON_THREAD(mThread,
                 WrapRunnable(pco,
                              &PeerConnectionObserver::OnStateChange,
-                             PCObserverStateType::IceState,
+                             PCObserverStateType::IceConnectionState,
+                             rv, static_cast<JSCompartment*>(nullptr)),
+                NS_DISPATCH_NORMAL);
+  return NS_OK;
+}
+
+nsresult
+PeerConnectionImpl::IceGatheringStateChange_m(PCImplIceGatheringState aState)
+{
+  PC_AUTO_ENTER_API_CALL(false);
+
+  CSFLogDebug(logTag, "%s", __FUNCTION__);
+
+  mIceGatheringState = aState;
+
+  // Would be nice if we had a means of converting one of these dom enums
+  // to a string that wasn't almost as much text as this switch statement...
+  switch (mIceGatheringState) {
+    case PCImplIceGatheringState::New:
+      STAMP_TIMECARD(mTimeCard, "Ice gathering state: new");
+      break;
+    case PCImplIceGatheringState::Gathering:
+      STAMP_TIMECARD(mTimeCard, "Ice gathering state: gathering");
+      break;
+    case PCImplIceGatheringState::Complete:
+      STAMP_TIMECARD(mTimeCard, "Ice state: complete");
+      break;
+  }
+
+  nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
+  if (!pco) {
+    return NS_OK;
+  }
+  WrappableJSErrorResult rv;
+  RUN_ON_THREAD(mThread,
+                WrapRunnable(pco,
+                             &PeerConnectionObserver::OnStateChange,
+                             PCObserverStateType::IceGatheringState,
                              rv, static_cast<JSCompartment*>(nullptr)),
                 NS_DISPATCH_NORMAL);
   return NS_OK;
 }
 
 #ifdef MOZILLA_INTERNAL_API
 void PeerConnectionImpl::GetStats_s(
     uint32_t trackId,
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -217,19 +217,20 @@ public:
     PC_AUTO_ENTER_API_CALL_NO_CHECK();
     return mMedia;
   }
 
   // Handle system to allow weak references to be passed through C code
   virtual const std::string& GetHandle();
 
   // ICE events
-  void IceGatheringCompleted(NrIceCtx *aCtx);
-  void IceCompleted(NrIceCtx *aCtx);
-  void IceFailed(NrIceCtx *aCtx);
+  void IceConnectionStateChange(NrIceCtx* ctx,
+                                NrIceCtx::ConnectionState state);
+  void IceGatheringStateChange(NrIceCtx* ctx,
+                               NrIceCtx::GatheringState state);
   void IceStreamReady(NrIceMediaStream *aStream);
 
   static void ListenThread(void *aData);
   static void ConnectThread(void *aData);
 
   // Get the main thread
   nsCOMPtr<nsIThread> GetMainThread() {
     PC_AUTO_ENTER_API_CALL_NO_CHECK();
@@ -285,22 +286,24 @@ public:
   {
     rv = CreateAnswer(aConstraints);
   }
 
   NS_IMETHODIMP CreateOffer(const MediaConstraintsExternal& aConstraints);
   NS_IMETHODIMP CreateAnswer(const MediaConstraintsExternal& aConstraints);
 
   NS_IMETHODIMP SetLocalDescription (int32_t aAction, const char* aSDP);
+
   void SetLocalDescription (int32_t aAction, const nsAString& aSDP, ErrorResult &rv)
   {
     rv = SetLocalDescription(aAction, NS_ConvertUTF16toUTF8(aSDP).get());
   }
 
   NS_IMETHODIMP SetRemoteDescription (int32_t aAction, const char* aSDP);
+
   void SetRemoteDescription (int32_t aAction, const nsAString& aSDP, ErrorResult &rv)
   {
     rv = SetRemoteDescription(aAction, NS_ConvertUTF16toUTF8(aSDP).get());
   }
 
   NS_IMETHODIMP_TO_ERRORRESULT(GetStats, ErrorResult &rv,
                                mozilla::dom::MediaStreamTrack *aSelector,
                                bool internalStats)
@@ -311,24 +314,26 @@ public:
   NS_IMETHODIMP_TO_ERRORRESULT(GetLogging, ErrorResult &rv,
                                const nsAString& pattern)
   {
     rv = GetLogging(pattern);
   }
 
   NS_IMETHODIMP AddIceCandidate(const char* aCandidate, const char* aMid,
                                 unsigned short aLevel);
+
   void AddIceCandidate(const nsAString& aCandidate, const nsAString& aMid,
                        unsigned short aLevel, ErrorResult &rv)
   {
     rv = AddIceCandidate(NS_ConvertUTF16toUTF8(aCandidate).get(),
                          NS_ConvertUTF16toUTF8(aMid).get(), aLevel);
   }
 
   NS_IMETHODIMP CloseStreams();
+
   void CloseStreams(ErrorResult &rv)
   {
     rv = CloseStreams();
   }
 
   NS_IMETHODIMP_TO_ERRORRESULT(AddStream, ErrorResult &rv,
                                DOMMediaStream& aMediaStream)
   {
@@ -337,66 +342,84 @@ public:
 
   NS_IMETHODIMP_TO_ERRORRESULT(RemoveStream, ErrorResult &rv,
                                DOMMediaStream& aMediaStream)
   {
     rv = RemoveStream(aMediaStream);
   }
 
   NS_IMETHODIMP GetLocalDescription(char** aSDP);
+
   void GetLocalDescription(nsAString& aSDP)
   {
     char *tmp;
     GetLocalDescription(&tmp);
     aSDP.AssignASCII(tmp);
     delete tmp;
   }
 
   NS_IMETHODIMP GetRemoteDescription(char** aSDP);
+
   void GetRemoteDescription(nsAString& aSDP)
   {
     char *tmp;
     GetRemoteDescription(&tmp);
     aSDP.AssignASCII(tmp);
     delete tmp;
   }
 
   NS_IMETHODIMP ReadyState(mozilla::dom::PCImplReadyState* aState);
+
   mozilla::dom::PCImplReadyState ReadyState()
   {
     mozilla::dom::PCImplReadyState state;
     ReadyState(&state);
     return state;
   }
 
   NS_IMETHODIMP SignalingState(mozilla::dom::PCImplSignalingState* aState);
+
   mozilla::dom::PCImplSignalingState SignalingState()
   {
     mozilla::dom::PCImplSignalingState state;
     SignalingState(&state);
     return state;
   }
 
   NS_IMETHODIMP SipccState(mozilla::dom::PCImplSipccState* aState);
+
   mozilla::dom::PCImplSipccState SipccState()
   {
     mozilla::dom::PCImplSipccState state;
     SipccState(&state);
     return state;
   }
 
-  NS_IMETHODIMP IceState(mozilla::dom::PCImplIceState* aState);
-  mozilla::dom::PCImplIceState IceState()
+  NS_IMETHODIMP IceConnectionState(
+      mozilla::dom::PCImplIceConnectionState* aState);
+
+  mozilla::dom::PCImplIceConnectionState IceConnectionState()
   {
-    mozilla::dom::PCImplIceState state;
-    IceState(&state);
+    mozilla::dom::PCImplIceConnectionState state;
+    IceConnectionState(&state);
+    return state;
+  }
+
+  NS_IMETHODIMP IceGatheringState(
+      mozilla::dom::PCImplIceGatheringState* aState);
+
+  mozilla::dom::PCImplIceGatheringState IceGatheringState()
+  {
+    mozilla::dom::PCImplIceGatheringState state;
+    IceGatheringState(&state);
     return state;
   }
 
   NS_IMETHODIMP Close();
+
   void Close(ErrorResult &rv)
   {
     rv = Close();
   }
 
   nsresult InitializeDataChannel(int track_id, uint16_t aLocalport,
                                  uint16_t aRemoteport, uint16_t aNumstreams);
 
@@ -484,17 +507,20 @@ private:
   void virtualDestroyNSSReference() MOZ_FINAL;
   nsresult GetTimeSinceEpoch(DOMHighResTimeStamp *result);
 #endif
 
   // Shut down media - called on main thread only
   void ShutdownMedia();
 
   // ICE callbacks run on the right thread.
-  nsresult IceStateChange_m(mozilla::dom::PCImplIceState aState);
+  nsresult IceConnectionStateChange_m(
+      mozilla::dom::PCImplIceConnectionState aState);
+  nsresult IceGatheringStateChange_m(
+      mozilla::dom::PCImplIceGatheringState aState);
 
 #ifdef MOZILLA_INTERNAL_API
   // Fills in an RTCStatsReportInternal. Must be run on STS.
   void GetStats_s(uint32_t trackId,
                   bool internalStats,
                   DOMHighResTimeStamp now);
 
   // Sends an RTCStatsReport to JS. Must run on main thread.
@@ -516,17 +542,18 @@ private:
   Timecard *mTimeCard;
 
   // The call
   mozilla::ScopedDeletePtr<Internal> mInternal;
   mozilla::dom::PCImplReadyState mReadyState;
   mozilla::dom::PCImplSignalingState mSignalingState;
 
   // ICE State
-  mozilla::dom::PCImplIceState mIceState;
+  mozilla::dom::PCImplIceConnectionState mIceConnectionState;
+  mozilla::dom::PCImplIceGatheringState mIceGatheringState;
 
   nsCOMPtr<nsIThread> mThread;
   // TODO: Remove if we ever properly wire PeerConnection for cycle-collection.
   nsWeakPtr mPCObserver;
 
   nsCOMPtr<nsPIDOMWindow> mWindow;
 
   // The SDP sent in from JS - here for debugging.
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -173,22 +173,22 @@ nsresult PeerConnectionMedia::Init(const
   if (NS_FAILED(rv = mDNSResolver->Init())) {
     CSFLogError(logTag, "%s: Failed to initialize dns resolver", __FUNCTION__);
     return rv;
   }
   if (NS_FAILED(rv = mIceCtx->SetResolver(mDNSResolver->AllocateResolver()))) {
     CSFLogError(logTag, "%s: Failed to get dns resolver", __FUNCTION__);
     return rv;
   }
-  mIceCtx->SignalGatheringCompleted.connect(this,
-                                            &PeerConnectionMedia::IceGatheringCompleted);
-  mIceCtx->SignalCompleted.connect(this,
-                                   &PeerConnectionMedia::IceCompleted);
-  mIceCtx->SignalFailed.connect(this,
-                                &PeerConnectionMedia::IceFailed);
+  mIceCtx->SignalGatheringStateChange.connect(
+      this,
+      &PeerConnectionMedia::IceGatheringStateChange);
+  mIceCtx->SignalConnectionStateChange.connect(
+      this,
+      &PeerConnectionMedia::IceConnectionStateChange);
 
   // Create three streams to start with.
   // One each for audio, video and DataChannel
   // TODO: this will be re-visited
   RefPtr<NrIceMediaStream> audioStream =
     mIceCtx->CreateStream((mParent->GetHandle()+"/stream1/audio").c_str(), 2);
   RefPtr<NrIceMediaStream> videoStream =
     mIceCtx->CreateStream((mParent->GetHandle()+"/stream2/video").c_str(), 2);
@@ -419,34 +419,27 @@ PeerConnectionMedia::AddRemoteStreamHint
     pInfo->mTrackTypeHints |= DOMMediaStream::HINT_CONTENTS_AUDIO;
   }
 
   return NS_OK;
 }
 
 
 void
-PeerConnectionMedia::IceGatheringCompleted(NrIceCtx *aCtx)
+PeerConnectionMedia::IceGatheringStateChange(NrIceCtx* ctx,
+                                             NrIceCtx::GatheringState state)
 {
-  MOZ_ASSERT(aCtx);
-  SignalIceGatheringCompleted(aCtx);
+  SignalIceGatheringStateChange(ctx, state);
 }
 
 void
-PeerConnectionMedia::IceCompleted(NrIceCtx *aCtx)
+PeerConnectionMedia::IceConnectionStateChange(NrIceCtx* ctx,
+                                              NrIceCtx::ConnectionState state)
 {
-  MOZ_ASSERT(aCtx);
-  SignalIceCompleted(aCtx);
-}
-
-void
-PeerConnectionMedia::IceFailed(NrIceCtx *aCtx)
-{
-  MOZ_ASSERT(aCtx);
-  SignalIceFailed(aCtx);
+  SignalIceConnectionStateChange(ctx, state);
 }
 
 void
 PeerConnectionMedia::IceStreamReady(NrIceMediaStream *aStream)
 {
   MOZ_ASSERT(aStream);
 
   CSFLogDebug(logTag, "%s: %s", __FUNCTION__, aStream->name().c_str());
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -329,32 +329,34 @@ class PeerConnectionMedia : public sigsl
                   const mozilla::RefPtr<mozilla::MediaSessionConduit> &aConduit) {
     int index_inner = aIndex * 2 + (aReceive ? 0 : 1);
 
     MOZ_ASSERT(!mConduits[index_inner]);
     mConduits[index_inner] = aConduit;
   }
 
   // ICE state signals
-  sigslot::signal1<mozilla::NrIceCtx *> SignalIceGatheringCompleted;  // Done gathering
-  sigslot::signal1<mozilla::NrIceCtx *> SignalIceCompleted;  // Done handshaking
-  sigslot::signal1<mozilla::NrIceCtx *> SignalIceFailed;  // Self explanatory
+  sigslot::signal2<mozilla::NrIceCtx*, mozilla::NrIceCtx::GatheringState>
+      SignalIceGatheringStateChange;
+  sigslot::signal2<mozilla::NrIceCtx*, mozilla::NrIceCtx::ConnectionState>
+      SignalIceConnectionStateChange;
 
  private:
   // Shutdown media transport. Must be called on STS thread.
   void ShutdownMediaTransport_s();
 
   // Final destruction of the media stream. Must be called on the main
   // thread.
   void SelfDestruct_m();
 
   // ICE events
-  void IceGatheringCompleted(mozilla::NrIceCtx *aCtx);
-  void IceCompleted(mozilla::NrIceCtx *aCtx);
-  void IceFailed(mozilla::NrIceCtx *aCtx);
+  void IceGatheringStateChange(mozilla::NrIceCtx* ctx,
+                               mozilla::NrIceCtx::GatheringState state);
+  void IceConnectionStateChange(mozilla::NrIceCtx* ctx,
+                                mozilla::NrIceCtx::ConnectionState state);
   void IceStreamReady(mozilla::NrIceMediaStream *aStream);
 
   // The parent PC
   PeerConnectionImpl *mParent;
 
   // A list of streams returned from GetUserMedia
   mozilla::Mutex mLocalSourceStreamsLock;
   nsTArray<nsRefPtr<LocalSourceStreamInfo> > mLocalSourceStreams;
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -411,38 +411,47 @@ TestObserver::NotifyDataChannel(nsIDOMDa
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TestObserver::OnStateChange(PCObserverStateType state_type, ER&, void*)
 {
   nsresult rv;
   PCImplReadyState gotready;
-  PCImplIceState gotice;
+  PCImplIceConnectionState gotice;
+  PCImplIceGatheringState goticegathering;
   PCImplSipccState gotsipcc;
   PCImplSignalingState gotsignaling;
 
   std::cout << name << ": ";
 
   switch (state_type)
   {
   case PCObserverStateType::ReadyState:
     rv = pc->ReadyState(&gotready);
     NS_ENSURE_SUCCESS(rv, rv);
     std::cout << "Ready State: "
               << PCImplReadyStateValues::strings[int(gotready)].value
               << std::endl;
     break;
-  case PCObserverStateType::IceState:
-    rv = pc->IceState(&gotice);
+  case PCObserverStateType::IceConnectionState:
+    rv = pc->IceConnectionState(&gotice);
     NS_ENSURE_SUCCESS(rv, rv);
-    std::cout << "ICE State: "
-              << PCImplIceStateValues::strings[int(gotice)].value
+    std::cout << "ICE Connection State: "
+              << PCImplIceConnectionStateValues::strings[int(gotice)].value
               << std::endl;
     break;
+  case PCObserverStateType::IceGatheringState:
+    rv = pc->IceGatheringState(&goticegathering);
+    NS_ENSURE_SUCCESS(rv, rv);
+    std::cout
+        << "ICE Gathering State: "
+        << PCImplIceGatheringStateValues::strings[int(goticegathering)].value
+        << std::endl;
+    break;
   case PCObserverStateType::SdpState:
     std::cout << "SDP State: " << std::endl;
     // NS_ENSURE_SUCCESS(rv, rv);
     break;
   case PCObserverStateType::SipccState:
     rv = pc->SipccState(&gotsipcc);
     NS_ENSURE_SUCCESS(rv, rv);
     std::cout << "SIPCC State: "
@@ -453,16 +462,17 @@ TestObserver::OnStateChange(PCObserverSt
     rv = pc->SignalingState(&gotsignaling);
     NS_ENSURE_SUCCESS(rv, rv);
     std::cout << "Signaling State: "
               << PCImplSignalingStateValues::strings[int(gotsignaling)].value
               << std::endl;
     break;
   default:
     // Unknown State
+    MOZ_CRASH("Unknown state change type.");
     break;
   }
 
   lastStateType = state_type;
   return NS_OK;
 }
 
 
@@ -754,42 +764,50 @@ class SignalingAgent {
     mozilla::SyncRunnable::DispatchToThread(thread,
       WrapRunnable(this, &SignalingAgent::Init_m, thread));
 
     ASSERT_TRUE_WAIT(sipcc_state() == PCImplSipccState::Started,
                      kDefaultTimeout);
   }
 
   void WaitForGather() {
-    ASSERT_TRUE_WAIT(ice_state() == PCImplIceState::IceWaiting, 5000);
+    ASSERT_TRUE_WAIT(ice_gathering_state() == PCImplIceGatheringState::Complete,
+                     5000);
 
     std::cout << name << ": Init Complete" << std::endl;
   }
 
   bool WaitForGatherAllowFail() {
-    EXPECT_TRUE_WAIT(ice_state() == PCImplIceState::IceWaiting ||
-                     ice_state() == PCImplIceState::IceFailed, 5000);
-
-    if (ice_state() == PCImplIceState::IceFailed) {
+    EXPECT_TRUE_WAIT(
+        ice_gathering_state() == PCImplIceGatheringState::Complete ||
+        ice_connection_state() == PCImplIceConnectionState::Failed,
+        5000);
+
+    if (ice_connection_state() == PCImplIceConnectionState::Failed) {
       std::cout << name << ": Init Failed" << std::endl;
       return false;
     }
 
     std::cout << name << "Init Complete" << std::endl;
     return true;
   }
 
   PCImplSipccState sipcc_state()
   {
     return pc->SipccState();
   }
 
-  PCImplIceState ice_state()
+  PCImplIceConnectionState ice_connection_state()
   {
-    return pc->IceState();
+    return pc->IceConnectionState();
+  }
+
+  PCImplIceGatheringState ice_gathering_state()
+  {
+    return pc->IceGatheringState();
   }
 
   PCImplSignalingState signaling_state()
   {
     return pc->SignalingState();
   }
 
   void Close()
@@ -1036,17 +1054,17 @@ void CreateAnswer(sipcc::MediaConstraint
       }
     }
     ASSERT_TRUE_WAIT(pObserver->addIceSuccessCount == expectAddIce,
                      kDefaultTimeout);
   }
 
 
   bool IceCompleted() {
-    return pc->IceState() == PCImplIceState::IceConnected;
+    return pc->IceConnectionState() == PCImplIceConnectionState::Connected;
   }
 
   void AddIceCandidate(const char* candidate, const char* mid, unsigned short level,
                        bool expectSuccess) {
     PCImplSignalingState endState = signaling_state();
     pObserver->state = TestObserver::stateNoResponse;
     pc->AddIceCandidate(candidate, mid, level);
     ASSERT_TRUE_WAIT(pObserver->state != TestObserver::stateNoResponse,