LCOV - code coverage report
Current view: top level - media/webrtc/signaling/src/peerconnection - PeerConnectionImpl.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 2023 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 144 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       3             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include <cstdlib>
       6             : #include <cerrno>
       7             : #include <deque>
       8             : #include <set>
       9             : #include <sstream>
      10             : #include <vector>
      11             : 
      12             : #include "CSFLog.h"
      13             : #include "timecard.h"
      14             : 
      15             : #include "jsapi.h"
      16             : #include "nspr.h"
      17             : #include "nss.h"
      18             : #include "pk11pub.h"
      19             : 
      20             : #include "nsNetCID.h"
      21             : #include "nsILoadContext.h"
      22             : #include "nsIProperty.h"
      23             : #include "nsIPropertyBag2.h"
      24             : #include "nsIServiceManager.h"
      25             : #include "nsISimpleEnumerator.h"
      26             : #include "nsServiceManagerUtils.h"
      27             : #include "nsISocketTransportService.h"
      28             : #include "nsIConsoleService.h"
      29             : #include "nsThreadUtils.h"
      30             : #include "nsIPrefService.h"
      31             : #include "nsIPrefBranch.h"
      32             : #include "nsProxyRelease.h"
      33             : #include "nsQueryObject.h"
      34             : #include "prtime.h"
      35             : 
      36             : #include "AudioConduit.h"
      37             : #include "VideoConduit.h"
      38             : #include "runnable_utils.h"
      39             : #include "PeerConnectionCtx.h"
      40             : #include "PeerConnectionImpl.h"
      41             : #include "PeerConnectionMedia.h"
      42             : #include "nsDOMDataChannelDeclarations.h"
      43             : #include "dtlsidentity.h"
      44             : #include "signaling/src/sdp/SdpAttribute.h"
      45             : 
      46             : #include "signaling/src/jsep/JsepTrack.h"
      47             : #include "signaling/src/jsep/JsepSession.h"
      48             : #include "signaling/src/jsep/JsepSessionImpl.h"
      49             : 
      50             : #include "mozilla/IntegerPrintfMacros.h"
      51             : #include "mozilla/Sprintf.h"
      52             : 
      53             : #ifdef XP_WIN
      54             : // We need to undef the MS macro for nsIDocument::CreateEvent
      55             : #ifdef CreateEvent
      56             : #undef CreateEvent
      57             : #endif
      58             : #endif // XP_WIN
      59             : 
      60             : #include "nsIDocument.h"
      61             : #include "nsGlobalWindow.h"
      62             : #include "nsDOMDataChannel.h"
      63             : #include "mozilla/dom/Location.h"
      64             : #include "mozilla/dom/Performance.h"
      65             : #include "mozilla/TimeStamp.h"
      66             : #include "mozilla/Telemetry.h"
      67             : #include "mozilla/Preferences.h"
      68             : #include "mozilla/PublicSSL.h"
      69             : #include "nsXULAppAPI.h"
      70             : #include "nsContentUtils.h"
      71             : #include "nsDOMJSUtils.h"
      72             : #include "nsIScriptError.h"
      73             : #include "nsPrintfCString.h"
      74             : #include "nsURLHelper.h"
      75             : #include "nsNetUtil.h"
      76             : #include "nsIURLParser.h"
      77             : #include "nsIDOMDataChannel.h"
      78             : #include "NullPrincipal.h"
      79             : #include "mozilla/PeerIdentity.h"
      80             : #include "mozilla/dom/RTCCertificate.h"
      81             : #include "mozilla/dom/RTCConfigurationBinding.h"
      82             : #include "mozilla/dom/RTCDTMFSenderBinding.h"
      83             : #include "mozilla/dom/RTCDTMFToneChangeEvent.h"
      84             : #include "mozilla/dom/RTCRtpSenderBinding.h"
      85             : #include "mozilla/dom/RTCStatsReportBinding.h"
      86             : #include "mozilla/dom/RTCPeerConnectionBinding.h"
      87             : #include "mozilla/dom/PeerConnectionImplBinding.h"
      88             : #include "mozilla/dom/DataChannelBinding.h"
      89             : #include "mozilla/dom/PerformanceTiming.h"
      90             : #include "mozilla/dom/PluginCrashedEvent.h"
      91             : #include "MediaStreamList.h"
      92             : #include "MediaStreamTrack.h"
      93             : #include "AudioStreamTrack.h"
      94             : #include "VideoStreamTrack.h"
      95             : #include "nsIScriptGlobalObject.h"
      96             : #include "MediaStreamGraph.h"
      97             : #include "DOMMediaStream.h"
      98             : #include "rlogconnector.h"
      99             : #include "WebrtcGlobalInformation.h"
     100             : #include "mozilla/dom/Event.h"
     101             : #include "nsIDOMCustomEvent.h"
     102             : #include "mozilla/EventDispatcher.h"
     103             : #include "mozilla/net/DataChannelProtocol.h"
     104             : 
     105             : #include "MediaStreamGraphImpl.h"
     106             : 
     107             : #ifdef XP_WIN
     108             : // We need to undef the MS macro again in case the windows include file
     109             : // got imported after we included nsIDocument.h
     110             : #ifdef CreateEvent
     111             : #undef CreateEvent
     112             : #endif
     113             : #endif // XP_WIN
     114             : 
     115             : #include "MediaSegment.h"
     116             : 
     117             : #ifdef USE_FAKE_PCOBSERVER
     118             : #include "FakePCObserver.h"
     119             : #else
     120             : #include "mozilla/dom/PeerConnectionObserverBinding.h"
     121             : #endif
     122             : #include "mozilla/dom/PeerConnectionObserverEnumsBinding.h"
     123             : 
     124             : #ifdef MOZ_WEBRTC_OMX
     125             : #include "OMXVideoCodec.h"
     126             : #include "OMXCodecWrapper.h"
     127             : #endif
     128             : 
     129             : #define ICE_PARSING "In RTCConfiguration passed to RTCPeerConnection constructor"
     130             : 
     131             : using namespace mozilla;
     132             : using namespace mozilla::dom;
     133             : 
     134             : typedef PCObserverString ObString;
     135             : 
     136             : static const char* logTag = "PeerConnectionImpl";
     137             : static mozilla::LazyLogModule logModuleInfo("signaling");
     138             : 
     139             : // Getting exceptions back down from PCObserver is generally not harmful.
     140             : namespace {
     141             : // This is a terrible hack.  The problem is that SuppressException is not
     142             : // inline, and we link this file without libxul in some cases (e.g. for our test
     143             : // setup).  So we can't use ErrorResult or IgnoredErrorResult because those call
     144             : // SuppressException...  And we can't use FastErrorResult because we can't
     145             : // include BindingUtils.h, because our linking is completely fucked up.  Use
     146             : // BaseErrorResult directly.  Please do not let me see _anyone_ doing this
     147             : // without really careful review from someone who knows what they are doing.
     148           0 : class JSErrorResult :
     149             :     public binding_danger::TErrorResult<binding_danger::JustAssertCleanupPolicy>
     150             : {
     151             : public:
     152           0 :   ~JSErrorResult()
     153           0 :   {
     154           0 :     SuppressException();
     155           0 :   }
     156             : };
     157             : 
     158             : // The WrapRunnable() macros copy passed-in args and passes them to the function
     159             : // later on the other thread. ErrorResult cannot be passed like this because it
     160             : // disallows copy-semantics.
     161             : //
     162             : // This WrappableJSErrorResult hack solves this by not actually copying the
     163             : // ErrorResult, but creating a new one instead, which works because we don't
     164             : // care about the result.
     165             : //
     166             : // Since this is for JS-calls, these can only be dispatched to the main thread.
     167             : 
     168             : class WrappableJSErrorResult {
     169             : public:
     170           0 :   WrappableJSErrorResult()
     171           0 :     : mRv(MakeUnique<JSErrorResult>()),
     172           0 :       isCopy(false) {}
     173           0 :   WrappableJSErrorResult(const WrappableJSErrorResult &other)
     174           0 :     : mRv(MakeUnique<JSErrorResult>()),
     175           0 :       isCopy(true) {}
     176           0 :   ~WrappableJSErrorResult() {
     177           0 :     if (isCopy) {
     178           0 :       MOZ_ASSERT(NS_IsMainThread());
     179             :     }
     180           0 :   }
     181           0 :   operator ErrorResult &() { return *mRv; }
     182             : private:
     183             :   mozilla::UniquePtr<JSErrorResult> mRv;
     184             :   bool isCopy;
     185             : };
     186             : 
     187             : }
     188             : 
     189           0 : static nsresult InitNSSInContent()
     190             : {
     191           0 :   NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_SAME_THREAD);
     192             : 
     193           0 :   if (!XRE_IsContentProcess()) {
     194           0 :     MOZ_ASSERT_UNREACHABLE("Must be called in content process");
     195             :     return NS_ERROR_FAILURE;
     196             :   }
     197             : 
     198             :   static bool nssStarted = false;
     199           0 :   if (nssStarted) {
     200           0 :     return NS_OK;
     201             :   }
     202             : 
     203           0 :   if (NSS_NoDB_Init(nullptr) != SECSuccess) {
     204           0 :     CSFLogError(logTag, "NSS_NoDB_Init failed.");
     205           0 :     return NS_ERROR_FAILURE;
     206             :   }
     207             : 
     208           0 :   if (NS_FAILED(mozilla::psm::InitializeCipherSuite())) {
     209           0 :     CSFLogError(logTag, "Fail to set up nss cipher suite.");
     210           0 :     return NS_ERROR_FAILURE;
     211             :   }
     212             : 
     213           0 :   mozilla::psm::DisableMD5();
     214             : 
     215           0 :   nssStarted = true;
     216             : 
     217           0 :   return NS_OK;
     218             : }
     219             : 
     220             : namespace mozilla {
     221             :   class DataChannel;
     222             : }
     223             : 
     224             : class nsIDOMDataChannel;
     225             : 
     226             : // XXX Workaround for bug 998092 to maintain the existing broken semantics
     227             : template<>
     228             : struct nsISupportsWeakReference::COMTypeInfo<nsSupportsWeakReference, void> {
     229             :   static const nsIID kIID;
     230             : };
     231             : const nsIID nsISupportsWeakReference::COMTypeInfo<nsSupportsWeakReference, void>::kIID = NS_ISUPPORTSWEAKREFERENCE_IID;
     232             : 
     233             : namespace mozilla {
     234             : 
     235           0 : RTCStatsQuery::RTCStatsQuery(bool internal) :
     236             :   failed(false),
     237             :   internalStats(internal),
     238           0 :   grabAllLevels(false) {
     239           0 : }
     240             : 
     241           0 : RTCStatsQuery::~RTCStatsQuery() {
     242           0 :   MOZ_ASSERT(NS_IsMainThread());
     243           0 : }
     244             : 
     245             : 
     246           0 : NS_IMPL_ISUPPORTS0(PeerConnectionImpl)
     247             : 
     248             : bool
     249           0 : PeerConnectionImpl::WrapObject(JSContext* aCx,
     250             :                                JS::Handle<JSObject*> aGivenProto,
     251             :                                JS::MutableHandle<JSObject*> aReflector)
     252             : {
     253           0 :   return PeerConnectionImplBinding::Wrap(aCx, this, aGivenProto, aReflector);
     254             : }
     255             : 
     256           0 : bool PCUuidGenerator::Generate(std::string* idp) {
     257             :   nsresult rv;
     258             : 
     259           0 :   if(!mGenerator) {
     260           0 :     mGenerator = do_GetService("@mozilla.org/uuid-generator;1", &rv);
     261           0 :     if (NS_FAILED(rv)) {
     262           0 :       return false;
     263             :     }
     264           0 :     if (!mGenerator) {
     265           0 :       return false;
     266             :     }
     267             :   }
     268             : 
     269             :   nsID id;
     270           0 :   rv = mGenerator->GenerateUUIDInPlace(&id);
     271           0 :   if (NS_FAILED(rv)) {
     272           0 :     return false;
     273             :   }
     274             :   char buffer[NSID_LENGTH];
     275           0 :   id.ToProvidedString(buffer);
     276           0 :   idp->assign(buffer);
     277             : 
     278           0 :   return true;
     279             : }
     280             : 
     281           0 : bool IsPrivateBrowsing(nsPIDOMWindowInner* aWindow)
     282             : {
     283           0 :   if (!aWindow) {
     284           0 :     return false;
     285             :   }
     286             : 
     287           0 :   nsIDocument *doc = aWindow->GetExtantDoc();
     288           0 :   if (!doc) {
     289           0 :     return false;
     290             :   }
     291             : 
     292           0 :   nsILoadContext *loadContext = doc->GetLoadContext();
     293           0 :   return loadContext && loadContext->UsePrivateBrowsing();
     294             : }
     295             : 
     296           0 : PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
     297           0 : : mTimeCard(MOZ_LOG_TEST(logModuleInfo,LogLevel::Error) ?
     298             :             create_timecard() : nullptr)
     299             :   , mSignalingState(PCImplSignalingState::SignalingStable)
     300             :   , mIceConnectionState(PCImplIceConnectionState::New)
     301             :   , mIceGatheringState(PCImplIceGatheringState::New)
     302             :   , mDtlsConnected(false)
     303             :   , mWindow(nullptr)
     304             :   , mCertificate(nullptr)
     305             :   , mPrivacyRequested(false)
     306             :   , mSTSThread(nullptr)
     307             :   , mAllowIceLoopback(false)
     308             :   , mAllowIceLinkLocal(false)
     309             :   , mForceIceTcp(false)
     310             :   , mMedia(nullptr)
     311             :   , mUuidGen(MakeUnique<PCUuidGenerator>())
     312             :   , mHaveConfiguredCodecs(false)
     313             :   , mHaveDataStream(false)
     314             :   , mAddCandidateErrorCount(0)
     315             :   , mTrickle(true) // TODO(ekr@rtfm.com): Use pref
     316             :   , mNegotiationNeeded(false)
     317           0 :   , mPrivateWindow(false)
     318             : {
     319           0 :   MOZ_ASSERT(NS_IsMainThread());
     320           0 :   auto log = RLogConnector::CreateInstance();
     321           0 :   if (aGlobal) {
     322           0 :     mWindow = do_QueryInterface(aGlobal->GetAsSupports());
     323           0 :     if (IsPrivateBrowsing(mWindow)) {
     324           0 :       mPrivateWindow = true;
     325           0 :       log->EnterPrivateMode();
     326             :     }
     327             :   }
     328           0 :   CSFLogInfo(logTag, "%s: PeerConnectionImpl constructor for %s",
     329           0 :              __FUNCTION__, mHandle.c_str());
     330           0 :   STAMP_TIMECARD(mTimeCard, "Constructor Completed");
     331           0 :   mAllowIceLoopback = Preferences::GetBool(
     332             :     "media.peerconnection.ice.loopback", false);
     333           0 :   mAllowIceLinkLocal = Preferences::GetBool(
     334             :     "media.peerconnection.ice.link_local", false);
     335           0 :   mForceIceTcp = Preferences::GetBool(
     336             :     "media.peerconnection.ice.force_ice_tcp", false);
     337           0 :   memset(mMaxReceiving, 0, sizeof(mMaxReceiving));
     338           0 :   memset(mMaxSending, 0, sizeof(mMaxSending));
     339           0 : }
     340             : 
     341           0 : PeerConnectionImpl::~PeerConnectionImpl()
     342             : {
     343           0 :   if (mTimeCard) {
     344           0 :     STAMP_TIMECARD(mTimeCard, "Destructor Invoked");
     345           0 :     print_timecard(mTimeCard);
     346           0 :     destroy_timecard(mTimeCard);
     347           0 :     mTimeCard = nullptr;
     348             :   }
     349             :   // This aborts if not on main thread (in Debug builds)
     350           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
     351           0 :   if (mPrivateWindow) {
     352           0 :     auto * log = RLogConnector::GetInstance();
     353           0 :     if (log) {
     354           0 :       log->ExitPrivateMode();
     355             :     }
     356           0 :     mPrivateWindow = false;
     357             :   }
     358           0 :   if (PeerConnectionCtx::isActive()) {
     359           0 :     PeerConnectionCtx::GetInstance()->mPeerConnections.erase(mHandle);
     360             :   } else {
     361           0 :     CSFLogError(logTag, "PeerConnectionCtx is already gone. Ignoring...");
     362             :   }
     363             : 
     364           0 :   CSFLogInfo(logTag, "%s: PeerConnectionImpl destructor invoked for %s",
     365           0 :              __FUNCTION__, mHandle.c_str());
     366             : 
     367           0 :   Close();
     368             : 
     369             :   // Since this and Initialize() occur on MainThread, they can't both be
     370             :   // running at once
     371             : 
     372             :   // Right now, we delete PeerConnectionCtx at XPCOM shutdown only, but we
     373             :   // probably want to shut it down more aggressively to save memory.  We
     374             :   // could shut down here when there are no uses.  It might be more optimal
     375             :   // to release off a timer (and XPCOM Shutdown) to avoid churn
     376           0 : }
     377             : 
     378             : already_AddRefed<DOMMediaStream>
     379           0 : PeerConnectionImpl::MakeMediaStream()
     380             : {
     381             :   MediaStreamGraph* graph =
     382           0 :     MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
     383           0 :                                   AudioChannel::Normal, GetWindow());
     384             : 
     385             :   RefPtr<DOMMediaStream> stream =
     386           0 :     DOMMediaStream::CreateSourceStreamAsInput(GetWindow(), graph);
     387             : 
     388           0 :   CSFLogDebug(logTag, "Created media stream %p, inner: %p", stream.get(), stream->GetInputStream());
     389             : 
     390           0 :   return stream.forget();
     391             : }
     392             : 
     393             : nsresult
     394           0 : PeerConnectionImpl::CreateRemoteSourceStreamInfo(RefPtr<RemoteSourceStreamInfo>*
     395             :                                                  aInfo,
     396             :                                                  const std::string& aStreamID)
     397             : {
     398           0 :   MOZ_ASSERT(aInfo);
     399           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
     400             : 
     401           0 :   RefPtr<DOMMediaStream> stream = MakeMediaStream();
     402           0 :   if (!stream) {
     403           0 :     return NS_ERROR_FAILURE;
     404             :   }
     405             : 
     406           0 :   RefPtr<RemoteSourceStreamInfo> remote;
     407           0 :   remote = new RemoteSourceStreamInfo(stream.forget(), mMedia, aStreamID);
     408           0 :   *aInfo = remote;
     409             : 
     410           0 :   return NS_OK;
     411             : }
     412             : 
     413             : /**
     414             :  * In JS, an RTCConfiguration looks like this:
     415             :  *
     416             :  * { "iceServers": [ { url:"stun:stun.example.org" },
     417             :  *                   { url:"turn:turn.example.org?transport=udp",
     418             :  *                     username: "jib", credential:"mypass"} ] }
     419             :  *
     420             :  * This function converts that into an internal PeerConnectionConfiguration
     421             :  * object.
     422             :  */
     423             : nsresult
     424           0 : PeerConnectionConfiguration::Init(const RTCConfiguration& aSrc)
     425             : {
     426           0 :   if (aSrc.mIceServers.WasPassed()) {
     427           0 :     for (size_t i = 0; i < aSrc.mIceServers.Value().Length(); i++) {
     428           0 :       nsresult rv = AddIceServer(aSrc.mIceServers.Value()[i]);
     429           0 :       NS_ENSURE_SUCCESS(rv, rv);
     430             :     }
     431             :   }
     432             : 
     433           0 :   switch (aSrc.mBundlePolicy) {
     434             :     case dom::RTCBundlePolicy::Balanced:
     435           0 :       setBundlePolicy(kBundleBalanced);
     436           0 :       break;
     437             :     case dom::RTCBundlePolicy::Max_compat:
     438           0 :       setBundlePolicy(kBundleMaxCompat);
     439           0 :       break;
     440             :     case dom::RTCBundlePolicy::Max_bundle:
     441           0 :       setBundlePolicy(kBundleMaxBundle);
     442           0 :       break;
     443             :     default:
     444           0 :       MOZ_CRASH();
     445             :   }
     446             : 
     447           0 :   switch (aSrc.mIceTransportPolicy) {
     448             :     case dom::RTCIceTransportPolicy::Relay:
     449           0 :       setIceTransportPolicy(NrIceCtx::ICE_POLICY_RELAY);
     450           0 :       break;
     451             :     case dom::RTCIceTransportPolicy::All:
     452           0 :       if (Preferences::GetBool("media.peerconnection.ice.no_host", false)) {
     453           0 :         setIceTransportPolicy(NrIceCtx::ICE_POLICY_NO_HOST);
     454             :       } else {
     455           0 :         setIceTransportPolicy(NrIceCtx::ICE_POLICY_ALL);
     456             :       }
     457           0 :       break;
     458             :     default:
     459           0 :       MOZ_CRASH();
     460             :   }
     461           0 :   return NS_OK;
     462             : }
     463             : 
     464             : nsresult
     465           0 : PeerConnectionConfiguration::AddIceServer(const RTCIceServer &aServer)
     466             : {
     467           0 :   NS_ENSURE_STATE(aServer.mUrls.WasPassed());
     468           0 :   NS_ENSURE_STATE(aServer.mUrls.Value().IsStringSequence());
     469           0 :   auto &urls = aServer.mUrls.Value().GetAsStringSequence();
     470           0 :   for (size_t i = 0; i < urls.Length(); i++) {
     471             :     // Without STUN/TURN handlers, NS_NewURI returns nsSimpleURI rather than
     472             :     // nsStandardURL. To parse STUN/TURN URI's to spec
     473             :     // http://tools.ietf.org/html/draft-nandakumar-rtcweb-stun-uri-02#section-3
     474             :     // http://tools.ietf.org/html/draft-petithuguenin-behave-turn-uri-03#section-3
     475             :     // we parse out the query-string, and use ParseAuthority() on the rest
     476           0 :     RefPtr<nsIURI> url;
     477           0 :     nsresult rv = NS_NewURI(getter_AddRefs(url), urls[i]);
     478           0 :     NS_ENSURE_SUCCESS(rv, rv);
     479           0 :     bool isStun = false, isStuns = false, isTurn = false, isTurns = false;
     480           0 :     url->SchemeIs("stun", &isStun);
     481           0 :     url->SchemeIs("stuns", &isStuns);
     482           0 :     url->SchemeIs("turn", &isTurn);
     483           0 :     url->SchemeIs("turns", &isTurns);
     484           0 :     if (!(isStun || isStuns || isTurn || isTurns)) {
     485           0 :       return NS_ERROR_FAILURE;
     486             :     }
     487           0 :     if (isStuns) {
     488           0 :       continue; // TODO: Support STUNS (Bug 1056934)
     489             :     }
     490           0 :     nsAutoCString spec;
     491           0 :     rv = url->GetSpec(spec);
     492           0 :     NS_ENSURE_SUCCESS(rv, rv);
     493             : 
     494             :     // TODO(jib@mozilla.com): Revisit once nsURI supports STUN/TURN (Bug 833509)
     495             :     int32_t port;
     496           0 :     nsAutoCString host;
     497           0 :     nsAutoCString transport;
     498             :     {
     499             :       uint32_t hostPos;
     500             :       int32_t hostLen;
     501           0 :       nsAutoCString path;
     502           0 :       rv = url->GetPath(path);
     503           0 :       NS_ENSURE_SUCCESS(rv, rv);
     504             : 
     505             :       // Tolerate query-string + parse 'transport=[udp|tcp]' by hand.
     506           0 :       int32_t questionmark = path.FindChar('?');
     507           0 :       if (questionmark >= 0) {
     508           0 :         const nsCString match = NS_LITERAL_CSTRING("transport=");
     509             : 
     510           0 :         for (int32_t i = questionmark, endPos; i >= 0; i = endPos) {
     511           0 :           endPos = path.FindCharInSet("&", i + 1);
     512           0 :           const nsDependentCSubstring fieldvaluepair = Substring(path, i + 1,
     513           0 :                                                                  endPos);
     514           0 :           if (StringBeginsWith(fieldvaluepair, match)) {
     515           0 :             transport = Substring(fieldvaluepair, match.Length());
     516           0 :             ToLowerCase(transport);
     517             :           }
     518             :         }
     519           0 :         path.SetLength(questionmark);
     520             :       }
     521             : 
     522           0 :       rv = net_GetAuthURLParser()->ParseAuthority(path.get(), path.Length(),
     523             :                                                   nullptr,  nullptr,
     524             :                                                   nullptr,  nullptr,
     525           0 :                                                   &hostPos,  &hostLen, &port);
     526           0 :       NS_ENSURE_SUCCESS(rv, rv);
     527           0 :       if (!hostLen) {
     528           0 :         return NS_ERROR_FAILURE;
     529             :       }
     530           0 :       if (hostPos > 1)  /* The username was removed */
     531           0 :         return NS_ERROR_FAILURE;
     532           0 :       path.Mid(host, hostPos, hostLen);
     533             :     }
     534           0 :     if (port == -1)
     535           0 :       port = (isStuns || isTurns)? 5349 : 3478;
     536             : 
     537           0 :     if (isStuns || isTurns) {
     538             :       // Should we barf if transport is set to udp or something?
     539           0 :       transport = kNrIceTransportTls;
     540             :     }
     541             : 
     542           0 :     if (transport.IsEmpty()) {
     543           0 :       transport = kNrIceTransportUdp;
     544             :     }
     545             : 
     546           0 :     if (isTurn || isTurns) {
     547           0 :       NS_ConvertUTF16toUTF8 credential(aServer.mCredential.Value());
     548           0 :       NS_ConvertUTF16toUTF8 username(aServer.mUsername.Value());
     549             : 
     550           0 :       if (!addTurnServer(host.get(), port,
     551             :                          username.get(),
     552             :                          credential.get(),
     553             :                          transport.get())) {
     554           0 :         return NS_ERROR_FAILURE;
     555           0 :       }
     556             :     } else {
     557           0 :       if (!addStunServer(host.get(), port, transport.get())) {
     558           0 :         return NS_ERROR_FAILURE;
     559             :       }
     560             :     }
     561             :   }
     562           0 :   return NS_OK;
     563             : }
     564             : 
     565             : nsresult
     566           0 : PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
     567             :                                nsGlobalWindow* aWindow,
     568             :                                const PeerConnectionConfiguration& aConfiguration,
     569             :                                nsISupports* aThread)
     570             : {
     571             :   nsresult res;
     572             : 
     573           0 :   MOZ_ASSERT(NS_IsMainThread());
     574           0 :   MOZ_ASSERT(aThread);
     575           0 :   if (!mThread) {
     576           0 :     mThread = do_QueryInterface(aThread);
     577           0 :     MOZ_ASSERT(mThread);
     578             :   }
     579           0 :   CheckThread();
     580             : 
     581           0 :   mPCObserver = do_GetWeakReference(&aObserver);
     582             : 
     583             :   // Find the STS thread
     584             : 
     585           0 :   mSTSThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &res);
     586           0 :   MOZ_ASSERT(mSTSThread);
     587             : 
     588             :   // Initialize NSS if we are in content process. For chrome process, NSS should already
     589             :   // been initialized.
     590           0 :   if (XRE_IsParentProcess()) {
     591             :     // This code interferes with the C++ unit test startup code.
     592           0 :     nsCOMPtr<nsISupports> nssDummy = do_GetService("@mozilla.org/psm;1", &res);
     593           0 :     NS_ENSURE_SUCCESS(res, res);
     594             :   } else {
     595           0 :     NS_ENSURE_SUCCESS(res = InitNSSInContent(), res);
     596             :   }
     597             : 
     598             :   // Currently no standalone unit tests for DataChannel,
     599             :   // which is the user of mWindow
     600           0 :   MOZ_ASSERT(aWindow);
     601           0 :   mWindow = aWindow->AsInner();
     602           0 :   NS_ENSURE_STATE(mWindow);
     603             : 
     604           0 :   PRTime timestamp = PR_Now();
     605             :   // Ok if we truncate this.
     606             :   char temp[128];
     607             : 
     608           0 :   nsAutoCString locationCStr;
     609             : 
     610           0 :   if (RefPtr<Location> location = mWindow->GetLocation()) {
     611           0 :     nsAutoString locationAStr;
     612           0 :     res = location->ToString(locationAStr);
     613           0 :     NS_ENSURE_SUCCESS(res, res);
     614             : 
     615           0 :     CopyUTF16toUTF8(locationAStr, locationCStr);
     616             :   }
     617             : 
     618           0 :   SprintfLiteral(temp,
     619             :                  "%" PRIu64 " (id=%" PRIu64 " url=%s)",
     620             :                  static_cast<uint64_t>(timestamp),
     621           0 :                  static_cast<uint64_t>(mWindow ? mWindow->WindowID() : 0),
     622           0 :                  locationCStr.get() ? locationCStr.get() : "NULL");
     623             : 
     624           0 :   mName = temp;
     625             : 
     626             :   // Generate a random handle
     627             :   unsigned char handle_bin[8];
     628             :   SECStatus rv;
     629           0 :   rv = PK11_GenerateRandom(handle_bin, sizeof(handle_bin));
     630           0 :   if (rv != SECSuccess) {
     631           0 :     MOZ_CRASH();
     632             :     return NS_ERROR_UNEXPECTED;
     633             :   }
     634             : 
     635             :   char hex[17];
     636           0 :   SprintfLiteral(hex, "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
     637           0 :                  handle_bin[0],
     638           0 :                  handle_bin[1],
     639           0 :                  handle_bin[2],
     640           0 :                  handle_bin[3],
     641           0 :                  handle_bin[4],
     642           0 :                  handle_bin[5],
     643           0 :                  handle_bin[6],
     644           0 :                  handle_bin[7]);
     645             : 
     646           0 :   mHandle = hex;
     647             : 
     648           0 :   STAMP_TIMECARD(mTimeCard, "Initializing PC Ctx");
     649           0 :   res = PeerConnectionCtx::InitializeGlobal(mThread, mSTSThread);
     650           0 :   NS_ENSURE_SUCCESS(res, res);
     651             : 
     652           0 :   mMedia = new PeerConnectionMedia(this);
     653             : 
     654             :   // Connect ICE slots.
     655           0 :   mMedia->SignalIceGatheringStateChange.connect(
     656             :       this,
     657           0 :       &PeerConnectionImpl::IceGatheringStateChange);
     658           0 :   mMedia->SignalUpdateDefaultCandidate.connect(
     659             :       this,
     660           0 :       &PeerConnectionImpl::UpdateDefaultCandidate);
     661           0 :   mMedia->SignalEndOfLocalCandidates.connect(
     662             :       this,
     663           0 :       &PeerConnectionImpl::EndOfLocalCandidates);
     664           0 :   mMedia->SignalIceConnectionStateChange.connect(
     665             :       this,
     666           0 :       &PeerConnectionImpl::IceConnectionStateChange);
     667             : 
     668           0 :   mMedia->SignalCandidate.connect(this, &PeerConnectionImpl::CandidateReady);
     669             : 
     670             :   // Initialize the media object.
     671           0 :   res = mMedia->Init(aConfiguration.getStunServers(),
     672             :                      aConfiguration.getTurnServers(),
     673             :                      aConfiguration.getIceTransportPolicy());
     674           0 :   if (NS_FAILED(res)) {
     675           0 :     CSFLogError(logTag, "%s: Couldn't initialize media object", __FUNCTION__);
     676           0 :     return res;
     677             :   }
     678             : 
     679           0 :   PeerConnectionCtx::GetInstance()->mPeerConnections[mHandle] = this;
     680             : 
     681           0 :   mJsepSession = MakeUnique<JsepSessionImpl>(mName,
     682           0 :                                              MakeUnique<PCUuidGenerator>());
     683             : 
     684           0 :   res = mJsepSession->Init();
     685           0 :   if (NS_FAILED(res)) {
     686           0 :     CSFLogError(logTag, "%s: Couldn't init JSEP Session, res=%u",
     687             :                         __FUNCTION__,
     688           0 :                         static_cast<unsigned>(res));
     689           0 :     return res;
     690             :   }
     691             : 
     692           0 :   res = mJsepSession->SetIceCredentials(mMedia->ice_ctx()->ufrag(),
     693           0 :                                         mMedia->ice_ctx()->pwd());
     694           0 :   if (NS_FAILED(res)) {
     695           0 :     CSFLogError(logTag, "%s: Couldn't set ICE credentials, res=%u",
     696             :                          __FUNCTION__,
     697           0 :                          static_cast<unsigned>(res));
     698           0 :     return res;
     699             :   }
     700             : 
     701           0 :   res = mJsepSession->SetBundlePolicy(aConfiguration.getBundlePolicy());
     702           0 :   if (NS_FAILED(res)) {
     703           0 :     CSFLogError(logTag, "%s: Couldn't set bundle policy, res=%u, error=%s",
     704             :                         __FUNCTION__,
     705             :                         static_cast<unsigned>(res),
     706           0 :                         mJsepSession->GetLastError().c_str());
     707           0 :     return res;
     708             :   }
     709             : 
     710           0 :   return NS_OK;
     711             : }
     712             : 
     713             : void
     714           0 : PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
     715             :                                nsGlobalWindow& aWindow,
     716             :                                const RTCConfiguration& aConfiguration,
     717             :                                nsISupports* aThread,
     718             :                                ErrorResult &rv)
     719             : {
     720           0 :   MOZ_ASSERT(NS_IsMainThread());
     721           0 :   MOZ_ASSERT(aThread);
     722           0 :   mThread = do_QueryInterface(aThread);
     723             : 
     724           0 :   PeerConnectionConfiguration converted;
     725           0 :   nsresult res = converted.Init(aConfiguration);
     726           0 :   if (NS_FAILED(res)) {
     727           0 :     CSFLogError(logTag, "%s: Invalid RTCConfiguration", __FUNCTION__);
     728           0 :     rv.Throw(res);
     729           0 :     return;
     730             :   }
     731             : 
     732           0 :   res = Initialize(aObserver, &aWindow, converted, aThread);
     733           0 :   if (NS_FAILED(res)) {
     734           0 :     rv.Throw(res);
     735           0 :     return;
     736             :   }
     737             : 
     738           0 :   if (!aConfiguration.mPeerIdentity.IsEmpty()) {
     739           0 :     mPeerIdentity = new PeerIdentity(aConfiguration.mPeerIdentity);
     740           0 :     mPrivacyRequested = true;
     741             :   }
     742             : }
     743             : 
     744             : void
     745           0 : PeerConnectionImpl::SetCertificate(mozilla::dom::RTCCertificate& aCertificate)
     746             : {
     747           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
     748           0 :   MOZ_ASSERT(!mCertificate, "This can only be called once");
     749           0 :   mCertificate = &aCertificate;
     750             : 
     751           0 :   std::vector<uint8_t> fingerprint;
     752             :   nsresult rv = CalculateFingerprint(DtlsIdentity::DEFAULT_HASH_ALGORITHM,
     753           0 :                                      &fingerprint);
     754           0 :   if (NS_FAILED(rv)) {
     755             :     CSFLogError(logTag, "%s: Couldn't calculate fingerprint, rv=%u",
     756           0 :                 __FUNCTION__, static_cast<unsigned>(rv));
     757           0 :     mCertificate = nullptr;
     758           0 :     return;
     759             :   }
     760           0 :   rv = mJsepSession->AddDtlsFingerprint(DtlsIdentity::DEFAULT_HASH_ALGORITHM,
     761           0 :                                         fingerprint);
     762           0 :   if (NS_FAILED(rv)) {
     763             :     CSFLogError(logTag, "%s: Couldn't set DTLS credentials, rv=%u",
     764           0 :                 __FUNCTION__, static_cast<unsigned>(rv));
     765           0 :     mCertificate = nullptr;
     766             :   }
     767             : }
     768             : 
     769             : const RefPtr<mozilla::dom::RTCCertificate>&
     770           0 : PeerConnectionImpl::Certificate() const
     771             : {
     772           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
     773           0 :   return mCertificate;
     774             : }
     775             : 
     776             : RefPtr<DtlsIdentity>
     777           0 : PeerConnectionImpl::Identity() const
     778             : {
     779           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
     780           0 :   MOZ_ASSERT(mCertificate);
     781           0 :   return mCertificate->CreateDtlsIdentity();
     782             : }
     783             : 
     784           0 : class CompareCodecPriority {
     785             :   public:
     786           0 :     void SetPreferredCodec(int32_t preferredCodec) {
     787             :       // This pref really ought to be a string, preferably something like
     788             :       // "H264" or "VP8" instead of a payload type.
     789             :       // Bug 1101259.
     790           0 :       std::ostringstream os;
     791           0 :       os << preferredCodec;
     792           0 :       mPreferredCodec = os.str();
     793           0 :     }
     794             : 
     795           0 :     bool operator()(JsepCodecDescription* lhs,
     796             :                     JsepCodecDescription* rhs) const {
     797           0 :       if (!mPreferredCodec.empty() &&
     798           0 :           lhs->mDefaultPt == mPreferredCodec &&
     799           0 :           rhs->mDefaultPt != mPreferredCodec) {
     800           0 :         return true;
     801             :       }
     802             : 
     803           0 :       if (lhs->mStronglyPreferred && !rhs->mStronglyPreferred) {
     804           0 :         return true;
     805             :       }
     806             : 
     807           0 :       return false;
     808             :     }
     809             : 
     810             :   private:
     811             :     std::string mPreferredCodec;
     812             : };
     813             : 
     814             : class ConfigureCodec {
     815             :   public:
     816           0 :     explicit ConfigureCodec(nsCOMPtr<nsIPrefBranch>& branch) :
     817             :       mHardwareH264Enabled(false),
     818             :       mHardwareH264Supported(false),
     819             :       mSoftwareH264Enabled(false),
     820             :       mH264Enabled(false),
     821             :       mVP9Enabled(false),
     822             :       mH264Level(13), // minimum suggested for WebRTC spec
     823             :       mH264MaxBr(0), // Unlimited
     824             :       mH264MaxMbps(0), // Unlimited
     825             :       mVP8MaxFs(0),
     826             :       mVP8MaxFr(0),
     827             :       mUseTmmbr(false),
     828             :       mUseRemb(false),
     829             :       mUseAudioFec(false),
     830             :       mRedUlpfecEnabled(false),
     831           0 :       mDtmfEnabled(false)
     832             :     {
     833             : #ifdef MOZ_WEBRTC_OMX
     834             :       // Check to see if what HW codecs are available (not in use) at this moment.
     835             :       // Note that streaming video decode can reserve a decoder
     836             : 
     837             :       // XXX See bug 1018791 Implement W3 codec reservation policy
     838             :       // Note that currently, OMXCodecReservation needs to be held by an sp<> because it puts
     839             :       // 'this' into an sp<EventListener> to talk to the resource reservation code
     840             : 
     841             :       // This pref is a misnomer; it is solely for h264 _hardware_ support.
     842             :       branch->GetBoolPref("media.peerconnection.video.h264_enabled",
     843             :           &mHardwareH264Enabled);
     844             : 
     845             :       if (mHardwareH264Enabled) {
     846             :         // Ok, it is preffed on. Can we actually do it?
     847             :         android::sp<android::OMXCodecReservation> encode = new android::OMXCodecReservation(true);
     848             :         android::sp<android::OMXCodecReservation> decode = new android::OMXCodecReservation(false);
     849             : 
     850             :         // Currently we just check if they're available right now, which will fail if we're
     851             :         // trying to call ourself, for example.  It will work for most real-world cases, like
     852             :         // if we try to add a person to a 2-way call to make a 3-way mesh call
     853             :         if (encode->ReserveOMXCodec() && decode->ReserveOMXCodec()) {
     854             :           CSFLogDebug( logTag, "%s: H264 hardware codec available", __FUNCTION__);
     855             :           mHardwareH264Supported = true;
     856             :         }
     857             :       }
     858             : 
     859             : #endif // MOZ_WEBRTC_OMX
     860             : 
     861           0 :       mSoftwareH264Enabled = PeerConnectionCtx::GetInstance()->gmpHasH264();
     862             : 
     863           0 :       mH264Enabled = mHardwareH264Supported || mSoftwareH264Enabled;
     864             : 
     865           0 :       branch->GetIntPref("media.navigator.video.h264.level", &mH264Level);
     866           0 :       mH264Level &= 0xFF;
     867             : 
     868           0 :       branch->GetIntPref("media.navigator.video.h264.max_br", &mH264MaxBr);
     869             : 
     870             : #ifdef MOZ_WEBRTC_OMX
     871             :       // Level 1.2; but let's allow CIF@30 or QVGA@30+ by default
     872             :       mH264MaxMbps = 11880;
     873             : #endif
     874             : 
     875           0 :       branch->GetIntPref("media.navigator.video.h264.max_mbps", &mH264MaxMbps);
     876             : 
     877           0 :       branch->GetBoolPref("media.peerconnection.video.vp9_enabled",
     878           0 :           &mVP9Enabled);
     879             : 
     880           0 :       branch->GetIntPref("media.navigator.video.max_fs", &mVP8MaxFs);
     881           0 :       if (mVP8MaxFs <= 0) {
     882           0 :         mVP8MaxFs = 12288; // We must specify something other than 0
     883             :       }
     884             : 
     885           0 :       branch->GetIntPref("media.navigator.video.max_fr", &mVP8MaxFr);
     886           0 :       if (mVP8MaxFr <= 0) {
     887           0 :         mVP8MaxFr = 60; // We must specify something other than 0
     888             :       }
     889             : 
     890             :       // TMMBR is enabled from a pref in about:config
     891           0 :       branch->GetBoolPref("media.navigator.video.use_tmmbr", &mUseTmmbr);
     892             : 
     893             :       // REMB is enabled by default, but can be disabled from about:config
     894           0 :       branch->GetBoolPref("media.navigator.video.use_remb", &mUseRemb);
     895             : 
     896           0 :       branch->GetBoolPref("media.navigator.audio.use_fec", &mUseAudioFec);
     897             : 
     898           0 :       branch->GetBoolPref("media.navigator.video.red_ulpfec_enabled",
     899           0 :                           &mRedUlpfecEnabled);
     900             : 
     901             :       // media.peerconnection.dtmf.enabled controls both sdp generation for
     902             :       // DTMF support as well as DTMF exposure to DOM
     903           0 :       branch->GetBoolPref("media.peerconnection.dtmf.enabled", &mDtmfEnabled);
     904           0 :     }
     905             : 
     906           0 :     void operator()(JsepCodecDescription* codec) const
     907             :     {
     908           0 :       switch (codec->mType) {
     909             :         case SdpMediaSection::kAudio:
     910             :           {
     911             :             JsepAudioCodecDescription& audioCodec =
     912           0 :               static_cast<JsepAudioCodecDescription&>(*codec);
     913           0 :             if (audioCodec.mName == "opus") {
     914           0 :               audioCodec.mFECEnabled = mUseAudioFec;
     915           0 :             } else if (audioCodec.mName == "telephone-event") {
     916           0 :               audioCodec.mEnabled = mDtmfEnabled;
     917             :             }
     918             :           }
     919           0 :           break;
     920             :         case SdpMediaSection::kVideo:
     921             :           {
     922             :             JsepVideoCodecDescription& videoCodec =
     923           0 :               static_cast<JsepVideoCodecDescription&>(*codec);
     924             : 
     925           0 :             if (videoCodec.mName == "H264") {
     926             :               // Override level
     927           0 :               videoCodec.mProfileLevelId &= 0xFFFF00;
     928           0 :               videoCodec.mProfileLevelId |= mH264Level;
     929             : 
     930           0 :               videoCodec.mConstraints.maxBr = mH264MaxBr;
     931             : 
     932           0 :               videoCodec.mConstraints.maxMbps = mH264MaxMbps;
     933             : 
     934             :               // Might disable it, but we set up other params anyway
     935           0 :               videoCodec.mEnabled = mH264Enabled;
     936             : 
     937           0 :               if (videoCodec.mPacketizationMode == 0 && !mSoftwareH264Enabled) {
     938             :                 // We're assuming packetization mode 0 is unsupported by
     939             :                 // hardware.
     940           0 :                 videoCodec.mEnabled = false;
     941             :               }
     942             : 
     943           0 :               if (mHardwareH264Supported) {
     944           0 :                 videoCodec.mStronglyPreferred = true;
     945             :               }
     946           0 :             } else if (videoCodec.mName == "red") {
     947           0 :               videoCodec.mEnabled = mRedUlpfecEnabled;
     948           0 :             } else if (videoCodec.mName == "ulpfec") {
     949           0 :               videoCodec.mEnabled = mRedUlpfecEnabled;
     950           0 :             } else if (videoCodec.mName == "VP8" || videoCodec.mName == "VP9") {
     951           0 :               if (videoCodec.mName == "VP9" && !mVP9Enabled) {
     952           0 :                 videoCodec.mEnabled = false;
     953           0 :                 break;
     954             :               }
     955           0 :               videoCodec.mConstraints.maxFs = mVP8MaxFs;
     956           0 :               videoCodec.mConstraints.maxFps = mVP8MaxFr;
     957             :             }
     958             : 
     959           0 :             if (mUseTmmbr) {
     960           0 :               videoCodec.EnableTmmbr();
     961             :             }
     962           0 :             if (mUseRemb) {
     963           0 :               videoCodec.EnableRemb();
     964             :             }
     965             :           }
     966           0 :           break;
     967             :         case SdpMediaSection::kText:
     968             :         case SdpMediaSection::kApplication:
     969             :         case SdpMediaSection::kMessage:
     970             :           {} // Nothing to configure for these.
     971             :       }
     972           0 :     }
     973             : 
     974             :   private:
     975             :     bool mHardwareH264Enabled;
     976             :     bool mHardwareH264Supported;
     977             :     bool mSoftwareH264Enabled;
     978             :     bool mH264Enabled;
     979             :     bool mVP9Enabled;
     980             :     int32_t mH264Level;
     981             :     int32_t mH264MaxBr;
     982             :     int32_t mH264MaxMbps;
     983             :     int32_t mVP8MaxFs;
     984             :     int32_t mVP8MaxFr;
     985             :     bool mUseTmmbr;
     986             :     bool mUseRemb;
     987             :     bool mUseAudioFec;
     988             :     bool mRedUlpfecEnabled;
     989             :     bool mDtmfEnabled;
     990             : };
     991             : 
     992             : class ConfigureRedCodec {
     993             :   public:
     994           0 :     explicit ConfigureRedCodec(nsCOMPtr<nsIPrefBranch>& branch,
     995           0 :                                std::vector<uint8_t>* redundantEncodings) :
     996           0 :       mRedundantEncodings(redundantEncodings)
     997             :     {
     998             :       // if we wanted to override or modify which encodings are considered
     999             :       // for redundant encodings, we'd probably want to handle it here by
    1000             :       // checking prefs modifying the operator() code below
    1001           0 :     }
    1002             : 
    1003           0 :     void operator()(JsepCodecDescription* codec) const
    1004             :     {
    1005           0 :       if (codec->mType == SdpMediaSection::kVideo &&
    1006           0 :           codec->mEnabled == false) {
    1007           0 :         uint8_t pt = (uint8_t)strtoul(codec->mDefaultPt.c_str(), nullptr, 10);
    1008             :         // don't search for the codec payload type unless we have a valid
    1009             :         // conversion (non-zero)
    1010           0 :         if (pt != 0) {
    1011             :           std::vector<uint8_t>::iterator it =
    1012           0 :             std::find(mRedundantEncodings->begin(),
    1013           0 :                       mRedundantEncodings->end(),
    1014           0 :                       pt);
    1015           0 :           if (it != mRedundantEncodings->end()) {
    1016           0 :             mRedundantEncodings->erase(it);
    1017             :           }
    1018             :         }
    1019             :       }
    1020           0 :     }
    1021             : 
    1022             :   private:
    1023             :     std::vector<uint8_t>* mRedundantEncodings;
    1024             : };
    1025             : 
    1026             : nsresult
    1027           0 : PeerConnectionImpl::ConfigureJsepSessionCodecs() {
    1028             :   nsresult res;
    1029             :   nsCOMPtr<nsIPrefService> prefs =
    1030           0 :     do_GetService("@mozilla.org/preferences-service;1", &res);
    1031             : 
    1032           0 :   if (NS_FAILED(res)) {
    1033           0 :     CSFLogError(logTag, "%s: Couldn't get prefs service, res=%u",
    1034             :         __FUNCTION__,
    1035           0 :         static_cast<unsigned>(res));
    1036           0 :     return res;
    1037             :   }
    1038             : 
    1039           0 :   nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
    1040           0 :   if (!branch) {
    1041           0 :     CSFLogError(logTag, "%s: Couldn't get prefs branch", __FUNCTION__);
    1042           0 :     return NS_ERROR_FAILURE;
    1043             :   }
    1044             : 
    1045           0 :   ConfigureCodec configurer(branch);
    1046           0 :   mJsepSession->ForEachCodec(configurer);
    1047             : 
    1048             :   // first find the red codec description
    1049           0 :   std::vector<JsepCodecDescription*>& codecs = mJsepSession->Codecs();
    1050           0 :   JsepVideoCodecDescription* redCodec = nullptr;
    1051           0 :   for (auto codec : codecs) {
    1052             :     // we only really care about finding the RED codec if it is
    1053             :     // enabled
    1054           0 :     if (codec->mName == "red" && codec->mEnabled) {
    1055           0 :       redCodec = static_cast<JsepVideoCodecDescription*>(codec);
    1056           0 :       break;
    1057             :     }
    1058             :   }
    1059             :   // if red codec was found, configure it for the other enabled codecs
    1060           0 :   if (redCodec) {
    1061           0 :     ConfigureRedCodec configureRed(branch, &(redCodec->mRedundantEncodings));
    1062           0 :     mJsepSession->ForEachCodec(configureRed);
    1063             :   }
    1064             : 
    1065             :   // We use this to sort the list of codecs once everything is configured
    1066           0 :   CompareCodecPriority comparator;
    1067             : 
    1068             :   // Sort by priority
    1069           0 :   int32_t preferredCodec = 0;
    1070           0 :   branch->GetIntPref("media.navigator.video.preferred_codec",
    1071           0 :                      &preferredCodec);
    1072             : 
    1073           0 :   if (preferredCodec) {
    1074           0 :     comparator.SetPreferredCodec(preferredCodec);
    1075             :   }
    1076             : 
    1077           0 :   mJsepSession->SortCodecs(comparator);
    1078           0 :   return NS_OK;
    1079             : }
    1080             : 
    1081             : // Data channels won't work without a window, so in order for the C++ unit
    1082             : // tests to work (it doesn't have a window available) we ifdef the following
    1083             : // two implementations.
    1084             : NS_IMETHODIMP
    1085           0 : PeerConnectionImpl::EnsureDataConnection(uint16_t aLocalPort,
    1086             :                                          uint16_t aNumstreams,
    1087             :                                          uint32_t aMaxMessageSize,
    1088             :                                          bool aMMSSet)
    1089             : {
    1090           0 :   PC_AUTO_ENTER_API_CALL(false);
    1091             : 
    1092           0 :   if (mDataConnection) {
    1093           0 :     CSFLogDebug(logTag,"%s DataConnection already connected",__FUNCTION__);
    1094             :     // Ignore the request to connect when already connected.  This entire
    1095             :     // implementation is temporary.  Ignore aNumstreams as it's merely advisory
    1096             :     // and we increase the number of streams dynamically as needed.
    1097           0 :     return NS_OK;
    1098             :   }
    1099             : 
    1100             :   nsCOMPtr<nsIEventTarget> target = mWindow
    1101           0 :       ? mWindow->EventTargetFor(TaskCategory::Other)
    1102           0 :       : nullptr;
    1103           0 :   mDataConnection = new DataChannelConnection(this, target);
    1104           0 :   if (!mDataConnection->Init(aLocalPort, aNumstreams, true)) {
    1105           0 :     CSFLogError(logTag,"%s DataConnection Init Failed",__FUNCTION__);
    1106           0 :     return NS_ERROR_FAILURE;
    1107             :   }
    1108           0 :   CSFLogDebug(logTag,"%s DataChannelConnection %p attached to %s",
    1109           0 :               __FUNCTION__, (void*) mDataConnection.get(), mHandle.c_str());
    1110           0 :   return NS_OK;
    1111             : }
    1112             : 
    1113             : nsresult
    1114           0 : PeerConnectionImpl::GetDatachannelParameters(
    1115             :     uint32_t* channels,
    1116             :     uint16_t* localport,
    1117             :     uint16_t* remoteport,
    1118             :     uint32_t* remotemaxmessagesize,
    1119             :     bool*     mmsset,
    1120             :     uint16_t* level) const {
    1121             : 
    1122           0 :   auto trackPairs = mJsepSession->GetNegotiatedTrackPairs();
    1123           0 :   for (auto& trackPair : trackPairs) {
    1124             :     bool sendDataChannel =
    1125           0 :       trackPair.mSending &&
    1126           0 :       trackPair.mSending->GetMediaType() == SdpMediaSection::kApplication;
    1127             :     bool recvDataChannel =
    1128           0 :       trackPair.mReceiving &&
    1129           0 :       trackPair.mReceiving->GetMediaType() == SdpMediaSection::kApplication;
    1130             :     (void)recvDataChannel;
    1131           0 :     MOZ_ASSERT(sendDataChannel == recvDataChannel);
    1132             : 
    1133           0 :     if (sendDataChannel) {
    1134             :       // This will release assert if there is no such index, and that's ok
    1135             :       const JsepTrackEncoding& encoding =
    1136           0 :         trackPair.mSending->GetNegotiatedDetails()->GetEncoding(0);
    1137             : 
    1138           0 :       if (encoding.GetCodecs().empty()) {
    1139             :         CSFLogError(logTag, "%s: Negotiated m=application with no codec. "
    1140             :                             "This is likely to be broken.",
    1141           0 :                             __FUNCTION__);
    1142           0 :         return NS_ERROR_FAILURE;
    1143             :       }
    1144             : 
    1145           0 :       for (const JsepCodecDescription* codec : encoding.GetCodecs()) {
    1146           0 :         if (codec->mType != SdpMediaSection::kApplication) {
    1147           0 :           CSFLogError(logTag, "%s: Codec type for m=application was %u, this "
    1148             :                               "is a bug.",
    1149             :                               __FUNCTION__,
    1150           0 :                               static_cast<unsigned>(codec->mType));
    1151           0 :           MOZ_ASSERT(false, "Codec for m=application was not \"application\"");
    1152           0 :           return NS_ERROR_FAILURE;
    1153             :         }
    1154             : 
    1155           0 :         if (codec->mName != "webrtc-datachannel") {
    1156           0 :           CSFLogWarn(logTag, "%s: Codec for m=application was not "
    1157             :                              "webrtc-datachannel (was instead %s). ",
    1158             :                              __FUNCTION__,
    1159           0 :                              codec->mName.c_str());
    1160           0 :           continue;
    1161             :         }
    1162             : 
    1163           0 :         if (codec->mChannels) {
    1164           0 :           *channels = codec->mChannels;
    1165             :         } else {
    1166           0 :           *channels = WEBRTC_DATACHANNEL_STREAMS_DEFAULT;
    1167             :         }
    1168           0 :         *localport =
    1169           0 :           static_cast<const JsepApplicationCodecDescription*>(codec)->mLocalPort;
    1170           0 :         *remoteport =
    1171           0 :           static_cast<const JsepApplicationCodecDescription*>(codec)->mRemotePort;
    1172           0 :         *remotemaxmessagesize = static_cast<const JsepApplicationCodecDescription*>
    1173           0 :           (codec)->mRemoteMaxMessageSize;
    1174           0 :         *mmsset = static_cast<const JsepApplicationCodecDescription*>
    1175           0 :           (codec)->mRemoteMMSSet;
    1176           0 :         if (trackPair.HasBundleLevel()) {
    1177           0 :           *level = static_cast<uint16_t>(trackPair.BundleLevel());
    1178             :         } else {
    1179           0 :           *level = static_cast<uint16_t>(trackPair.mLevel);
    1180             :         }
    1181           0 :         return NS_OK;
    1182             :       }
    1183             :     }
    1184             :   }
    1185             : 
    1186           0 :   *channels = 0;
    1187           0 :   *localport = 0;
    1188           0 :   *remoteport = 0;
    1189           0 :   *remotemaxmessagesize = 0;
    1190           0 :   *mmsset = false;
    1191           0 :   *level = 0;
    1192           0 :   return NS_ERROR_FAILURE;
    1193             : }
    1194             : 
    1195             : /* static */
    1196             : void
    1197           0 : PeerConnectionImpl::DeferredAddTrackToJsepSession(
    1198             :     const std::string& pcHandle,
    1199             :     SdpMediaSection::MediaType type,
    1200             :     const std::string& streamId,
    1201             :     const std::string& trackId)
    1202             : {
    1203           0 :   PeerConnectionWrapper wrapper(pcHandle);
    1204             : 
    1205           0 :   if (wrapper.impl()) {
    1206           0 :     if (!PeerConnectionCtx::GetInstance()->isReady()) {
    1207           0 :       MOZ_CRASH("Why is DeferredAddTrackToJsepSession being executed when the "
    1208             :                 "PeerConnectionCtx isn't ready?");
    1209             :     }
    1210           0 :     wrapper.impl()->AddTrackToJsepSession(type, streamId, trackId);
    1211             :   }
    1212           0 : }
    1213             : 
    1214             : nsresult
    1215           0 : PeerConnectionImpl::AddTrackToJsepSession(SdpMediaSection::MediaType type,
    1216             :                                           const std::string& streamId,
    1217             :                                           const std::string& trackId)
    1218             : {
    1219           0 :   nsresult res = ConfigureJsepSessionCodecs();
    1220           0 :   if (NS_FAILED(res)) {
    1221           0 :     CSFLogError(logTag, "Failed to configure codecs");
    1222           0 :     return res;
    1223             :   }
    1224             : 
    1225           0 :   res = mJsepSession->AddTrack(
    1226           0 :       new JsepTrack(type, streamId, trackId, sdp::kSend));
    1227             : 
    1228           0 :   if (NS_FAILED(res)) {
    1229           0 :     std::string errorString = mJsepSession->GetLastError();
    1230           0 :     CSFLogError(logTag, "%s (%s) : pc = %s, error = %s",
    1231             :                 __FUNCTION__,
    1232             :                 type == SdpMediaSection::kAudio ? "audio" : "video",
    1233             :                 mHandle.c_str(),
    1234           0 :                 errorString.c_str());
    1235           0 :     return NS_ERROR_FAILURE;
    1236             :   }
    1237             : 
    1238           0 :   return NS_OK;
    1239             : }
    1240             : 
    1241             : nsresult
    1242           0 : PeerConnectionImpl::InitializeDataChannel()
    1243             : {
    1244           0 :   PC_AUTO_ENTER_API_CALL(false);
    1245           0 :   CSFLogDebug(logTag, "%s", __FUNCTION__);
    1246             : 
    1247           0 :   uint32_t channels = 0;
    1248           0 :   uint16_t localport = 0;
    1249           0 :   uint16_t remoteport = 0;
    1250           0 :   uint32_t remotemaxmessagesize = 0;
    1251           0 :   bool mmsset = false;
    1252           0 :   uint16_t level = 0;
    1253             :   nsresult rv = GetDatachannelParameters(&channels, &localport, &remoteport,
    1254           0 :                                          &remotemaxmessagesize, &mmsset, &level);
    1255             : 
    1256           0 :   if (NS_FAILED(rv)) {
    1257           0 :     CSFLogDebug(logTag, "%s: We did not negotiate datachannel", __FUNCTION__);
    1258           0 :     return NS_OK;
    1259             :   }
    1260             : 
    1261           0 :   if (channels > MAX_NUM_STREAMS) {
    1262           0 :     channels = MAX_NUM_STREAMS;
    1263             :   }
    1264             : 
    1265           0 :   rv = EnsureDataConnection(localport, channels, remotemaxmessagesize, mmsset);
    1266           0 :   if (NS_SUCCEEDED(rv)) {
    1267             :     // use the specified TransportFlow
    1268           0 :     RefPtr<TransportFlow> flow = mMedia->GetTransportFlow(level, false).get();
    1269           0 :     CSFLogDebug(logTag, "Transportflow[%u] = %p",
    1270           0 :                         static_cast<unsigned>(level), flow.get());
    1271           0 :     if (flow) {
    1272           0 :       if (mDataConnection->ConnectViaTransportFlow(flow,
    1273             :                                                    localport,
    1274             :                                                    remoteport)) {
    1275           0 :         return NS_OK;
    1276             :       }
    1277             :     }
    1278             :     // If we inited the DataConnection, call Destroy() before releasing it
    1279           0 :     mDataConnection->Destroy();
    1280             :   }
    1281           0 :   mDataConnection = nullptr;
    1282           0 :   return NS_ERROR_FAILURE;
    1283             : }
    1284             : 
    1285             : already_AddRefed<nsDOMDataChannel>
    1286           0 : PeerConnectionImpl::CreateDataChannel(const nsAString& aLabel,
    1287             :                                       const nsAString& aProtocol,
    1288             :                                       uint16_t aType,
    1289             :                                       bool ordered,
    1290             :                                       uint16_t aMaxTime,
    1291             :                                       uint16_t aMaxNum,
    1292             :                                       bool aExternalNegotiated,
    1293             :                                       uint16_t aStream,
    1294             :                                       ErrorResult &rv)
    1295             : {
    1296           0 :   RefPtr<nsDOMDataChannel> result;
    1297           0 :   rv = CreateDataChannel(aLabel, aProtocol, aType, ordered,
    1298             :                          aMaxTime, aMaxNum, aExternalNegotiated,
    1299           0 :                          aStream, getter_AddRefs(result));
    1300           0 :   return result.forget();
    1301             : }
    1302             : 
    1303             : NS_IMETHODIMP
    1304           0 : PeerConnectionImpl::CreateDataChannel(const nsAString& aLabel,
    1305             :                                       const nsAString& aProtocol,
    1306             :                                       uint16_t aType,
    1307             :                                       bool ordered,
    1308             :                                       uint16_t aMaxTime,
    1309             :                                       uint16_t aMaxNum,
    1310             :                                       bool aExternalNegotiated,
    1311             :                                       uint16_t aStream,
    1312             :                                       nsDOMDataChannel** aRetval)
    1313             : {
    1314           0 :   PC_AUTO_ENTER_API_CALL(false);
    1315           0 :   MOZ_ASSERT(aRetval);
    1316             : 
    1317           0 :   RefPtr<DataChannel> dataChannel;
    1318             :   DataChannelConnection::Type theType =
    1319           0 :     static_cast<DataChannelConnection::Type>(aType);
    1320             : 
    1321             :   nsresult rv = EnsureDataConnection(WEBRTC_DATACHANNEL_PORT_DEFAULT,
    1322             :                                      WEBRTC_DATACHANNEL_STREAMS_DEFAULT,
    1323             :                                      WEBRTC_DATACHANELL_MAX_MESSAGE_SIZE_DEFAULT,
    1324           0 :                                      false);
    1325           0 :   if (NS_FAILED(rv)) {
    1326           0 :     return rv;
    1327             :   }
    1328           0 :   dataChannel = mDataConnection->Open(
    1329           0 :     NS_ConvertUTF16toUTF8(aLabel), NS_ConvertUTF16toUTF8(aProtocol), theType,
    1330             :     ordered,
    1331           0 :     aType == DataChannelConnection::PARTIAL_RELIABLE_REXMIT ? aMaxNum :
    1332             :     (aType == DataChannelConnection::PARTIAL_RELIABLE_TIMED ? aMaxTime : 0),
    1333             :     nullptr, nullptr, aExternalNegotiated, aStream
    1334           0 :   );
    1335           0 :   NS_ENSURE_TRUE(dataChannel,NS_ERROR_FAILURE);
    1336             : 
    1337           0 :   CSFLogDebug(logTag, "%s: making DOMDataChannel", __FUNCTION__);
    1338             : 
    1339           0 :   if (!mHaveDataStream) {
    1340             : 
    1341           0 :     std::string streamId;
    1342           0 :     std::string trackId;
    1343             : 
    1344             :     // Generate random ids because these aren't linked to any local streams.
    1345           0 :     if (!mUuidGen->Generate(&streamId)) {
    1346           0 :       return NS_ERROR_FAILURE;
    1347             :     }
    1348           0 :     if (!mUuidGen->Generate(&trackId)) {
    1349           0 :       return NS_ERROR_FAILURE;
    1350             :     }
    1351             : 
    1352             :     RefPtr<JsepTrack> track(new JsepTrack(
    1353             :           mozilla::SdpMediaSection::kApplication,
    1354             :           streamId,
    1355             :           trackId,
    1356           0 :           sdp::kSend));
    1357             : 
    1358           0 :     rv = mJsepSession->AddTrack(track);
    1359           0 :     if (NS_FAILED(rv)) {
    1360             :       CSFLogError(logTag, "%s: Failed to add application track.",
    1361           0 :                           __FUNCTION__);
    1362           0 :       return rv;
    1363             :     }
    1364           0 :     mHaveDataStream = true;
    1365           0 :     OnNegotiationNeeded();
    1366             :   }
    1367             :   nsIDOMDataChannel *retval;
    1368           0 :   rv = NS_NewDOMDataChannel(dataChannel.forget(), mWindow, &retval);
    1369           0 :   if (NS_FAILED(rv)) {
    1370           0 :     return rv;
    1371             :   }
    1372           0 :   *aRetval = static_cast<nsDOMDataChannel*>(retval);
    1373           0 :   return NS_OK;
    1374             : }
    1375             : 
    1376             : // do_QueryObjectReferent() - Helps get PeerConnectionObserver from nsWeakPtr.
    1377             : //
    1378             : // nsWeakPtr deals in XPCOM interfaces, while webidl bindings are concrete objs.
    1379             : // TODO: Turn this into a central (template) function somewhere (Bug 939178)
    1380             : //
    1381             : // Without it, each weak-ref call in this file would look like this:
    1382             : //
    1383             : //  nsCOMPtr<nsISupportsWeakReference> tmp = do_QueryReferent(mPCObserver);
    1384             : //  if (!tmp) {
    1385             : //    return;
    1386             : //  }
    1387             : //  RefPtr<nsSupportsWeakReference> tmp2 = do_QueryObject(tmp);
    1388             : //  RefPtr<PeerConnectionObserver> pco = static_cast<PeerConnectionObserver*>(&*tmp2);
    1389             : 
    1390             : static already_AddRefed<PeerConnectionObserver>
    1391           0 : do_QueryObjectReferent(nsIWeakReference* aRawPtr) {
    1392           0 :   nsCOMPtr<nsISupportsWeakReference> tmp = do_QueryReferent(aRawPtr);
    1393           0 :   if (!tmp) {
    1394           0 :     return nullptr;
    1395             :   }
    1396           0 :   RefPtr<nsSupportsWeakReference> tmp2 = do_QueryObject(tmp);
    1397           0 :   RefPtr<PeerConnectionObserver> tmp3 = static_cast<PeerConnectionObserver*>(&*tmp2);
    1398           0 :   return tmp3.forget();
    1399             : }
    1400             : 
    1401             : 
    1402             : // Not a member function so that we don't need to keep the PC live.
    1403           0 : static void NotifyDataChannel_m(RefPtr<nsIDOMDataChannel> aChannel,
    1404             :                                 RefPtr<PeerConnectionObserver> aObserver)
    1405             : {
    1406           0 :   MOZ_ASSERT(NS_IsMainThread());
    1407           0 :   JSErrorResult rv;
    1408           0 :   RefPtr<nsDOMDataChannel> channel = static_cast<nsDOMDataChannel*>(&*aChannel);
    1409           0 :   aObserver->NotifyDataChannel(*channel, rv);
    1410           0 :   NS_DataChannelAppReady(aChannel);
    1411           0 : }
    1412             : 
    1413             : void
    1414           0 : PeerConnectionImpl::NotifyDataChannel(already_AddRefed<DataChannel> aChannel)
    1415             : {
    1416           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    1417             : 
    1418             :   // XXXkhuey this is completely fucked up.  We can't use RefPtr<DataChannel>
    1419             :   // here because DataChannel's AddRef/Release are non-virtual and not visible
    1420             :   // if !MOZILLA_INTERNAL_API, but this function leaks the DataChannel if
    1421             :   // !MOZILLA_INTERNAL_API because it never transfers the ref to
    1422             :   // NS_NewDOMDataChannel.
    1423           0 :   DataChannel* channel = aChannel.take();
    1424           0 :   MOZ_ASSERT(channel);
    1425             : 
    1426           0 :   CSFLogDebug(logTag, "%s: channel: %p", __FUNCTION__, channel);
    1427             : 
    1428           0 :   nsCOMPtr<nsIDOMDataChannel> domchannel;
    1429           0 :   nsresult rv = NS_NewDOMDataChannel(already_AddRefed<DataChannel>(channel),
    1430           0 :                                      mWindow, getter_AddRefs(domchannel));
    1431           0 :   NS_ENSURE_SUCCESS_VOID(rv);
    1432             : 
    1433           0 :   mHaveDataStream = true;
    1434             : 
    1435           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
    1436           0 :   if (!pco) {
    1437           0 :     return;
    1438             :   }
    1439             : 
    1440             :   RUN_ON_THREAD(mThread,
    1441           0 :                 WrapRunnableNM(NotifyDataChannel_m,
    1442           0 :                                domchannel.get(),
    1443             :                                pco),
    1444           0 :                 NS_DISPATCH_NORMAL);
    1445             : }
    1446             : 
    1447             : NS_IMETHODIMP
    1448           0 : PeerConnectionImpl::CreateOffer(const RTCOfferOptions& aOptions)
    1449             : {
    1450           0 :   JsepOfferOptions options;
    1451             :   // convert the RTCOfferOptions to JsepOfferOptions
    1452           0 :   if (aOptions.mOfferToReceiveAudio.WasPassed()) {
    1453             :     options.mOfferToReceiveAudio =
    1454           0 :       mozilla::Some(size_t(aOptions.mOfferToReceiveAudio.Value()));
    1455             :   }
    1456             : 
    1457           0 :   if (aOptions.mOfferToReceiveVideo.WasPassed()) {
    1458             :     options.mOfferToReceiveVideo =
    1459           0 :         mozilla::Some(size_t(aOptions.mOfferToReceiveVideo.Value()));
    1460             :   }
    1461             : 
    1462           0 :   options.mIceRestart = mozilla::Some(aOptions.mIceRestart);
    1463             : 
    1464           0 :   if (aOptions.mMozDontOfferDataChannel.WasPassed()) {
    1465             :     options.mDontOfferDataChannel =
    1466           0 :       mozilla::Some(aOptions.mMozDontOfferDataChannel.Value());
    1467             :   }
    1468           0 :   return CreateOffer(options);
    1469             : }
    1470             : 
    1471           0 : static void DeferredCreateOffer(const std::string& aPcHandle,
    1472             :                                 const JsepOfferOptions& aOptions) {
    1473           0 :   PeerConnectionWrapper wrapper(aPcHandle);
    1474             : 
    1475           0 :   if (wrapper.impl()) {
    1476           0 :     if (!PeerConnectionCtx::GetInstance()->isReady()) {
    1477           0 :       MOZ_CRASH("Why is DeferredCreateOffer being executed when the "
    1478             :                 "PeerConnectionCtx isn't ready?");
    1479             :     }
    1480           0 :     wrapper.impl()->CreateOffer(aOptions);
    1481             :   }
    1482           0 : }
    1483             : 
    1484             : // Used by unit tests and the IDL CreateOffer.
    1485             : NS_IMETHODIMP
    1486           0 : PeerConnectionImpl::CreateOffer(const JsepOfferOptions& aOptions)
    1487             : {
    1488           0 :   PC_AUTO_ENTER_API_CALL(true);
    1489           0 :   bool restartIce = aOptions.mIceRestart.isSome() && *(aOptions.mIceRestart);
    1490           0 :   if (!restartIce &&
    1491           0 :       mMedia->GetIceRestartState() ==
    1492             :           PeerConnectionMedia::ICE_RESTART_PROVISIONAL) {
    1493           0 :     RollbackIceRestart();
    1494             :   }
    1495             : 
    1496           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
    1497           0 :   if (!pco) {
    1498           0 :     return NS_OK;
    1499             :   }
    1500             : 
    1501           0 :   if (!PeerConnectionCtx::GetInstance()->isReady()) {
    1502             :     // Uh oh. We're not ready yet. Enqueue this operation.
    1503           0 :     PeerConnectionCtx::GetInstance()->queueJSEPOperation(
    1504           0 :         WrapRunnableNM(DeferredCreateOffer, mHandle, aOptions));
    1505           0 :     STAMP_TIMECARD(mTimeCard, "Deferring CreateOffer (not ready)");
    1506           0 :     return NS_OK;
    1507             :   }
    1508             : 
    1509           0 :   CSFLogDebug(logTag, "CreateOffer()");
    1510             : 
    1511             :   nsresult nrv;
    1512           0 :   if (restartIce &&
    1513           0 :       !mJsepSession->GetLocalDescription(kJsepDescriptionCurrent).empty()) {
    1514             :     // If restart is requested and a restart is already in progress, we
    1515             :     // need to make room for the restart request so we either rollback
    1516             :     // or finalize to "clear" the previous restart.
    1517           0 :     if (mMedia->GetIceRestartState() ==
    1518             :             PeerConnectionMedia::ICE_RESTART_PROVISIONAL) {
    1519             :       // we're mid-restart and can rollback
    1520           0 :       RollbackIceRestart();
    1521           0 :     } else if (mMedia->GetIceRestartState() ==
    1522             :                    PeerConnectionMedia::ICE_RESTART_COMMITTED) {
    1523             :       // we're mid-restart and can't rollback, finalize restart even
    1524             :       // though we're not really ready yet
    1525           0 :       FinalizeIceRestart();
    1526             :     }
    1527             : 
    1528           0 :     CSFLogInfo(logTag, "Offerer restarting ice");
    1529           0 :     nrv = SetupIceRestart();
    1530           0 :     if (NS_FAILED(nrv)) {
    1531             :       CSFLogError(logTag, "%s: SetupIceRestart failed, res=%u",
    1532             :                            __FUNCTION__,
    1533           0 :                            static_cast<unsigned>(nrv));
    1534           0 :       return nrv;
    1535             :     }
    1536             :   }
    1537             : 
    1538           0 :   nrv = ConfigureJsepSessionCodecs();
    1539           0 :   if (NS_FAILED(nrv)) {
    1540           0 :     CSFLogError(logTag, "Failed to configure codecs");
    1541           0 :     return nrv;
    1542             :   }
    1543             : 
    1544           0 :   STAMP_TIMECARD(mTimeCard, "Create Offer");
    1545             : 
    1546           0 :   std::string offer;
    1547             : 
    1548           0 :   nrv = mJsepSession->CreateOffer(aOptions, &offer);
    1549           0 :   JSErrorResult rv;
    1550           0 :   if (NS_FAILED(nrv)) {
    1551             :     Error error;
    1552           0 :     switch (nrv) {
    1553             :       case NS_ERROR_UNEXPECTED:
    1554           0 :         error = kInvalidState;
    1555           0 :         break;
    1556             :       default:
    1557           0 :         error = kInternalError;
    1558             :     }
    1559           0 :     std::string errorString = mJsepSession->GetLastError();
    1560             : 
    1561           0 :     CSFLogError(logTag, "%s: pc = %s, error = %s",
    1562           0 :                 __FUNCTION__, mHandle.c_str(), errorString.c_str());
    1563           0 :     pco->OnCreateOfferError(error, ObString(errorString.c_str()), rv);
    1564             :   } else {
    1565           0 :     pco->OnCreateOfferSuccess(ObString(offer.c_str()), rv);
    1566             :   }
    1567             : 
    1568           0 :   UpdateSignalingState();
    1569           0 :   return NS_OK;
    1570             : }
    1571             : 
    1572             : NS_IMETHODIMP
    1573           0 : PeerConnectionImpl::CreateAnswer()
    1574             : {
    1575           0 :   PC_AUTO_ENTER_API_CALL(true);
    1576             : 
    1577           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
    1578           0 :   if (!pco) {
    1579           0 :     return NS_OK;
    1580             :   }
    1581             : 
    1582           0 :   CSFLogDebug(logTag, "CreateAnswer()");
    1583             : 
    1584             :   nsresult nrv;
    1585           0 :   if (mJsepSession->RemoteIceIsRestarting()) {
    1586           0 :     if (mMedia->GetIceRestartState() ==
    1587             :             PeerConnectionMedia::ICE_RESTART_COMMITTED) {
    1588           0 :       FinalizeIceRestart();
    1589           0 :     } else if (!mMedia->IsIceRestarting()) {
    1590           0 :       CSFLogInfo(logTag, "Answerer restarting ice");
    1591           0 :       nrv = SetupIceRestart();
    1592           0 :       if (NS_FAILED(nrv)) {
    1593             :         CSFLogError(logTag, "%s: SetupIceRestart failed, res=%u",
    1594             :                              __FUNCTION__,
    1595           0 :                              static_cast<unsigned>(nrv));
    1596           0 :         return nrv;
    1597             :       }
    1598             :     }
    1599             :   }
    1600             : 
    1601           0 :   STAMP_TIMECARD(mTimeCard, "Create Answer");
    1602             :   // TODO(bug 1098015): Once RTCAnswerOptions is standardized, we'll need to
    1603             :   // add it as a param to CreateAnswer, and convert it here.
    1604             :   JsepAnswerOptions options;
    1605           0 :   std::string answer;
    1606             : 
    1607           0 :   nrv = mJsepSession->CreateAnswer(options, &answer);
    1608           0 :   JSErrorResult rv;
    1609           0 :   if (NS_FAILED(nrv)) {
    1610             :     Error error;
    1611           0 :     switch (nrv) {
    1612             :       case NS_ERROR_UNEXPECTED:
    1613           0 :         error = kInvalidState;
    1614           0 :         break;
    1615             :       default:
    1616           0 :         error = kInternalError;
    1617             :     }
    1618           0 :     std::string errorString = mJsepSession->GetLastError();
    1619             : 
    1620           0 :     CSFLogError(logTag, "%s: pc = %s, error = %s",
    1621           0 :                 __FUNCTION__, mHandle.c_str(), errorString.c_str());
    1622           0 :     pco->OnCreateAnswerError(error, ObString(errorString.c_str()), rv);
    1623             :   } else {
    1624           0 :     pco->OnCreateAnswerSuccess(ObString(answer.c_str()), rv);
    1625             :   }
    1626             : 
    1627           0 :   UpdateSignalingState();
    1628             : 
    1629           0 :   return NS_OK;
    1630             : }
    1631             : 
    1632             : nsresult
    1633           0 : PeerConnectionImpl::SetupIceRestart()
    1634             : {
    1635           0 :   if (mMedia->IsIceRestarting()) {
    1636             :     CSFLogError(logTag, "%s: ICE already restarting",
    1637           0 :                          __FUNCTION__);
    1638           0 :     return NS_ERROR_UNEXPECTED;
    1639             :   }
    1640             : 
    1641           0 :   std::string ufrag = mMedia->ice_ctx()->GetNewUfrag();
    1642           0 :   std::string pwd = mMedia->ice_ctx()->GetNewPwd();
    1643           0 :   if (ufrag.empty() || pwd.empty()) {
    1644           0 :     CSFLogError(logTag, "%s: Bad ICE credentials (ufrag:'%s'/pwd:'%s')",
    1645             :                          __FUNCTION__,
    1646           0 :                          ufrag.c_str(), pwd.c_str());
    1647           0 :     return NS_ERROR_UNEXPECTED;
    1648             :   }
    1649             : 
    1650             :   // hold on to the current ice creds in case of rollback
    1651           0 :   mPreviousIceUfrag = mJsepSession->GetUfrag();
    1652           0 :   mPreviousIcePwd = mJsepSession->GetPwd();
    1653           0 :   mMedia->BeginIceRestart(ufrag, pwd);
    1654             : 
    1655           0 :   nsresult nrv = mJsepSession->SetIceCredentials(ufrag, pwd);
    1656           0 :   if (NS_FAILED(nrv)) {
    1657             :     CSFLogError(logTag, "%s: Couldn't set ICE credentials, res=%u",
    1658             :                          __FUNCTION__,
    1659           0 :                          static_cast<unsigned>(nrv));
    1660           0 :     return nrv;
    1661             :   }
    1662             : 
    1663           0 :   return NS_OK;
    1664             : }
    1665             : 
    1666             : nsresult
    1667           0 : PeerConnectionImpl::RollbackIceRestart()
    1668             : {
    1669           0 :   mMedia->RollbackIceRestart();
    1670             :   // put back the previous ice creds
    1671           0 :   nsresult nrv = mJsepSession->SetIceCredentials(mPreviousIceUfrag,
    1672           0 :                                                  mPreviousIcePwd);
    1673           0 :   if (NS_FAILED(nrv)) {
    1674             :     CSFLogError(logTag, "%s: Couldn't set ICE credentials, res=%u",
    1675             :                          __FUNCTION__,
    1676           0 :                          static_cast<unsigned>(nrv));
    1677           0 :     return nrv;
    1678             :   }
    1679           0 :   mPreviousIceUfrag = "";
    1680           0 :   mPreviousIcePwd = "";
    1681             : 
    1682           0 :   return NS_OK;
    1683             : }
    1684             : 
    1685             : void
    1686           0 : PeerConnectionImpl::FinalizeIceRestart()
    1687             : {
    1688           0 :   mMedia->FinalizeIceRestart();
    1689             :   // clear the previous ice creds since they are no longer needed
    1690           0 :   mPreviousIceUfrag = "";
    1691           0 :   mPreviousIcePwd = "";
    1692           0 : }
    1693             : 
    1694             : NS_IMETHODIMP
    1695           0 : PeerConnectionImpl::SetLocalDescription(int32_t aAction, const char* aSDP)
    1696             : {
    1697           0 :   PC_AUTO_ENTER_API_CALL(true);
    1698             : 
    1699           0 :   if (!aSDP) {
    1700           0 :     CSFLogError(logTag, "%s - aSDP is NULL", __FUNCTION__);
    1701           0 :     return NS_ERROR_FAILURE;
    1702             :   }
    1703             : 
    1704           0 :   JSErrorResult rv;
    1705           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
    1706           0 :   if (!pco) {
    1707           0 :     return NS_OK;
    1708             :   }
    1709             : 
    1710           0 :   STAMP_TIMECARD(mTimeCard, "Set Local Description");
    1711             : 
    1712           0 :   bool isolated = mMedia->AnyLocalTrackHasPeerIdentity();
    1713           0 :   mPrivacyRequested = mPrivacyRequested || isolated;
    1714             : 
    1715           0 :   mLocalRequestedSDP = aSDP;
    1716             : 
    1717             :   JsepSdpType sdpType;
    1718           0 :   switch (aAction) {
    1719             :     case IPeerConnection::kActionOffer:
    1720           0 :       sdpType = mozilla::kJsepSdpOffer;
    1721           0 :       break;
    1722             :     case IPeerConnection::kActionAnswer:
    1723           0 :       sdpType = mozilla::kJsepSdpAnswer;
    1724           0 :       break;
    1725             :     case IPeerConnection::kActionPRAnswer:
    1726           0 :       sdpType = mozilla::kJsepSdpPranswer;
    1727           0 :       break;
    1728             :     case IPeerConnection::kActionRollback:
    1729           0 :       sdpType = mozilla::kJsepSdpRollback;
    1730           0 :       break;
    1731             :     default:
    1732           0 :       MOZ_ASSERT(false);
    1733             :       return NS_ERROR_FAILURE;
    1734             : 
    1735             :   }
    1736           0 :   nsresult nrv = mJsepSession->SetLocalDescription(sdpType,
    1737           0 :                                                    mLocalRequestedSDP);
    1738           0 :   if (NS_FAILED(nrv)) {
    1739             :     Error error;
    1740           0 :     switch (nrv) {
    1741             :       case NS_ERROR_INVALID_ARG:
    1742           0 :         error = kInvalidSessionDescription;
    1743           0 :         break;
    1744             :       case NS_ERROR_UNEXPECTED:
    1745           0 :         error = kInvalidState;
    1746           0 :         break;
    1747             :       default:
    1748           0 :         error = kInternalError;
    1749             :     }
    1750             : 
    1751           0 :     std::string errorString = mJsepSession->GetLastError();
    1752           0 :     CSFLogError(logTag, "%s: pc = %s, error = %s",
    1753           0 :                 __FUNCTION__, mHandle.c_str(), errorString.c_str());
    1754           0 :     pco->OnSetLocalDescriptionError(error, ObString(errorString.c_str()), rv);
    1755             :   } else {
    1756           0 :     pco->OnSetLocalDescriptionSuccess(rv);
    1757             :   }
    1758             : 
    1759           0 :   UpdateSignalingState(sdpType == mozilla::kJsepSdpRollback);
    1760           0 :   return NS_OK;
    1761             : }
    1762             : 
    1763           0 : static void DeferredSetRemote(const std::string& aPcHandle,
    1764             :                               int32_t aAction,
    1765             :                               const std::string& aSdp) {
    1766           0 :   PeerConnectionWrapper wrapper(aPcHandle);
    1767             : 
    1768           0 :   if (wrapper.impl()) {
    1769           0 :     if (!PeerConnectionCtx::GetInstance()->isReady()) {
    1770           0 :       MOZ_CRASH("Why is DeferredSetRemote being executed when the "
    1771             :                 "PeerConnectionCtx isn't ready?");
    1772             :     }
    1773           0 :     wrapper.impl()->SetRemoteDescription(aAction, aSdp.c_str());
    1774             :   }
    1775           0 : }
    1776             : 
    1777           0 : static void StartTrack(MediaStream* aSource,
    1778             :                        TrackID aTrackId,
    1779             :                        nsAutoPtr<MediaSegment>&& aSegment) {
    1780           0 :   class Message : public ControlMessage {
    1781             :    public:
    1782           0 :     Message(MediaStream* aStream,
    1783             :             TrackID aTrack,
    1784             :             nsAutoPtr<MediaSegment>&& aSegment)
    1785           0 :       : ControlMessage(aStream),
    1786             :         track_id_(aTrack),
    1787           0 :         segment_(aSegment) {}
    1788             : 
    1789           0 :     virtual void Run() override {
    1790           0 :       TrackRate track_rate = segment_->GetType() == MediaSegment::AUDIO ?
    1791           0 :         WEBRTC_DEFAULT_SAMPLE_RATE : mStream->GraphRate();
    1792           0 :       StreamTime current_end = mStream->GetTracksEnd();
    1793             :       TrackTicks current_ticks =
    1794           0 :         mStream->TimeToTicksRoundUp(track_rate, current_end);
    1795             : 
    1796             :       // Add a track 'now' to avoid possible underrun, especially if we add
    1797             :       // a track "later".
    1798             : 
    1799           0 :       if (current_end != 0L) {
    1800           0 :         CSFLogDebug(logTag, "added track @ %u -> %f",
    1801             :                     static_cast<unsigned>(current_end),
    1802           0 :                     mStream->StreamTimeToSeconds(current_end));
    1803             :       }
    1804             : 
    1805             :       // To avoid assertions, we need to insert a dummy segment that covers up
    1806             :       // to the "start" time for the track
    1807           0 :       segment_->AppendNullData(current_ticks);
    1808           0 :       if (segment_->GetType() == MediaSegment::AUDIO) {
    1809           0 :         mStream->AsSourceStream()->AddAudioTrack(
    1810             :             track_id_,
    1811             :             WEBRTC_DEFAULT_SAMPLE_RATE,
    1812             :             0,
    1813           0 :             static_cast<AudioSegment*>(segment_.forget()));
    1814             :       } else {
    1815           0 :         mStream->AsSourceStream()->AddTrack(track_id_, 0, segment_.forget());
    1816             :       }
    1817           0 :     }
    1818             :    private:
    1819             :     TrackID track_id_;
    1820             :     nsAutoPtr<MediaSegment> segment_;
    1821             :   };
    1822             : 
    1823           0 :   aSource->GraphImpl()->AppendMessage(
    1824           0 :       MakeUnique<Message>(aSource, aTrackId, Move(aSegment)));
    1825             :   CSFLogInfo(logTag, "Dispatched track-add for track id %u on stream %p",
    1826           0 :              aTrackId, aSource);
    1827           0 : }
    1828             : 
    1829             : 
    1830             : nsresult
    1831           0 : PeerConnectionImpl::CreateNewRemoteTracks(RefPtr<PeerConnectionObserver>& aPco)
    1832             : {
    1833           0 :   JSErrorResult jrv;
    1834             : 
    1835             :   std::vector<RefPtr<JsepTrack>> newTracks =
    1836           0 :     mJsepSession->GetRemoteTracksAdded();
    1837             : 
    1838             :   // Group new tracks by stream id
    1839           0 :   std::map<std::string, std::vector<RefPtr<JsepTrack>>> tracksByStreamId;
    1840           0 :   for (auto track : newTracks) {
    1841           0 :     if (track->GetMediaType() == mozilla::SdpMediaSection::kApplication) {
    1842             :       // Ignore datachannel
    1843           0 :       continue;
    1844             :     }
    1845             : 
    1846           0 :     tracksByStreamId[track->GetStreamId()].push_back(track);
    1847             :   }
    1848             : 
    1849           0 :   for (auto& id : tracksByStreamId) {
    1850           0 :     std::string streamId = id.first;
    1851           0 :     std::vector<RefPtr<JsepTrack>>& tracks = id.second;
    1852             : 
    1853           0 :     bool newStream = false;
    1854             :     RefPtr<RemoteSourceStreamInfo> info =
    1855           0 :       mMedia->GetRemoteStreamById(streamId);
    1856           0 :     if (!info) {
    1857           0 :       newStream = true;
    1858           0 :       nsresult nrv = CreateRemoteSourceStreamInfo(&info, streamId);
    1859           0 :       if (NS_FAILED(nrv)) {
    1860           0 :         aPco->OnSetRemoteDescriptionError(
    1861             :             kInternalError,
    1862           0 :             ObString("CreateRemoteSourceStreamInfo failed"),
    1863           0 :             jrv);
    1864           0 :         return nrv;
    1865             :       }
    1866             : 
    1867           0 :       nrv = mMedia->AddRemoteStream(info);
    1868           0 :       if (NS_FAILED(nrv)) {
    1869           0 :         aPco->OnSetRemoteDescriptionError(
    1870             :             kInternalError,
    1871           0 :             ObString("AddRemoteStream failed"),
    1872           0 :             jrv);
    1873           0 :         return nrv;
    1874             :       }
    1875             : 
    1876           0 :       CSFLogDebug(logTag, "Added remote stream %s", info->GetId().c_str());
    1877             : 
    1878           0 :       info->GetMediaStream()->AssignId(NS_ConvertUTF8toUTF16(streamId.c_str()));
    1879           0 :       info->GetMediaStream()->SetLogicalStreamStartTime(
    1880           0 :           info->GetMediaStream()->GetPlaybackStream()->GetCurrentTime());
    1881             :     }
    1882             : 
    1883           0 :     Sequence<OwningNonNull<DOMMediaStream>> streams;
    1884           0 :     if (!streams.AppendElement(OwningNonNull<DOMMediaStream>(
    1885           0 :             *info->GetMediaStream()),
    1886             :             fallible)) {
    1887           0 :       MOZ_ASSERT(false);
    1888             :       return NS_ERROR_FAILURE;
    1889             :     }
    1890             : 
    1891             :     // Set the principal used for creating the tracks. This makes the stream
    1892             :     // data (audio/video samples) accessible to the receiving page. We're
    1893             :     // only certain that privacy hasn't been requested if we're connected.
    1894           0 :     nsCOMPtr<nsIPrincipal> principal;
    1895           0 :     nsIDocument* doc = GetWindow()->GetExtantDoc();
    1896           0 :     MOZ_ASSERT(doc);
    1897           0 :     if (mDtlsConnected && !PrivacyRequested()) {
    1898           0 :       principal = doc->NodePrincipal();
    1899             :     } else {
    1900             :       // we're either certain that we need isolation for the streams, OR
    1901             :       // we're not sure and we can fix the stream in SetDtlsConnected
    1902           0 :       principal =  NullPrincipal::CreateWithInheritedAttributes(doc->NodePrincipal());
    1903             :     }
    1904             : 
    1905             :     // We need to select unique ids, just use max + 1
    1906           0 :     TrackID maxTrackId = 0;
    1907             :     {
    1908           0 :       nsTArray<RefPtr<dom::MediaStreamTrack>> domTracks;
    1909           0 :       info->GetMediaStream()->GetTracks(domTracks);
    1910           0 :       for (auto& track : domTracks) {
    1911           0 :         maxTrackId = std::max(maxTrackId, track->mTrackID);
    1912             :       }
    1913             :     }
    1914             : 
    1915           0 :     for (RefPtr<JsepTrack>& track : tracks) {
    1916           0 :       std::string webrtcTrackId(track->GetTrackId());
    1917           0 :       if (!info->HasTrack(webrtcTrackId)) {
    1918             :         RefPtr<RemoteTrackSource> source =
    1919           0 :           new RemoteTrackSource(principal, nsString());
    1920           0 :         TrackID trackID = ++maxTrackId;
    1921           0 :         RefPtr<MediaStreamTrack> domTrack;
    1922           0 :         nsAutoPtr<MediaSegment> segment;
    1923           0 :         if (track->GetMediaType() == SdpMediaSection::kAudio) {
    1924             :           domTrack =
    1925           0 :             info->GetMediaStream()->CreateDOMTrack(trackID,
    1926             :                                                    MediaSegment::AUDIO,
    1927           0 :                                                    source);
    1928           0 :           info->GetMediaStream()->AddTrackInternal(domTrack);
    1929           0 :           segment = new AudioSegment;
    1930             :         } else {
    1931             :           domTrack =
    1932           0 :             info->GetMediaStream()->CreateDOMTrack(trackID,
    1933             :                                                    MediaSegment::VIDEO,
    1934           0 :                                                    source);
    1935           0 :           info->GetMediaStream()->AddTrackInternal(domTrack);
    1936           0 :           segment = new VideoSegment;
    1937             :         }
    1938             : 
    1939           0 :         StartTrack(info->GetMediaStream()->GetInputStream()->AsSourceStream(),
    1940           0 :                    trackID, Move(segment));
    1941           0 :         info->AddTrack(webrtcTrackId, domTrack);
    1942           0 :         CSFLogDebug(logTag, "Added remote track %s/%s",
    1943           0 :                     info->GetId().c_str(), webrtcTrackId.c_str());
    1944             : 
    1945           0 :         domTrack->AssignId(NS_ConvertUTF8toUTF16(webrtcTrackId.c_str()));
    1946           0 :         aPco->OnAddTrack(*domTrack, streams, jrv);
    1947           0 :         if (jrv.Failed()) {
    1948           0 :           CSFLogError(logTag, ": OnAddTrack(%s) failed! Error: %u",
    1949             :                       webrtcTrackId.c_str(),
    1950           0 :                       jrv.ErrorCodeAsInt());
    1951             :         }
    1952             :       }
    1953             :     }
    1954             : 
    1955           0 :     if (newStream) {
    1956           0 :       aPco->OnAddStream(*info->GetMediaStream(), jrv);
    1957           0 :       if (jrv.Failed()) {
    1958           0 :         CSFLogError(logTag, ": OnAddStream() failed! Error: %u",
    1959           0 :                     jrv.ErrorCodeAsInt());
    1960             :       }
    1961             :     }
    1962             :   }
    1963           0 :   return NS_OK;
    1964             : }
    1965             : 
    1966             : void
    1967           0 : PeerConnectionImpl::RemoveOldRemoteTracks(RefPtr<PeerConnectionObserver>& aPco)
    1968             : {
    1969           0 :   JSErrorResult jrv;
    1970             : 
    1971             :   std::vector<RefPtr<JsepTrack>> removedTracks =
    1972           0 :     mJsepSession->GetRemoteTracksRemoved();
    1973             : 
    1974           0 :   for (auto& removedTrack : removedTracks) {
    1975           0 :     const std::string& streamId = removedTrack->GetStreamId();
    1976           0 :     const std::string& trackId = removedTrack->GetTrackId();
    1977             : 
    1978           0 :     RefPtr<RemoteSourceStreamInfo> info = mMedia->GetRemoteStreamById(streamId);
    1979           0 :     if (!info) {
    1980           0 :       MOZ_ASSERT(false, "A stream/track was removed that wasn't in PCMedia. "
    1981             :                         "This is a bug.");
    1982             :       continue;
    1983             :     }
    1984             : 
    1985           0 :     mMedia->RemoveRemoteTrack(streamId, trackId);
    1986             : 
    1987           0 :     DOMMediaStream* stream = info->GetMediaStream();
    1988           0 :     nsTArray<RefPtr<MediaStreamTrack>> tracks;
    1989           0 :     stream->GetTracks(tracks);
    1990           0 :     for (auto& track : tracks) {
    1991           0 :       if (PeerConnectionImpl::GetTrackId(*track) == trackId) {
    1992           0 :         aPco->OnRemoveTrack(*track, jrv);
    1993           0 :         break;
    1994             :       }
    1995             :     }
    1996             : 
    1997             :     // We might be holding the last ref, but that's ok.
    1998           0 :     if (!info->GetTrackCount()) {
    1999           0 :       aPco->OnRemoveStream(*stream, jrv);
    2000             :     }
    2001             :   }
    2002           0 : }
    2003             : 
    2004             : NS_IMETHODIMP
    2005           0 : PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP)
    2006             : {
    2007           0 :   PC_AUTO_ENTER_API_CALL(true);
    2008             : 
    2009           0 :   if (!aSDP) {
    2010           0 :     CSFLogError(logTag, "%s - aSDP is NULL", __FUNCTION__);
    2011           0 :     return NS_ERROR_FAILURE;
    2012             :   }
    2013             : 
    2014           0 :   JSErrorResult jrv;
    2015           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
    2016           0 :   if (!pco) {
    2017           0 :     return NS_OK;
    2018             :   }
    2019             : 
    2020           0 :   if (action == IPeerConnection::kActionOffer) {
    2021           0 :     if (!PeerConnectionCtx::GetInstance()->isReady()) {
    2022             :       // Uh oh. We're not ready yet. Enqueue this operation. (This must be a
    2023             :       // remote offer, or else we would not have gotten this far)
    2024           0 :       PeerConnectionCtx::GetInstance()->queueJSEPOperation(
    2025           0 :           WrapRunnableNM(DeferredSetRemote,
    2026             :             mHandle,
    2027             :             action,
    2028           0 :             std::string(aSDP)));
    2029           0 :       STAMP_TIMECARD(mTimeCard, "Deferring SetRemote (not ready)");
    2030           0 :       return NS_OK;
    2031             :     }
    2032             : 
    2033           0 :     nsresult nrv = ConfigureJsepSessionCodecs();
    2034           0 :     if (NS_FAILED(nrv)) {
    2035           0 :       CSFLogError(logTag, "Failed to configure codecs");
    2036           0 :       return nrv;
    2037             :     }
    2038             :   }
    2039             : 
    2040           0 :   STAMP_TIMECARD(mTimeCard, "Set Remote Description");
    2041             : 
    2042           0 :   mRemoteRequestedSDP = aSDP;
    2043             :   JsepSdpType sdpType;
    2044           0 :   switch (action) {
    2045             :     case IPeerConnection::kActionOffer:
    2046           0 :       sdpType = mozilla::kJsepSdpOffer;
    2047           0 :       break;
    2048             :     case IPeerConnection::kActionAnswer:
    2049           0 :       sdpType = mozilla::kJsepSdpAnswer;
    2050           0 :       break;
    2051             :     case IPeerConnection::kActionPRAnswer:
    2052           0 :       sdpType = mozilla::kJsepSdpPranswer;
    2053           0 :       break;
    2054             :     case IPeerConnection::kActionRollback:
    2055           0 :       sdpType = mozilla::kJsepSdpRollback;
    2056           0 :       break;
    2057             :     default:
    2058           0 :       MOZ_ASSERT(false);
    2059             :       return NS_ERROR_FAILURE;
    2060             :   }
    2061             : 
    2062           0 :   nsresult nrv = mJsepSession->SetRemoteDescription(sdpType,
    2063           0 :                                                     mRemoteRequestedSDP);
    2064           0 :   if (NS_FAILED(nrv)) {
    2065             :     Error error;
    2066           0 :     switch (nrv) {
    2067             :       case NS_ERROR_INVALID_ARG:
    2068           0 :         error = kInvalidSessionDescription;
    2069           0 :         break;
    2070             :       case NS_ERROR_UNEXPECTED:
    2071           0 :         error = kInvalidState;
    2072           0 :         break;
    2073             :       default:
    2074           0 :         error = kInternalError;
    2075             :     }
    2076             : 
    2077           0 :     std::string errorString = mJsepSession->GetLastError();
    2078           0 :     CSFLogError(logTag, "%s: pc = %s, error = %s",
    2079           0 :                 __FUNCTION__, mHandle.c_str(), errorString.c_str());
    2080           0 :     pco->OnSetRemoteDescriptionError(error, ObString(errorString.c_str()), jrv);
    2081             :   } else {
    2082           0 :     nrv = CreateNewRemoteTracks(pco);
    2083           0 :     if (NS_FAILED(nrv)) {
    2084             :       // aPco was already notified, just return early.
    2085           0 :       return NS_OK;
    2086             :     }
    2087             : 
    2088           0 :     RemoveOldRemoteTracks(pco);
    2089             : 
    2090           0 :     pco->OnSetRemoteDescriptionSuccess(jrv);
    2091           0 :     startCallTelem();
    2092             :   }
    2093             : 
    2094           0 :   UpdateSignalingState(sdpType == mozilla::kJsepSdpRollback);
    2095           0 :   return NS_OK;
    2096             : }
    2097             : 
    2098             : // WebRTC uses highres time relative to the UNIX epoch (Jan 1, 1970, UTC).
    2099             : 
    2100             : nsresult
    2101           0 : PeerConnectionImpl::GetTimeSinceEpoch(DOMHighResTimeStamp *result) {
    2102           0 :   MOZ_ASSERT(NS_IsMainThread());
    2103           0 :   Performance *perf = mWindow->GetPerformance();
    2104           0 :   NS_ENSURE_TRUE(perf && perf->Timing(), NS_ERROR_UNEXPECTED);
    2105           0 :   *result = perf->Now() + perf->Timing()->NavigationStart();
    2106           0 :   return NS_OK;
    2107             : }
    2108             : 
    2109             : class RTCStatsReportInternalConstruct : public RTCStatsReportInternal {
    2110             : public:
    2111           0 :   RTCStatsReportInternalConstruct(const nsString &pcid, DOMHighResTimeStamp now) {
    2112           0 :     mPcid = pcid;
    2113           0 :     mRtpContributingSourceStats.Construct();
    2114           0 :     mInboundRTPStreamStats.Construct();
    2115           0 :     mOutboundRTPStreamStats.Construct();
    2116           0 :     mMediaStreamTrackStats.Construct();
    2117           0 :     mMediaStreamStats.Construct();
    2118           0 :     mTransportStats.Construct();
    2119           0 :     mIceComponentStats.Construct();
    2120           0 :     mIceCandidatePairStats.Construct();
    2121           0 :     mIceCandidateStats.Construct();
    2122           0 :     mCodecStats.Construct();
    2123           0 :     mTimestamp.Construct(now);
    2124           0 :   }
    2125             : };
    2126             : 
    2127             : NS_IMETHODIMP
    2128           0 : PeerConnectionImpl::GetStats(MediaStreamTrack *aSelector) {
    2129           0 :   PC_AUTO_ENTER_API_CALL(true);
    2130             : 
    2131           0 :   if (!mMedia) {
    2132             :     // Since we zero this out before the d'tor, we should check.
    2133           0 :     return NS_ERROR_UNEXPECTED;
    2134             :   }
    2135             : 
    2136           0 :   nsAutoPtr<RTCStatsQuery> query(new RTCStatsQuery(false));
    2137             : 
    2138           0 :   nsresult rv = BuildStatsQuery_m(aSelector, query.get());
    2139             : 
    2140           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2141             : 
    2142           0 :   RUN_ON_THREAD(mSTSThread,
    2143           0 :                 WrapRunnableNM(&PeerConnectionImpl::GetStatsForPCObserver_s,
    2144             :                                mHandle,
    2145             :                                query),
    2146           0 :                 NS_DISPATCH_NORMAL);
    2147           0 :   return NS_OK;
    2148             : }
    2149             : 
    2150             : NS_IMETHODIMP
    2151           0 : PeerConnectionImpl::AddIceCandidate(const char* aCandidate, const char* aMid, unsigned short aLevel) {
    2152           0 :   PC_AUTO_ENTER_API_CALL(true);
    2153             : 
    2154           0 :   if (mForceIceTcp && std::string::npos != std::string(aCandidate).find(" UDP ")) {
    2155           0 :     CSFLogError(logTag, "Blocking remote UDP candidate: %s", aCandidate);
    2156           0 :     return NS_OK;
    2157             :   }
    2158             : 
    2159           0 :   JSErrorResult rv;
    2160           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
    2161           0 :   if (!pco) {
    2162           0 :     return NS_OK;
    2163             :   }
    2164             : 
    2165           0 :   STAMP_TIMECARD(mTimeCard, "Add Ice Candidate");
    2166             : 
    2167           0 :   CSFLogDebug(logTag, "AddIceCandidate: %s", aCandidate);
    2168             : 
    2169             :   // When remote candidates are added before our ICE ctx is up and running
    2170             :   // (the transition to New is async through STS, so this is not impossible),
    2171             :   // we won't record them as trickle candidates. Is this what we want?
    2172           0 :   if(!mIceStartTime.IsNull()) {
    2173           0 :     TimeDuration timeDelta = TimeStamp::Now() - mIceStartTime;
    2174           0 :     if (mIceConnectionState == PCImplIceConnectionState::Failed) {
    2175           0 :       Telemetry::Accumulate(Telemetry::WEBRTC_ICE_LATE_TRICKLE_ARRIVAL_TIME,
    2176           0 :                             timeDelta.ToMilliseconds());
    2177             :     } else {
    2178           0 :       Telemetry::Accumulate(Telemetry::WEBRTC_ICE_ON_TIME_TRICKLE_ARRIVAL_TIME,
    2179           0 :                             timeDelta.ToMilliseconds());
    2180             :     }
    2181             :   }
    2182             : 
    2183           0 :   nsresult res = mJsepSession->AddRemoteIceCandidate(aCandidate, aMid, aLevel);
    2184             : 
    2185           0 :   if (NS_SUCCEEDED(res)) {
    2186             :     // We do not bother PCMedia about this before offer/answer concludes.
    2187             :     // Once offer/answer concludes, PCMedia will extract these candidates from
    2188             :     // the remote SDP.
    2189           0 :     if (mSignalingState == PCImplSignalingState::SignalingStable) {
    2190           0 :       mMedia->AddIceCandidate(aCandidate, aMid, aLevel);
    2191             :     }
    2192           0 :     pco->OnAddIceCandidateSuccess(rv);
    2193             :   } else {
    2194           0 :     ++mAddCandidateErrorCount;
    2195             :     Error error;
    2196           0 :     switch (res) {
    2197             :       case NS_ERROR_UNEXPECTED:
    2198           0 :         error = kInvalidState;
    2199           0 :         break;
    2200             :       case NS_ERROR_INVALID_ARG:
    2201           0 :         error = kInvalidCandidate;
    2202           0 :         break;
    2203             :       default:
    2204           0 :         error = kInternalError;
    2205             :     }
    2206             : 
    2207           0 :     std::string errorString = mJsepSession->GetLastError();
    2208             : 
    2209           0 :     CSFLogError(logTag, "Failed to incorporate remote candidate into SDP:"
    2210             :                         " res = %u, candidate = %s, level = %u, error = %s",
    2211             :                         static_cast<unsigned>(res),
    2212             :                         aCandidate,
    2213             :                         static_cast<unsigned>(aLevel),
    2214           0 :                         errorString.c_str());
    2215             : 
    2216           0 :     pco->OnAddIceCandidateError(error, ObString(errorString.c_str()), rv);
    2217             :   }
    2218             : 
    2219           0 :   return NS_OK;
    2220             : }
    2221             : 
    2222             : void
    2223           0 : PeerConnectionImpl::UpdateNetworkState(bool online) {
    2224           0 :   if (!mMedia) {
    2225           0 :     return;
    2226             :   }
    2227           0 :   mMedia->UpdateNetworkState(online);
    2228             : }
    2229             : 
    2230             : NS_IMETHODIMP
    2231           0 : PeerConnectionImpl::CloseStreams() {
    2232           0 :   PC_AUTO_ENTER_API_CALL(false);
    2233             : 
    2234           0 :   return NS_OK;
    2235             : }
    2236             : 
    2237             : nsresult
    2238           0 : PeerConnectionImpl::SetPeerIdentity(const nsAString& aPeerIdentity)
    2239             : {
    2240           0 :   PC_AUTO_ENTER_API_CALL(true);
    2241           0 :   MOZ_ASSERT(!aPeerIdentity.IsEmpty());
    2242             : 
    2243             :   // once set, this can't be changed
    2244           0 :   if (mPeerIdentity) {
    2245           0 :     if (!mPeerIdentity->Equals(aPeerIdentity)) {
    2246           0 :       return NS_ERROR_FAILURE;
    2247             :     }
    2248             :   } else {
    2249           0 :     mPeerIdentity = new PeerIdentity(aPeerIdentity);
    2250           0 :     nsIDocument* doc = GetWindow()->GetExtantDoc();
    2251           0 :     if (!doc) {
    2252           0 :       CSFLogInfo(logTag, "Can't update principal on streams; document gone");
    2253           0 :       return NS_ERROR_FAILURE;
    2254             :     }
    2255           0 :     MediaStreamTrack* allTracks = nullptr;
    2256           0 :     mMedia->UpdateSinkIdentity_m(allTracks, doc->NodePrincipal(), mPeerIdentity);
    2257             :   }
    2258           0 :   return NS_OK;
    2259             : }
    2260             : 
    2261             : nsresult
    2262           0 : PeerConnectionImpl::SetDtlsConnected(bool aPrivacyRequested)
    2263             : {
    2264           0 :   PC_AUTO_ENTER_API_CALL(false);
    2265             : 
    2266             :   // For this, as with mPrivacyRequested, once we've connected to a peer, we
    2267             :   // fixate on that peer.  Dealing with multiple peers or connections is more
    2268             :   // than this run-down wreck of an object can handle.
    2269             :   // Besides, this is only used to say if we have been connected ever.
    2270           0 :   if (!mPrivacyRequested && !aPrivacyRequested && !mDtlsConnected) {
    2271             :     // now we know that privacy isn't needed for sure
    2272           0 :     nsIDocument* doc = GetWindow()->GetExtantDoc();
    2273           0 :     if (!doc) {
    2274           0 :       CSFLogInfo(logTag, "Can't update principal on streams; document gone");
    2275           0 :       return NS_ERROR_FAILURE;
    2276             :     }
    2277           0 :     mMedia->UpdateRemoteStreamPrincipals_m(doc->NodePrincipal());
    2278             :   }
    2279           0 :   mDtlsConnected = true;
    2280           0 :   mPrivacyRequested = mPrivacyRequested || aPrivacyRequested;
    2281           0 :   return NS_OK;
    2282             : }
    2283             : 
    2284             : void
    2285           0 : PeerConnectionImpl::PrincipalChanged(MediaStreamTrack* aTrack) {
    2286           0 :   nsIDocument* doc = GetWindow()->GetExtantDoc();
    2287           0 :   if (doc) {
    2288           0 :     mMedia->UpdateSinkIdentity_m(aTrack, doc->NodePrincipal(), mPeerIdentity);
    2289             :   } else {
    2290           0 :     CSFLogInfo(logTag, "Can't update sink principal; document gone");
    2291             :   }
    2292           0 : }
    2293             : 
    2294             : std::string
    2295           0 : PeerConnectionImpl::GetTrackId(const MediaStreamTrack& aTrack)
    2296             : {
    2297           0 :   nsString wideTrackId;
    2298           0 :   aTrack.GetId(wideTrackId);
    2299           0 :   return NS_ConvertUTF16toUTF8(wideTrackId).get();
    2300             : }
    2301             : 
    2302             : std::string
    2303           0 : PeerConnectionImpl::GetStreamId(const DOMMediaStream& aStream)
    2304             : {
    2305           0 :   nsString wideStreamId;
    2306           0 :   aStream.GetId(wideStreamId);
    2307           0 :   return NS_ConvertUTF16toUTF8(wideStreamId).get();
    2308             : }
    2309             : 
    2310             : void
    2311           0 : PeerConnectionImpl::OnMediaError(const std::string& aError)
    2312             : {
    2313           0 :   CSFLogError(logTag, "Encountered media error! %s", aError.c_str());
    2314             :   // TODO: Let content know about this somehow.
    2315           0 : }
    2316             : 
    2317             : nsresult
    2318           0 : PeerConnectionImpl::AddTrack(MediaStreamTrack& aTrack,
    2319             :                              const Sequence<OwningNonNull<DOMMediaStream>>& aStreams)
    2320             : {
    2321           0 :   PC_AUTO_ENTER_API_CALL(true);
    2322             : 
    2323           0 :   if (!aStreams.Length()) {
    2324           0 :     CSFLogError(logTag, "%s: At least one stream arg required", __FUNCTION__);
    2325           0 :     return NS_ERROR_FAILURE;
    2326             :   }
    2327             : 
    2328           0 :   return AddTrack(aTrack, aStreams[0]);
    2329             : }
    2330             : 
    2331             : nsresult
    2332           0 : PeerConnectionImpl::AddTrack(MediaStreamTrack& aTrack,
    2333             :                              DOMMediaStream& aMediaStream)
    2334             : {
    2335           0 :   std::string streamId = PeerConnectionImpl::GetStreamId(aMediaStream);
    2336           0 :   std::string trackId = PeerConnectionImpl::GetTrackId(aTrack);
    2337           0 :   nsresult res = mMedia->AddTrack(aMediaStream, streamId, aTrack, trackId);
    2338           0 :   if (NS_FAILED(res)) {
    2339           0 :     return res;
    2340             :   }
    2341             : 
    2342           0 :   CSFLogDebug(logTag, "Added track (%s) to stream %s",
    2343           0 :                       trackId.c_str(), streamId.c_str());
    2344             : 
    2345           0 :   aTrack.AddPrincipalChangeObserver(this);
    2346           0 :   PrincipalChanged(&aTrack);
    2347             : 
    2348           0 :   if (aTrack.AsAudioStreamTrack()) {
    2349           0 :     res = AddTrackToJsepSession(SdpMediaSection::kAudio, streamId, trackId);
    2350           0 :     if (NS_FAILED(res)) {
    2351           0 :       return res;
    2352             :     }
    2353             :   }
    2354             : 
    2355           0 :   if (aTrack.AsVideoStreamTrack()) {
    2356           0 :     if (!Preferences::GetBool("media.peerconnection.video.enabled", true)) {
    2357             :       // Before this code was moved, this would silently ignore just like it
    2358             :       // does now. Is this actually what we want to do?
    2359           0 :       return NS_OK;
    2360             :     }
    2361             : 
    2362           0 :     res = AddTrackToJsepSession(SdpMediaSection::kVideo, streamId, trackId);
    2363           0 :     if (NS_FAILED(res)) {
    2364           0 :       return res;
    2365             :     }
    2366             :   }
    2367           0 :   OnNegotiationNeeded();
    2368           0 :   return NS_OK;
    2369             : }
    2370             : 
    2371             : RefPtr<MediaPipeline>
    2372           0 : PeerConnectionImpl::GetMediaPipelineForTrack(MediaStreamTrack& aRecvTrack)
    2373             : {
    2374           0 :   for (size_t i = 0; i < mMedia->RemoteStreamsLength(); ++i) {
    2375           0 :     if (mMedia->GetRemoteStreamByIndex(i)->GetMediaStream()->
    2376           0 :         HasTrack(aRecvTrack)) {
    2377           0 :       auto& pipelines = mMedia->GetRemoteStreamByIndex(i)->GetPipelines();
    2378           0 :       std::string trackId = PeerConnectionImpl::GetTrackId(aRecvTrack);
    2379           0 :       auto it = pipelines.find(trackId);
    2380           0 :       if (it != pipelines.end()) {
    2381           0 :         return it->second;
    2382             :       }
    2383             :     }
    2384             :   }
    2385             : 
    2386           0 :   return nullptr;
    2387             : }
    2388             : 
    2389             : nsresult
    2390           0 : PeerConnectionImpl::AddRIDExtension(MediaStreamTrack& aRecvTrack,
    2391             :                                     unsigned short aExtensionId)
    2392             : {
    2393           0 :   RefPtr<MediaPipeline> pipeline = GetMediaPipelineForTrack(aRecvTrack);
    2394           0 :   if (pipeline) {
    2395           0 :     pipeline->AddRIDExtension_m(aExtensionId);
    2396             :   }
    2397           0 :   return NS_OK;
    2398             : }
    2399             : 
    2400             : nsresult
    2401           0 : PeerConnectionImpl::AddRIDFilter(MediaStreamTrack& aRecvTrack,
    2402             :                                  const nsAString& aRid)
    2403             : {
    2404           0 :   RefPtr<MediaPipeline> pipeline = GetMediaPipelineForTrack(aRecvTrack);
    2405           0 :   if (pipeline) {
    2406           0 :     pipeline->AddRIDFilter_m(NS_ConvertUTF16toUTF8(aRid).get());
    2407             :   }
    2408           0 :   return NS_OK;
    2409             : }
    2410             : 
    2411             : NS_IMETHODIMP
    2412           0 : PeerConnectionImpl::RemoveTrack(MediaStreamTrack& aTrack) {
    2413           0 :   PC_AUTO_ENTER_API_CALL(true);
    2414             : 
    2415           0 :   std::string trackId = PeerConnectionImpl::GetTrackId(aTrack);
    2416             : 
    2417           0 :   nsString wideTrackId;
    2418           0 :   aTrack.GetId(wideTrackId);
    2419           0 :   for (size_t i = 0; i < mDTMFStates.Length(); ++i) {
    2420           0 :     if (mDTMFStates[i].mTrackId == wideTrackId) {
    2421           0 :       mDTMFStates[i].mSendTimer->Cancel();
    2422           0 :       mDTMFStates.RemoveElementAt(i);
    2423           0 :       break;
    2424             :     }
    2425             :   }
    2426             : 
    2427           0 :   RefPtr<LocalSourceStreamInfo> info = media()->GetLocalStreamByTrackId(trackId);
    2428             : 
    2429           0 :   if (!info) {
    2430           0 :     CSFLogError(logTag, "%s: Unknown stream", __FUNCTION__);
    2431           0 :     return NS_ERROR_INVALID_ARG;
    2432             :   }
    2433             : 
    2434             :   nsresult rv =
    2435           0 :     mJsepSession->RemoveTrack(info->GetId(), trackId);
    2436             : 
    2437           0 :   if (NS_FAILED(rv)) {
    2438           0 :     CSFLogError(logTag, "%s: Unknown stream/track ids %s %s",
    2439             :                 __FUNCTION__,
    2440             :                 info->GetId().c_str(),
    2441           0 :                 trackId.c_str());
    2442           0 :     return rv;
    2443             :   }
    2444             : 
    2445           0 :   media()->RemoveLocalTrack(info->GetId(), trackId);
    2446             : 
    2447           0 :   aTrack.RemovePrincipalChangeObserver(this);
    2448             : 
    2449           0 :   OnNegotiationNeeded();
    2450             : 
    2451           0 :   return NS_OK;
    2452             : }
    2453             : 
    2454           0 : static int GetDTMFToneCode(uint16_t c)
    2455             : {
    2456           0 :   const char* DTMF_TONECODES = "0123456789*#ABCD";
    2457             : 
    2458           0 :   if (c == ',') {
    2459             :     // , is a special character indicating a 2 second delay
    2460           0 :     return -1;
    2461             :   }
    2462             : 
    2463           0 :   const char* i = strchr(DTMF_TONECODES, c);
    2464           0 :   MOZ_ASSERT(i);
    2465           0 :   return i - DTMF_TONECODES;
    2466             : }
    2467             : 
    2468             : NS_IMETHODIMP
    2469           0 : PeerConnectionImpl::InsertDTMF(mozilla::dom::RTCRtpSender& sender,
    2470             :                                const nsAString& tones, uint32_t duration,
    2471             :                                uint32_t interToneGap) {
    2472           0 :   PC_AUTO_ENTER_API_CALL(false);
    2473             : 
    2474             :   // Check values passed in from PeerConnection.js
    2475           0 :   MOZ_ASSERT(duration >= 40, "duration must be at least 40");
    2476           0 :   MOZ_ASSERT(duration <= 6000, "duration must be at most 6000");
    2477           0 :   MOZ_ASSERT(interToneGap >= 30, "interToneGap must be at least 30");
    2478             : 
    2479           0 :   JSErrorResult jrv;
    2480             : 
    2481             :   // Retrieve track
    2482           0 :   RefPtr<MediaStreamTrack> mst = sender.GetTrack(jrv);
    2483           0 :   if (jrv.Failed()) {
    2484           0 :     NS_WARNING("Failed to retrieve track for RTCRtpSender!");
    2485           0 :     return jrv.StealNSResult();
    2486             :   }
    2487             : 
    2488           0 :   nsString senderTrackId;
    2489           0 :   mst->GetId(senderTrackId);
    2490             : 
    2491             :   // Attempt to locate state for the DTMFSender
    2492           0 :   DTMFState* state = nullptr;
    2493           0 :   for (auto& dtmfState : mDTMFStates) {
    2494           0 :     if (dtmfState.mTrackId == senderTrackId) {
    2495           0 :       state = &dtmfState;
    2496           0 :       break;
    2497             :     }
    2498             :   }
    2499             : 
    2500             :   // No state yet, create a new one
    2501           0 :   if (!state) {
    2502           0 :     state = mDTMFStates.AppendElement();
    2503           0 :     state->mPeerConnectionImpl = this;
    2504           0 :     state->mTrackId = senderTrackId;
    2505           0 :     state->mSendTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
    2506           0 :     MOZ_ASSERT(state->mSendTimer);
    2507             :   }
    2508           0 :   MOZ_ASSERT(state);
    2509             : 
    2510           0 :   auto trackPairs = mJsepSession->GetNegotiatedTrackPairs();
    2511           0 :   state->mLevel = -1;
    2512           0 :   for (auto& trackPair : trackPairs) {
    2513           0 :     if (state->mTrackId.EqualsASCII(trackPair.mSending->GetTrackId().c_str())) {
    2514           0 :       if (trackPair.HasBundleLevel()) {
    2515           0 :         state->mLevel = trackPair.BundleLevel();
    2516             :       } else {
    2517           0 :         state->mLevel = trackPair.mLevel;
    2518             :       }
    2519           0 :       break;
    2520             :     }
    2521             :   }
    2522             : 
    2523           0 :   state->mTones = tones;
    2524           0 :   state->mDuration = duration;
    2525           0 :   state->mInterToneGap = interToneGap;
    2526           0 :   if (!state->mTones.IsEmpty()) {
    2527           0 :     state->mSendTimer->InitWithNamedFuncCallback(DTMFSendTimerCallback_m, state, 0,
    2528             :                                                  nsITimer::TYPE_ONE_SHOT,
    2529           0 :                                                  "DTMFSendTimerCallback_m");
    2530             :   }
    2531           0 :   return NS_OK;
    2532             : }
    2533             : 
    2534             : NS_IMETHODIMP
    2535           0 : PeerConnectionImpl::GetDTMFToneBuffer(mozilla::dom::RTCRtpSender& sender,
    2536             :                                       nsAString& outToneBuffer) {
    2537           0 :   PC_AUTO_ENTER_API_CALL(false);
    2538             : 
    2539           0 :   JSErrorResult jrv;
    2540             : 
    2541             :   // Retrieve track
    2542           0 :   RefPtr<MediaStreamTrack> mst = sender.GetTrack(jrv);
    2543           0 :   if (jrv.Failed()) {
    2544           0 :     NS_WARNING("Failed to retrieve track for RTCRtpSender!");
    2545           0 :     return jrv.StealNSResult();
    2546             :   }
    2547             : 
    2548           0 :   nsString senderTrackId;
    2549           0 :   mst->GetId(senderTrackId);
    2550             : 
    2551             :   // Attempt to locate state for the DTMFSender
    2552           0 :   for (auto& dtmfState : mDTMFStates) {
    2553           0 :     if (dtmfState.mTrackId == senderTrackId) {
    2554           0 :       outToneBuffer = dtmfState.mTones;
    2555           0 :       break;
    2556             :     }
    2557             :   }
    2558             : 
    2559           0 :   return NS_OK;
    2560             : }
    2561             : 
    2562             : NS_IMETHODIMP
    2563           0 : PeerConnectionImpl::ReplaceTrack(MediaStreamTrack& aThisTrack,
    2564             :                                  MediaStreamTrack& aWithTrack) {
    2565           0 :   PC_AUTO_ENTER_API_CALL(true);
    2566             : 
    2567           0 :   nsString trackId;
    2568           0 :   aThisTrack.GetId(trackId);
    2569             : 
    2570           0 :   for (size_t i = 0; i < mDTMFStates.Length(); ++i) {
    2571           0 :     if (mDTMFStates[i].mTrackId == trackId) {
    2572           0 :       mDTMFStates[i].mSendTimer->Cancel();
    2573           0 :       mDTMFStates.RemoveElementAt(i);
    2574           0 :       break;
    2575             :     }
    2576             :   }
    2577             : 
    2578           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
    2579           0 :   if (!pco) {
    2580           0 :     return NS_ERROR_UNEXPECTED;
    2581             :   }
    2582           0 :   JSErrorResult jrv;
    2583             : 
    2584           0 :   if (&aThisTrack == &aWithTrack) {
    2585           0 :     pco->OnReplaceTrackSuccess(jrv);
    2586           0 :     if (jrv.Failed()) {
    2587           0 :       CSFLogError(logTag, "Error firing replaceTrack success callback");
    2588           0 :       return NS_ERROR_UNEXPECTED;
    2589             :     }
    2590           0 :     return NS_OK;
    2591             :   }
    2592             : 
    2593           0 :   nsString thisKind;
    2594           0 :   aThisTrack.GetKind(thisKind);
    2595           0 :   nsString withKind;
    2596           0 :   aWithTrack.GetKind(withKind);
    2597             : 
    2598           0 :   if (thisKind != withKind) {
    2599           0 :     pco->OnReplaceTrackError(kIncompatibleMediaStreamTrack,
    2600           0 :                              ObString(mJsepSession->GetLastError().c_str()),
    2601           0 :                              jrv);
    2602           0 :     if (jrv.Failed()) {
    2603           0 :       CSFLogError(logTag, "Error firing replaceTrack success callback");
    2604           0 :       return NS_ERROR_UNEXPECTED;
    2605             :     }
    2606           0 :     return NS_OK;
    2607             :   }
    2608           0 :   std::string origTrackId = PeerConnectionImpl::GetTrackId(aThisTrack);
    2609           0 :   std::string newTrackId = PeerConnectionImpl::GetTrackId(aWithTrack);
    2610             : 
    2611             :   RefPtr<LocalSourceStreamInfo> info =
    2612           0 :     media()->GetLocalStreamByTrackId(origTrackId);
    2613           0 :   if (!info) {
    2614           0 :     CSFLogError(logTag, "Could not find stream from trackId");
    2615           0 :     return NS_ERROR_UNEXPECTED;
    2616             :   }
    2617             : 
    2618           0 :   std::string origStreamId = info->GetId();
    2619             :   std::string newStreamId =
    2620           0 :     PeerConnectionImpl::GetStreamId(*aWithTrack.mOwningStream);
    2621             : 
    2622           0 :   nsresult rv = mJsepSession->ReplaceTrack(origStreamId,
    2623             :                                            origTrackId,
    2624             :                                            newStreamId,
    2625           0 :                                            newTrackId);
    2626           0 :   if (NS_FAILED(rv)) {
    2627           0 :     pco->OnReplaceTrackError(kInvalidMediastreamTrack,
    2628           0 :                              ObString(mJsepSession->GetLastError().c_str()),
    2629           0 :                              jrv);
    2630           0 :     if (jrv.Failed()) {
    2631           0 :       CSFLogError(logTag, "Error firing replaceTrack error callback");
    2632           0 :       return NS_ERROR_UNEXPECTED;
    2633             :     }
    2634           0 :     return NS_OK;
    2635             :   }
    2636             : 
    2637           0 :   rv = media()->ReplaceTrack(origStreamId,
    2638             :                              origTrackId,
    2639             :                              aWithTrack,
    2640             :                              newStreamId,
    2641           0 :                              newTrackId);
    2642             : 
    2643           0 :   if (NS_FAILED(rv)) {
    2644           0 :     CSFLogError(logTag, "Unexpected error in ReplaceTrack: %d",
    2645           0 :                         static_cast<int>(rv));
    2646           0 :     pco->OnReplaceTrackError(kInvalidMediastreamTrack,
    2647           0 :                              ObString("Failed to replace track"),
    2648           0 :                              jrv);
    2649           0 :     if (jrv.Failed()) {
    2650           0 :       CSFLogError(logTag, "Error firing replaceTrack error callback");
    2651           0 :       return NS_ERROR_UNEXPECTED;
    2652             :     }
    2653           0 :     return NS_OK;
    2654             :   }
    2655           0 :   aThisTrack.RemovePrincipalChangeObserver(this);
    2656           0 :   aWithTrack.AddPrincipalChangeObserver(this);
    2657           0 :   PrincipalChanged(&aWithTrack);
    2658             : 
    2659             :   // We update the media pipelines here so we can apply different codec
    2660             :   // settings for different sources (e.g. screensharing as opposed to camera.)
    2661             :   // TODO: We should probably only do this if the source has in fact changed.
    2662             : 
    2663           0 :   if (NS_FAILED((rv = mMedia->UpdateMediaPipelines(*mJsepSession)))) {
    2664           0 :     CSFLogError(logTag, "Error Updating MediaPipelines");
    2665           0 :     return rv;
    2666             :   }
    2667             : 
    2668           0 :   pco->OnReplaceTrackSuccess(jrv);
    2669           0 :   if (jrv.Failed()) {
    2670           0 :     CSFLogError(logTag, "Error firing replaceTrack success callback");
    2671           0 :     return NS_ERROR_UNEXPECTED;
    2672             :   }
    2673             : 
    2674           0 :   return NS_OK;
    2675             : }
    2676             : 
    2677             : NS_IMETHODIMP
    2678           0 : PeerConnectionImpl::SetParameters(MediaStreamTrack& aTrack,
    2679             :                                   const RTCRtpParameters& aParameters) {
    2680           0 :   PC_AUTO_ENTER_API_CALL(true);
    2681             : 
    2682           0 :   std::vector<JsepTrack::JsConstraints> constraints;
    2683           0 :   if (aParameters.mEncodings.WasPassed()) {
    2684           0 :     for (auto& encoding : aParameters.mEncodings.Value()) {
    2685           0 :       JsepTrack::JsConstraints constraint;
    2686           0 :       if (encoding.mRid.WasPassed()) {
    2687           0 :         constraint.rid = NS_ConvertUTF16toUTF8(encoding.mRid.Value()).get();
    2688             :       }
    2689           0 :       if (encoding.mMaxBitrate.WasPassed()) {
    2690           0 :         constraint.constraints.maxBr = encoding.mMaxBitrate.Value();
    2691             :       }
    2692           0 :       constraint.constraints.scaleDownBy = encoding.mScaleResolutionDownBy;
    2693           0 :       constraints.push_back(constraint);
    2694             :     }
    2695             :   }
    2696           0 :   return SetParameters(aTrack, constraints);
    2697             : }
    2698             : 
    2699             : nsresult
    2700           0 : PeerConnectionImpl::SetParameters(
    2701             :     MediaStreamTrack& aTrack,
    2702             :     const std::vector<JsepTrack::JsConstraints>& aConstraints)
    2703             : {
    2704           0 :   std::string trackId = PeerConnectionImpl::GetTrackId(aTrack);
    2705           0 :   RefPtr<LocalSourceStreamInfo> info = media()->GetLocalStreamByTrackId(trackId);
    2706           0 :   if (!info) {
    2707           0 :     CSFLogError(logTag, "%s: Unknown stream", __FUNCTION__);
    2708           0 :     return NS_ERROR_INVALID_ARG;
    2709             :   }
    2710           0 :   std::string streamId = info->GetId();
    2711             : 
    2712           0 :   return mJsepSession->SetParameters(streamId, trackId, aConstraints);
    2713             : }
    2714             : 
    2715             : NS_IMETHODIMP
    2716           0 : PeerConnectionImpl::GetParameters(MediaStreamTrack& aTrack,
    2717             :                                   RTCRtpParameters& aOutParameters) {
    2718           0 :   PC_AUTO_ENTER_API_CALL(true);
    2719             : 
    2720           0 :   std::vector<JsepTrack::JsConstraints> constraints;
    2721           0 :   nsresult rv = GetParameters(aTrack, &constraints);
    2722           0 :   if (NS_FAILED(rv)) {
    2723           0 :     return rv;
    2724             :   }
    2725           0 :   aOutParameters.mEncodings.Construct();
    2726           0 :   for (auto& constraint : constraints) {
    2727           0 :     RTCRtpEncodingParameters encoding;
    2728           0 :     encoding.mRid.Construct(NS_ConvertASCIItoUTF16(constraint.rid.c_str()));
    2729           0 :     encoding.mMaxBitrate.Construct(constraint.constraints.maxBr);
    2730           0 :     encoding.mScaleResolutionDownBy = constraint.constraints.scaleDownBy;
    2731           0 :     aOutParameters.mEncodings.Value().AppendElement(Move(encoding), fallible);
    2732             :   }
    2733           0 :   return NS_OK;
    2734             : }
    2735             : 
    2736             : nsresult
    2737           0 : PeerConnectionImpl::GetParameters(
    2738             :     MediaStreamTrack& aTrack,
    2739             :     std::vector<JsepTrack::JsConstraints>* aOutConstraints)
    2740             : {
    2741           0 :   std::string trackId = PeerConnectionImpl::GetTrackId(aTrack);
    2742           0 :   RefPtr<LocalSourceStreamInfo> info = media()->GetLocalStreamByTrackId(trackId);
    2743           0 :   if (!info) {
    2744           0 :     CSFLogError(logTag, "%s: Unknown stream", __FUNCTION__);
    2745           0 :     return NS_ERROR_INVALID_ARG;
    2746             :   }
    2747           0 :   std::string streamId = info->GetId();
    2748             : 
    2749           0 :   return mJsepSession->GetParameters(streamId, trackId, aOutConstraints);
    2750             : }
    2751             : 
    2752             : nsresult
    2753           0 : PeerConnectionImpl::CalculateFingerprint(
    2754             :     const std::string& algorithm,
    2755             :     std::vector<uint8_t>* fingerprint) const {
    2756             :   uint8_t buf[DtlsIdentity::HASH_ALGORITHM_MAX_LENGTH];
    2757           0 :   size_t len = 0;
    2758             : 
    2759           0 :   MOZ_ASSERT(fingerprint);
    2760           0 :   const UniqueCERTCertificate& cert = mCertificate->Certificate();
    2761           0 :   nsresult rv = DtlsIdentity::ComputeFingerprint(cert, algorithm,
    2762             :                                                  &buf[0], sizeof(buf),
    2763           0 :                                                  &len);
    2764           0 :   if (NS_FAILED(rv)) {
    2765             :     CSFLogError(logTag, "Unable to calculate certificate fingerprint, rv=%u",
    2766           0 :                         static_cast<unsigned>(rv));
    2767           0 :     return rv;
    2768             :   }
    2769           0 :   MOZ_ASSERT(len > 0 && len <= DtlsIdentity::HASH_ALGORITHM_MAX_LENGTH);
    2770           0 :   fingerprint->assign(buf, buf + len);
    2771           0 :   return NS_OK;
    2772             : }
    2773             : 
    2774             : NS_IMETHODIMP
    2775           0 : PeerConnectionImpl::GetFingerprint(char** fingerprint)
    2776             : {
    2777           0 :   MOZ_ASSERT(fingerprint);
    2778           0 :   MOZ_ASSERT(mCertificate);
    2779           0 :   std::vector<uint8_t> fp;
    2780           0 :   nsresult rv = CalculateFingerprint(DtlsIdentity::DEFAULT_HASH_ALGORITHM, &fp);
    2781           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2782           0 :   std::ostringstream os;
    2783             :   os << DtlsIdentity::DEFAULT_HASH_ALGORITHM << ' '
    2784           0 :      << SdpFingerprintAttributeList::FormatFingerprint(fp);
    2785           0 :   std::string fpStr = os.str();
    2786             : 
    2787           0 :   char* tmp = new char[fpStr.size() + 1];
    2788           0 :   std::copy(fpStr.begin(), fpStr.end(), tmp);
    2789           0 :   tmp[fpStr.size()] = '\0';
    2790             : 
    2791           0 :   *fingerprint = tmp;
    2792           0 :   return NS_OK;
    2793             : }
    2794             : 
    2795             : NS_IMETHODIMP
    2796           0 : PeerConnectionImpl::GetLocalDescription(nsAString& aSDP)
    2797             : {
    2798           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    2799             : 
    2800           0 :   std::string localSdp = mJsepSession->GetLocalDescription(
    2801           0 :       kJsepDescriptionPendingOrCurrent);
    2802           0 :   aSDP = NS_ConvertASCIItoUTF16(localSdp.c_str());
    2803             : 
    2804           0 :   return NS_OK;
    2805             : }
    2806             : 
    2807             : NS_IMETHODIMP
    2808           0 : PeerConnectionImpl::GetCurrentLocalDescription(nsAString& aSDP)
    2809             : {
    2810           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    2811             : 
    2812           0 :   std::string localSdp = mJsepSession->GetLocalDescription(kJsepDescriptionCurrent);
    2813           0 :   aSDP = NS_ConvertASCIItoUTF16(localSdp.c_str());
    2814             : 
    2815           0 :   return NS_OK;
    2816             : }
    2817             : 
    2818             : NS_IMETHODIMP
    2819           0 : PeerConnectionImpl::GetPendingLocalDescription(nsAString& aSDP)
    2820             : {
    2821           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    2822             : 
    2823           0 :   std::string localSdp = mJsepSession->GetLocalDescription(kJsepDescriptionPending);
    2824           0 :   aSDP = NS_ConvertASCIItoUTF16(localSdp.c_str());
    2825             : 
    2826           0 :   return NS_OK;
    2827             : }
    2828             : 
    2829             : NS_IMETHODIMP
    2830           0 : PeerConnectionImpl::GetRemoteDescription(nsAString& aSDP)
    2831             : {
    2832           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    2833             : 
    2834           0 :   std::string remoteSdp = mJsepSession->GetRemoteDescription(
    2835           0 :       kJsepDescriptionPendingOrCurrent);
    2836           0 :   aSDP = NS_ConvertASCIItoUTF16(remoteSdp.c_str());
    2837             : 
    2838           0 :   return NS_OK;
    2839             : }
    2840             : 
    2841             : NS_IMETHODIMP
    2842           0 : PeerConnectionImpl::GetCurrentRemoteDescription(nsAString& aSDP)
    2843             : {
    2844           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    2845             : 
    2846           0 :   std::string remoteSdp = mJsepSession->GetRemoteDescription(kJsepDescriptionCurrent);
    2847           0 :   aSDP = NS_ConvertASCIItoUTF16(remoteSdp.c_str());
    2848             : 
    2849           0 :   return NS_OK;
    2850             : }
    2851             : 
    2852             : NS_IMETHODIMP
    2853           0 : PeerConnectionImpl::GetPendingRemoteDescription(nsAString& aSDP)
    2854             : {
    2855           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    2856             : 
    2857           0 :   std::string remoteSdp = mJsepSession->GetRemoteDescription(kJsepDescriptionPending);
    2858           0 :   aSDP = NS_ConvertASCIItoUTF16(remoteSdp.c_str());
    2859             : 
    2860           0 :   return NS_OK;
    2861             : }
    2862             : 
    2863             : NS_IMETHODIMP
    2864           0 : PeerConnectionImpl::SignalingState(PCImplSignalingState* aState)
    2865             : {
    2866           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    2867           0 :   MOZ_ASSERT(aState);
    2868             : 
    2869           0 :   *aState = mSignalingState;
    2870           0 :   return NS_OK;
    2871             : }
    2872             : 
    2873             : NS_IMETHODIMP
    2874           0 : PeerConnectionImpl::IceConnectionState(PCImplIceConnectionState* aState)
    2875             : {
    2876           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    2877           0 :   MOZ_ASSERT(aState);
    2878             : 
    2879           0 :   *aState = mIceConnectionState;
    2880           0 :   return NS_OK;
    2881             : }
    2882             : 
    2883             : NS_IMETHODIMP
    2884           0 : PeerConnectionImpl::IceGatheringState(PCImplIceGatheringState* aState)
    2885             : {
    2886           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    2887           0 :   MOZ_ASSERT(aState);
    2888             : 
    2889           0 :   *aState = mIceGatheringState;
    2890           0 :   return NS_OK;
    2891             : }
    2892             : 
    2893             : nsresult
    2894           0 : PeerConnectionImpl::CheckApiState(bool assert_ice_ready) const
    2895             : {
    2896           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    2897           0 :   MOZ_ASSERT(mTrickle || !assert_ice_ready ||
    2898             :              (mIceGatheringState == PCImplIceGatheringState::Complete));
    2899             : 
    2900           0 :   if (IsClosed()) {
    2901           0 :     CSFLogError(logTag, "%s: called API while closed", __FUNCTION__);
    2902           0 :     return NS_ERROR_FAILURE;
    2903             :   }
    2904           0 :   if (!mMedia) {
    2905           0 :     CSFLogError(logTag, "%s: called API with disposed mMedia", __FUNCTION__);
    2906           0 :     return NS_ERROR_FAILURE;
    2907             :   }
    2908           0 :   return NS_OK;
    2909             : }
    2910             : 
    2911             : NS_IMETHODIMP
    2912           0 : PeerConnectionImpl::Close()
    2913             : {
    2914           0 :   CSFLogDebug(logTag, "%s: for %s", __FUNCTION__, mHandle.c_str());
    2915           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    2916             : 
    2917           0 :   SetSignalingState_m(PCImplSignalingState::SignalingClosed);
    2918             : 
    2919           0 :   return NS_OK;
    2920             : }
    2921             : 
    2922             : bool
    2923           0 : PeerConnectionImpl::PluginCrash(uint32_t aPluginID,
    2924             :                                 const nsAString& aPluginName)
    2925             : {
    2926             :   // fire an event to the DOM window if this is "ours"
    2927           0 :   bool result = mMedia ? mMedia->AnyCodecHasPluginID(aPluginID) : false;
    2928           0 :   if (!result) {
    2929           0 :     return false;
    2930             :   }
    2931             : 
    2932           0 :   CSFLogError(logTag, "%s: Our plugin %llu crashed", __FUNCTION__, static_cast<unsigned long long>(aPluginID));
    2933             : 
    2934           0 :   nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
    2935           0 :   if (!doc) {
    2936           0 :     NS_WARNING("Couldn't get document for PluginCrashed event!");
    2937           0 :     return true;
    2938             :   }
    2939             : 
    2940           0 :   PluginCrashedEventInit init;
    2941           0 :   init.mPluginID = aPluginID;
    2942           0 :   init.mPluginName = aPluginName;
    2943           0 :   init.mSubmittedCrashReport = false;
    2944           0 :   init.mGmpPlugin = true;
    2945           0 :   init.mBubbles = true;
    2946           0 :   init.mCancelable = true;
    2947             : 
    2948             :   RefPtr<PluginCrashedEvent> event =
    2949           0 :     PluginCrashedEvent::Constructor(doc, NS_LITERAL_STRING("PluginCrashed"), init);
    2950             : 
    2951           0 :   event->SetTrusted(true);
    2952           0 :   event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
    2953             : 
    2954           0 :   EventDispatcher::DispatchDOMEvent(mWindow, nullptr, event, nullptr, nullptr);
    2955             : 
    2956           0 :   return true;
    2957             : }
    2958             : 
    2959             : void
    2960           0 : PeerConnectionImpl::RecordEndOfCallTelemetry() const
    2961             : {
    2962           0 :   if (!mJsepSession) {
    2963           0 :     return;
    2964             :   }
    2965             : 
    2966             :   // Exit early if no connection information was ever exchanged,
    2967             :   // This prevents distortion of telemetry data.
    2968           0 :   if (mLocalRequestedSDP.empty() && mRemoteRequestedSDP.empty()) {
    2969           0 :     return;
    2970             :   }
    2971             : 
    2972             :   // Bitmask used for WEBRTC/LOOP_CALL_TYPE telemetry reporting
    2973             :   static const uint32_t kAudioTypeMask = 1;
    2974             :   static const uint32_t kVideoTypeMask = 2;
    2975             :   static const uint32_t kDataChannelTypeMask = 4;
    2976             : 
    2977             :   // Report end-of-call Telemetry
    2978           0 :   if (mJsepSession->GetNegotiations() > 0) {
    2979           0 :     Telemetry::Accumulate(Telemetry::WEBRTC_RENEGOTIATIONS,
    2980           0 :                           mJsepSession->GetNegotiations()-1);
    2981             :   }
    2982           0 :   Telemetry::Accumulate(Telemetry::WEBRTC_MAX_VIDEO_SEND_TRACK,
    2983           0 :                         mMaxSending[SdpMediaSection::MediaType::kVideo]);
    2984           0 :   Telemetry::Accumulate(Telemetry::WEBRTC_MAX_VIDEO_RECEIVE_TRACK,
    2985           0 :                         mMaxReceiving[SdpMediaSection::MediaType::kVideo]);
    2986           0 :   Telemetry::Accumulate(Telemetry::WEBRTC_MAX_AUDIO_SEND_TRACK,
    2987           0 :                         mMaxSending[SdpMediaSection::MediaType::kAudio]);
    2988           0 :   Telemetry::Accumulate(Telemetry::WEBRTC_MAX_AUDIO_RECEIVE_TRACK,
    2989           0 :                         mMaxReceiving[SdpMediaSection::MediaType::kAudio]);
    2990             :   // DataChannels appear in both Sending and Receiving
    2991           0 :   Telemetry::Accumulate(Telemetry::WEBRTC_DATACHANNEL_NEGOTIATED,
    2992           0 :                         mMaxSending[SdpMediaSection::MediaType::kApplication]);
    2993             :   // Enumerated/bitmask: 1 = Audio, 2 = Video, 4 = DataChannel
    2994             :   // A/V = 3, A/V/D = 7, etc
    2995           0 :   uint32_t type = 0;
    2996           0 :   if (mMaxSending[SdpMediaSection::MediaType::kAudio] ||
    2997           0 :       mMaxReceiving[SdpMediaSection::MediaType::kAudio]) {
    2998           0 :     type = kAudioTypeMask;
    2999             :   }
    3000           0 :   if (mMaxSending[SdpMediaSection::MediaType::kVideo] ||
    3001           0 :       mMaxReceiving[SdpMediaSection::MediaType::kVideo]) {
    3002           0 :     type |= kVideoTypeMask;
    3003             :   }
    3004           0 :   if (mMaxSending[SdpMediaSection::MediaType::kApplication]) {
    3005           0 :     type |= kDataChannelTypeMask;
    3006             :   }
    3007             :   Telemetry::Accumulate(Telemetry::WEBRTC_CALL_TYPE,
    3008           0 :                         type);
    3009             : }
    3010             : 
    3011             : nsresult
    3012           0 : PeerConnectionImpl::CloseInt()
    3013             : {
    3014           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    3015             : 
    3016           0 :   for (auto& dtmfState : mDTMFStates) {
    3017           0 :     dtmfState.mSendTimer->Cancel();
    3018             :   }
    3019             : 
    3020             :   // We do this at the end of the call because we want to make sure we've waited
    3021             :   // for all trickle ICE candidates to come in; this can happen well after we've
    3022             :   // transitioned to connected. As a bonus, this allows us to detect race
    3023             :   // conditions where a stats dispatch happens right as the PC closes.
    3024           0 :   if (!mPrivateWindow) {
    3025           0 :     RecordLongtermICEStatistics();
    3026             :   }
    3027           0 :   RecordEndOfCallTelemetry();
    3028           0 :   CSFLogInfo(logTag, "%s: Closing PeerConnectionImpl %s; "
    3029           0 :              "ending call", __FUNCTION__, mHandle.c_str());
    3030           0 :   if (mJsepSession) {
    3031           0 :     mJsepSession->Close();
    3032             :   }
    3033           0 :   if (mDataConnection) {
    3034           0 :     CSFLogInfo(logTag, "%s: Destroying DataChannelConnection %p for %s",
    3035           0 :                __FUNCTION__, (void *) mDataConnection.get(), mHandle.c_str());
    3036           0 :     mDataConnection->Destroy();
    3037           0 :     mDataConnection = nullptr; // it may not go away until the runnables are dead
    3038             :   }
    3039           0 :   ShutdownMedia();
    3040             : 
    3041             :   // DataConnection will need to stay alive until all threads/runnables exit
    3042             : 
    3043           0 :   return NS_OK;
    3044             : }
    3045             : 
    3046             : void
    3047           0 : PeerConnectionImpl::ShutdownMedia()
    3048             : {
    3049           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    3050             : 
    3051           0 :   if (!mMedia)
    3052           0 :     return;
    3053             : 
    3054             :   // before we destroy references to local tracks, detach from them
    3055           0 :   for(uint32_t i = 0; i < media()->LocalStreamsLength(); ++i) {
    3056           0 :     LocalSourceStreamInfo *info = media()->GetLocalStreamByIndex(i);
    3057           0 :     for (const auto& pair : info->GetMediaStreamTracks()) {
    3058           0 :       pair.second->RemovePrincipalChangeObserver(this);
    3059             :     }
    3060             :   }
    3061             : 
    3062             :   // End of call to be recorded in Telemetry
    3063           0 :   if (!mStartTime.IsNull()){
    3064           0 :     TimeDuration timeDelta = TimeStamp::Now() - mStartTime;
    3065           0 :     Telemetry::Accumulate(Telemetry::WEBRTC_CALL_DURATION,
    3066           0 :                           timeDelta.ToSeconds());
    3067             :   }
    3068             : 
    3069             :   // Forget the reference so that we can transfer it to
    3070             :   // SelfDestruct().
    3071           0 :   mMedia.forget().take()->SelfDestruct();
    3072             : }
    3073             : 
    3074             : void
    3075           0 : PeerConnectionImpl::SetSignalingState_m(PCImplSignalingState aSignalingState,
    3076             :                                         bool rollback)
    3077             : {
    3078           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    3079           0 :   if (mSignalingState == aSignalingState ||
    3080           0 :       mSignalingState == PCImplSignalingState::SignalingClosed) {
    3081           0 :     return;
    3082             :   }
    3083             : 
    3084           0 :   if (aSignalingState == PCImplSignalingState::SignalingHaveLocalOffer ||
    3085           0 :       (aSignalingState == PCImplSignalingState::SignalingStable &&
    3086           0 :        mSignalingState == PCImplSignalingState::SignalingHaveRemoteOffer &&
    3087           0 :        !rollback)) {
    3088           0 :     mMedia->EnsureTransports(*mJsepSession);
    3089             :   }
    3090             : 
    3091           0 :   mSignalingState = aSignalingState;
    3092             : 
    3093           0 :   bool fireNegotiationNeeded = false;
    3094           0 :   if (mSignalingState == PCImplSignalingState::SignalingStable) {
    3095           0 :     if (mMedia->GetIceRestartState() ==
    3096             :             PeerConnectionMedia::ICE_RESTART_PROVISIONAL) {
    3097           0 :       if (rollback) {
    3098           0 :         RollbackIceRestart();
    3099             :       } else {
    3100           0 :         mMedia->CommitIceRestart();
    3101             :       }
    3102             :     }
    3103             : 
    3104             :     // Either negotiation is done, or we've rolled back. In either case, we
    3105             :     // need to re-evaluate whether further negotiation is required.
    3106           0 :     mNegotiationNeeded = false;
    3107             :     // If we're rolling back a local offer, we might need to remove some
    3108             :     // transports, but nothing further needs to be done.
    3109           0 :     mMedia->ActivateOrRemoveTransports(*mJsepSession, mForceIceTcp);
    3110           0 :     if (!rollback) {
    3111           0 :       if (NS_FAILED(mMedia->UpdateMediaPipelines(*mJsepSession))) {
    3112           0 :         CSFLogError(logTag, "Error Updating MediaPipelines");
    3113           0 :         NS_ASSERTION(false, "Error Updating MediaPipelines in SetSignalingState_m()");
    3114             :         // XXX what now?  Not much we can do but keep going, without major restructuring
    3115             :       }
    3116           0 :       InitializeDataChannel();
    3117           0 :       mMedia->StartIceChecks(*mJsepSession);
    3118             :     }
    3119             : 
    3120           0 :     if (!mJsepSession->AllLocalTracksAreAssigned()) {
    3121             :       CSFLogInfo(logTag, "Not all local tracks were assigned to an "
    3122             :                  "m-section, either because the offerer did not offer"
    3123             :                  " to receive enough tracks, or because tracks were "
    3124             :                  "added after CreateOffer/Answer, but before "
    3125             :                  "offer/answer completed. This requires "
    3126           0 :                  "renegotiation.");
    3127           0 :       fireNegotiationNeeded = true;
    3128             :     }
    3129             : 
    3130             :     // Telemetry: record info on the current state of streams/renegotiations/etc
    3131             :     // Note: this code gets run on rollbacks as well!
    3132             : 
    3133             :     // Update the max channels used with each direction for each type
    3134             :     uint16_t receiving[SdpMediaSection::kMediaTypes];
    3135             :     uint16_t sending[SdpMediaSection::kMediaTypes];
    3136           0 :     mJsepSession->CountTracks(receiving, sending);
    3137           0 :     for (size_t i = 0; i < SdpMediaSection::kMediaTypes; i++) {
    3138           0 :       if (mMaxReceiving[i] < receiving[i]) {
    3139           0 :         mMaxReceiving[i] = receiving[i];
    3140             :       }
    3141           0 :       if (mMaxSending[i] < sending[i]) {
    3142           0 :         mMaxSending[i] = sending[i];
    3143             :       }
    3144             :     }
    3145             :   }
    3146             : 
    3147           0 :   if (mSignalingState == PCImplSignalingState::SignalingClosed) {
    3148           0 :     CloseInt();
    3149             :   }
    3150             : 
    3151           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
    3152           0 :   if (!pco) {
    3153           0 :     return;
    3154             :   }
    3155           0 :   JSErrorResult rv;
    3156           0 :   pco->OnStateChange(PCObserverStateType::SignalingState, rv);
    3157             : 
    3158           0 :   if (fireNegotiationNeeded) {
    3159             :     // We don't use MaybeFireNegotiationNeeded here, since content might have
    3160             :     // already cased a transition from stable.
    3161           0 :     OnNegotiationNeeded();
    3162             :   }
    3163             : }
    3164             : 
    3165             : void
    3166           0 : PeerConnectionImpl::UpdateSignalingState(bool rollback) {
    3167             :   mozilla::JsepSignalingState state =
    3168           0 :       mJsepSession->GetState();
    3169             : 
    3170             :   PCImplSignalingState newState;
    3171             : 
    3172           0 :   switch(state) {
    3173             :     case kJsepStateStable:
    3174           0 :       newState = PCImplSignalingState::SignalingStable;
    3175           0 :       break;
    3176             :     case kJsepStateHaveLocalOffer:
    3177           0 :       newState = PCImplSignalingState::SignalingHaveLocalOffer;
    3178           0 :       break;
    3179             :     case kJsepStateHaveRemoteOffer:
    3180           0 :       newState = PCImplSignalingState::SignalingHaveRemoteOffer;
    3181           0 :       break;
    3182             :     case kJsepStateHaveLocalPranswer:
    3183           0 :       newState = PCImplSignalingState::SignalingHaveLocalPranswer;
    3184           0 :       break;
    3185             :     case kJsepStateHaveRemotePranswer:
    3186           0 :       newState = PCImplSignalingState::SignalingHaveRemotePranswer;
    3187           0 :       break;
    3188             :     case kJsepStateClosed:
    3189           0 :       newState = PCImplSignalingState::SignalingClosed;
    3190           0 :       break;
    3191             :     default:
    3192           0 :       MOZ_CRASH();
    3193             :   }
    3194             : 
    3195           0 :   SetSignalingState_m(newState, rollback);
    3196           0 : }
    3197             : 
    3198             : bool
    3199           0 : PeerConnectionImpl::IsClosed() const
    3200             : {
    3201           0 :   return mSignalingState == PCImplSignalingState::SignalingClosed;
    3202             : }
    3203             : 
    3204             : bool
    3205           0 : PeerConnectionImpl::HasMedia() const
    3206             : {
    3207           0 :   return mMedia;
    3208             : }
    3209             : 
    3210           0 : PeerConnectionWrapper::PeerConnectionWrapper(const std::string& handle)
    3211           0 :     : impl_(nullptr) {
    3212           0 :   if (PeerConnectionCtx::GetInstance()->mPeerConnections.find(handle) ==
    3213           0 :     PeerConnectionCtx::GetInstance()->mPeerConnections.end()) {
    3214           0 :     return;
    3215             :   }
    3216             : 
    3217           0 :   PeerConnectionImpl *impl = PeerConnectionCtx::GetInstance()->mPeerConnections[handle];
    3218             : 
    3219           0 :   if (!impl->media())
    3220           0 :     return;
    3221             : 
    3222           0 :   impl_ = impl;
    3223             : }
    3224             : 
    3225             : const std::string&
    3226           0 : PeerConnectionImpl::GetHandle()
    3227             : {
    3228           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    3229           0 :   return mHandle;
    3230             : }
    3231             : 
    3232             : const std::string&
    3233           0 : PeerConnectionImpl::GetName()
    3234             : {
    3235           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    3236           0 :   return mName;
    3237             : }
    3238             : 
    3239             : static mozilla::dom::PCImplIceConnectionState
    3240           0 : toDomIceConnectionState(NrIceCtx::ConnectionState state) {
    3241           0 :   switch (state) {
    3242             :     case NrIceCtx::ICE_CTX_INIT:
    3243           0 :       return PCImplIceConnectionState::New;
    3244             :     case NrIceCtx::ICE_CTX_CHECKING:
    3245           0 :       return PCImplIceConnectionState::Checking;
    3246             :     case NrIceCtx::ICE_CTX_CONNECTED:
    3247           0 :       return PCImplIceConnectionState::Connected;
    3248             :     case NrIceCtx::ICE_CTX_COMPLETED:
    3249           0 :       return PCImplIceConnectionState::Completed;
    3250             :     case NrIceCtx::ICE_CTX_FAILED:
    3251           0 :       return PCImplIceConnectionState::Failed;
    3252             :     case NrIceCtx::ICE_CTX_DISCONNECTED:
    3253           0 :       return PCImplIceConnectionState::Disconnected;
    3254             :     case NrIceCtx::ICE_CTX_CLOSED:
    3255           0 :       return PCImplIceConnectionState::Closed;
    3256             :   }
    3257           0 :   MOZ_CRASH();
    3258             : }
    3259             : 
    3260             : static mozilla::dom::PCImplIceGatheringState
    3261           0 : toDomIceGatheringState(NrIceCtx::GatheringState state) {
    3262           0 :   switch (state) {
    3263             :     case NrIceCtx::ICE_CTX_GATHER_INIT:
    3264           0 :       return PCImplIceGatheringState::New;
    3265             :     case NrIceCtx::ICE_CTX_GATHER_STARTED:
    3266           0 :       return PCImplIceGatheringState::Gathering;
    3267             :     case NrIceCtx::ICE_CTX_GATHER_COMPLETE:
    3268           0 :       return PCImplIceGatheringState::Complete;
    3269             :   }
    3270           0 :   MOZ_CRASH();
    3271             : }
    3272             : 
    3273             : void
    3274           0 : PeerConnectionImpl::CandidateReady(const std::string& candidate,
    3275             :                                    uint16_t level) {
    3276           0 :   PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
    3277             : 
    3278           0 :   if (mForceIceTcp && std::string::npos != candidate.find(" UDP ")) {
    3279           0 :     CSFLogError(logTag, "Blocking local UDP candidate: %s", candidate.c_str());
    3280           0 :     return;
    3281             :   }
    3282             : 
    3283           0 :   std::string mid;
    3284           0 :   bool skipped = false;
    3285           0 :   nsresult res = mJsepSession->AddLocalIceCandidate(candidate,
    3286             :                                                     level,
    3287             :                                                     &mid,
    3288           0 :                                                     &skipped);
    3289             : 
    3290           0 :   if (NS_FAILED(res)) {
    3291           0 :     std::string errorString = mJsepSession->GetLastError();
    3292             : 
    3293           0 :     CSFLogError(logTag, "Failed to incorporate local candidate into SDP:"
    3294             :                         " res = %u, candidate = %s, level = %u, error = %s",
    3295             :                         static_cast<unsigned>(res),
    3296             :                         candidate.c_str(),
    3297             :                         static_cast<unsigned>(level),
    3298           0 :                         errorString.c_str());
    3299           0 :     return;
    3300             :   }
    3301             : 
    3302           0 :   if (skipped) {
    3303           0 :     CSFLogDebug(logTag, "Skipped adding local candidate %s (level %u) to SDP, "
    3304             :                         "this typically happens because the m-section is "
    3305             :                         "bundled, which means it doesn't make sense for it to "
    3306             :                         "have its own transport-related attributes.",
    3307             :                         candidate.c_str(),
    3308           0 :                         static_cast<unsigned>(level));
    3309           0 :     return;
    3310             :   }
    3311             : 
    3312           0 :   CSFLogDebug(logTag, "Passing local candidate to content: %s",
    3313           0 :               candidate.c_str());
    3314           0 :   SendLocalIceCandidateToContent(level, mid, candidate);
    3315             : }
    3316             : 
    3317             : static void
    3318           0 : SendLocalIceCandidateToContentImpl(nsWeakPtr weakPCObserver,
    3319             :                                    uint16_t level,
    3320             :                                    const std::string& mid,
    3321             :                                    const std::string& candidate) {
    3322           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(weakPCObserver);
    3323           0 :   if (!pco) {
    3324           0 :     return;
    3325             :   }
    3326             : 
    3327           0 :   JSErrorResult rv;
    3328           0 :   pco->OnIceCandidate(level,
    3329           0 :                       ObString(mid.c_str()),
    3330           0 :                       ObString(candidate.c_str()),
    3331           0 :                       rv);
    3332             : }
    3333             : 
    3334             : void
    3335           0 : PeerConnectionImpl::SendLocalIceCandidateToContent(
    3336             :     uint16_t level,
    3337             :     const std::string& mid,
    3338             :     const std::string& candidate) {
    3339             :   // We dispatch this because OnSetLocalDescriptionSuccess does a setTimeout(0)
    3340             :   // to unwind the stack, but the event handlers don't. We need to ensure that
    3341             :   // the candidates do not skip ahead of the callback.
    3342             :   NS_DispatchToMainThread(
    3343           0 :       WrapRunnableNM(&SendLocalIceCandidateToContentImpl,
    3344             :                      mPCObserver,
    3345             :                      level,
    3346             :                      mid,
    3347             :                      candidate),
    3348           0 :       NS_DISPATCH_NORMAL);
    3349           0 : }
    3350             : 
    3351           0 : static bool isDone(PCImplIceConnectionState state) {
    3352           0 :   return state != PCImplIceConnectionState::Checking &&
    3353           0 :          state != PCImplIceConnectionState::New;
    3354             : }
    3355             : 
    3356           0 : static bool isSucceeded(PCImplIceConnectionState state) {
    3357           0 :   return state == PCImplIceConnectionState::Connected ||
    3358           0 :          state == PCImplIceConnectionState::Completed;
    3359             : }
    3360             : 
    3361           0 : static bool isFailed(PCImplIceConnectionState state) {
    3362           0 :   return state == PCImplIceConnectionState::Failed;
    3363             : }
    3364             : 
    3365           0 : void PeerConnectionImpl::IceConnectionStateChange(
    3366             :     NrIceCtx* ctx,
    3367             :     NrIceCtx::ConnectionState state) {
    3368           0 :   PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
    3369             : 
    3370           0 :   CSFLogDebug(logTag, "%s", __FUNCTION__);
    3371             : 
    3372           0 :   auto domState = toDomIceConnectionState(state);
    3373           0 :   if (domState == mIceConnectionState) {
    3374             :     // no work to be done since the states are the same.
    3375             :     // this can happen during ICE rollback situations.
    3376           0 :     return;
    3377             :   }
    3378             : 
    3379           0 :   if (!isDone(mIceConnectionState) && isDone(domState)) {
    3380           0 :     if (isSucceeded(domState)) {
    3381           0 :       Telemetry::Accumulate(
    3382             :           Telemetry::WEBRTC_ICE_ADD_CANDIDATE_ERRORS_GIVEN_SUCCESS,
    3383           0 :           mAddCandidateErrorCount);
    3384           0 :     } else if (isFailed(domState)) {
    3385           0 :       Telemetry::Accumulate(
    3386             :           Telemetry::WEBRTC_ICE_ADD_CANDIDATE_ERRORS_GIVEN_FAILURE,
    3387           0 :           mAddCandidateErrorCount);
    3388             :     }
    3389             :   }
    3390             : 
    3391           0 :   mIceConnectionState = domState;
    3392             : 
    3393           0 :   if (mIceConnectionState == PCImplIceConnectionState::Connected ||
    3394           0 :       mIceConnectionState == PCImplIceConnectionState::Completed ||
    3395           0 :       mIceConnectionState == PCImplIceConnectionState::Failed) {
    3396           0 :     if (mMedia->IsIceRestarting()) {
    3397           0 :       FinalizeIceRestart();
    3398             :     }
    3399             :   }
    3400             : 
    3401             :   // Would be nice if we had a means of converting one of these dom enums
    3402             :   // to a string that wasn't almost as much text as this switch statement...
    3403           0 :   switch (mIceConnectionState) {
    3404             :     case PCImplIceConnectionState::New:
    3405           0 :       STAMP_TIMECARD(mTimeCard, "Ice state: new");
    3406           0 :       break;
    3407             :     case PCImplIceConnectionState::Checking:
    3408             :       // For telemetry
    3409           0 :       mIceStartTime = TimeStamp::Now();
    3410           0 :       STAMP_TIMECARD(mTimeCard, "Ice state: checking");
    3411           0 :       break;
    3412             :     case PCImplIceConnectionState::Connected:
    3413           0 :       STAMP_TIMECARD(mTimeCard, "Ice state: connected");
    3414           0 :       break;
    3415             :     case PCImplIceConnectionState::Completed:
    3416           0 :       STAMP_TIMECARD(mTimeCard, "Ice state: completed");
    3417           0 :       break;
    3418             :     case PCImplIceConnectionState::Failed:
    3419           0 :       STAMP_TIMECARD(mTimeCard, "Ice state: failed");
    3420           0 :       break;
    3421             :     case PCImplIceConnectionState::Disconnected:
    3422           0 :       STAMP_TIMECARD(mTimeCard, "Ice state: disconnected");
    3423           0 :       break;
    3424             :     case PCImplIceConnectionState::Closed:
    3425           0 :       STAMP_TIMECARD(mTimeCard, "Ice state: closed");
    3426           0 :       break;
    3427             :     default:
    3428           0 :       MOZ_ASSERT_UNREACHABLE("Unexpected mIceConnectionState!");
    3429             :   }
    3430             : 
    3431           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
    3432           0 :   if (!pco) {
    3433           0 :     return;
    3434             :   }
    3435           0 :   WrappableJSErrorResult rv;
    3436           0 :   RUN_ON_THREAD(mThread,
    3437           0 :                 WrapRunnable(pco,
    3438             :                              &PeerConnectionObserver::OnStateChange,
    3439             :                              PCObserverStateType::IceConnectionState,
    3440             :                              rv, static_cast<JSCompartment*>(nullptr)),
    3441           0 :                 NS_DISPATCH_NORMAL);
    3442             : }
    3443             : 
    3444             : void
    3445           0 : PeerConnectionImpl::IceGatheringStateChange(
    3446             :     NrIceCtx* ctx,
    3447             :     NrIceCtx::GatheringState state)
    3448             : {
    3449           0 :   PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
    3450             : 
    3451           0 :   CSFLogDebug(logTag, "%s", __FUNCTION__);
    3452             : 
    3453           0 :   mIceGatheringState = toDomIceGatheringState(state);
    3454             : 
    3455             :   // Would be nice if we had a means of converting one of these dom enums
    3456             :   // to a string that wasn't almost as much text as this switch statement...
    3457           0 :   switch (mIceGatheringState) {
    3458             :     case PCImplIceGatheringState::New:
    3459           0 :       STAMP_TIMECARD(mTimeCard, "Ice gathering state: new");
    3460           0 :       break;
    3461             :     case PCImplIceGatheringState::Gathering:
    3462           0 :       STAMP_TIMECARD(mTimeCard, "Ice gathering state: gathering");
    3463           0 :       break;
    3464             :     case PCImplIceGatheringState::Complete:
    3465           0 :       STAMP_TIMECARD(mTimeCard, "Ice gathering state: complete");
    3466           0 :       break;
    3467             :     default:
    3468           0 :       MOZ_ASSERT_UNREACHABLE("Unexpected mIceGatheringState!");
    3469             :   }
    3470             : 
    3471           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
    3472           0 :   if (!pco) {
    3473           0 :     return;
    3474             :   }
    3475           0 :   WrappableJSErrorResult rv;
    3476           0 :   RUN_ON_THREAD(mThread,
    3477           0 :                 WrapRunnable(pco,
    3478             :                              &PeerConnectionObserver::OnStateChange,
    3479             :                              PCObserverStateType::IceGatheringState,
    3480             :                              rv, static_cast<JSCompartment*>(nullptr)),
    3481           0 :                 NS_DISPATCH_NORMAL);
    3482             : 
    3483           0 :   if (mIceGatheringState == PCImplIceGatheringState::Complete) {
    3484           0 :     SendLocalIceCandidateToContent(0, "", "");
    3485             :   }
    3486             : }
    3487             : 
    3488             : void
    3489           0 : PeerConnectionImpl::UpdateDefaultCandidate(const std::string& defaultAddr,
    3490             :                                            uint16_t defaultPort,
    3491             :                                            const std::string& defaultRtcpAddr,
    3492             :                                            uint16_t defaultRtcpPort,
    3493             :                                            uint16_t level) {
    3494           0 :   CSFLogDebug(logTag, "%s", __FUNCTION__);
    3495           0 :   mJsepSession->UpdateDefaultCandidate(defaultAddr,
    3496             :                                        defaultPort,
    3497             :                                        defaultRtcpAddr,
    3498             :                                        defaultRtcpPort,
    3499           0 :                                        level);
    3500           0 : }
    3501             : 
    3502             : void
    3503           0 : PeerConnectionImpl::EndOfLocalCandidates(uint16_t level) {
    3504           0 :   CSFLogDebug(logTag, "%s", __FUNCTION__);
    3505           0 :   mJsepSession->EndOfLocalCandidates(level);
    3506           0 : }
    3507             : 
    3508             : nsresult
    3509           0 : PeerConnectionImpl::BuildStatsQuery_m(
    3510             :     mozilla::dom::MediaStreamTrack *aSelector,
    3511             :     RTCStatsQuery *query) {
    3512             : 
    3513           0 :   if (!HasMedia()) {
    3514           0 :     return NS_ERROR_UNEXPECTED;
    3515             :   }
    3516             : 
    3517           0 :   if (!mThread) {
    3518           0 :     CSFLogError(logTag, "Could not build stats query, no MainThread");
    3519           0 :     return NS_ERROR_UNEXPECTED;
    3520             :   }
    3521             : 
    3522           0 :   nsresult rv = GetTimeSinceEpoch(&(query->now));
    3523           0 :   if (NS_FAILED(rv)) {
    3524           0 :     CSFLogError(logTag, "Could not build stats query, could not get timestamp");
    3525           0 :     return rv;
    3526             :   }
    3527             : 
    3528             :   // Note: mMedia->ice_ctx() is deleted on STS thread; so make sure we grab and hold
    3529             :   // a ref instead of making multiple calls.  NrIceCtx uses threadsafe refcounting.
    3530             :   // NOTE: Do this after all other failure tests, to ensure we don't
    3531             :   // accidentally release the Ctx on Mainthread.
    3532           0 :   query->iceCtx = mMedia->ice_ctx();
    3533           0 :   if (!query->iceCtx) {
    3534           0 :     CSFLogError(logTag, "Could not build stats query, no ice_ctx");
    3535           0 :     return NS_ERROR_UNEXPECTED;
    3536             :   }
    3537             : 
    3538             :   // We do not use the pcHandle here, since that's risky to expose to content.
    3539             :   query->report = new RTCStatsReportInternalConstruct(
    3540           0 :       NS_ConvertASCIItoUTF16(mName.c_str()),
    3541           0 :       query->now);
    3542             : 
    3543           0 :   query->iceStartTime = mIceStartTime;
    3544           0 :   query->failed = isFailed(mIceConnectionState);
    3545             : 
    3546             :   // Populate SDP on main
    3547           0 :   if (query->internalStats) {
    3548           0 :     if (mJsepSession) {
    3549             :       // TODO we probably should report Current and Pending SDPs here
    3550             :       // separately. Plus the raw SDP we got from JS (mLocalRequestedSDP).
    3551             :       // And if it's the offer or answer would also be nice.
    3552           0 :       std::string localDescription = mJsepSession->GetLocalDescription(
    3553           0 :           kJsepDescriptionPendingOrCurrent);
    3554           0 :       std::string remoteDescription = mJsepSession->GetRemoteDescription(
    3555           0 :           kJsepDescriptionPendingOrCurrent);
    3556           0 :       query->report->mLocalSdp.Construct(
    3557           0 :           NS_ConvertASCIItoUTF16(localDescription.c_str()));
    3558           0 :       query->report->mRemoteSdp.Construct(
    3559           0 :           NS_ConvertASCIItoUTF16(remoteDescription.c_str()));
    3560             :     }
    3561             :   }
    3562             : 
    3563             :   // Gather up pipelines from mMedia so they may be inspected on STS
    3564             : 
    3565           0 :   std::string trackId;
    3566           0 :   if (aSelector) {
    3567           0 :     trackId = PeerConnectionImpl::GetTrackId(*aSelector);
    3568             :   }
    3569             : 
    3570           0 :   for (int i = 0, len = mMedia->LocalStreamsLength(); i < len; i++) {
    3571           0 :     for (auto pipeline : mMedia->GetLocalStreamByIndex(i)->GetPipelines()) {
    3572           0 :       if (!aSelector || pipeline.second->trackid() == trackId) {
    3573           0 :         query->pipelines.AppendElement(pipeline.second);
    3574             :       }
    3575             :     }
    3576             :   }
    3577           0 :   for (int i = 0, len = mMedia->RemoteStreamsLength(); i < len; i++) {
    3578           0 :     for (auto pipeline : mMedia->GetRemoteStreamByIndex(i)->GetPipelines()) {
    3579           0 :       if (!aSelector || pipeline.second->trackid() == trackId) {
    3580           0 :         query->pipelines.AppendElement(pipeline.second);
    3581             :       }
    3582             :     }
    3583             :   }
    3584             : 
    3585           0 :   if (!aSelector) {
    3586           0 :     query->grabAllLevels = true;
    3587             :   }
    3588             : 
    3589           0 :   return rv;
    3590             : }
    3591             : 
    3592           0 : static void ToRTCIceCandidateStats(
    3593             :     const std::vector<NrIceCandidate>& candidates,
    3594             :     RTCStatsType candidateType,
    3595             :     const nsString& componentId,
    3596             :     DOMHighResTimeStamp now,
    3597             :     RTCStatsReportInternal* report) {
    3598             : 
    3599           0 :   MOZ_ASSERT(report);
    3600           0 :   for (const auto& candidate : candidates) {
    3601           0 :     RTCIceCandidateStats cand;
    3602           0 :     cand.mType.Construct(candidateType);
    3603           0 :     NS_ConvertASCIItoUTF16 codeword(candidate.codeword.c_str());
    3604           0 :     cand.mComponentId.Construct(componentId);
    3605           0 :     cand.mId.Construct(codeword);
    3606           0 :     cand.mTimestamp.Construct(now);
    3607             :     cand.mCandidateType.Construct(
    3608           0 :         RTCStatsIceCandidateType(candidate.type));
    3609             :     cand.mIpAddress.Construct(
    3610           0 :         NS_ConvertASCIItoUTF16(candidate.cand_addr.host.c_str()));
    3611           0 :     cand.mPortNumber.Construct(candidate.cand_addr.port);
    3612             :     cand.mTransport.Construct(
    3613           0 :         NS_ConvertASCIItoUTF16(candidate.cand_addr.transport.c_str()));
    3614           0 :     if (candidateType == RTCStatsType::Local_candidate) {
    3615             :       cand.mMozLocalTransport.Construct(
    3616           0 :           NS_ConvertASCIItoUTF16(candidate.local_addr.transport.c_str()));
    3617             :     }
    3618           0 :     report->mIceCandidateStats.Value().AppendElement(cand, fallible);
    3619             :   }
    3620           0 : }
    3621             : 
    3622           0 : static void RecordIceStats_s(
    3623             :     NrIceMediaStream& mediaStream,
    3624             :     bool internalStats,
    3625             :     DOMHighResTimeStamp now,
    3626             :     RTCStatsReportInternal* report) {
    3627             : 
    3628           0 :   NS_ConvertASCIItoUTF16 transportId(mediaStream.name().c_str());
    3629             : 
    3630           0 :   std::vector<NrIceCandidatePair> candPairs;
    3631           0 :   nsresult res = mediaStream.GetCandidatePairs(&candPairs);
    3632           0 :   if (NS_FAILED(res)) {
    3633           0 :     CSFLogError(logTag, "%s: Error getting candidate pairs", __FUNCTION__);
    3634           0 :     return;
    3635             :   }
    3636             : 
    3637           0 :   for (auto& candPair : candPairs) {
    3638           0 :     NS_ConvertASCIItoUTF16 codeword(candPair.codeword.c_str());
    3639           0 :     NS_ConvertASCIItoUTF16 localCodeword(candPair.local.codeword.c_str());
    3640           0 :     NS_ConvertASCIItoUTF16 remoteCodeword(candPair.remote.codeword.c_str());
    3641             :     // Only expose candidate-pair statistics to chrome, until we've thought
    3642             :     // through the implications of exposing it to content.
    3643             : 
    3644           0 :     RTCIceCandidatePairStats s;
    3645           0 :     s.mId.Construct(codeword);
    3646           0 :     s.mTransportId.Construct(transportId);
    3647           0 :     s.mTimestamp.Construct(now);
    3648           0 :     s.mType.Construct(RTCStatsType::Candidate_pair);
    3649           0 :     s.mLocalCandidateId.Construct(localCodeword);
    3650           0 :     s.mRemoteCandidateId.Construct(remoteCodeword);
    3651           0 :     s.mNominated.Construct(candPair.nominated);
    3652           0 :     s.mWritable.Construct(candPair.writable);
    3653           0 :     s.mReadable.Construct(candPair.readable);
    3654           0 :     s.mPriority.Construct(candPair.priority);
    3655           0 :     s.mSelected.Construct(candPair.selected);
    3656           0 :     s.mBytesSent.Construct(candPair.bytes_sent);
    3657           0 :     s.mBytesReceived.Construct(candPair.bytes_recvd);
    3658           0 :     s.mLastPacketSentTimestamp.Construct(candPair.ms_since_last_send);
    3659           0 :     s.mLastPacketReceivedTimestamp.Construct(candPair.ms_since_last_recv);
    3660           0 :     s.mState.Construct(RTCStatsIceCandidatePairState(candPair.state));
    3661           0 :     report->mIceCandidatePairStats.Value().AppendElement(s, fallible);
    3662             :   }
    3663             : 
    3664           0 :   std::vector<NrIceCandidate> candidates;
    3665           0 :   if (NS_SUCCEEDED(mediaStream.GetLocalCandidates(&candidates))) {
    3666             :     ToRTCIceCandidateStats(candidates,
    3667             :                            RTCStatsType::Local_candidate,
    3668             :                            transportId,
    3669             :                            now,
    3670           0 :                            report);
    3671             :   }
    3672           0 :   candidates.clear();
    3673             : 
    3674           0 :   if (NS_SUCCEEDED(mediaStream.GetRemoteCandidates(&candidates))) {
    3675             :     ToRTCIceCandidateStats(candidates,
    3676             :                            RTCStatsType::Remote_candidate,
    3677             :                            transportId,
    3678             :                            now,
    3679           0 :                            report);
    3680             :   }
    3681             : }
    3682             : 
    3683             : nsresult
    3684           0 : PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
    3685             : 
    3686           0 :   ASSERT_ON_THREAD(query->iceCtx->thread());
    3687             : 
    3688             :   // Gather stats from pipelines provided (can't touch mMedia + stream on STS)
    3689             : 
    3690           0 :   for (size_t p = 0; p < query->pipelines.Length(); ++p) {
    3691           0 :     const MediaPipeline& mp = *query->pipelines[p];
    3692           0 :     bool isAudio = (mp.Conduit()->type() == MediaSessionConduit::AUDIO);
    3693             :     nsString mediaType = isAudio ?
    3694           0 :         NS_LITERAL_STRING("audio") : NS_LITERAL_STRING("video");
    3695           0 :     nsString idstr = mediaType;
    3696           0 :     idstr.AppendLiteral("_");
    3697           0 :     idstr.AppendInt(mp.level());
    3698             : 
    3699             :     // TODO(@@NG):ssrcs handle Conduits having multiple stats at the same level
    3700             :     // This is pending spec work
    3701             :     // Gather pipeline stats.
    3702           0 :     switch (mp.direction()) {
    3703             :       case MediaPipeline::TRANSMIT: {
    3704           0 :         nsString localId = NS_LITERAL_STRING("outbound_rtp_") + idstr;
    3705           0 :         nsString remoteId;
    3706           0 :         nsString ssrc;
    3707           0 :         std::vector<unsigned int> ssrcvals = mp.Conduit()->GetLocalSSRCs();
    3708           0 :         if (!ssrcvals.empty()) {
    3709           0 :           ssrc.AppendInt(ssrcvals[0]);
    3710             :         }
    3711             :         {
    3712             :           // First, fill in remote stat with rtcp receiver data, if present.
    3713             :           // ReceiverReports have less information than SenderReports,
    3714             :           // so fill in what we can.
    3715             :           DOMHighResTimeStamp timestamp;
    3716             :           uint32_t jitterMs;
    3717             :           uint32_t packetsReceived;
    3718             :           uint64_t bytesReceived;
    3719             :           uint32_t packetsLost;
    3720             :           int32_t rtt;
    3721           0 :           if (mp.Conduit()->GetRTCPReceiverReport(&timestamp, &jitterMs,
    3722             :                                                   &packetsReceived,
    3723             :                                                   &bytesReceived,
    3724             :                                                   &packetsLost,
    3725           0 :                                                   &rtt)) {
    3726           0 :             remoteId = NS_LITERAL_STRING("outbound_rtcp_") + idstr;
    3727           0 :             RTCInboundRTPStreamStats s;
    3728           0 :             s.mTimestamp.Construct(timestamp);
    3729           0 :             s.mId.Construct(remoteId);
    3730           0 :             s.mType.Construct(RTCStatsType::Inbound_rtp);
    3731           0 :             if (ssrc.Length()) {
    3732           0 :               s.mSsrc.Construct(ssrc);
    3733             :             }
    3734           0 :             s.mMediaType.Construct(mediaType);
    3735           0 :             s.mJitter.Construct(double(jitterMs)/1000);
    3736           0 :             s.mRemoteId.Construct(localId);
    3737           0 :             s.mIsRemote = true;
    3738           0 :             s.mPacketsReceived.Construct(packetsReceived);
    3739           0 :             s.mBytesReceived.Construct(bytesReceived);
    3740           0 :             s.mPacketsLost.Construct(packetsLost);
    3741           0 :             if (rtt > 0) {
    3742           0 :               s.mRoundTripTime.Construct(rtt);
    3743             :             }
    3744           0 :             query->report->mInboundRTPStreamStats.Value().AppendElement(s,
    3745           0 :                                                                         fallible);
    3746             :           }
    3747             :         }
    3748             :         // Then, fill in local side (with cross-link to remote only if present)
    3749             :         {
    3750           0 :           RTCOutboundRTPStreamStats s;
    3751           0 :           s.mTimestamp.Construct(query->now);
    3752           0 :           s.mId.Construct(localId);
    3753           0 :           s.mType.Construct(RTCStatsType::Outbound_rtp);
    3754           0 :           if (ssrc.Length()) {
    3755           0 :             s.mSsrc.Construct(ssrc);
    3756             :           }
    3757           0 :           s.mMediaType.Construct(mediaType);
    3758           0 :           s.mRemoteId.Construct(remoteId);
    3759           0 :           s.mIsRemote = false;
    3760           0 :           s.mPacketsSent.Construct(mp.rtp_packets_sent());
    3761           0 :           s.mBytesSent.Construct(mp.rtp_bytes_sent());
    3762             : 
    3763             :           // Fill in packet type statistics
    3764           0 :           webrtc::RtcpPacketTypeCounter counters;
    3765           0 :           if (mp.Conduit()->GetSendPacketTypeStats(&counters)) {
    3766           0 :             s.mNackCount.Construct(counters.nack_packets);
    3767             :             // Fill in video only packet type stats
    3768           0 :             if (!isAudio) {
    3769           0 :               s.mFirCount.Construct(counters.fir_packets);
    3770           0 :               s.mPliCount.Construct(counters.pli_packets);
    3771             :             }
    3772             :           }
    3773             : 
    3774             :           // Lastly, fill in video encoder stats if this is video
    3775           0 :           if (!isAudio) {
    3776             :             double framerateMean;
    3777             :             double framerateStdDev;
    3778             :             double bitrateMean;
    3779             :             double bitrateStdDev;
    3780             :             uint32_t droppedFrames;
    3781             :             uint32_t framesEncoded;
    3782           0 :             if (mp.Conduit()->GetVideoEncoderStats(&framerateMean,
    3783             :                                                    &framerateStdDev,
    3784             :                                                    &bitrateMean,
    3785             :                                                    &bitrateStdDev,
    3786             :                                                    &droppedFrames,
    3787           0 :                                                    &framesEncoded)) {
    3788           0 :               s.mFramerateMean.Construct(framerateMean);
    3789           0 :               s.mFramerateStdDev.Construct(framerateStdDev);
    3790           0 :               s.mBitrateMean.Construct(bitrateMean);
    3791           0 :               s.mBitrateStdDev.Construct(bitrateStdDev);
    3792           0 :               s.mDroppedFrames.Construct(droppedFrames);
    3793           0 :               s.mFramesEncoded.Construct(framesEncoded);
    3794             :             }
    3795             :           }
    3796           0 :           query->report->mOutboundRTPStreamStats.Value().AppendElement(s,
    3797           0 :                                                                        fallible);
    3798             :         }
    3799           0 :         break;
    3800             :       }
    3801             :       case MediaPipeline::RECEIVE: {
    3802           0 :         nsString localId = NS_LITERAL_STRING("inbound_rtp_") + idstr;
    3803           0 :         nsString remoteId;
    3804           0 :         nsString ssrc;
    3805             :         unsigned int ssrcval;
    3806           0 :         if (mp.Conduit()->GetRemoteSSRC(&ssrcval)) {
    3807           0 :           ssrc.AppendInt(ssrcval);
    3808             :         }
    3809             :         {
    3810             :           // First, fill in remote stat with rtcp sender data, if present.
    3811             :           DOMHighResTimeStamp timestamp;
    3812             :           uint32_t packetsSent;
    3813             :           uint64_t bytesSent;
    3814           0 :           if (mp.Conduit()->GetRTCPSenderReport(&timestamp,
    3815           0 :                                                 &packetsSent, &bytesSent)) {
    3816           0 :             remoteId = NS_LITERAL_STRING("inbound_rtcp_") + idstr;
    3817           0 :             RTCOutboundRTPStreamStats s;
    3818           0 :             s.mTimestamp.Construct(timestamp);
    3819           0 :             s.mId.Construct(remoteId);
    3820           0 :             s.mType.Construct(RTCStatsType::Outbound_rtp);
    3821           0 :             if (ssrc.Length()) {
    3822           0 :               s.mSsrc.Construct(ssrc);
    3823             :             }
    3824           0 :             s.mMediaType.Construct(mediaType);
    3825           0 :             s.mRemoteId.Construct(localId);
    3826           0 :             s.mIsRemote = true;
    3827           0 :             s.mPacketsSent.Construct(packetsSent);
    3828           0 :             s.mBytesSent.Construct(bytesSent);
    3829           0 :             query->report->mOutboundRTPStreamStats.Value().AppendElement(s,
    3830           0 :                                                                          fallible);
    3831             :           }
    3832             :         }
    3833             :         // Then, fill in local side (with cross-link to remote only if present)
    3834           0 :         RTCInboundRTPStreamStats s;
    3835           0 :         s.mTimestamp.Construct(query->now);
    3836           0 :         s.mId.Construct(localId);
    3837           0 :         s.mType.Construct(RTCStatsType::Inbound_rtp);
    3838           0 :         if (ssrc.Length()) {
    3839           0 :           s.mSsrc.Construct(ssrc);
    3840             :         }
    3841           0 :         s.mMediaType.Construct(mediaType);
    3842             :         unsigned int jitterMs, packetsLost;
    3843           0 :         if (mp.Conduit()->GetRTPStats(&jitterMs, &packetsLost)) {
    3844           0 :           s.mJitter.Construct(double(jitterMs)/1000);
    3845           0 :           s.mPacketsLost.Construct(packetsLost);
    3846             :         }
    3847           0 :         if (remoteId.Length()) {
    3848           0 :           s.mRemoteId.Construct(remoteId);
    3849             :         }
    3850           0 :         s.mIsRemote = false;
    3851           0 :         s.mPacketsReceived.Construct(mp.rtp_packets_received());
    3852           0 :         s.mBytesReceived.Construct(mp.rtp_bytes_received());
    3853             : 
    3854           0 :         if (query->internalStats && isAudio) {
    3855             :           int32_t jitterBufferDelay;
    3856             :           int32_t playoutBufferDelay;
    3857             :           int32_t avSyncDelta;
    3858           0 :           if (mp.Conduit()->GetAVStats(&jitterBufferDelay,
    3859             :                                        &playoutBufferDelay,
    3860           0 :                                        &avSyncDelta)) {
    3861           0 :             s.mMozJitterBufferDelay.Construct(jitterBufferDelay);
    3862           0 :             s.mMozAvSyncDelay.Construct(avSyncDelta);
    3863             :           }
    3864             :         }
    3865             :         // Fill in packet type statistics
    3866           0 :         webrtc::RtcpPacketTypeCounter counters;
    3867           0 :         if (mp.Conduit()->GetRecvPacketTypeStats(&counters)) {
    3868           0 :           s.mNackCount.Construct(counters.nack_packets);
    3869             :           // Fill in video only packet type stats
    3870           0 :           if (!isAudio) {
    3871           0 :             s.mFirCount.Construct(counters.fir_packets);
    3872           0 :             s.mPliCount.Construct(counters.pli_packets);
    3873             :           }
    3874             :         }
    3875             :         // Lastly, fill in video decoder stats if this is video
    3876           0 :         if (!isAudio) {
    3877             :           double framerateMean;
    3878             :           double framerateStdDev;
    3879             :           double bitrateMean;
    3880             :           double bitrateStdDev;
    3881             :           uint32_t discardedPackets;
    3882             :           uint32_t framesDecoded;
    3883           0 :           if (mp.Conduit()->GetVideoDecoderStats(&framerateMean,
    3884             :                                                  &framerateStdDev,
    3885             :                                                  &bitrateMean,
    3886             :                                                  &bitrateStdDev,
    3887             :                                                  &discardedPackets,
    3888           0 :                                                  &framesDecoded)) {
    3889           0 :             s.mFramerateMean.Construct(framerateMean);
    3890           0 :             s.mFramerateStdDev.Construct(framerateStdDev);
    3891           0 :             s.mBitrateMean.Construct(bitrateMean);
    3892           0 :             s.mBitrateStdDev.Construct(bitrateStdDev);
    3893           0 :             s.mDiscardedPackets.Construct(discardedPackets);
    3894           0 :             s.mFramesDecoded.Construct(framesDecoded);
    3895             :           }
    3896             :         }
    3897           0 :         query->report->mInboundRTPStreamStats.Value().AppendElement(s,
    3898           0 :                                                                     fallible);
    3899             :         // Fill in Contributing Source statistics
    3900           0 :         mp.GetContributingSourceStats(localId,
    3901           0 :             query->report->mRtpContributingSourceStats.Value());
    3902           0 :         break;
    3903             :       }
    3904             :     }
    3905             : 
    3906           0 :     if (!query->grabAllLevels) {
    3907             :       // If we're grabbing all levels, that means we want datachannels too,
    3908             :       // which don't have pipelines.
    3909           0 :       if (query->iceCtx->GetStream(p)) {
    3910           0 :         RecordIceStats_s(*query->iceCtx->GetStream(p),
    3911           0 :                          query->internalStats,
    3912             :                          query->now,
    3913           0 :                          query->report);
    3914             :       }
    3915             :     }
    3916             :   }
    3917             : 
    3918           0 :   if (query->grabAllLevels) {
    3919           0 :     for (size_t i = 0; i < query->iceCtx->GetStreamCount(); ++i) {
    3920           0 :       if (query->iceCtx->GetStream(i)) {
    3921           0 :         RecordIceStats_s(*query->iceCtx->GetStream(i),
    3922           0 :                          query->internalStats,
    3923             :                          query->now,
    3924           0 :                          query->report);
    3925             :       }
    3926             :     }
    3927             :   }
    3928             : 
    3929             :   // NrIceCtx must be destroyed on STS, so it is not safe
    3930             :   // to dispatch it back to main.
    3931           0 :   query->iceCtx = nullptr;
    3932           0 :   return NS_OK;
    3933             : }
    3934             : 
    3935           0 : void PeerConnectionImpl::GetStatsForPCObserver_s(
    3936             :     const std::string& pcHandle, // The Runnable holds the memory
    3937             :     nsAutoPtr<RTCStatsQuery> query) {
    3938             : 
    3939           0 :   MOZ_ASSERT(query);
    3940           0 :   MOZ_ASSERT(query->iceCtx);
    3941           0 :   ASSERT_ON_THREAD(query->iceCtx->thread());
    3942             : 
    3943           0 :   nsresult rv = PeerConnectionImpl::ExecuteStatsQuery_s(query.get());
    3944             : 
    3945             :   NS_DispatchToMainThread(
    3946           0 :       WrapRunnableNM(
    3947             :           &PeerConnectionImpl::DeliverStatsReportToPCObserver_m,
    3948             :           pcHandle,
    3949             :           rv,
    3950             :           query),
    3951           0 :       NS_DISPATCH_NORMAL);
    3952           0 : }
    3953             : 
    3954           0 : void PeerConnectionImpl::DeliverStatsReportToPCObserver_m(
    3955             :     const std::string& pcHandle,
    3956             :     nsresult result,
    3957             :     nsAutoPtr<RTCStatsQuery> query) {
    3958             : 
    3959             :   // Is the PeerConnectionImpl still around?
    3960           0 :   PeerConnectionWrapper pcw(pcHandle);
    3961           0 :   if (pcw.impl()) {
    3962             :     RefPtr<PeerConnectionObserver> pco =
    3963           0 :         do_QueryObjectReferent(pcw.impl()->mPCObserver);
    3964           0 :     if (pco) {
    3965           0 :       JSErrorResult rv;
    3966           0 :       if (NS_SUCCEEDED(result)) {
    3967           0 :         pco->OnGetStatsSuccess(*query->report, rv);
    3968             :       } else {
    3969           0 :         pco->OnGetStatsError(kInternalError,
    3970           0 :             ObString("Failed to fetch statistics"),
    3971           0 :             rv);
    3972             :       }
    3973             : 
    3974           0 :       if (rv.Failed()) {
    3975           0 :         CSFLogError(logTag, "Error firing stats observer callback");
    3976             :       }
    3977             :     }
    3978             :   }
    3979           0 : }
    3980             : 
    3981             : void
    3982           0 : PeerConnectionImpl::RecordLongtermICEStatistics() {
    3983           0 :   WebrtcGlobalInformation::StoreLongTermICEStatistics(*this);
    3984           0 : }
    3985             : 
    3986             : void
    3987           0 : PeerConnectionImpl::OnNegotiationNeeded()
    3988             : {
    3989           0 :   if (mSignalingState != PCImplSignalingState::SignalingStable) {
    3990             :     // We will check whether we need to renegotiate when we reach stable again
    3991           0 :     return;
    3992             :   }
    3993             : 
    3994           0 :   if (mNegotiationNeeded) {
    3995           0 :     return;
    3996             :   }
    3997             : 
    3998           0 :   mNegotiationNeeded = true;
    3999             : 
    4000             :   RUN_ON_THREAD(mThread,
    4001           0 :                 WrapRunnableNM(&MaybeFireNegotiationNeeded_static, mHandle),
    4002           0 :                 NS_DISPATCH_NORMAL);
    4003             : }
    4004             : 
    4005             : /* static */
    4006             : void
    4007           0 : PeerConnectionImpl::MaybeFireNegotiationNeeded_static(
    4008             :     const std::string& pcHandle)
    4009             : {
    4010           0 :   PeerConnectionWrapper wrapper(pcHandle);
    4011           0 :   if (!wrapper.impl()) {
    4012           0 :     return;
    4013             :   }
    4014             : 
    4015           0 :   wrapper.impl()->MaybeFireNegotiationNeeded();
    4016             : }
    4017             : 
    4018             : void
    4019           0 : PeerConnectionImpl::MaybeFireNegotiationNeeded()
    4020             : {
    4021           0 :   if (!mNegotiationNeeded) {
    4022           0 :     return;
    4023             :   }
    4024             : 
    4025           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
    4026           0 :   if (!pco) {
    4027           0 :     return;
    4028             :   }
    4029             : 
    4030           0 :   JSErrorResult rv;
    4031           0 :   pco->OnNegotiationNeeded(rv);
    4032             : }
    4033             : 
    4034             : void
    4035           0 : PeerConnectionImpl::IceStreamReady(NrIceMediaStream *aStream)
    4036             : {
    4037           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    4038           0 :   MOZ_ASSERT(aStream);
    4039             : 
    4040           0 :   CSFLogDebug(logTag, "%s: %s", __FUNCTION__, aStream->name().c_str());
    4041           0 : }
    4042             : 
    4043             : //Telemetry for when calls start
    4044             : void
    4045           0 : PeerConnectionImpl::startCallTelem() {
    4046           0 :   if (!mStartTime.IsNull()) {
    4047           0 :     return;
    4048             :   }
    4049             : 
    4050             :   // Start time for calls
    4051           0 :   mStartTime = TimeStamp::Now();
    4052             : 
    4053             :   // Increment session call counter
    4054             :   // If we want to track Loop calls independently here, we need two histograms.
    4055           0 :   Telemetry::Accumulate(Telemetry::WEBRTC_CALL_COUNT_2, 1);
    4056             : }
    4057             : 
    4058             : NS_IMETHODIMP
    4059           0 : PeerConnectionImpl::GetLocalStreams(nsTArray<RefPtr<DOMMediaStream > >& result)
    4060             : {
    4061           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    4062           0 :   for(uint32_t i=0; i < media()->LocalStreamsLength(); i++) {
    4063           0 :     LocalSourceStreamInfo *info = media()->GetLocalStreamByIndex(i);
    4064           0 :     NS_ENSURE_TRUE(info, NS_ERROR_UNEXPECTED);
    4065           0 :     result.AppendElement(info->GetMediaStream());
    4066             :   }
    4067           0 :   return NS_OK;
    4068             : }
    4069             : 
    4070             : NS_IMETHODIMP
    4071           0 : PeerConnectionImpl::GetRemoteStreams(nsTArray<RefPtr<DOMMediaStream > >& result)
    4072             : {
    4073           0 :   PC_AUTO_ENTER_API_CALL_NO_CHECK();
    4074           0 :   for(uint32_t i=0; i < media()->RemoteStreamsLength(); i++) {
    4075           0 :     RemoteSourceStreamInfo *info = media()->GetRemoteStreamByIndex(i);
    4076           0 :     NS_ENSURE_TRUE(info, NS_ERROR_UNEXPECTED);
    4077           0 :     result.AppendElement(info->GetMediaStream());
    4078             :   }
    4079           0 :   return NS_OK;
    4080             : }
    4081             : 
    4082             : void
    4083           0 : PeerConnectionImpl::DTMFSendTimerCallback_m(nsITimer* timer, void* closure)
    4084             : {
    4085           0 :   MOZ_ASSERT(NS_IsMainThread());
    4086             : 
    4087           0 :   auto state = static_cast<DTMFState*>(closure);
    4088             : 
    4089           0 :   nsString eventTone;
    4090           0 :   if (!state->mTones.IsEmpty()) {
    4091           0 :     uint16_t toneChar = state->mTones.CharAt(0);
    4092           0 :     int tone = GetDTMFToneCode(toneChar);
    4093             : 
    4094           0 :     eventTone.Assign(toneChar);
    4095             : 
    4096           0 :     state->mTones.Cut(0, 1);
    4097             : 
    4098           0 :     if (tone == -1) {
    4099           0 :       state->mSendTimer->InitWithNamedFuncCallback(DTMFSendTimerCallback_m, state,
    4100             :                                                    2000, nsITimer::TYPE_ONE_SHOT,
    4101           0 :                                                    "DTMFSendTimerCallback_m");
    4102             :     } else {
    4103             :       // Reset delay if necessary
    4104           0 :       state->mSendTimer->InitWithNamedFuncCallback(DTMFSendTimerCallback_m, state,
    4105           0 :                                                    state->mDuration + state->mInterToneGap,
    4106             :                                                    nsITimer::TYPE_ONE_SHOT,
    4107           0 :                                                    "DTMFSendTimerCallback_m");
    4108             : 
    4109             :       RefPtr<AudioSessionConduit> conduit =
    4110           0 :         state->mPeerConnectionImpl->mMedia->GetAudioConduit(state->mLevel);
    4111             : 
    4112           0 :       if (conduit) {
    4113           0 :         uint32_t duration = state->mDuration;
    4114           0 :         state->mPeerConnectionImpl->mSTSThread->Dispatch(WrapRunnableNM([conduit, tone, duration] () {
    4115             :             //Note: We default to channel 0, not inband, and 6dB attenuation.
    4116             :             //      here. We might want to revisit these choices in the future.
    4117           0 :             conduit->InsertDTMFTone(0, tone, true, duration, 6);
    4118           0 :           }), NS_DISPATCH_NORMAL);
    4119             :       }
    4120             : 
    4121             :     }
    4122             :   } else {
    4123           0 :     state->mSendTimer->Cancel();
    4124             :   }
    4125             : 
    4126           0 :   RefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(state->mPeerConnectionImpl->mPCObserver);
    4127           0 :   if (!pco) {
    4128           0 :     NS_WARNING("Failed to dispatch the RTCDTMFToneChange event!");
    4129           0 :     return;
    4130             :   }
    4131             : 
    4132           0 :   JSErrorResult jrv;
    4133           0 :   pco->OnDTMFToneChange(state->mTrackId, eventTone, jrv);
    4134             : 
    4135           0 :   if (jrv.Failed()) {
    4136           0 :     NS_WARNING("Failed to dispatch the RTCDTMFToneChange event!");
    4137           0 :     return;
    4138             :   }
    4139             : }
    4140             : 
    4141             : }  // end mozilla namespace

Generated by: LCOV version 1.13