Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE
authorCiure Andrei <aciure@mozilla.com>
Fri, 28 Sep 2018 11:58:15 +0300
changeset 486998 6285038e0fabb98fd6cd3e15022a570a07fa2ff4
parent 486989 d563efb11c415afd6fbec8bacad247b5ed9065b6 (current diff)
parent 486997 20d42e205b19be1d4c75640beed91dba04f6650d (diff)
child 486999 87cd2cf69eb5a9b360aa21413e9b9d184d723b37
push id246
push userfmarier@mozilla.com
push dateSat, 13 Oct 2018 00:15:40 +0000
reviewersmerge
milestone64.0a1
Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE
--- a/build/moz.configure/tup.configure
+++ b/build/moz.configure/tup.configure
@@ -8,17 +8,17 @@
 # ==============================================================
 
 tup = check_prog('TUP', ['tup'])
 
 @depends(tup)
 @checking('for tup version')
 @imports('re')
 def tup_version(tup):
-    tup_min_version = '0.7.7'
+    tup_min_version = '0.7.8'
     out = check_cmd_output(tup, '--version',
                            onerror=lambda: die('Failed to get tup version'))
     m = re.search(r'tup v?([0-9]+\.[0-9]+\.[0-9]+)', out)
 
     if not m:
         raise FatalCheckError('Unknown version of tup: %s' % out)
     ver = Version(m.group(1))
 
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1790,16 +1790,22 @@ nsCSSFrameConstructor::CreateGeneratedCo
                                                   ComputedStyle& aStyle,
                                                   CSSPseudoElementType aPseudoElement,
                                                   FrameConstructionItemList& aItems)
 {
   MOZ_ASSERT(aPseudoElement == CSSPseudoElementType::before ||
              aPseudoElement == CSSPseudoElementType::after,
              "unexpected aPseudoElement");
 
+  if (aParentFrame && aParentFrame->IsHTMLVideoFrame()) {
+    // Video frames may not be leafs when backed by an UA widget, but we still don't want to expose generated content.
+    MOZ_ASSERT(aOriginatingElement.GetShadowRoot()->IsUAWidget());
+    return;
+  }
+
   ServoStyleSet* styleSet = mPresShell->StyleSet();
 
   // Probe for the existence of the pseudo-element
   RefPtr<ComputedStyle> pseudoStyle =
     styleSet->ProbePseudoElementStyle(aOriginatingElement, aPseudoElement, &aStyle);
   if (!pseudoStyle) {
     return;
   }
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/1493741.html
@@ -0,0 +1,6 @@
+<style>
+  video::after {
+    content: "";
+  }
+</style>
+<video></video>
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -708,9 +708,10 @@ load 1483972.html
 load 1486457.html
 load 1489287.html
 load 1489863.html
 load 1489770.html
 load 1490032.html
 load 1490685.html
 load 1493708.html
 load 1493710.html
+load 1493741.html
 load 1494380.html
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -77,17 +77,16 @@
 #include "nsIScriptError.h"
 #include "nsPrintfCString.h"
 #include "nsURLHelper.h"
 #include "nsNetUtil.h"
 #include "nsIURLParser.h"
 #include "js/GCAnnotations.h"
 #include "mozilla/PeerIdentity.h"
 #include "mozilla/dom/RTCCertificate.h"
-#include "mozilla/dom/RTCConfigurationBinding.h"
 #include "mozilla/dom/RTCDTMFSenderBinding.h"
 #include "mozilla/dom/RTCDTMFToneChangeEvent.h"
 #include "mozilla/dom/RTCRtpReceiverBinding.h"
 #include "mozilla/dom/RTCRtpSenderBinding.h"
 #include "mozilla/dom/RTCStatsReportBinding.h"
 #include "mozilla/dom/RTCPeerConnectionBinding.h"
 #include "mozilla/dom/PeerConnectionImplBinding.h"
 #include "mozilla/dom/RTCDataChannelBinding.h"
@@ -408,172 +407,20 @@ PeerConnectionImpl::~PeerConnectionImpl(
   // running at once
 
   // Right now, we delete PeerConnectionCtx at XPCOM shutdown only, but we
   // probably want to shut it down more aggressively to save memory.  We
   // could shut down here when there are no uses.  It might be more optimal
   // to release off a timer (and XPCOM Shutdown) to avoid churn
 }
 
-/**
- * In JS, an RTCConfiguration looks like this:
- *
- * { "iceServers": [ { url:"stun:stun.example.org" },
- *                   { url:"turn:turn.example.org?transport=udp",
- *                     username: "jib", credential:"mypass"} ] }
- *
- * This function converts that into an internal PeerConnectionConfiguration
- * object.
- */
-nsresult
-PeerConnectionConfiguration::Init(const RTCConfiguration& aSrc)
-{
-  if (aSrc.mIceServers.WasPassed()) {
-    for (size_t i = 0; i < aSrc.mIceServers.Value().Length(); i++) {
-      nsresult rv = AddIceServer(aSrc.mIceServers.Value()[i]);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-
-  switch (aSrc.mBundlePolicy) {
-    case dom::RTCBundlePolicy::Balanced:
-      setBundlePolicy(kBundleBalanced);
-      break;
-    case dom::RTCBundlePolicy::Max_compat:
-      setBundlePolicy(kBundleMaxCompat);
-      break;
-    case dom::RTCBundlePolicy::Max_bundle:
-      setBundlePolicy(kBundleMaxBundle);
-      break;
-    default:
-      MOZ_CRASH();
-  }
-
-  switch (aSrc.mIceTransportPolicy) {
-    case dom::RTCIceTransportPolicy::Relay:
-      setIceTransportPolicy(NrIceCtx::ICE_POLICY_RELAY);
-      break;
-    case dom::RTCIceTransportPolicy::All:
-      if (Preferences::GetBool("media.peerconnection.ice.no_host", false)) {
-        setIceTransportPolicy(NrIceCtx::ICE_POLICY_NO_HOST);
-      } else {
-        setIceTransportPolicy(NrIceCtx::ICE_POLICY_ALL);
-      }
-      break;
-    default:
-      MOZ_CRASH();
-  }
-  return NS_OK;
-}
-
-nsresult
-PeerConnectionConfiguration::AddIceServer(const RTCIceServer &aServer)
-{
-  NS_ENSURE_STATE(aServer.mUrls.WasPassed());
-  NS_ENSURE_STATE(aServer.mUrls.Value().IsStringSequence());
-  auto &urls = aServer.mUrls.Value().GetAsStringSequence();
-  for (size_t i = 0; i < urls.Length(); i++) {
-    // Without STUN/TURN handlers, NS_NewURI returns nsSimpleURI rather than
-    // nsStandardURL. To parse STUN/TURN URI's to spec
-    // http://tools.ietf.org/html/draft-nandakumar-rtcweb-stun-uri-02#section-3
-    // http://tools.ietf.org/html/draft-petithuguenin-behave-turn-uri-03#section-3
-    // we parse out the query-string, and use ParseAuthority() on the rest
-    RefPtr<nsIURI> url;
-    nsresult rv = NS_NewURI(getter_AddRefs(url), urls[i]);
-    NS_ENSURE_SUCCESS(rv, rv);
-    bool isStun = false, isStuns = false, isTurn = false, isTurns = false;
-    url->SchemeIs("stun", &isStun);
-    url->SchemeIs("stuns", &isStuns);
-    url->SchemeIs("turn", &isTurn);
-    url->SchemeIs("turns", &isTurns);
-    if (!(isStun || isStuns || isTurn || isTurns)) {
-      return NS_ERROR_FAILURE;
-    }
-    if (isStuns) {
-      continue; // TODO: Support STUNS (Bug 1056934)
-    }
-    nsAutoCString spec;
-    rv = url->GetSpec(spec);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // TODO(jib@mozilla.com): Revisit once nsURI supports STUN/TURN (Bug 833509)
-    int32_t port;
-    nsAutoCString host;
-    nsAutoCString transport;
-    {
-      uint32_t hostPos;
-      int32_t hostLen;
-      nsAutoCString path;
-      rv = url->GetPathQueryRef(path);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      // Tolerate query-string + parse 'transport=[udp|tcp]' by hand.
-      int32_t questionmark = path.FindChar('?');
-      if (questionmark >= 0) {
-        const nsCString match = NS_LITERAL_CSTRING("transport=");
-
-        for (int32_t i = questionmark, endPos; i >= 0; i = endPos) {
-          endPos = path.FindCharInSet("&", i + 1);
-          const nsDependentCSubstring fieldvaluepair = Substring(path, i + 1,
-                                                                 endPos);
-          if (StringBeginsWith(fieldvaluepair, match)) {
-            transport = Substring(fieldvaluepair, match.Length());
-            ToLowerCase(transport);
-          }
-        }
-        path.SetLength(questionmark);
-      }
-
-      rv = net_GetAuthURLParser()->ParseAuthority(path.get(), path.Length(),
-                                                  nullptr,  nullptr,
-                                                  nullptr,  nullptr,
-                                                  &hostPos,  &hostLen, &port);
-      NS_ENSURE_SUCCESS(rv, rv);
-      if (!hostLen) {
-        return NS_ERROR_FAILURE;
-      }
-      if (hostPos > 1)  /* The username was removed */
-        return NS_ERROR_FAILURE;
-      path.Mid(host, hostPos, hostLen);
-    }
-    if (port == -1)
-      port = (isStuns || isTurns)? 5349 : 3478;
-
-    if (isStuns || isTurns) {
-      // Should we barf if transport is set to udp or something?
-      transport = kNrIceTransportTls;
-    }
-
-    if (transport.IsEmpty()) {
-      transport = kNrIceTransportUdp;
-    }
-
-    if (isTurn || isTurns) {
-      NS_ConvertUTF16toUTF8 credential(aServer.mCredential.Value());
-      NS_ConvertUTF16toUTF8 username(aServer.mUsername.Value());
-
-      if (!addTurnServer(host.get(), port,
-                         username.get(),
-                         credential.get(),
-                         transport.get())) {
-        return NS_ERROR_FAILURE;
-      }
-    } else {
-      if (!addStunServer(host.get(), port, transport.get())) {
-        return NS_ERROR_FAILURE;
-      }
-    }
-  }
-  return NS_OK;
-}
-
 nsresult
 PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
                                nsGlobalWindowInner* aWindow,
-                               const PeerConnectionConfiguration& aConfiguration,
+                               const RTCConfiguration& aConfiguration,
                                nsISupports* aThread)
 {
   nsresult res;
 
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aThread);
   if (!mThread) {
     mThread = do_QueryInterface(aThread);
@@ -666,19 +513,17 @@ PeerConnectionImpl::Initialize(PeerConne
       &PeerConnectionImpl::EndOfLocalCandidates);
   mMedia->SignalIceConnectionStateChange.connect(
       this,
       &PeerConnectionImpl::IceConnectionStateChange);
 
   mMedia->SignalCandidate.connect(this, &PeerConnectionImpl::CandidateReady);
 
   // Initialize the media object.
-  res = mMedia->Init(aConfiguration.getStunServers(),
-                     aConfiguration.getTurnServers(),
-                     aConfiguration.getIceTransportPolicy());
+  res = mMedia->Init(aConfiguration);
   if (NS_FAILED(res)) {
     CSFLogError(LOGTAG, "%s: Couldn't initialize media object", __FUNCTION__);
     return res;
   }
 
   PeerConnectionCtx::GetInstance()->mPeerConnections[mHandle] = this;
 
   mJsepSession = MakeUnique<JsepSessionImpl>(mName,
@@ -687,17 +532,32 @@ PeerConnectionImpl::Initialize(PeerConne
   res = mJsepSession->Init();
   if (NS_FAILED(res)) {
     CSFLogError(LOGTAG, "%s: Couldn't init JSEP Session, res=%u",
                         __FUNCTION__,
                         static_cast<unsigned>(res));
     return res;
   }
 
-  res = mJsepSession->SetBundlePolicy(aConfiguration.getBundlePolicy());
+  JsepBundlePolicy bundlePolicy;
+  switch (aConfiguration.mBundlePolicy) {
+    case dom::RTCBundlePolicy::Balanced:
+      bundlePolicy = kBundleBalanced;
+      break;
+    case dom::RTCBundlePolicy::Max_compat:
+      bundlePolicy = kBundleMaxCompat;
+      break;
+    case dom::RTCBundlePolicy::Max_bundle:
+      bundlePolicy = kBundleMaxBundle;
+      break;
+    default:
+      MOZ_CRASH();
+  }
+
+  res = mJsepSession->SetBundlePolicy(bundlePolicy);
   if (NS_FAILED(res)) {
     CSFLogError(LOGTAG, "%s: Couldn't set bundle policy, res=%u, error=%s",
                         __FUNCTION__,
                         static_cast<unsigned>(res),
                         mJsepSession->GetLastError().c_str());
     return res;
   }
 
@@ -710,25 +570,17 @@ PeerConnectionImpl::Initialize(PeerConne
                                const RTCConfiguration& aConfiguration,
                                nsISupports* aThread,
                                ErrorResult &rv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aThread);
   mThread = do_QueryInterface(aThread);
 
-  PeerConnectionConfiguration converted;
-  nsresult res = converted.Init(aConfiguration);
-  if (NS_FAILED(res)) {
-    CSFLogError(LOGTAG, "%s: Invalid RTCConfiguration", __FUNCTION__);
-    rv.Throw(res);
-    return;
-  }
-
-  res = Initialize(aObserver, &aWindow, converted, aThread);
+  nsresult res = Initialize(aObserver, &aWindow, aConfiguration, aThread);
   if (NS_FAILED(res)) {
     rv.Throw(res);
     return;
   }
 
   if (!aConfiguration.mPeerIdentity.IsEmpty()) {
     mPeerIdentity = new PeerIdentity(aConfiguration.mPeerIdentity);
     mPrivacyRequested = true;
@@ -2799,50 +2651,16 @@ PeerConnectionImpl::GetHandle()
 
 const std::string&
 PeerConnectionImpl::GetName()
 {
   PC_AUTO_ENTER_API_CALL_NO_CHECK();
   return mName;
 }
 
-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_CONNECTED:
-      return PCImplIceConnectionState::Connected;
-    case NrIceCtx::ICE_CTX_COMPLETED:
-      return PCImplIceConnectionState::Completed;
-    case NrIceCtx::ICE_CTX_FAILED:
-      return PCImplIceConnectionState::Failed;
-    case NrIceCtx::ICE_CTX_DISCONNECTED:
-      return PCImplIceConnectionState::Disconnected;
-    case NrIceCtx::ICE_CTX_CLOSED:
-      return PCImplIceConnectionState::Closed;
-  }
-  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();
-}
-
 void
 PeerConnectionImpl::CandidateReady(const std::string& candidate,
                                    const std::string& transportId) {
   PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
 
   if (mForceIceTcp && std::string::npos != candidate.find(" UDP ")) {
     CSFLogWarn(LOGTAG, "Blocking local UDP candidate: %s", candidate.c_str());
     return;
@@ -2930,23 +2748,21 @@ static bool isSucceeded(PCImplIceConnect
          state == PCImplIceConnectionState::Completed;
 }
 
 static bool isFailed(PCImplIceConnectionState state) {
   return state == PCImplIceConnectionState::Failed;
 }
 
 void PeerConnectionImpl::IceConnectionStateChange(
-    NrIceCtx* ctx,
-    NrIceCtx::ConnectionState state) {
+    dom::PCImplIceConnectionState domState) {
   PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
 
   CSFLogDebug(LOGTAG, "%s", __FUNCTION__);
 
-  auto domState = toDomIceConnectionState(state);
   if (domState == mIceConnectionState) {
     // no work to be done since the states are the same.
     // this can happen during ICE rollback situations.
     return;
   }
 
   if (!isDone(mIceConnectionState) && isDone(domState)) {
     if (isSucceeded(domState)) {
@@ -3003,25 +2819,23 @@ void PeerConnectionImpl::IceConnectionSt
     return;
   }
 
   WrappableJSErrorResult rv;
   pco->OnStateChange(PCObserverStateType::IceConnectionState, rv);
 }
 
 void
-PeerConnectionImpl::IceGatheringStateChange(
-    NrIceCtx* ctx,
-    NrIceCtx::GatheringState state)
+PeerConnectionImpl::IceGatheringStateChange(dom::PCImplIceGatheringState state)
 {
   PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
 
   CSFLogDebug(LOGTAG, "%s", __FUNCTION__);
 
-  mIceGatheringState = toDomIceGatheringState(state);
+  mIceGatheringState = state;
 
   // 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:
@@ -3089,18 +2903,18 @@ PeerConnectionImpl::BuildStatsQuery_m(
     CSFLogError(LOGTAG, "Could not build stats query, could not get timestamp");
     return rv;
   }
 
   // Note: mMedia->ice_ctx() is deleted on STS thread; so make sure we grab and hold
   // a ref instead of making multiple calls.  NrIceCtx uses threadsafe refcounting.
   // NOTE: Do this after all other failure tests, to ensure we don't
   // accidentally release the Ctx on Mainthread.
-  query->iceCtx = mMedia->ice_ctx();
-  if (!query->iceCtx) {
+  query->media = mMedia;
+  if (!query->media) {
     CSFLogError(LOGTAG, "Could not build stats query, no ice_ctx");
     return NS_ERROR_UNEXPECTED;
   }
 
   // We do not use the pcHandle here, since that's risky to expose to content.
   query->report = new RTCStatsReportInternalConstruct(
       NS_ConvertASCIItoUTF16(mName.c_str()),
       query->now);
@@ -3146,127 +2960,20 @@ PeerConnectionImpl::BuildStatsQuery_m(
 
   if (!aSelector) {
     query->grabAllLevels = true;
   }
 
   return rv;
 }
 
-static void ToRTCIceCandidateStats(
-    const std::vector<NrIceCandidate>& candidates,
-    RTCStatsType candidateType,
-    const nsString& componentId,
-    DOMHighResTimeStamp now,
-    RTCStatsReportInternal* report) {
-
-  MOZ_ASSERT(report);
-  for (const auto& candidate : candidates) {
-    RTCIceCandidateStats cand;
-    cand.mType.Construct(candidateType);
-    NS_ConvertASCIItoUTF16 codeword(candidate.codeword.c_str());
-    cand.mComponentId.Construct(componentId);
-    cand.mId.Construct(codeword);
-    cand.mTimestamp.Construct(now);
-    cand.mCandidateType.Construct(
-        RTCStatsIceCandidateType(candidate.type));
-    cand.mIpAddress.Construct(
-        NS_ConvertASCIItoUTF16(candidate.cand_addr.host.c_str()));
-    cand.mPortNumber.Construct(candidate.cand_addr.port);
-    cand.mTransport.Construct(
-        NS_ConvertASCIItoUTF16(candidate.cand_addr.transport.c_str()));
-    if (candidateType == RTCStatsType::Local_candidate) {
-      cand.mMozLocalTransport.Construct(
-          NS_ConvertASCIItoUTF16(candidate.local_addr.transport.c_str()));
-    }
-    report->mIceCandidateStats.Value().AppendElement(cand, fallible);
-    if (candidate.trickled) {
-      report->mTrickledIceCandidateStats.Value().AppendElement(cand, fallible);
-    }
-  }
-}
-
-static void RecordIceStats_s(
-    const NrIceMediaStream& mediaStream,
-    bool internalStats,
-    DOMHighResTimeStamp now,
-    RTCStatsReportInternal* report) {
-
-  NS_ConvertASCIItoUTF16 transportId(mediaStream.GetId().c_str());
-
-  std::vector<NrIceCandidatePair> candPairs;
-  nsresult res = mediaStream.GetCandidatePairs(&candPairs);
-  if (NS_FAILED(res)) {
-    CSFLogError(LOGTAG,
-        "%s: Error getting candidate pairs for transport id \"%s\"",
-        __FUNCTION__, mediaStream.GetId().c_str());
-    return;
-  }
-
-  for (auto& candPair : candPairs) {
-    NS_ConvertASCIItoUTF16 codeword(candPair.codeword.c_str());
-    NS_ConvertASCIItoUTF16 localCodeword(candPair.local.codeword.c_str());
-    NS_ConvertASCIItoUTF16 remoteCodeword(candPair.remote.codeword.c_str());
-    // Only expose candidate-pair statistics to chrome, until we've thought
-    // through the implications of exposing it to content.
-
-    RTCIceCandidatePairStats s;
-    s.mId.Construct(codeword);
-    s.mTransportId.Construct(transportId);
-    s.mTimestamp.Construct(now);
-    s.mType.Construct(RTCStatsType::Candidate_pair);
-    s.mLocalCandidateId.Construct(localCodeword);
-    s.mRemoteCandidateId.Construct(remoteCodeword);
-    s.mNominated.Construct(candPair.nominated);
-    s.mWritable.Construct(candPair.writable);
-    s.mReadable.Construct(candPair.readable);
-    s.mPriority.Construct(candPair.priority);
-    s.mSelected.Construct(candPair.selected);
-    s.mBytesSent.Construct(candPair.bytes_sent);
-    s.mBytesReceived.Construct(candPair.bytes_recvd);
-    s.mLastPacketSentTimestamp.Construct(candPair.ms_since_last_send);
-    s.mLastPacketReceivedTimestamp.Construct(candPair.ms_since_last_recv);
-    s.mState.Construct(RTCStatsIceCandidatePairState(candPair.state));
-    s.mComponentId.Construct(candPair.component_id);
-    report->mIceCandidatePairStats.Value().AppendElement(s, fallible);
-  }
-
-  std::vector<NrIceCandidate> candidates;
-  if (NS_SUCCEEDED(mediaStream.GetLocalCandidates(&candidates))) {
-    ToRTCIceCandidateStats(candidates,
-                           RTCStatsType::Local_candidate,
-                           transportId,
-                           now,
-                           report);
-    // add the local candidates unparsed string to a sequence
-    for (const auto& candidate : candidates) {
-      report->mRawLocalCandidates.Value().AppendElement(
-          NS_ConvertASCIItoUTF16(candidate.label.c_str()), fallible);
-    }
-  }
-  candidates.clear();
-
-  if (NS_SUCCEEDED(mediaStream.GetRemoteCandidates(&candidates))) {
-    ToRTCIceCandidateStats(candidates,
-                           RTCStatsType::Remote_candidate,
-                           transportId,
-                           now,
-                           report);
-    // add the remote candidates unparsed string to a sequence
-    for (const auto& candidate : candidates) {
-      report->mRawRemoteCandidates.Value().AppendElement(
-          NS_ConvertASCIItoUTF16(candidate.label.c_str()), fallible);
-    }
-  }
-}
-
 nsresult
 PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
 
-  ASSERT_ON_THREAD(query->iceCtx->thread());
+  ASSERT_ON_THREAD(query->media->GetSTSThread());
 
   // Gather stats from pipelines provided (can't touch mMedia + stream on STS)
 
   for (size_t p = 0; p < query->pipelines.Length(); ++p) {
     MOZ_ASSERT(query->pipelines[p]);
     MOZ_ASSERT(query->pipelines[p]->Conduit());
     if (!query->pipelines[p] || !query->pipelines[p]->Conduit()) {
       // continue if we don't have a valid conduit
@@ -3480,42 +3187,36 @@ PeerConnectionImpl::ExecuteStatsQuery_s(
         mp.GetContributingSourceStats(localId,
             query->report->mRtpContributingSourceStats.Value());
         break;
       }
     }
   }
 
   if (query->grabAllLevels) {
-    for (const auto& stream : query->iceCtx->GetStreams()) {
-      RecordIceStats_s(*stream,
-                       query->internalStats,
-                       query->now,
-                       query->report);
-    }
-  } else if (query->iceCtx->GetStream(query->transportId)) {
-    RecordIceStats_s(*query->iceCtx->GetStream(query->transportId),
-                     query->internalStats,
-                     query->now,
-                     query->report);
+    query->media->GetAllIceStats_s(query->internalStats,
+                                   query->now,
+                                   query->report);
+  } else {
+    query->media->GetIceStats_s(query->transportId,
+                                query->internalStats,
+                                query->now,
+                                query->report);
   }
 
-  // NrIceCtx must be destroyed on STS, so it is not safe
-  // to dispatch it back to main.
-  query->iceCtx = nullptr;
   return NS_OK;
 }
 
 void PeerConnectionImpl::GetStatsForPCObserver_s(
     const std::string& pcHandle, // The Runnable holds the memory
     nsAutoPtr<RTCStatsQuery> query) {
 
   MOZ_ASSERT(query);
-  MOZ_ASSERT(query->iceCtx);
-  ASSERT_ON_THREAD(query->iceCtx->thread());
+  MOZ_ASSERT(query->media);
+  ASSERT_ON_THREAD(query->media->GetSTSThread());
 
   nsresult rv = PeerConnectionImpl::ExecuteStatsQuery_s(query.get());
 
   NS_DispatchToMainThread(
       WrapRunnableNM(
           &PeerConnectionImpl::DeliverStatsReportToPCObserver_m,
           pcHandle,
           rv,
@@ -3566,25 +3267,16 @@ PeerConnectionImpl::RecordIceRestartStat
       ++mIceRestartCount;
       break;
     case mozilla::kJsepSdpRollback:
       ++mIceRollbackCount;
       break;
   }
 }
 
-void
-PeerConnectionImpl::IceStreamReady(NrIceMediaStream *aStream)
-{
-  PC_AUTO_ENTER_API_CALL_NO_CHECK();
-  MOZ_ASSERT(aStream);
-
-  CSFLogDebug(LOGTAG, "%s: %s", __FUNCTION__, aStream->name().c_str());
-}
-
 //Telemetry for when calls start
 void
 PeerConnectionImpl::startCallTelem() {
   if (!mStartTime.IsNull()) {
     return;
   }
 
   // Start time for calls
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -13,18 +13,16 @@
 
 #include "prlock.h"
 #include "mozilla/RefPtr.h"
 #include "nsWeakPtr.h"
 #include "nsAutoPtr.h"
 #include "nsIWeakReferenceUtils.h" // for the definition of nsWeakPtr
 #include "IPeerConnection.h"
 #include "sigslot.h"
-#include "nricectx.h"
-#include "nricemediastream.h"
 #include "nsComponentManagerUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsIUUIDGenerator.h"
 #include "nsIThread.h"
 #include "mozilla/Mutex.h"
 
 // Work around nasty macro in webrtc/voice_engine/voice_engine_defines.h
 #ifdef GetLastError
@@ -34,16 +32,17 @@
 #include "signaling/src/jsep/JsepSession.h"
 #include "signaling/src/jsep/JsepSessionImpl.h"
 #include "signaling/src/sdp/SdpMediaSection.h"
 
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/PeerConnectionImplEnumsBinding.h"
 #include "mozilla/dom/RTCPeerConnectionBinding.h" // mozPacketDumpType, maybe move?
 #include "mozilla/dom/RTCRtpTransceiverBinding.h"
+#include "mozilla/dom/RTCConfigurationBinding.h"
 #include "PrincipalChangeObserver.h"
 #include "StreamTracks.h"
 
 #include "mozilla/TimeStamp.h"
 #include "mozilla/net/DataChannel.h"
 #include "VideoUtils.h"
 #include "VideoSegment.h"
 #include "mozilla/dom/RTCStatsReportBinding.h"
@@ -56,20 +55,16 @@ class AFakePCObserver;
 #endif
 }
 
 class nsDOMDataChannel;
 
 namespace mozilla {
 class DataChannel;
 class DtlsIdentity;
-class NrIceCtx;
-class NrIceMediaStream;
-class NrIceStunServer;
-class NrIceTurnServer;
 class MediaPipeline;
 class TransceiverImpl;
 
 namespace dom {
 class RTCCertificate;
 struct RTCConfiguration;
 struct RTCRtpSourceEntry;
 class RTCDTMFSender;
@@ -109,90 +104,33 @@ already_AddRefed<resulttype> func (__VA_
 struct MediaStreamTable;
 
 namespace mozilla {
 
 using mozilla::dom::PeerConnectionObserver;
 using mozilla::dom::RTCConfiguration;
 using mozilla::dom::RTCIceServer;
 using mozilla::dom::RTCOfferOptions;
-using mozilla::NrIceCtx;
-using mozilla::NrIceMediaStream;
 using mozilla::DtlsIdentity;
 using mozilla::ErrorResult;
-using mozilla::NrIceStunServer;
-using mozilla::NrIceTurnServer;
 using mozilla::PeerIdentity;
 
 class PeerConnectionWrapper;
 class PeerConnectionMedia;
 class RemoteSourceStreamInfo;
 
 // Uuid Generator
 class PCUuidGenerator : public mozilla::JsepUuidGenerator {
  public:
   virtual bool Generate(std::string* idp) override;
 
  private:
   nsCOMPtr<nsIUUIDGenerator> mGenerator;
 };
 
-class PeerConnectionConfiguration
-{
-public:
-  PeerConnectionConfiguration()
-  : mBundlePolicy(kBundleBalanced),
-    mIceTransportPolicy(NrIceCtx::ICE_POLICY_ALL) {}
-
-  bool addStunServer(const std::string& addr, uint16_t port,
-                     const char* transport)
-  {
-    UniquePtr<NrIceStunServer> server(NrIceStunServer::Create(addr, port, transport));
-    if (!server) {
-      return false;
-    }
-    addStunServer(*server);
-    return true;
-  }
-  bool addTurnServer(const std::string& addr, uint16_t port,
-                     const std::string& username,
-                     const std::string& pwd,
-                     const char* transport)
-  {
-    // TODO(ekr@rtfm.com): Need support for SASLprep for
-    // username and password. Bug # ???
-    std::vector<unsigned char> password(pwd.begin(), pwd.end());
-
-    UniquePtr<NrIceTurnServer> server(NrIceTurnServer::Create(addr, port, username, password,
-							      transport));
-    if (!server) {
-      return false;
-    }
-    addTurnServer(*server);
-    return true;
-  }
-  void addStunServer(const NrIceStunServer& server) { mStunServers.push_back (server); }
-  void addTurnServer(const NrIceTurnServer& server) { mTurnServers.push_back (server); }
-  const std::vector<NrIceStunServer>& getStunServers() const { return mStunServers; }
-  const std::vector<NrIceTurnServer>& getTurnServers() const { return mTurnServers; }
-  void setBundlePolicy(JsepBundlePolicy policy) { mBundlePolicy = policy;}
-  JsepBundlePolicy getBundlePolicy() const { return mBundlePolicy; }
-  void setIceTransportPolicy(NrIceCtx::Policy policy) { mIceTransportPolicy = policy;}
-  NrIceCtx::Policy getIceTransportPolicy() const { return mIceTransportPolicy; }
-
-  nsresult Init(const RTCConfiguration& aSrc);
-  nsresult AddIceServer(const RTCIceServer& aServer);
-
-private:
-  std::vector<NrIceStunServer> mStunServers;
-  std::vector<NrIceTurnServer> mTurnServers;
-  JsepBundlePolicy mBundlePolicy;
-  NrIceCtx::Policy mIceTransportPolicy;
-};
-
 // Not an inner class so we can forward declare.
 class RTCStatsQuery {
   public:
     explicit RTCStatsQuery(bool internalStats);
     ~RTCStatsQuery();
 
     nsAutoPtr<mozilla::dom::RTCStatsReportInternal> report;
     std::string error;
@@ -202,17 +140,17 @@ class RTCStatsQuery {
     bool failed;
 
   private:
     friend class PeerConnectionImpl;
     std::string pcName;
     bool internalStats;
     nsTArray<RefPtr<mozilla::MediaPipeline>> pipelines;
     std::string transportId;
-    RefPtr<NrIceCtx> iceCtx;
+    RefPtr<PeerConnectionMedia> media;
     bool grabAllLevels;
     DOMHighResTimeStamp now;
 };
 
 // Enter an API call and check that the state is OK,
 // the PC isn't closed, etc.
 #define PC_AUTO_ENTER_API_CALL(assert_ice_ready) \
     do { \
@@ -283,27 +221,24 @@ public:
 
   // Handle system to allow weak references to be passed through C code
   virtual const std::string& GetHandle();
 
   // Name suitable for exposing to content
   virtual const std::string& GetName();
 
   // ICE events
-  void IceConnectionStateChange(NrIceCtx* ctx,
-                                NrIceCtx::ConnectionState state);
-  void IceGatheringStateChange(NrIceCtx* ctx,
-                               NrIceCtx::GatheringState state);
+  void IceConnectionStateChange(dom::PCImplIceConnectionState state);
+  void IceGatheringStateChange(dom::PCImplIceGatheringState state);
   void UpdateDefaultCandidate(const std::string& defaultAddr,
                               uint16_t defaultPort,
                               const std::string& defaultRtcpAddr,
                               uint16_t defaultRtcpPort,
                               const std::string& transportId);
   void EndOfLocalCandidates(const std::string& transportId);
-  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();
     return mThread;
@@ -315,22 +250,19 @@ public:
     return mSTSThread;
   }
 
   nsPIDOMWindowInner* GetWindow() const {
     PC_AUTO_ENTER_API_CALL_NO_CHECK();
     return mWindow;
   }
 
-  // Initialize PeerConnection from a PeerConnectionConfiguration object
-  // (used directly by unit-tests, and indirectly by the JS entry point)
-  // This is necessary because RTCConfiguration can't be used by unit-tests
   nsresult Initialize(PeerConnectionObserver& aObserver,
                       nsGlobalWindowInner* aWindow,
-                      const PeerConnectionConfiguration& aConfiguration,
+                      const RTCConfiguration& aConfiguration,
                       nsISupports* aThread);
 
   // Initialize PeerConnection from an RTCConfiguration object (JS entrypoint)
   void Initialize(PeerConnectionObserver& aObserver,
                   nsGlobalWindowInner& aWindow,
                   const RTCConfiguration& aConfiguration,
                   nsISupports* aThread,
                   ErrorResult &rv);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -126,18 +126,17 @@ PeerConnectionMedia::StunAddrsHandler::O
   if (pcm_) {
     pcm_->mStunAddrs = addrs;
     pcm_->mLocalAddrsCompleted = true;
     pcm_->mStunAddrsRequest = nullptr;
     pcm_->FlushIceCtxOperationQueueIfReady();
     // If parent process returns 0 STUN addresses, change ICE connection
     // state to failed.
     if (!pcm_->mStunAddrs.Length()) {
-      pcm_->SignalIceConnectionStateChange(pcm_->mIceCtx.get(),
-                                           NrIceCtx::ICE_CTX_FAILED);
+      pcm_->SignalIceConnectionStateChange(dom::PCImplIceConnectionState::Failed);
     }
 
     pcm_ = nullptr;
   }
 }
 
 PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
     : mParent(parent),
@@ -235,65 +234,203 @@ PeerConnectionMedia::InitProxy()
   if (NS_FAILED(rv)) {
     CSFLogError(LOGTAG, "%s: Failed to resolve protocol proxy: %d", __FUNCTION__, (int)rv);
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
-nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_servers,
-                                   const std::vector<NrIceTurnServer>& turn_servers,
-                                   NrIceCtx::Policy policy)
+static nsresult addNrIceServer(const nsString& aIceUrl,
+                               const dom::RTCIceServer& aIceServer,
+                               std::vector<NrIceStunServer>* aStunServersOut,
+                               std::vector<NrIceTurnServer>* aTurnServersOut)
+{
+  // Without STUN/TURN handlers, NS_NewURI returns nsSimpleURI rather than
+  // nsStandardURL. To parse STUN/TURN URI's to spec
+  // http://tools.ietf.org/html/draft-nandakumar-rtcweb-stun-uri-02#section-3
+  // http://tools.ietf.org/html/draft-petithuguenin-behave-turn-uri-03#section-3
+  // we parse out the query-string, and use ParseAuthority() on the rest
+  RefPtr<nsIURI> url;
+  nsresult rv = NS_NewURI(getter_AddRefs(url), aIceUrl);
+  NS_ENSURE_SUCCESS(rv, rv);
+  bool isStun = false, isStuns = false, isTurn = false, isTurns = false;
+  url->SchemeIs("stun", &isStun);
+  url->SchemeIs("stuns", &isStuns);
+  url->SchemeIs("turn", &isTurn);
+  url->SchemeIs("turns", &isTurns);
+  if (!(isStun || isStuns || isTurn || isTurns)) {
+    return NS_ERROR_FAILURE;
+  }
+  if (isStuns) {
+    return NS_OK; // TODO: Support STUNS (Bug 1056934)
+  }
+
+  nsAutoCString spec;
+  rv = url->GetSpec(spec);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // TODO(jib@mozilla.com): Revisit once nsURI supports STUN/TURN (Bug 833509)
+  int32_t port;
+  nsAutoCString host;
+  nsAutoCString transport;
+  {
+    uint32_t hostPos;
+    int32_t hostLen;
+    nsAutoCString path;
+    rv = url->GetPathQueryRef(path);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Tolerate query-string + parse 'transport=[udp|tcp]' by hand.
+    int32_t questionmark = path.FindChar('?');
+    if (questionmark >= 0) {
+      const nsCString match = NS_LITERAL_CSTRING("transport=");
+
+      for (int32_t i = questionmark, endPos; i >= 0; i = endPos) {
+        endPos = path.FindCharInSet("&", i + 1);
+        const nsDependentCSubstring fieldvaluepair = Substring(path, i + 1,
+            endPos);
+        if (StringBeginsWith(fieldvaluepair, match)) {
+          transport = Substring(fieldvaluepair, match.Length());
+          ToLowerCase(transport);
+        }
+      }
+      path.SetLength(questionmark);
+    }
+
+    rv = net_GetAuthURLParser()->ParseAuthority(path.get(), path.Length(),
+        nullptr,  nullptr,
+        nullptr,  nullptr,
+        &hostPos,  &hostLen, &port);
+    NS_ENSURE_SUCCESS(rv, rv);
+    if (!hostLen) {
+      return NS_ERROR_FAILURE;
+    }
+    if (hostPos > 1) {
+       /* The username was removed */
+      return NS_ERROR_FAILURE;
+    }
+    path.Mid(host, hostPos, hostLen);
+  }
+  if (port == -1) {
+    port = (isStuns || isTurns)? 5349 : 3478;
+  }
+
+  if (isStuns || isTurns) {
+    // Should we barf if transport is set to udp or something?
+    transport = kNrIceTransportTls;
+  }
+
+  if (transport.IsEmpty()) {
+    transport = kNrIceTransportUdp;
+  }
+
+  if (isTurn || isTurns) {
+    std::string pwd(NS_ConvertUTF16toUTF8(aIceServer.mCredential.Value()).get());
+    std::string username(NS_ConvertUTF16toUTF8(aIceServer.mUsername.Value()).get());
+
+    std::vector<unsigned char> password(pwd.begin(), pwd.end());
+
+    UniquePtr<NrIceTurnServer> server(NrIceTurnServer::Create(host.get(), port, username, password, transport.get()));
+    if (!server) {
+      return NS_ERROR_FAILURE;
+    }
+    aTurnServersOut->emplace_back(std::move(*server));
+  } else {
+    UniquePtr<NrIceStunServer> server(NrIceStunServer::Create(host.get(), port, transport.get()));
+    if (!server) {
+      return NS_ERROR_FAILURE;
+    }
+    aStunServersOut->emplace_back(std::move(*server));
+  }
+  return NS_OK;
+}
+
+static NrIceCtx::Policy toNrIcePolicy(dom::RTCIceTransportPolicy aPolicy)
+{
+  switch (aPolicy) {
+    case dom::RTCIceTransportPolicy::Relay:
+      return NrIceCtx::ICE_POLICY_RELAY;
+    case dom::RTCIceTransportPolicy::All:
+      if (Preferences::GetBool("media.peerconnection.ice.no_host", false)) {
+        return NrIceCtx::ICE_POLICY_NO_HOST;
+      } else {
+        return NrIceCtx::ICE_POLICY_ALL;
+      }
+    default:
+      MOZ_CRASH();
+  }
+  return NrIceCtx::ICE_POLICY_ALL;
+}
+
+nsresult PeerConnectionMedia::Init(const dom::RTCConfiguration& aConfiguration)
 {
   nsresult rv = InitProxy();
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool ice_tcp = Preferences::GetBool("media.peerconnection.ice.tcp", false);
 
   // setup the stun local addresses IPC async call
   InitLocalAddrs();
 
   NrIceCtx::InitializeGlobals(mParent->GetAllowIceLoopback(),
-                              ice_tcp,
-                              mParent->GetAllowIceLinkLocal());
+      ice_tcp,
+      mParent->GetAllowIceLinkLocal());
 
   // TODO(ekr@rtfm.com): need some way to set not offerer later
   // Looks like a bug in the NrIceCtx API.
-  mIceCtx = NrIceCtx::Create("PC:" + mParentName, policy);
+  mIceCtx = NrIceCtx::Create("PC:" + mParentName,
+      toNrIcePolicy(aConfiguration.mIceTransportPolicy));
   if(!mIceCtx) {
     CSFLogError(LOGTAG, "%s: Failed to create Ice Context", __FUNCTION__);
     return NS_ERROR_FAILURE;
   }
 
-  if (NS_FAILED(rv = mIceCtx->SetStunServers(stun_servers))) {
+  std::vector<NrIceStunServer> stunServers;
+  std::vector<NrIceTurnServer> turnServers;
+
+  if (aConfiguration.mIceServers.WasPassed()) {
+    for (const auto& iceServer : aConfiguration.mIceServers.Value()) {
+      NS_ENSURE_STATE(iceServer.mUrls.WasPassed());
+      NS_ENSURE_STATE(iceServer.mUrls.Value().IsStringSequence());
+      for (const auto& iceUrl : iceServer.mUrls.Value().GetAsStringSequence()) {
+        rv = addNrIceServer(iceUrl, iceServer, &stunServers, &turnServers);
+        if (NS_FAILED(rv)) {
+          CSFLogError(LOGTAG, "%s: invalid STUN/TURN server: %s",
+                      __FUNCTION__, NS_ConvertUTF16toUTF8(iceUrl).get());
+          return rv;
+        }
+      }
+    }
+  }
+
+  if (NS_FAILED(rv = mIceCtx->SetStunServers(stunServers))) {
     CSFLogError(LOGTAG, "%s: Failed to set stun servers", __FUNCTION__);
     return rv;
   }
   // Give us a way to globally turn off TURN support
   bool disabled = Preferences::GetBool("media.peerconnection.turn.disable", false);
   if (!disabled) {
-    if (NS_FAILED(rv = mIceCtx->SetTurnServers(turn_servers))) {
+    if (NS_FAILED(rv = mIceCtx->SetTurnServers(turnServers))) {
       CSFLogError(LOGTAG, "%s: Failed to set turn servers", __FUNCTION__);
       return rv;
     }
-  } else if (!turn_servers.empty()) {
+  } else if (!turnServers.empty()) {
     CSFLogError(LOGTAG, "%s: Setting turn servers disabled", __FUNCTION__);
   }
   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()))) {
+        mIceCtx->SetResolver(mDNSResolver->AllocateResolver()))) {
     CSFLogError(LOGTAG, "%s: Failed to get dns resolver", __FUNCTION__);
     return rv;
   }
   ConnectSignals(mIceCtx.get());
-
   return NS_OK;
 }
 
 void
 PeerConnectionMedia::EnsureTransports(const JsepSession& aSession)
 {
   for (const auto& transceiver : aSession.GetTransceivers()) {
     if (transceiver->HasOwnTransport()) {
@@ -512,30 +649,29 @@ PeerConnectionMedia::UpdateTransportFlow
 
   return UpdateTransportFlow(true, aTransceiver.mTransport);
 }
 
 // Accessing the PCMedia should be safe here because we shouldn't
 // have enqueued this function unless it was still active and
 // the ICE data is destroyed on the STS.
 static void
-FinalizeTransportFlow_s(RefPtr<PeerConnectionMedia> aPCMedia,
+FinalizeTransportFlow_s(const RefPtr<NrIceCtx>& aIceCtx,
                         nsAutoPtr<PacketDumper> aPacketDumper,
                         const RefPtr<TransportFlow>& aFlow,
                         const std::string& aId,
                         bool aIsRtcp,
                         TransportLayerIce* aIceLayer,
                         TransportLayerDtls* aDtlsLayer,
                         TransportLayerSrtp* aSrtpLayer)
 {
   TransportLayerPacketDumper* srtpDumper(new TransportLayerPacketDumper(
         std::move(aPacketDumper), dom::mozPacketDumpType::Srtp));
 
-  aIceLayer->SetParameters(aPCMedia->ice_media_stream(aId),
-                           aIsRtcp ? 2 : 1);
+  aIceLayer->SetParameters(aIceCtx->GetStream(aId), aIsRtcp ? 2 : 1);
   // TODO(bug 854518): Process errors.
   (void)aIceLayer->Init();
   (void)aDtlsLayer->Init();
   (void)srtpDumper->Init();
   (void)aSrtpLayer->Init();
   aDtlsLayer->Chain(aIceLayer);
   srtpDumper->Chain(aIceLayer);
   aSrtpLayer->Chain(srtpDumper);
@@ -627,19 +763,18 @@ PeerConnectionMedia::UpdateTransportFlow
   rv = dtls->SetAlpn(alpn, alpnDefault);
   if (NS_FAILED(rv)) {
     CSFLogError(LOGTAG, "Couldn't set ALPN");
     return rv;
   }
 
   nsAutoPtr<PacketDumper> packetDumper(new PacketDumper(mParent));
 
-  RefPtr<PeerConnectionMedia> pcMedia(this);
   rv = GetSTSThread()->Dispatch(
-      WrapRunnableNM(FinalizeTransportFlow_s, pcMedia, packetDumper, flow,
+      WrapRunnableNM(FinalizeTransportFlow_s, mIceCtx, packetDumper, flow,
                      aTransport.mTransportId, aIsRtcp,
                      ice.release(), dtls.release(), srtp.release()),
       NS_DISPATCH_NORMAL);
   if (NS_FAILED(rv)) {
     CSFLogError(LOGTAG, "Failed to dispatch FinalizeTransportFlow_s");
     return rv;
   }
 
@@ -962,16 +1097,153 @@ PeerConnectionMedia::ShutdownMediaTransp
 
   mIceCtx = nullptr;
 
   // we're holding a ref to 'this' that's released by SelfDestruct_m
   mMainThread->Dispatch(WrapRunnable(this, &PeerConnectionMedia::SelfDestruct_m),
                         NS_DISPATCH_NORMAL);
 }
 
+
+void
+PeerConnectionMedia::GetIceStats_s(
+    const std::string& aTransportId,
+    bool internalStats,
+    DOMHighResTimeStamp now,
+    RTCStatsReportInternal* report) const
+{
+  if (mIceCtx) {
+    auto stream = mIceCtx->GetStream(aTransportId);
+    if (stream) {
+      GetIceStats_s(*stream, internalStats, now, report);
+    }
+  }
+}
+
+void
+PeerConnectionMedia::GetAllIceStats_s(
+    bool internalStats,
+    DOMHighResTimeStamp now,
+    RTCStatsReportInternal* report) const
+{
+  if (mIceCtx) {
+    for (const auto& stream : mIceCtx->GetStreams()) {
+      GetIceStats_s(*stream, internalStats, now, report);
+    }
+  }
+}
+
+static void ToRTCIceCandidateStats(
+    const std::vector<NrIceCandidate>& candidates,
+    RTCStatsType candidateType,
+    const nsString& componentId,
+    DOMHighResTimeStamp now,
+    RTCStatsReportInternal* report) {
+
+  MOZ_ASSERT(report);
+  for (const auto& candidate : candidates) {
+    RTCIceCandidateStats cand;
+    cand.mType.Construct(candidateType);
+    NS_ConvertASCIItoUTF16 codeword(candidate.codeword.c_str());
+    cand.mComponentId.Construct(componentId);
+    cand.mId.Construct(codeword);
+    cand.mTimestamp.Construct(now);
+    cand.mCandidateType.Construct(
+        RTCStatsIceCandidateType(candidate.type));
+    cand.mIpAddress.Construct(
+        NS_ConvertASCIItoUTF16(candidate.cand_addr.host.c_str()));
+    cand.mPortNumber.Construct(candidate.cand_addr.port);
+    cand.mTransport.Construct(
+        NS_ConvertASCIItoUTF16(candidate.cand_addr.transport.c_str()));
+    if (candidateType == RTCStatsType::Local_candidate) {
+      cand.mMozLocalTransport.Construct(
+          NS_ConvertASCIItoUTF16(candidate.local_addr.transport.c_str()));
+    }
+    report->mIceCandidateStats.Value().AppendElement(cand, fallible);
+    if (candidate.trickled) {
+      report->mTrickledIceCandidateStats.Value().AppendElement(cand, fallible);
+    }
+  }
+}
+
+void
+PeerConnectionMedia::GetIceStats_s(
+    const NrIceMediaStream& aStream,
+    bool internalStats,
+    DOMHighResTimeStamp now,
+    RTCStatsReportInternal* report) const
+{
+  NS_ConvertASCIItoUTF16 transportId(aStream.GetId().c_str());
+
+  std::vector<NrIceCandidatePair> candPairs;
+  nsresult res = aStream.GetCandidatePairs(&candPairs);
+  if (NS_FAILED(res)) {
+    CSFLogError(LOGTAG,
+        "%s: Error getting candidate pairs for transport id \"%s\"",
+        __FUNCTION__, aStream.GetId().c_str());
+    return;
+  }
+
+  for (auto& candPair : candPairs) {
+    NS_ConvertASCIItoUTF16 codeword(candPair.codeword.c_str());
+    NS_ConvertASCIItoUTF16 localCodeword(candPair.local.codeword.c_str());
+    NS_ConvertASCIItoUTF16 remoteCodeword(candPair.remote.codeword.c_str());
+    // Only expose candidate-pair statistics to chrome, until we've thought
+    // through the implications of exposing it to content.
+
+    RTCIceCandidatePairStats s;
+    s.mId.Construct(codeword);
+    s.mTransportId.Construct(transportId);
+    s.mTimestamp.Construct(now);
+    s.mType.Construct(RTCStatsType::Candidate_pair);
+    s.mLocalCandidateId.Construct(localCodeword);
+    s.mRemoteCandidateId.Construct(remoteCodeword);
+    s.mNominated.Construct(candPair.nominated);
+    s.mWritable.Construct(candPair.writable);
+    s.mReadable.Construct(candPair.readable);
+    s.mPriority.Construct(candPair.priority);
+    s.mSelected.Construct(candPair.selected);
+    s.mBytesSent.Construct(candPair.bytes_sent);
+    s.mBytesReceived.Construct(candPair.bytes_recvd);
+    s.mLastPacketSentTimestamp.Construct(candPair.ms_since_last_send);
+    s.mLastPacketReceivedTimestamp.Construct(candPair.ms_since_last_recv);
+    s.mState.Construct(RTCStatsIceCandidatePairState(candPair.state));
+    s.mComponentId.Construct(candPair.component_id);
+    report->mIceCandidatePairStats.Value().AppendElement(s, fallible);
+  }
+
+  std::vector<NrIceCandidate> candidates;
+  if (NS_SUCCEEDED(aStream.GetLocalCandidates(&candidates))) {
+    ToRTCIceCandidateStats(candidates,
+                           RTCStatsType::Local_candidate,
+                           transportId,
+                           now,
+                           report);
+    // add the local candidates unparsed string to a sequence
+    for (const auto& candidate : candidates) {
+      report->mRawLocalCandidates.Value().AppendElement(
+          NS_ConvertASCIItoUTF16(candidate.label.c_str()), fallible);
+    }
+  }
+  candidates.clear();
+
+  if (NS_SUCCEEDED(aStream.GetRemoteCandidates(&candidates))) {
+    ToRTCIceCandidateStats(candidates,
+                           RTCStatsType::Remote_candidate,
+                           transportId,
+                           now,
+                           report);
+    // add the remote candidates unparsed string to a sequence
+    for (const auto& candidate : candidates) {
+      report->mRawRemoteCandidates.Value().AppendElement(
+          NS_ConvertASCIItoUTF16(candidate.label.c_str()), fallible);
+    }
+  }
+}
+
 nsresult
 PeerConnectionMedia::AddTransceiver(
     JsepTransceiver* aJsepTransceiver,
     dom::MediaStreamTrack& aReceiveTrack,
     dom::MediaStreamTrack* aSendTrack,
     RefPtr<TransceiverImpl>* aTransceiverImpl)
 {
   if (!mCall) {
@@ -1192,30 +1464,64 @@ PeerConnectionMedia::GetDefaultCandidate
     CSFLogError(LOGTAG, "%s: GetDefaultCandidates failed for transport id %s, "
                         "res=%u",
                         __FUNCTION__,
                         aStream.GetId().c_str(),
                         static_cast<unsigned>(res));
   }
 }
 
+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_CONNECTED:
+      return PCImplIceConnectionState::Connected;
+    case NrIceCtx::ICE_CTX_COMPLETED:
+      return PCImplIceConnectionState::Completed;
+    case NrIceCtx::ICE_CTX_FAILED:
+      return PCImplIceConnectionState::Failed;
+    case NrIceCtx::ICE_CTX_DISCONNECTED:
+      return PCImplIceConnectionState::Disconnected;
+    case NrIceCtx::ICE_CTX_CLOSED:
+      return PCImplIceConnectionState::Closed;
+  }
+  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();
+}
+
 void
 PeerConnectionMedia::IceGatheringStateChange_m(NrIceCtx* ctx,
                                                NrIceCtx::GatheringState state)
 {
   ASSERT_ON_THREAD(mMainThread);
-  SignalIceGatheringStateChange(ctx, state);
+  SignalIceGatheringStateChange(toDomIceGatheringState(state));
 }
 
 void
 PeerConnectionMedia::IceConnectionStateChange_m(NrIceCtx* ctx,
                                                 NrIceCtx::ConnectionState state)
 {
   ASSERT_ON_THREAD(mMainThread);
-  SignalIceConnectionStateChange(ctx, state);
+  SignalIceConnectionStateChange(toDomIceConnectionState(state));
 }
 
 void
 PeerConnectionMedia::IceStreamReady_s(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
@@ -45,28 +45,27 @@ class JsepSession;
 // to something more explanatory (say, PeerConnectionTransportManager).
 class PeerConnectionMedia : public sigslot::has_slots<> {
   ~PeerConnectionMedia();
 
  public:
   explicit PeerConnectionMedia(PeerConnectionImpl *parent);
 
   PeerConnectionImpl* GetPC() { return mParent; }
-  nsresult Init(const std::vector<NrIceStunServer>& stun_servers,
-                const std::vector<NrIceTurnServer>& turn_servers,
-                NrIceCtx::Policy policy);
+  nsresult Init(const dom::RTCConfiguration& aConfiguration);
   // WARNING: This destroys the object!
   void SelfDestruct();
 
-  RefPtr<NrIceCtx> ice_ctx() const { return mIceCtx; }
-
-  RefPtr<NrIceMediaStream> ice_media_stream(
-      const std::string& aTransportId) const {
-    return mIceCtx->GetStream(aTransportId);
-  }
+  void GetIceStats_s(const std::string& aTransportId,
+                     bool internalStats,
+                     DOMHighResTimeStamp now,
+                     RTCStatsReportInternal* report) const;
+  void GetAllIceStats_s(bool internalStats,
+                        DOMHighResTimeStamp now,
+                        RTCStatsReportInternal* report) const;
 
   // Ensure ICE transports exist that we might need when offer/answer concludes
   void EnsureTransports(const JsepSession& aSession);
 
   // Activate ICE transports at the conclusion of offer/answer,
   // or when rollback occurs.
   nsresult UpdateTransports(const JsepSession& aSession,
                             const bool forceIceTcp);
@@ -156,19 +155,19 @@ class PeerConnectionMedia : public sigsl
   void RemoveTransportFlow(const std::string& aId, bool aRtcp);
   void ConnectDtlsListener_s(const RefPtr<TransportFlow>& aFlow);
   void DtlsConnected_s(TransportLayer* aFlow,
                        TransportLayer::State state);
   static void DtlsConnected_m(const std::string& aParentHandle,
                               bool aPrivacyRequested);
 
   // ICE state signals
-  sigslot::signal2<NrIceCtx*, NrIceCtx::GatheringState>
+  sigslot::signal1<mozilla::dom::PCImplIceGatheringState>
       SignalIceGatheringStateChange;
-  sigslot::signal2<NrIceCtx*, NrIceCtx::ConnectionState>
+  sigslot::signal1<mozilla::dom::PCImplIceConnectionState>
       SignalIceConnectionStateChange;
   // This passes a candidate:... attribute and transport id
   sigslot::signal2<const std::string&, const std::string&> SignalCandidate;
   // This passes address, port, transport id of the default candidate.
   sigslot::signal5<const std::string&, uint16_t,
                    const std::string&, uint16_t, const std::string&>
       SignalUpdateDefaultCandidate;
   sigslot::signal1<const std::string&>
@@ -286,16 +285,21 @@ class PeerConnectionMedia : public sigsl
                               uint16_t aDefaultPort,
                               const std::string& aDefaultRtcpAddr,
                               uint16_t aDefaultRtcpPort,
                               const std::string& aTransportId);
   bool IsIceCtxReady() const {
     return mProxyResolveCompleted && mLocalAddrsCompleted;
   }
 
+  void GetIceStats_s(const NrIceMediaStream& aStream,
+                     bool internalStats,
+                     DOMHighResTimeStamp now,
+                     RTCStatsReportInternal* report) const;
+
   // The parent PC
   PeerConnectionImpl *mParent;
   // and a loose handle on it for event driven stuff
   std::string mParentHandle;
   std::string mParentName;
 
   std::vector<RefPtr<TransceiverImpl>> mTransceivers;
 
--- a/python/mozbuild/mozbuild/backend/cargo_build_defs.py
+++ b/python/mozbuild/mozbuild/backend/cargo_build_defs.py
@@ -90,9 +90,43 @@ cargo_extra_outputs = {
         'shorthands/table.rs',
         'shorthands/text.rs',
         'shorthands/ui.rs',
         'shorthands/xul.rs',
     ],
     'webrender': [
         'shaders.rs',
     ],
+    'cranelift-codegen': [
+        'binemit-arm32.rs',
+        'binemit-arm64.rs',
+        'binemit-riscv.rs',
+        'binemit-x86.rs',
+        'encoding-arm32.rs',
+        'encoding-arm64.rs',
+        'encoding-riscv.rs',
+        'encoding-x86.rs',
+        'inst_builder.rs',
+        'legalize-arm32.rs',
+        'legalize-arm64.rs',
+        'legalize-riscv.rs',
+        'legalize-x86.rs',
+        'legalizer.rs',
+        'new_types.rs',
+        'opcodes.rs',
+        'registers-arm32.rs',
+        'registers-arm64.rs',
+        'registers-riscv.rs',
+        'registers-x86.rs',
+        'settings-arm32.rs',
+        'settings-arm64.rs',
+        'settings-riscv.rs',
+        'settings-x86.rs',
+        'settings.rs',
+        'types.rs',
+    ],
+    'target-lexicon': [
+        'host.rs',
+    ],
+    'baldrdash': [
+        'bindings.rs',
+    ],
 }
--- a/python/mozbuild/mozbuild/backend/tup.py
+++ b/python/mozbuild/mozbuild/backend/tup.py
@@ -458,24 +458,35 @@ class TupBackend(CommonBackend):
 
     def _gen_programs(self, backend_file):
         for p in backend_file.programs:
             self._gen_program(backend_file, p)
 
     def _gen_program(self, backend_file, prog):
         cc_or_cxx = 'CXX' if prog.cxx_link else 'CC'
         objs, _, _, shared_libs, os_libs, static_libs = self._expand_libs(prog)
+
         static_libs = self._lib_paths(backend_file.objdir, static_libs)
         shared_libs = self._lib_paths(backend_file.objdir, shared_libs)
 
         # Linking some programs will access libraries installed to dist/bin,
         # so depend on the installed libraries here. This can be made more
         # accurate once we start building libraries in their final locations.
         inputs = objs + static_libs + shared_libs + [self._shlibs]
 
+
+        rust_linked = [l for l in prog.linked_libraries
+                       if isinstance(l, RustLibrary)]
+
+        extra_inputs = []
+        if rust_linked:
+            extra_inputs = [self._rust_output_group(rust_linked[0].output_category) or
+                            self._rust_libs]
+            static_libs += self._lib_paths(backend_file.objdir, rust_linked)
+
         list_file_name = '%s.list' % prog.name.replace('.', '_')
         list_file = self._make_list_file(backend_file.objdir, objs, list_file_name)
 
         if isinstance(prog, SimpleProgram):
             outputs = [prog.name]
         else:
             outputs = [mozpath.relpath(prog.output_path.full_path,
                                        backend_file.objdir)]
@@ -489,16 +500,17 @@ class TupBackend(CommonBackend):
             [backend_file.environment.substs['MOZ_PROGRAM_LDFLAGS']] +
             shared_libs +
             [backend_file.environment.substs['OS_LIBS']] +
             os_libs
         )
         backend_file.rule(
             cmd=cmd,
             inputs=inputs,
+            extra_inputs=extra_inputs,
             outputs=outputs,
             display='LINK %o'
         )
 
 
     def _gen_host_library(self, backend_file):
         objs = backend_file.host_library.objs
         inputs = objs
@@ -800,29 +812,16 @@ class TupBackend(CommonBackend):
 
     def _gen_cargo_rules(self, backend_file, build_plan, cargo_env, output_group):
         invocations = build_plan['invocations']
         processed = set()
 
         rust_build_home = mozpath.join(self.environment.topobjdir,
                                        'toolkit/library/rust')
 
-        def get_libloading_outdir():
-            for invocation in invocations:
-                if (invocation['package_name'] == 'libloading' and
-                    invocation['outputs'][0].endswith('.rlib')):
-                    return invocation['env']['OUT_DIR']
-
-        def get_lmdb_sys_outdir():
-            for invocation in invocations:
-                if (invocation['package_name'] == 'lmdb-sys' and
-                    len(invocation['outputs']) >= 1 and
-                    invocation['outputs'][0].endswith('.rlib')):
-                    return invocation['env']['OUT_DIR']
-
         def display_name(invocation):
             output_str = ''
             if invocation['outputs']:
                 outputs = [os.path.basename(f) for f in invocation['outputs']]
                 output_str = ' -> [%s]' % self._trim_outputs(outputs)
             return '{name} v{version} {kind}{output}'.format(
                 name=invocation['package_name'],
                 version=invocation['package_version'],
@@ -859,20 +858,21 @@ class TupBackend(CommonBackend):
             command.append(invocation['program'])
             command.extend(cargo_quote(a.replace('dep-info,', ''))
                            for a in invocation['args'])
             outputs = invocation['outputs']
 
             invocation['full-deps'] = set()
 
             if os.path.basename(invocation['program']) == 'build-script-build':
+                out_dir = invocation['env']['OUT_DIR']
                 for output in cargo_extra_outputs.get(shortname, []):
-                    outputs.append(os.path.join(invocation['env']['OUT_DIR'], output))
+                    outputs.append(os.path.join(out_dir, output))
 
-                script_stdout = mozpath.join(rust_build_home,
+                script_stdout = mozpath.join(out_dir,
                                              '%s_%s_build_out.txt' % (shortname,
                                                                       invocation['kind']))
                 command.extend(['>', script_stdout])
                 outputs.append(script_stdout)
                 invocation['full-deps'].add(script_stdout)
 
             if os.path.basename(invocation['program']) == 'rustc':
                 all_dep_build_outputs = set(p for p in inputs
@@ -886,24 +886,26 @@ class TupBackend(CommonBackend):
                 seen_dep_outputs = set()
 
                 def is_lib(inv):
                     return any(t not in ('bin', 'example', 'test', 'custom-build',
                                          'bench')
                                for t in inv['target_kind'])
 
                 def get_output_files(inv):
-                    candidate_file = mozpath.join(rust_build_home,
-                                                  '%s_%s_build_out.txt' %
-                                                  (inv['package_name'],
-                                                   inv['kind']))
-                    if (candidate_file in all_dep_build_outputs and
-                        candidate_file not in seen_dep_outputs):
-                        dep_build_outputs.append(candidate_file)
-                        seen_dep_outputs.add(candidate_file)
+                    out_dir = inv['env'].get('OUT_DIR')
+                    if out_dir:
+                        candidate_file = mozpath.join(out_dir,
+                                                      '%s_%s_build_out.txt' %
+                                                      (inv['package_name'],
+                                                       inv['kind']))
+                        if (candidate_file in all_dep_build_outputs and
+                            candidate_file not in seen_dep_outputs):
+                            dep_build_outputs.append(candidate_file)
+                            seen_dep_outputs.add(candidate_file)
 
                     for dep in inv['deps']:
                         dep_inv = invocations[dep]
                         if shortname == inv['package_name'] or is_lib(dep_inv):
                             get_output_files(dep_inv)
 
                 get_output_files(invocation)
 
--- a/taskcluster/scripts/misc/build-tup-linux.sh
+++ b/taskcluster/scripts/misc/build-tup-linux.sh
@@ -1,24 +1,24 @@
 #!/bin/bash
 set -e -v
 
 # This script is for building tup on Linux.
 
-TUP_REVISION=e948a999a38fefa0ac0d92f6357f82aca2f9cb17
+TUP_REVISION=v0.7.8
 
 WORKSPACE=$HOME/workspace
 UPLOAD_DIR=$HOME/artifacts
 COMPRESS_EXT=xz
 export PATH=$WORKSPACE/build/src/gcc/bin:$PATH
 
 cd $WORKSPACE/build/src
 
 . taskcluster/scripts/misc/tooltool-download.sh
 
 git clone https://github.com/gittup/tup.git
 cd tup
 git checkout $TUP_REVISION
-echo 'CONFIG_TUP_SERVER=ldpreload' > tup.config
+(echo 'CONFIG_TUP_SERVER=ldpreload'; echo 'CONFIG_TUP_USE_SYSTEM_PCRE=n') > tup.config
 ./bootstrap-ldpreload.sh
 cd ..
 tar caf tup.tar.xz tup/tup tup/tup-ldpreload.so tup/tup.1
 cp tup.tar.xz $UPLOAD_DIR