media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2443 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include <cstdlib>
     1.9 +#include <cerrno>
    1.10 +#include <deque>
    1.11 +#include <sstream>
    1.12 +
    1.13 +#include "base/histogram.h"
    1.14 +#include "vcm.h"
    1.15 +#include "CSFLog.h"
    1.16 +#include "timecard.h"
    1.17 +#include "ccapi_call_info.h"
    1.18 +#include "CC_SIPCCCallInfo.h"
    1.19 +#include "ccapi_device_info.h"
    1.20 +#include "CC_SIPCCDeviceInfo.h"
    1.21 +#include "cpr_string.h"
    1.22 +#include "cpr_stdlib.h"
    1.23 +
    1.24 +#include "jsapi.h"
    1.25 +#include "nspr.h"
    1.26 +#include "nss.h"
    1.27 +#include "pk11pub.h"
    1.28 +
    1.29 +#include "nsNetCID.h"
    1.30 +#include "nsIProperty.h"
    1.31 +#include "nsIPropertyBag2.h"
    1.32 +#include "nsIServiceManager.h"
    1.33 +#include "nsISimpleEnumerator.h"
    1.34 +#include "nsServiceManagerUtils.h"
    1.35 +#include "nsISocketTransportService.h"
    1.36 +#include "nsIConsoleService.h"
    1.37 +#include "nsThreadUtils.h"
    1.38 +#include "nsProxyRelease.h"
    1.39 +#include "prtime.h"
    1.40 +
    1.41 +#include "AudioConduit.h"
    1.42 +#include "VideoConduit.h"
    1.43 +#include "runnable_utils.h"
    1.44 +#include "PeerConnectionCtx.h"
    1.45 +#include "PeerConnectionImpl.h"
    1.46 +#include "PeerConnectionMedia.h"
    1.47 +#include "nsDOMDataChannelDeclarations.h"
    1.48 +#include "dtlsidentity.h"
    1.49 +
    1.50 +#ifdef MOZILLA_INTERNAL_API
    1.51 +#include "nsPerformance.h"
    1.52 +#include "nsGlobalWindow.h"
    1.53 +#include "nsDOMDataChannel.h"
    1.54 +#include "mozilla/TimeStamp.h"
    1.55 +#include "mozilla/Telemetry.h"
    1.56 +#include "mozilla/Preferences.h"
    1.57 +#include "mozilla/PublicSSL.h"
    1.58 +#include "nsXULAppAPI.h"
    1.59 +#include "nsContentUtils.h"
    1.60 +#include "nsDOMJSUtils.h"
    1.61 +#include "nsIDocument.h"
    1.62 +#include "nsIScriptError.h"
    1.63 +#include "nsPrintfCString.h"
    1.64 +#include "nsURLHelper.h"
    1.65 +#include "nsNetUtil.h"
    1.66 +#include "nsIDOMDataChannel.h"
    1.67 +#include "nsIDOMLocation.h"
    1.68 +#include "mozilla/dom/RTCConfigurationBinding.h"
    1.69 +#include "mozilla/dom/RTCStatsReportBinding.h"
    1.70 +#include "mozilla/dom/RTCPeerConnectionBinding.h"
    1.71 +#include "mozilla/dom/PeerConnectionImplBinding.h"
    1.72 +#include "mozilla/dom/DataChannelBinding.h"
    1.73 +#include "MediaStreamList.h"
    1.74 +#include "MediaStreamTrack.h"
    1.75 +#include "AudioStreamTrack.h"
    1.76 +#include "VideoStreamTrack.h"
    1.77 +#include "nsIScriptGlobalObject.h"
    1.78 +#include "DOMMediaStream.h"
    1.79 +#include "rlogringbuffer.h"
    1.80 +#include "WebrtcGlobalInformation.h"
    1.81 +#endif
    1.82 +
    1.83 +#ifndef USE_FAKE_MEDIA_STREAMS
    1.84 +#include "MediaSegment.h"
    1.85 +#endif
    1.86 +
    1.87 +#ifdef USE_FAKE_PCOBSERVER
    1.88 +#include "FakePCObserver.h"
    1.89 +#else
    1.90 +#include "mozilla/dom/PeerConnectionObserverBinding.h"
    1.91 +#endif
    1.92 +#include "mozilla/dom/PeerConnectionObserverEnumsBinding.h"
    1.93 +
    1.94 +#define ICE_PARSING "In RTCConfiguration passed to RTCPeerConnection constructor"
    1.95 +
    1.96 +using namespace mozilla;
    1.97 +using namespace mozilla::dom;
    1.98 +
    1.99 +typedef PCObserverString ObString;
   1.100 +
   1.101 +static const char* logTag = "PeerConnectionImpl";
   1.102 +
   1.103 +#ifdef MOZILLA_INTERNAL_API
   1.104 +static nsresult InitNSSInContent()
   1.105 +{
   1.106 +  NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_SAME_THREAD);
   1.107 +
   1.108 +  if (XRE_GetProcessType() != GeckoProcessType_Content) {
   1.109 +    MOZ_ASSUME_UNREACHABLE("Must be called in content process");
   1.110 +  }
   1.111 +
   1.112 +  static bool nssStarted = false;
   1.113 +  if (nssStarted) {
   1.114 +    return NS_OK;
   1.115 +  }
   1.116 +
   1.117 +  if (NSS_NoDB_Init(nullptr) != SECSuccess) {
   1.118 +    CSFLogError(logTag, "NSS_NoDB_Init failed.");
   1.119 +    return NS_ERROR_FAILURE;
   1.120 +  }
   1.121 +
   1.122 +  if (NS_FAILED(mozilla::psm::InitializeCipherSuite())) {
   1.123 +    CSFLogError(logTag, "Fail to set up nss cipher suite.");
   1.124 +    return NS_ERROR_FAILURE;
   1.125 +  }
   1.126 +
   1.127 +  mozilla::psm::DisableMD5();
   1.128 +
   1.129 +  nssStarted = true;
   1.130 +
   1.131 +  return NS_OK;
   1.132 +}
   1.133 +#endif // MOZILLA_INTERNAL_API
   1.134 +
   1.135 +namespace mozilla {
   1.136 +  class DataChannel;
   1.137 +}
   1.138 +
   1.139 +class nsIDOMDataChannel;
   1.140 +
   1.141 +static const int MEDIA_STREAM_MUTE = 0x80;
   1.142 +
   1.143 +PRLogModuleInfo *signalingLogInfo() {
   1.144 +  static PRLogModuleInfo *logModuleInfo = nullptr;
   1.145 +  if (!logModuleInfo) {
   1.146 +    logModuleInfo = PR_NewLogModule("signaling");
   1.147 +  }
   1.148 +  return logModuleInfo;
   1.149 +}
   1.150 +
   1.151 +
   1.152 +namespace sipcc {
   1.153 +
   1.154 +#ifdef MOZILLA_INTERNAL_API
   1.155 +RTCStatsQuery::RTCStatsQuery(bool internal) : internalStats(internal) {
   1.156 +}
   1.157 +
   1.158 +RTCStatsQuery::~RTCStatsQuery() {
   1.159 +  MOZ_ASSERT(NS_IsMainThread());
   1.160 +}
   1.161 +
   1.162 +#endif
   1.163 +
   1.164 +// Getting exceptions back down from PCObserver is generally not harmful.
   1.165 +namespace {
   1.166 +class JSErrorResult : public ErrorResult
   1.167 +{
   1.168 +public:
   1.169 +  ~JSErrorResult()
   1.170 +  {
   1.171 +#ifdef MOZILLA_INTERNAL_API
   1.172 +    WouldReportJSException();
   1.173 +    if (IsJSException()) {
   1.174 +      MOZ_ASSERT(NS_IsMainThread());
   1.175 +      AutoJSContext cx;
   1.176 +      Optional<JS::Handle<JS::Value> > value(cx);
   1.177 +      StealJSException(cx, &value.Value());
   1.178 +    }
   1.179 +#endif
   1.180 +  }
   1.181 +};
   1.182 +
   1.183 +// The WrapRunnable() macros copy passed-in args and passes them to the function
   1.184 +// later on the other thread. ErrorResult cannot be passed like this because it
   1.185 +// disallows copy-semantics.
   1.186 +//
   1.187 +// This WrappableJSErrorResult hack solves this by not actually copying the
   1.188 +// ErrorResult, but creating a new one instead, which works because we don't
   1.189 +// care about the result.
   1.190 +//
   1.191 +// Since this is for JS-calls, these can only be dispatched to the main thread.
   1.192 +
   1.193 +class WrappableJSErrorResult {
   1.194 +public:
   1.195 +  WrappableJSErrorResult() : isCopy(false) {}
   1.196 +  WrappableJSErrorResult(WrappableJSErrorResult &other) : mRv(), isCopy(true) {}
   1.197 +  ~WrappableJSErrorResult() {
   1.198 +    if (isCopy) {
   1.199 +#ifdef MOZILLA_INTERNAL_API
   1.200 +      MOZ_ASSERT(NS_IsMainThread());
   1.201 +#endif
   1.202 +    }
   1.203 +  }
   1.204 +  operator JSErrorResult &() { return mRv; }
   1.205 +private:
   1.206 +  JSErrorResult mRv;
   1.207 +  bool isCopy;
   1.208 +};
   1.209 +}
   1.210 +
   1.211 +class PeerConnectionObserverDispatch : public nsRunnable {
   1.212 +
   1.213 +public:
   1.214 +  PeerConnectionObserverDispatch(CSF::CC_CallInfoPtr aInfo,
   1.215 +                                 nsRefPtr<PeerConnectionImpl> aPC,
   1.216 +                                 PeerConnectionObserver* aObserver)
   1.217 +      : mPC(aPC),
   1.218 +        mObserver(aObserver),
   1.219 +        mCode(static_cast<PeerConnectionImpl::Error>(aInfo->getStatusCode())),
   1.220 +        mReason(aInfo->getStatus()),
   1.221 +        mSdpStr(),
   1.222 +        mCandidateStr(),
   1.223 +        mCallState(aInfo->getCallState()),
   1.224 +        mFsmState(aInfo->getFsmState()),
   1.225 +        mStateStr(aInfo->callStateToString(mCallState)),
   1.226 +        mFsmStateStr(aInfo->fsmStateToString(mFsmState)) {
   1.227 +    if (mCallState == REMOTESTREAMADD) {
   1.228 +      MediaStreamTable *streams = nullptr;
   1.229 +      streams = aInfo->getMediaStreams();
   1.230 +      mRemoteStream = mPC->media()->GetRemoteStream(streams->media_stream_id);
   1.231 +      MOZ_ASSERT(mRemoteStream);
   1.232 +    } else if (mCallState == FOUNDICECANDIDATE) {
   1.233 +        mCandidateStr = aInfo->getCandidate();
   1.234 +    } else if ((mCallState == CREATEOFFERSUCCESS) ||
   1.235 +               (mCallState == CREATEANSWERSUCCESS)) {
   1.236 +        mSdpStr = aInfo->getSDP();
   1.237 +    }
   1.238 +  }
   1.239 +
   1.240 +  ~PeerConnectionObserverDispatch(){}
   1.241 +
   1.242 +#ifdef MOZILLA_INTERNAL_API
   1.243 +  class TracksAvailableCallback : public DOMMediaStream::OnTracksAvailableCallback
   1.244 +  {
   1.245 +  public:
   1.246 +    TracksAvailableCallback(DOMMediaStream::TrackTypeHints aTrackTypeHints,
   1.247 +                            nsRefPtr<PeerConnectionObserver> aObserver)
   1.248 +    : DOMMediaStream::OnTracksAvailableCallback(aTrackTypeHints)
   1.249 +    , mObserver(aObserver) {}
   1.250 +
   1.251 +    virtual void NotifyTracksAvailable(DOMMediaStream* aStream) MOZ_OVERRIDE
   1.252 +    {
   1.253 +      MOZ_ASSERT(NS_IsMainThread());
   1.254 +
   1.255 +      // Start currentTime from the point where this stream was successfully
   1.256 +      // returned.
   1.257 +      aStream->SetLogicalStreamStartTime(aStream->GetStream()->GetCurrentTime());
   1.258 +
   1.259 +      CSFLogInfo(logTag, "Returning success for OnAddStream()");
   1.260 +      // We are running on main thread here so we shouldn't have a race
   1.261 +      // on this callback
   1.262 +      JSErrorResult rv;
   1.263 +      mObserver->OnAddStream(*aStream, rv);
   1.264 +      if (rv.Failed()) {
   1.265 +        CSFLogError(logTag, ": OnAddStream() failed! Error: %d", rv.ErrorCode());
   1.266 +      }
   1.267 +    }
   1.268 +  private:
   1.269 +    nsRefPtr<PeerConnectionObserver> mObserver;
   1.270 +  };
   1.271 +#endif
   1.272 +
   1.273 +  NS_IMETHOD Run() {
   1.274 +
   1.275 +    CSFLogInfo(logTag, "PeerConnectionObserverDispatch processing "
   1.276 +               "mCallState = %d (%s), mFsmState = %d (%s)",
   1.277 +               mCallState, mStateStr.c_str(), mFsmState, mFsmStateStr.c_str());
   1.278 +
   1.279 +    if (mCallState == SETLOCALDESCERROR || mCallState == SETREMOTEDESCERROR) {
   1.280 +      const std::vector<std::string> &errors = mPC->GetSdpParseErrors();
   1.281 +      std::vector<std::string>::const_iterator i;
   1.282 +      for (i = errors.begin(); i != errors.end(); ++i) {
   1.283 +        mReason += " | SDP Parsing Error: " + *i;
   1.284 +      }
   1.285 +      if (errors.size()) {
   1.286 +        mCode = PeerConnectionImpl::kInvalidSessionDescription;
   1.287 +      }
   1.288 +      mPC->ClearSdpParseErrorMessages();
   1.289 +    }
   1.290 +
   1.291 +    if (mReason.length()) {
   1.292 +      CSFLogInfo(logTag, "Message contains error: %d: %s",
   1.293 +                 mCode, mReason.c_str());
   1.294 +    }
   1.295 +
   1.296 +    /*
   1.297 +     * While the fsm_states_t (FSM_DEF_*) constants are a proper superset
   1.298 +     * of SignalingState, and the order in which the SignalingState values
   1.299 +     * appear matches the order they appear in fsm_states_t, their underlying
   1.300 +     * numeric representation is different. Hence, we need to perform an
   1.301 +     * offset calculation to map from one to the other.
   1.302 +     */
   1.303 +
   1.304 +    if (mFsmState >= FSMDEF_S_STABLE && mFsmState <= FSMDEF_S_CLOSED) {
   1.305 +      int offset = FSMDEF_S_STABLE - int(PCImplSignalingState::SignalingStable);
   1.306 +      mPC->SetSignalingState_m(static_cast<PCImplSignalingState>(mFsmState - offset));
   1.307 +    } else {
   1.308 +      CSFLogError(logTag, ": **** UNHANDLED SIGNALING STATE : %d (%s)",
   1.309 +                  mFsmState, mFsmStateStr.c_str());
   1.310 +    }
   1.311 +
   1.312 +    JSErrorResult rv;
   1.313 +
   1.314 +    switch (mCallState) {
   1.315 +      case CREATEOFFERSUCCESS:
   1.316 +        mObserver->OnCreateOfferSuccess(ObString(mSdpStr.c_str()), rv);
   1.317 +        break;
   1.318 +
   1.319 +      case CREATEANSWERSUCCESS:
   1.320 +        mObserver->OnCreateAnswerSuccess(ObString(mSdpStr.c_str()), rv);
   1.321 +        break;
   1.322 +
   1.323 +      case CREATEOFFERERROR:
   1.324 +        mObserver->OnCreateOfferError(mCode, ObString(mReason.c_str()), rv);
   1.325 +        break;
   1.326 +
   1.327 +      case CREATEANSWERERROR:
   1.328 +        mObserver->OnCreateAnswerError(mCode, ObString(mReason.c_str()), rv);
   1.329 +        break;
   1.330 +
   1.331 +      case SETLOCALDESCSUCCESS:
   1.332 +        // TODO: The SDP Parse error list should be copied out and sent up
   1.333 +        // to the Javascript layer before being cleared here. Even though
   1.334 +        // there was not a failure, it is possible that the SDP parse generated
   1.335 +        // warnings. The WebRTC spec does not currently have a mechanism for
   1.336 +        // providing non-fatal warnings.
   1.337 +        mPC->ClearSdpParseErrorMessages();
   1.338 +        mObserver->OnSetLocalDescriptionSuccess(rv);
   1.339 +        break;
   1.340 +
   1.341 +      case SETREMOTEDESCSUCCESS:
   1.342 +        // TODO: The SDP Parse error list should be copied out and sent up
   1.343 +        // to the Javascript layer before being cleared here. Even though
   1.344 +        // there was not a failure, it is possible that the SDP parse generated
   1.345 +        // warnings. The WebRTC spec does not currently have a mechanism for
   1.346 +        // providing non-fatal warnings.
   1.347 +        mPC->ClearSdpParseErrorMessages();
   1.348 +        mObserver->OnSetRemoteDescriptionSuccess(rv);
   1.349 +#ifdef MOZILLA_INTERNAL_API
   1.350 +        mPC->startCallTelem();
   1.351 +#endif
   1.352 +        break;
   1.353 +
   1.354 +      case SETLOCALDESCERROR:
   1.355 +        mObserver->OnSetLocalDescriptionError(mCode,
   1.356 +                                              ObString(mReason.c_str()), rv);
   1.357 +        break;
   1.358 +
   1.359 +      case SETREMOTEDESCERROR:
   1.360 +        mObserver->OnSetRemoteDescriptionError(mCode,
   1.361 +                                               ObString(mReason.c_str()), rv);
   1.362 +        break;
   1.363 +
   1.364 +      case ADDICECANDIDATE:
   1.365 +        mObserver->OnAddIceCandidateSuccess(rv);
   1.366 +        break;
   1.367 +
   1.368 +      case ADDICECANDIDATEERROR:
   1.369 +        mObserver->OnAddIceCandidateError(mCode, ObString(mReason.c_str()), rv);
   1.370 +        break;
   1.371 +
   1.372 +      case FOUNDICECANDIDATE:
   1.373 +        {
   1.374 +            size_t end_of_level = mCandidateStr.find('\t');
   1.375 +            if (end_of_level == std::string::npos) {
   1.376 +                MOZ_ASSERT(false);
   1.377 +                return NS_OK;
   1.378 +            }
   1.379 +            std::string level = mCandidateStr.substr(0, end_of_level);
   1.380 +            if (!level.size()) {
   1.381 +                MOZ_ASSERT(false);
   1.382 +                return NS_OK;
   1.383 +            }
   1.384 +            char *endptr;
   1.385 +            errno = 0;
   1.386 +            unsigned long level_long =
   1.387 +                strtoul(level.c_str(), &endptr, 10);
   1.388 +            if (errno || *endptr != 0 || level_long > 65535) {
   1.389 +                /* Conversion failure */
   1.390 +                MOZ_ASSERT(false);
   1.391 +                return NS_OK;
   1.392 +            }
   1.393 +            size_t end_of_mid = mCandidateStr.find('\t', end_of_level + 1);
   1.394 +            if (end_of_mid == std::string::npos) {
   1.395 +                MOZ_ASSERT(false);
   1.396 +                return NS_OK;
   1.397 +            }
   1.398 +
   1.399 +            std::string mid = mCandidateStr.substr(end_of_level + 1,
   1.400 +                                                   end_of_mid - (end_of_level + 1));
   1.401 +
   1.402 +            std::string candidate = mCandidateStr.substr(end_of_mid + 1);
   1.403 +
   1.404 +            mObserver->OnIceCandidate(level_long & 0xffff,
   1.405 +                                      ObString(mid.c_str()),
   1.406 +                                      ObString(candidate.c_str()), rv);
   1.407 +        }
   1.408 +        break;
   1.409 +      case REMOTESTREAMADD:
   1.410 +        {
   1.411 +          DOMMediaStream* stream = nullptr;
   1.412 +
   1.413 +          if (!mRemoteStream) {
   1.414 +            CSFLogError(logTag, "%s: GetRemoteStream returned NULL", __FUNCTION__);
   1.415 +          } else {
   1.416 +            stream = mRemoteStream->GetMediaStream();
   1.417 +          }
   1.418 +
   1.419 +          if (!stream) {
   1.420 +            CSFLogError(logTag, "%s: GetMediaStream returned NULL", __FUNCTION__);
   1.421 +          } else {
   1.422 +#ifdef MOZILLA_INTERNAL_API
   1.423 +            TracksAvailableCallback* tracksAvailableCallback =
   1.424 +              new TracksAvailableCallback(mRemoteStream->mTrackTypeHints, mObserver);
   1.425 +
   1.426 +            stream->OnTracksAvailable(tracksAvailableCallback);
   1.427 +#else
   1.428 +            mObserver->OnAddStream(stream, rv);
   1.429 +#endif
   1.430 +          }
   1.431 +          break;
   1.432 +        }
   1.433 +
   1.434 +      case UPDATELOCALDESC:
   1.435 +        /* No action necessary */
   1.436 +        break;
   1.437 +
   1.438 +      default:
   1.439 +        CSFLogError(logTag, ": **** UNHANDLED CALL STATE : %d (%s)",
   1.440 +                    mCallState, mStateStr.c_str());
   1.441 +        break;
   1.442 +    }
   1.443 +    return NS_OK;
   1.444 +  }
   1.445 +
   1.446 +private:
   1.447 +  nsRefPtr<PeerConnectionImpl> mPC;
   1.448 +  nsRefPtr<PeerConnectionObserver> mObserver;
   1.449 +  PeerConnectionImpl::Error mCode;
   1.450 +  std::string mReason;
   1.451 +  std::string mSdpStr;
   1.452 +  std::string mCandidateStr;
   1.453 +  cc_call_state_t mCallState;
   1.454 +  fsmdef_states_t mFsmState;
   1.455 +  std::string mStateStr;
   1.456 +  std::string mFsmStateStr;
   1.457 +  nsRefPtr<RemoteSourceStreamInfo> mRemoteStream;
   1.458 +};
   1.459 +
   1.460 +NS_IMPL_ISUPPORTS0(PeerConnectionImpl)
   1.461 +
   1.462 +#ifdef MOZILLA_INTERNAL_API
   1.463 +JSObject*
   1.464 +PeerConnectionImpl::WrapObject(JSContext* aCx)
   1.465 +{
   1.466 +  return PeerConnectionImplBinding::Wrap(aCx, this);
   1.467 +}
   1.468 +#endif
   1.469 +
   1.470 +struct PeerConnectionImpl::Internal {
   1.471 +  CSF::CC_CallPtr mCall;
   1.472 +};
   1.473 +
   1.474 +PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
   1.475 +: mTimeCard(PR_LOG_TEST(signalingLogInfo(),PR_LOG_ERROR) ?
   1.476 +            create_timecard() : nullptr)
   1.477 +  , mInternal(new Internal())
   1.478 +  , mReadyState(PCImplReadyState::New)
   1.479 +  , mSignalingState(PCImplSignalingState::SignalingStable)
   1.480 +  , mIceConnectionState(PCImplIceConnectionState::New)
   1.481 +  , mIceGatheringState(PCImplIceGatheringState::New)
   1.482 +  , mWindow(nullptr)
   1.483 +  , mIdentity(nullptr)
   1.484 +  , mSTSThread(nullptr)
   1.485 +  , mLoadManager(nullptr)
   1.486 +  , mMedia(nullptr)
   1.487 +  , mNumAudioStreams(0)
   1.488 +  , mNumVideoStreams(0)
   1.489 +  , mHaveDataStream(false)
   1.490 +  , mTrickle(true) // TODO(ekr@rtfm.com): Use pref
   1.491 +{
   1.492 +#ifdef MOZILLA_INTERNAL_API
   1.493 +  MOZ_ASSERT(NS_IsMainThread());
   1.494 +  if (aGlobal) {
   1.495 +    mWindow = do_QueryInterface(aGlobal->GetAsSupports());
   1.496 +  }
   1.497 +#endif
   1.498 +  MOZ_ASSERT(mInternal);
   1.499 +  CSFLogInfo(logTag, "%s: PeerConnectionImpl constructor for %s",
   1.500 +             __FUNCTION__, mHandle.c_str());
   1.501 +  STAMP_TIMECARD(mTimeCard, "Constructor Completed");
   1.502 +}
   1.503 +
   1.504 +PeerConnectionImpl::~PeerConnectionImpl()
   1.505 +{
   1.506 +  if (mTimeCard) {
   1.507 +    STAMP_TIMECARD(mTimeCard, "Destructor Invoked");
   1.508 +    print_timecard(mTimeCard);
   1.509 +    destroy_timecard(mTimeCard);
   1.510 +    mTimeCard = nullptr;
   1.511 +  }
   1.512 +  // This aborts if not on main thread (in Debug builds)
   1.513 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
   1.514 +  if (PeerConnectionCtx::isActive()) {
   1.515 +    PeerConnectionCtx::GetInstance()->mPeerConnections.erase(mHandle);
   1.516 +  } else {
   1.517 +    CSFLogError(logTag, "PeerConnectionCtx is already gone. Ignoring...");
   1.518 +  }
   1.519 +
   1.520 +  CSFLogInfo(logTag, "%s: PeerConnectionImpl destructor invoked for %s",
   1.521 +             __FUNCTION__, mHandle.c_str());
   1.522 +  CloseInt();
   1.523 +
   1.524 +#ifdef MOZILLA_INTERNAL_API
   1.525 +  {
   1.526 +    // Deregister as an NSS Shutdown Object
   1.527 +    nsNSSShutDownPreventionLock locker;
   1.528 +    if (!isAlreadyShutDown()) {
   1.529 +      destructorSafeDestroyNSSReference();
   1.530 +      shutdown(calledFromObject);
   1.531 +    }
   1.532 +  }
   1.533 +  if (mLoadManager) {
   1.534 +      mozilla::LoadManagerDestroy(mLoadManager);
   1.535 +      mLoadManager = nullptr;
   1.536 +  }
   1.537 +#endif
   1.538 +
   1.539 +  // Since this and Initialize() occur on MainThread, they can't both be
   1.540 +  // running at once
   1.541 +
   1.542 +  // Right now, we delete PeerConnectionCtx at XPCOM shutdown only, but we
   1.543 +  // probably want to shut it down more aggressively to save memory.  We
   1.544 +  // could shut down here when there are no uses.  It might be more optimal
   1.545 +  // to release off a timer (and XPCOM Shutdown) to avoid churn
   1.546 +}
   1.547 +
   1.548 +already_AddRefed<DOMMediaStream>
   1.549 +PeerConnectionImpl::MakeMediaStream(nsPIDOMWindow* aWindow,
   1.550 +                                    uint32_t aHint)
   1.551 +{
   1.552 +  nsRefPtr<DOMMediaStream> stream =
   1.553 +    DOMMediaStream::CreateSourceStream(aWindow, aHint);
   1.554 +#ifdef MOZILLA_INTERNAL_API
   1.555 +  nsIDocument* doc = aWindow->GetExtantDoc();
   1.556 +  if (!doc) {
   1.557 +    return nullptr;
   1.558 +  }
   1.559 +  // Make the stream data (audio/video samples) accessible to the receiving page.
   1.560 +  stream->CombineWithPrincipal(doc->NodePrincipal());
   1.561 +#endif
   1.562 +
   1.563 +  CSFLogDebug(logTag, "Created media stream %p, inner: %p", stream.get(), stream->GetStream());
   1.564 +
   1.565 +  return stream.forget();
   1.566 +}
   1.567 +
   1.568 +nsresult
   1.569 +PeerConnectionImpl::CreateRemoteSourceStreamInfo(nsRefPtr<RemoteSourceStreamInfo>*
   1.570 +                                                 aInfo)
   1.571 +{
   1.572 +  MOZ_ASSERT(aInfo);
   1.573 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
   1.574 +
   1.575 +  // We need to pass a dummy hint here because FakeMediaStream currently
   1.576 +  // needs to actually propagate a hint for local streams.
   1.577 +  // TODO(ekr@rtfm.com): Clean up when we have explicit track lists.
   1.578 +  // See bug 834835.
   1.579 +  nsRefPtr<DOMMediaStream> stream = MakeMediaStream(mWindow, 0);
   1.580 +  if (!stream) {
   1.581 +    return NS_ERROR_FAILURE;
   1.582 +  }
   1.583 +
   1.584 +  static_cast<SourceMediaStream*>(stream->GetStream())->SetPullEnabled(true);
   1.585 +
   1.586 +  nsRefPtr<RemoteSourceStreamInfo> remote;
   1.587 +  remote = new RemoteSourceStreamInfo(stream.forget(), mMedia);
   1.588 +  *aInfo = remote;
   1.589 +
   1.590 +  return NS_OK;
   1.591 +}
   1.592 +
   1.593 +/**
   1.594 + * In JS, an RTCConfiguration looks like this:
   1.595 + *
   1.596 + * { "iceServers": [ { url:"stun:stun.example.org" },
   1.597 + *                   { url:"turn:turn.example.org?transport=udp",
   1.598 + *                     username: "jib", credential:"mypass"} ] }
   1.599 + *
   1.600 + * This function converts that into an internal IceConfiguration object.
   1.601 + */
   1.602 +nsresult
   1.603 +PeerConnectionImpl::ConvertRTCConfiguration(const RTCConfiguration& aSrc,
   1.604 +                                            IceConfiguration *aDst)
   1.605 +{
   1.606 +#ifdef MOZILLA_INTERNAL_API
   1.607 +  if (!aSrc.mIceServers.WasPassed()) {
   1.608 +    return NS_OK;
   1.609 +  }
   1.610 +  for (uint32_t i = 0; i < aSrc.mIceServers.Value().Length(); i++) {
   1.611 +    const RTCIceServer& server = aSrc.mIceServers.Value()[i];
   1.612 +    NS_ENSURE_TRUE(server.mUrl.WasPassed(), NS_ERROR_UNEXPECTED);
   1.613 +
   1.614 +    // Without STUN/TURN handlers, NS_NewURI returns nsSimpleURI rather than
   1.615 +    // nsStandardURL. To parse STUN/TURN URI's to spec
   1.616 +    // http://tools.ietf.org/html/draft-nandakumar-rtcweb-stun-uri-02#section-3
   1.617 +    // http://tools.ietf.org/html/draft-petithuguenin-behave-turn-uri-03#section-3
   1.618 +    // we parse out the query-string, and use ParseAuthority() on the rest
   1.619 +    nsRefPtr<nsIURI> url;
   1.620 +    nsresult rv = NS_NewURI(getter_AddRefs(url), server.mUrl.Value());
   1.621 +    NS_ENSURE_SUCCESS(rv, rv);
   1.622 +    bool isStun = false, isStuns = false, isTurn = false, isTurns = false;
   1.623 +    url->SchemeIs("stun", &isStun);
   1.624 +    url->SchemeIs("stuns", &isStuns);
   1.625 +    url->SchemeIs("turn", &isTurn);
   1.626 +    url->SchemeIs("turns", &isTurns);
   1.627 +    if (!(isStun || isStuns || isTurn || isTurns)) {
   1.628 +      return NS_ERROR_FAILURE;
   1.629 +    }
   1.630 +    nsAutoCString spec;
   1.631 +    rv = url->GetSpec(spec);
   1.632 +    NS_ENSURE_SUCCESS(rv, rv);
   1.633 +
   1.634 +    // TODO(jib@mozilla.com): Revisit once nsURI supports STUN/TURN (Bug 833509)
   1.635 +    int32_t port;
   1.636 +    nsAutoCString host;
   1.637 +    nsAutoCString transport;
   1.638 +    {
   1.639 +      uint32_t hostPos;
   1.640 +      int32_t hostLen;
   1.641 +      nsAutoCString path;
   1.642 +      rv = url->GetPath(path);
   1.643 +      NS_ENSURE_SUCCESS(rv, rv);
   1.644 +
   1.645 +      // Tolerate query-string + parse 'transport=[udp|tcp]' by hand.
   1.646 +      int32_t questionmark = path.FindChar('?');
   1.647 +      if (questionmark >= 0) {
   1.648 +        const nsCString match = NS_LITERAL_CSTRING("transport=");
   1.649 +
   1.650 +        for (int32_t i = questionmark, endPos; i >= 0; i = endPos) {
   1.651 +          endPos = path.FindCharInSet("&", i + 1);
   1.652 +          const nsDependentCSubstring fieldvaluepair = Substring(path, i + 1,
   1.653 +                                                                 endPos);
   1.654 +          if (StringBeginsWith(fieldvaluepair, match)) {
   1.655 +            transport = Substring(fieldvaluepair, match.Length());
   1.656 +            ToLowerCase(transport);
   1.657 +          }
   1.658 +        }
   1.659 +        path.SetLength(questionmark);
   1.660 +      }
   1.661 +
   1.662 +      rv = net_GetAuthURLParser()->ParseAuthority(path.get(), path.Length(),
   1.663 +                                                  nullptr,  nullptr,
   1.664 +                                                  nullptr,  nullptr,
   1.665 +                                                  &hostPos,  &hostLen, &port);
   1.666 +      NS_ENSURE_SUCCESS(rv, rv);
   1.667 +      if (!hostLen) {
   1.668 +        return NS_ERROR_FAILURE;
   1.669 +      }
   1.670 +      if (hostPos > 1)  /* The username was removed */
   1.671 +        return NS_ERROR_FAILURE;
   1.672 +      path.Mid(host, hostPos, hostLen);
   1.673 +    }
   1.674 +    if (port == -1)
   1.675 +      port = (isStuns || isTurns)? 5349 : 3478;
   1.676 +
   1.677 +    if (isTurn || isTurns) {
   1.678 +      NS_ConvertUTF16toUTF8 credential(server.mCredential);
   1.679 +      NS_ConvertUTF16toUTF8 username(server.mUsername);
   1.680 +
   1.681 +#ifdef MOZ_WIDGET_GONK
   1.682 +      if (transport == kNrIceTransportTcp)
   1.683 +          continue;
   1.684 +#endif
   1.685 +      if (!aDst->addTurnServer(host.get(), port,
   1.686 +                               username.get(),
   1.687 +                               credential.get(),
   1.688 +                               (transport.IsEmpty() ?
   1.689 +                                kNrIceTransportUdp : transport.get()))) {
   1.690 +        return NS_ERROR_FAILURE;
   1.691 +      }
   1.692 +    } else {
   1.693 +      if (!aDst->addStunServer(host.get(), port)) {
   1.694 +        return NS_ERROR_FAILURE;
   1.695 +      }
   1.696 +    }
   1.697 +  }
   1.698 +#endif
   1.699 +  return NS_OK;
   1.700 +}
   1.701 +
   1.702 +NS_IMETHODIMP
   1.703 +PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
   1.704 +                               nsGlobalWindow* aWindow,
   1.705 +                               const IceConfiguration* aConfiguration,
   1.706 +                               const RTCConfiguration* aRTCConfiguration,
   1.707 +                               nsISupports* aThread)
   1.708 +{
   1.709 +  nsresult res;
   1.710 +
   1.711 +  // Invariant: we receive configuration one way or the other but not both (XOR)
   1.712 +  MOZ_ASSERT(!aConfiguration != !aRTCConfiguration);
   1.713 +#ifdef MOZILLA_INTERNAL_API
   1.714 +  MOZ_ASSERT(NS_IsMainThread());
   1.715 +#endif
   1.716 +  MOZ_ASSERT(aThread);
   1.717 +  mThread = do_QueryInterface(aThread);
   1.718 +
   1.719 +  mPCObserver = do_GetWeakReference(&aObserver);
   1.720 +
   1.721 +  // Find the STS thread
   1.722 +
   1.723 +  mSTSThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &res);
   1.724 +  MOZ_ASSERT(mSTSThread);
   1.725 +#ifdef MOZILLA_INTERNAL_API
   1.726 +
   1.727 +  // Initialize NSS if we are in content process. For chrome process, NSS should already
   1.728 +  // been initialized.
   1.729 +  if (XRE_GetProcessType() == GeckoProcessType_Default) {
   1.730 +    // This code interferes with the C++ unit test startup code.
   1.731 +    nsCOMPtr<nsISupports> nssDummy = do_GetService("@mozilla.org/psm;1", &res);
   1.732 +    NS_ENSURE_SUCCESS(res, res);
   1.733 +  } else {
   1.734 +    NS_ENSURE_SUCCESS(res = InitNSSInContent(), res);
   1.735 +  }
   1.736 +
   1.737 +  // Currently no standalone unit tests for DataChannel,
   1.738 +  // which is the user of mWindow
   1.739 +  MOZ_ASSERT(aWindow);
   1.740 +  mWindow = aWindow;
   1.741 +  NS_ENSURE_STATE(mWindow);
   1.742 +
   1.743 +#endif // MOZILLA_INTERNAL_API
   1.744 +
   1.745 +  PRTime timestamp = PR_Now();
   1.746 +  // Ok if we truncate this.
   1.747 +  char temp[128];
   1.748 +
   1.749 +#ifdef MOZILLA_INTERNAL_API
   1.750 +  nsAutoCString locationCStr;
   1.751 +  nsIDOMLocation* location;
   1.752 +  res = mWindow->GetLocation(&location);
   1.753 +
   1.754 +  if (location && NS_SUCCEEDED(res)) {
   1.755 +    nsAutoString locationAStr;
   1.756 +    location->ToString(locationAStr);
   1.757 +    location->Release();
   1.758 +
   1.759 +    CopyUTF16toUTF8(locationAStr, locationCStr);
   1.760 +  }
   1.761 +
   1.762 +  PR_snprintf(
   1.763 +      temp,
   1.764 +      sizeof(temp),
   1.765 +      "%llu (id=%llu url=%s)",
   1.766 +      static_cast<unsigned long long>(timestamp),
   1.767 +      static_cast<unsigned long long>(mWindow ? mWindow->WindowID() : 0),
   1.768 +      locationCStr.get() ? locationCStr.get() : "NULL");
   1.769 +
   1.770 +#else
   1.771 +  PR_snprintf(temp, sizeof(temp), "%llu", (unsigned long long)timestamp);
   1.772 +#endif // MOZILLA_INTERNAL_API
   1.773 +
   1.774 +  mName = temp;
   1.775 +
   1.776 +  // Generate a random handle
   1.777 +  unsigned char handle_bin[8];
   1.778 +  SECStatus rv;
   1.779 +  rv = PK11_GenerateRandom(handle_bin, sizeof(handle_bin));
   1.780 +  if (rv != SECSuccess) {
   1.781 +    MOZ_CRASH();
   1.782 +    return NS_ERROR_UNEXPECTED;
   1.783 +  }
   1.784 +
   1.785 +  char hex[17];
   1.786 +  PR_snprintf(hex,sizeof(hex),"%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
   1.787 +    handle_bin[0],
   1.788 +    handle_bin[1],
   1.789 +    handle_bin[2],
   1.790 +    handle_bin[3],
   1.791 +    handle_bin[4],
   1.792 +    handle_bin[5],
   1.793 +    handle_bin[6],
   1.794 +    handle_bin[7]);
   1.795 +
   1.796 +  mHandle = hex;
   1.797 +
   1.798 +  STAMP_TIMECARD(mTimeCard, "Initializing PC Ctx");
   1.799 +  res = PeerConnectionCtx::InitializeGlobal(mThread, mSTSThread);
   1.800 +  NS_ENSURE_SUCCESS(res, res);
   1.801 +
   1.802 +  PeerConnectionCtx *pcctx = PeerConnectionCtx::GetInstance();
   1.803 +  MOZ_ASSERT(pcctx);
   1.804 +  STAMP_TIMECARD(mTimeCard, "Done Initializing PC Ctx");
   1.805 +
   1.806 +  mInternal->mCall = pcctx->createCall();
   1.807 +  if (!mInternal->mCall.get()) {
   1.808 +    CSFLogError(logTag, "%s: Couldn't Create Call Object", __FUNCTION__);
   1.809 +    return NS_ERROR_FAILURE;
   1.810 +  }
   1.811 +
   1.812 +  IceConfiguration converted;
   1.813 +  if (aRTCConfiguration) {
   1.814 +    res = ConvertRTCConfiguration(*aRTCConfiguration, &converted);
   1.815 +    if (NS_FAILED(res)) {
   1.816 +      CSFLogError(logTag, "%s: Invalid RTCConfiguration", __FUNCTION__);
   1.817 +      return res;
   1.818 +    }
   1.819 +    aConfiguration = &converted;
   1.820 +  }
   1.821 +
   1.822 +  mMedia = new PeerConnectionMedia(this);
   1.823 +
   1.824 +  // Connect ICE slots.
   1.825 +  mMedia->SignalIceGatheringStateChange.connect(
   1.826 +      this,
   1.827 +      &PeerConnectionImpl::IceGatheringStateChange);
   1.828 +  mMedia->SignalIceConnectionStateChange.connect(
   1.829 +      this,
   1.830 +      &PeerConnectionImpl::IceConnectionStateChange);
   1.831 +
   1.832 +  // Initialize the media object.
   1.833 +  res = mMedia->Init(aConfiguration->getStunServers(),
   1.834 +                     aConfiguration->getTurnServers());
   1.835 +  if (NS_FAILED(res)) {
   1.836 +    CSFLogError(logTag, "%s: Couldn't initialize media object", __FUNCTION__);
   1.837 +    return res;
   1.838 +  }
   1.839 +
   1.840 +  // Store under mHandle
   1.841 +  mInternal->mCall->setPeerConnection(mHandle);
   1.842 +  PeerConnectionCtx::GetInstance()->mPeerConnections[mHandle] = this;
   1.843 +
   1.844 +  STAMP_TIMECARD(mTimeCard, "Generating DTLS Identity");
   1.845 +  // Create the DTLS Identity
   1.846 +  mIdentity = DtlsIdentity::Generate();
   1.847 +  STAMP_TIMECARD(mTimeCard, "Done Generating DTLS Identity");
   1.848 +
   1.849 +  if (!mIdentity) {
   1.850 +    CSFLogError(logTag, "%s: Generate returned NULL", __FUNCTION__);
   1.851 +    return NS_ERROR_FAILURE;
   1.852 +  }
   1.853 +
   1.854 +  mFingerprint = mIdentity->GetFormattedFingerprint();
   1.855 +  if (mFingerprint.empty()) {
   1.856 +    CSFLogError(logTag, "%s: unable to get fingerprint", __FUNCTION__);
   1.857 +    return res;
   1.858 +  }
   1.859 +
   1.860 +#ifdef MOZILLA_INTERNAL_API
   1.861 +  if (mozilla::Preferences::GetBool("media.navigator.load_adapt", false)) {
   1.862 +    mLoadManager = mozilla::LoadManagerBuild();
   1.863 +  }
   1.864 +#endif
   1.865 +
   1.866 +  return NS_OK;
   1.867 +}
   1.868 +
   1.869 +RefPtr<DtlsIdentity> const
   1.870 +PeerConnectionImpl::GetIdentity() const
   1.871 +{
   1.872 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
   1.873 +  return mIdentity;
   1.874 +}
   1.875 +
   1.876 +std::string
   1.877 +PeerConnectionImpl::GetFingerprint() const
   1.878 +{
   1.879 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
   1.880 +  return mFingerprint;
   1.881 +}
   1.882 +
   1.883 +NS_IMETHODIMP
   1.884 +PeerConnectionImpl::FingerprintSplitHelper(std::string& fingerprint,
   1.885 +    size_t& spaceIdx) const
   1.886 +{
   1.887 +  fingerprint = GetFingerprint();
   1.888 +  spaceIdx = fingerprint.find_first_of(' ');
   1.889 +  if (spaceIdx == std::string::npos) {
   1.890 +    CSFLogError(logTag, "%s: fingerprint is messed up: %s",
   1.891 +        __FUNCTION__, fingerprint.c_str());
   1.892 +    return NS_ERROR_FAILURE;
   1.893 +  }
   1.894 +  return NS_OK;
   1.895 +}
   1.896 +
   1.897 +std::string
   1.898 +PeerConnectionImpl::GetFingerprintAlgorithm() const
   1.899 +{
   1.900 +  std::string fp;
   1.901 +  size_t spc;
   1.902 +  if (NS_SUCCEEDED(FingerprintSplitHelper(fp, spc))) {
   1.903 +    return fp.substr(0, spc);
   1.904 +  }
   1.905 +  return "";
   1.906 +}
   1.907 +
   1.908 +std::string
   1.909 +PeerConnectionImpl::GetFingerprintHexValue() const
   1.910 +{
   1.911 +  std::string fp;
   1.912 +  size_t spc;
   1.913 +  if (NS_SUCCEEDED(FingerprintSplitHelper(fp, spc))) {
   1.914 +    return fp.substr(spc + 1);
   1.915 +  }
   1.916 +  return "";
   1.917 +}
   1.918 +
   1.919 +
   1.920 +nsresult
   1.921 +PeerConnectionImpl::CreateFakeMediaStream(uint32_t aHint, nsIDOMMediaStream** aRetval)
   1.922 +{
   1.923 +  MOZ_ASSERT(aRetval);
   1.924 +  PC_AUTO_ENTER_API_CALL(false);
   1.925 +
   1.926 +  bool mute = false;
   1.927 +
   1.928 +  // Hack to allow you to mute the stream
   1.929 +  if (aHint & MEDIA_STREAM_MUTE) {
   1.930 +    mute = true;
   1.931 +    aHint &= ~MEDIA_STREAM_MUTE;
   1.932 +  }
   1.933 +
   1.934 +  nsRefPtr<DOMMediaStream> stream = MakeMediaStream(mWindow, aHint);
   1.935 +  if (!stream) {
   1.936 +    return NS_ERROR_FAILURE;
   1.937 +  }
   1.938 +
   1.939 +  if (!mute) {
   1.940 +    if (aHint & DOMMediaStream::HINT_CONTENTS_AUDIO) {
   1.941 +      new Fake_AudioGenerator(stream);
   1.942 +    } else {
   1.943 +#ifdef MOZILLA_INTERNAL_API
   1.944 +    new Fake_VideoGenerator(stream);
   1.945 +#endif
   1.946 +    }
   1.947 +  }
   1.948 +
   1.949 +  stream.forget(aRetval);
   1.950 +  return NS_OK;
   1.951 +}
   1.952 +
   1.953 +// Stubbing this call out for now.
   1.954 +// We can remove it when we are confident of datachannels being started
   1.955 +// correctly on SDP negotiation (bug 852908)
   1.956 +NS_IMETHODIMP
   1.957 +PeerConnectionImpl::ConnectDataConnection(uint16_t aLocalport,
   1.958 +                                          uint16_t aRemoteport,
   1.959 +                                          uint16_t aNumstreams)
   1.960 +{
   1.961 +  return NS_OK; // InitializeDataChannel(aLocalport, aRemoteport, aNumstreams);
   1.962 +}
   1.963 +
   1.964 +// Data channels won't work without a window, so in order for the C++ unit
   1.965 +// tests to work (it doesn't have a window available) we ifdef the following
   1.966 +// two implementations.
   1.967 +NS_IMETHODIMP
   1.968 +PeerConnectionImpl::EnsureDataConnection(uint16_t aNumstreams)
   1.969 +{
   1.970 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
   1.971 +
   1.972 +#ifdef MOZILLA_INTERNAL_API
   1.973 +  if (mDataConnection) {
   1.974 +    CSFLogDebug(logTag,"%s DataConnection already connected",__FUNCTION__);
   1.975 +    // Ignore the request to connect when already connected.  This entire
   1.976 +    // implementation is temporary.  Ignore aNumstreams as it's merely advisory
   1.977 +    // and we increase the number of streams dynamically as needed.
   1.978 +    return NS_OK;
   1.979 +  }
   1.980 +  mDataConnection = new DataChannelConnection(this);
   1.981 +  if (!mDataConnection->Init(5000, aNumstreams, true)) {
   1.982 +    CSFLogError(logTag,"%s DataConnection Init Failed",__FUNCTION__);
   1.983 +    return NS_ERROR_FAILURE;
   1.984 +  }
   1.985 +  CSFLogDebug(logTag,"%s DataChannelConnection %p attached to %s",
   1.986 +              __FUNCTION__, (void*) mDataConnection.get(), mHandle.c_str());
   1.987 +#endif
   1.988 +  return NS_OK;
   1.989 +}
   1.990 +
   1.991 +nsresult
   1.992 +PeerConnectionImpl::InitializeDataChannel(int track_id,
   1.993 +                                          uint16_t aLocalport,
   1.994 +                                          uint16_t aRemoteport,
   1.995 +                                          uint16_t aNumstreams)
   1.996 +{
   1.997 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
   1.998 +
   1.999 +#ifdef MOZILLA_INTERNAL_API
  1.1000 +  nsresult rv = EnsureDataConnection(aNumstreams);
  1.1001 +  if (NS_SUCCEEDED(rv)) {
  1.1002 +    // use the specified TransportFlow
  1.1003 +    nsRefPtr<TransportFlow> flow = mMedia->GetTransportFlow(track_id, false).get();
  1.1004 +    CSFLogDebug(logTag, "Transportflow[%d] = %p", track_id, flow.get());
  1.1005 +    if (flow) {
  1.1006 +      if (mDataConnection->ConnectViaTransportFlow(flow, aLocalport, aRemoteport)) {
  1.1007 +        return NS_OK;
  1.1008 +      }
  1.1009 +    }
  1.1010 +    // If we inited the DataConnection, call Destroy() before releasing it
  1.1011 +    mDataConnection->Destroy();
  1.1012 +  }
  1.1013 +  mDataConnection = nullptr;
  1.1014 +#endif
  1.1015 +  return NS_ERROR_FAILURE;
  1.1016 +}
  1.1017 +
  1.1018 +already_AddRefed<nsDOMDataChannel>
  1.1019 +PeerConnectionImpl::CreateDataChannel(const nsAString& aLabel,
  1.1020 +                                      const nsAString& aProtocol,
  1.1021 +                                      uint16_t aType,
  1.1022 +                                      bool outOfOrderAllowed,
  1.1023 +                                      uint16_t aMaxTime,
  1.1024 +                                      uint16_t aMaxNum,
  1.1025 +                                      bool aExternalNegotiated,
  1.1026 +                                      uint16_t aStream,
  1.1027 +                                      ErrorResult &rv)
  1.1028 +{
  1.1029 +#ifdef MOZILLA_INTERNAL_API
  1.1030 +  nsRefPtr<nsDOMDataChannel> result;
  1.1031 +  rv = CreateDataChannel(aLabel, aProtocol, aType, outOfOrderAllowed,
  1.1032 +                         aMaxTime, aMaxNum, aExternalNegotiated,
  1.1033 +                         aStream, getter_AddRefs(result));
  1.1034 +  return result.forget();
  1.1035 +#else
  1.1036 +  return nullptr;
  1.1037 +#endif
  1.1038 +}
  1.1039 +
  1.1040 +NS_IMETHODIMP
  1.1041 +PeerConnectionImpl::CreateDataChannel(const nsAString& aLabel,
  1.1042 +                                      const nsAString& aProtocol,
  1.1043 +                                      uint16_t aType,
  1.1044 +                                      bool outOfOrderAllowed,
  1.1045 +                                      uint16_t aMaxTime,
  1.1046 +                                      uint16_t aMaxNum,
  1.1047 +                                      bool aExternalNegotiated,
  1.1048 +                                      uint16_t aStream,
  1.1049 +                                      nsDOMDataChannel** aRetval)
  1.1050 +{
  1.1051 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1052 +  MOZ_ASSERT(aRetval);
  1.1053 +
  1.1054 +#ifdef MOZILLA_INTERNAL_API
  1.1055 +  nsRefPtr<DataChannel> dataChannel;
  1.1056 +  DataChannelConnection::Type theType =
  1.1057 +    static_cast<DataChannelConnection::Type>(aType);
  1.1058 +
  1.1059 +  nsresult rv = EnsureDataConnection(WEBRTC_DATACHANNEL_STREAMS_DEFAULT);
  1.1060 +  if (NS_FAILED(rv)) {
  1.1061 +    return rv;
  1.1062 +  }
  1.1063 +  dataChannel = mDataConnection->Open(
  1.1064 +    NS_ConvertUTF16toUTF8(aLabel), NS_ConvertUTF16toUTF8(aProtocol), theType,
  1.1065 +    !outOfOrderAllowed,
  1.1066 +    aType == DataChannelConnection::PARTIAL_RELIABLE_REXMIT ? aMaxNum :
  1.1067 +    (aType == DataChannelConnection::PARTIAL_RELIABLE_TIMED ? aMaxTime : 0),
  1.1068 +    nullptr, nullptr, aExternalNegotiated, aStream
  1.1069 +  );
  1.1070 +  NS_ENSURE_TRUE(dataChannel,NS_ERROR_FAILURE);
  1.1071 +
  1.1072 +  CSFLogDebug(logTag, "%s: making DOMDataChannel", __FUNCTION__);
  1.1073 +
  1.1074 +  if (!mHaveDataStream) {
  1.1075 +    // XXX stream_id of 0 might confuse things...
  1.1076 +    mInternal->mCall->addStream(0, 2, DATA, 0);
  1.1077 +    mHaveDataStream = true;
  1.1078 +  }
  1.1079 +  nsIDOMDataChannel *retval;
  1.1080 +  rv = NS_NewDOMDataChannel(dataChannel.forget(), mWindow, &retval);
  1.1081 +  if (NS_FAILED(rv)) {
  1.1082 +    return rv;
  1.1083 +  }
  1.1084 +  *aRetval = static_cast<nsDOMDataChannel*>(retval);
  1.1085 +#endif
  1.1086 +  return NS_OK;
  1.1087 +}
  1.1088 +
  1.1089 +// do_QueryObjectReferent() - Helps get PeerConnectionObserver from nsWeakPtr.
  1.1090 +//
  1.1091 +// nsWeakPtr deals in XPCOM interfaces, while webidl bindings are concrete objs.
  1.1092 +// TODO: Turn this into a central (template) function somewhere (Bug 939178)
  1.1093 +//
  1.1094 +// Without it, each weak-ref call in this file would look like this:
  1.1095 +//
  1.1096 +//  nsCOMPtr<nsISupportsWeakReference> tmp = do_QueryReferent(mPCObserver);
  1.1097 +//  if (!tmp) {
  1.1098 +//    return;
  1.1099 +//  }
  1.1100 +//  nsRefPtr<nsSupportsWeakReference> tmp2 = do_QueryObject(tmp);
  1.1101 +//  nsRefPtr<PeerConnectionObserver> pco = static_cast<PeerConnectionObserver*>(&*tmp2);
  1.1102 +
  1.1103 +static already_AddRefed<PeerConnectionObserver>
  1.1104 +do_QueryObjectReferent(nsIWeakReference* aRawPtr) {
  1.1105 +  nsCOMPtr<nsISupportsWeakReference> tmp = do_QueryReferent(aRawPtr);
  1.1106 +  if (!tmp) {
  1.1107 +    return nullptr;
  1.1108 +  }
  1.1109 +  nsRefPtr<nsSupportsWeakReference> tmp2 = do_QueryObject(tmp);
  1.1110 +  nsRefPtr<PeerConnectionObserver> tmp3 = static_cast<PeerConnectionObserver*>(&*tmp2);
  1.1111 +  return tmp3.forget();
  1.1112 +}
  1.1113 +
  1.1114 +void
  1.1115 +PeerConnectionImpl::NotifyConnection()
  1.1116 +{
  1.1117 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1118 +
  1.1119 +  CSFLogDebug(logTag, "%s", __FUNCTION__);
  1.1120 +
  1.1121 +#ifdef MOZILLA_INTERNAL_API
  1.1122 +  nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
  1.1123 +  if (!pco) {
  1.1124 +    return;
  1.1125 +  }
  1.1126 +  WrappableJSErrorResult rv;
  1.1127 +  RUN_ON_THREAD(mThread,
  1.1128 +                WrapRunnable(pco,
  1.1129 +                             &PeerConnectionObserver::NotifyConnection,
  1.1130 +                             rv, static_cast<JSCompartment*>(nullptr)),
  1.1131 +                NS_DISPATCH_NORMAL);
  1.1132 +#endif
  1.1133 +}
  1.1134 +
  1.1135 +void
  1.1136 +PeerConnectionImpl::NotifyClosedConnection()
  1.1137 +{
  1.1138 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1139 +
  1.1140 +  CSFLogDebug(logTag, "%s", __FUNCTION__);
  1.1141 +
  1.1142 +#ifdef MOZILLA_INTERNAL_API
  1.1143 +  nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
  1.1144 +  if (!pco) {
  1.1145 +    return;
  1.1146 +  }
  1.1147 +  WrappableJSErrorResult rv;
  1.1148 +  RUN_ON_THREAD(mThread,
  1.1149 +    WrapRunnable(pco, &PeerConnectionObserver::NotifyClosedConnection,
  1.1150 +                 rv, static_cast<JSCompartment*>(nullptr)),
  1.1151 +    NS_DISPATCH_NORMAL);
  1.1152 +#endif
  1.1153 +}
  1.1154 +
  1.1155 +
  1.1156 +#ifdef MOZILLA_INTERNAL_API
  1.1157 +// Not a member function so that we don't need to keep the PC live.
  1.1158 +static void NotifyDataChannel_m(nsRefPtr<nsIDOMDataChannel> aChannel,
  1.1159 +                                nsRefPtr<PeerConnectionObserver> aObserver)
  1.1160 +{
  1.1161 +  MOZ_ASSERT(NS_IsMainThread());
  1.1162 +  JSErrorResult rv;
  1.1163 +  nsRefPtr<nsDOMDataChannel> channel = static_cast<nsDOMDataChannel*>(&*aChannel);
  1.1164 +  aObserver->NotifyDataChannel(*channel, rv);
  1.1165 +  NS_DataChannelAppReady(aChannel);
  1.1166 +}
  1.1167 +#endif
  1.1168 +
  1.1169 +void
  1.1170 +PeerConnectionImpl::NotifyDataChannel(already_AddRefed<DataChannel> aChannel)
  1.1171 +{
  1.1172 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1173 +
  1.1174 +  // XXXkhuey this is completely fucked up.  We can't use nsRefPtr<DataChannel>
  1.1175 +  // here because DataChannel's AddRef/Release are non-virtual and not visible
  1.1176 +  // if !MOZILLA_INTERNAL_API, but this function leaks the DataChannel if
  1.1177 +  // !MOZILLA_INTERNAL_API because it never transfers the ref to
  1.1178 +  // NS_NewDOMDataChannel.
  1.1179 +  DataChannel* channel = aChannel.take();
  1.1180 +  MOZ_ASSERT(channel);
  1.1181 +
  1.1182 +  CSFLogDebug(logTag, "%s: channel: %p", __FUNCTION__, channel);
  1.1183 +
  1.1184 +#ifdef MOZILLA_INTERNAL_API
  1.1185 +  nsCOMPtr<nsIDOMDataChannel> domchannel;
  1.1186 +  nsresult rv = NS_NewDOMDataChannel(already_AddRefed<DataChannel>(channel),
  1.1187 +                                     mWindow, getter_AddRefs(domchannel));
  1.1188 +  NS_ENSURE_SUCCESS_VOID(rv);
  1.1189 +
  1.1190 +  nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
  1.1191 +  if (!pco) {
  1.1192 +    return;
  1.1193 +  }
  1.1194 +
  1.1195 +  RUN_ON_THREAD(mThread,
  1.1196 +                WrapRunnableNM(NotifyDataChannel_m,
  1.1197 +                               domchannel.get(),
  1.1198 +                               pco),
  1.1199 +                NS_DISPATCH_NORMAL);
  1.1200 +#endif
  1.1201 +}
  1.1202 +
  1.1203 +NS_IMETHODIMP
  1.1204 +PeerConnectionImpl::CreateOffer(const MediaConstraintsInternal& aConstraints)
  1.1205 +{
  1.1206 +  return CreateOffer(MediaConstraintsExternal (aConstraints));
  1.1207 +}
  1.1208 +
  1.1209 +// Used by unit tests and the IDL CreateOffer.
  1.1210 +NS_IMETHODIMP
  1.1211 +PeerConnectionImpl::CreateOffer(const MediaConstraintsExternal& aConstraints)
  1.1212 +{
  1.1213 +  PC_AUTO_ENTER_API_CALL(true);
  1.1214 +
  1.1215 +  Timecard *tc = mTimeCard;
  1.1216 +  mTimeCard = nullptr;
  1.1217 +  STAMP_TIMECARD(tc, "Create Offer");
  1.1218 +
  1.1219 +  cc_media_constraints_t* cc_constraints = aConstraints.build();
  1.1220 +  NS_ENSURE_TRUE(cc_constraints, NS_ERROR_UNEXPECTED);
  1.1221 +  mInternal->mCall->createOffer(cc_constraints, tc);
  1.1222 +  return NS_OK;
  1.1223 +}
  1.1224 +
  1.1225 +NS_IMETHODIMP
  1.1226 +PeerConnectionImpl::CreateAnswer(const MediaConstraintsInternal& aConstraints)
  1.1227 +{
  1.1228 +  return CreateAnswer(MediaConstraintsExternal (aConstraints));
  1.1229 +}
  1.1230 +
  1.1231 +NS_IMETHODIMP
  1.1232 +PeerConnectionImpl::CreateAnswer(const MediaConstraintsExternal& aConstraints)
  1.1233 +{
  1.1234 +  PC_AUTO_ENTER_API_CALL(true);
  1.1235 +
  1.1236 +  Timecard *tc = mTimeCard;
  1.1237 +  mTimeCard = nullptr;
  1.1238 +  STAMP_TIMECARD(tc, "Create Answer");
  1.1239 +
  1.1240 +  cc_media_constraints_t* cc_constraints = aConstraints.build();
  1.1241 +  NS_ENSURE_TRUE(cc_constraints, NS_ERROR_UNEXPECTED);
  1.1242 +  mInternal->mCall->createAnswer(cc_constraints, tc);
  1.1243 +  return NS_OK;
  1.1244 +}
  1.1245 +
  1.1246 +NS_IMETHODIMP
  1.1247 +PeerConnectionImpl::SetLocalDescription(int32_t aAction, const char* aSDP)
  1.1248 +{
  1.1249 +  PC_AUTO_ENTER_API_CALL(true);
  1.1250 +
  1.1251 +  if (!aSDP) {
  1.1252 +    CSFLogError(logTag, "%s - aSDP is NULL", __FUNCTION__);
  1.1253 +    return NS_ERROR_FAILURE;
  1.1254 +  }
  1.1255 +
  1.1256 +  Timecard *tc = mTimeCard;
  1.1257 +  mTimeCard = nullptr;
  1.1258 +  STAMP_TIMECARD(tc, "Set Local Description");
  1.1259 +
  1.1260 +  mLocalRequestedSDP = aSDP;
  1.1261 +  mInternal->mCall->setLocalDescription((cc_jsep_action_t)aAction,
  1.1262 +                                        mLocalRequestedSDP, tc);
  1.1263 +  return NS_OK;
  1.1264 +}
  1.1265 +
  1.1266 +NS_IMETHODIMP
  1.1267 +PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP)
  1.1268 +{
  1.1269 +  PC_AUTO_ENTER_API_CALL(true);
  1.1270 +
  1.1271 +  if (!aSDP) {
  1.1272 +    CSFLogError(logTag, "%s - aSDP is NULL", __FUNCTION__);
  1.1273 +    return NS_ERROR_FAILURE;
  1.1274 +  }
  1.1275 +
  1.1276 +  Timecard *tc = mTimeCard;
  1.1277 +  mTimeCard = nullptr;
  1.1278 +  STAMP_TIMECARD(tc, "Set Remote Description");
  1.1279 +
  1.1280 +  mRemoteRequestedSDP = aSDP;
  1.1281 +  mInternal->mCall->setRemoteDescription((cc_jsep_action_t)action,
  1.1282 +                                         mRemoteRequestedSDP, tc);
  1.1283 +  return NS_OK;
  1.1284 +}
  1.1285 +
  1.1286 +// WebRTC uses highres time relative to the UNIX epoch (Jan 1, 1970, UTC).
  1.1287 +
  1.1288 +#ifdef MOZILLA_INTERNAL_API
  1.1289 +nsresult
  1.1290 +PeerConnectionImpl::GetTimeSinceEpoch(DOMHighResTimeStamp *result) {
  1.1291 +  MOZ_ASSERT(NS_IsMainThread());
  1.1292 +  nsPerformance *perf = mWindow->GetPerformance();
  1.1293 +  NS_ENSURE_TRUE(perf && perf->Timing(), NS_ERROR_UNEXPECTED);
  1.1294 +  *result = perf->Now() + perf->Timing()->NavigationStart();
  1.1295 +  return NS_OK;
  1.1296 +}
  1.1297 +
  1.1298 +class RTCStatsReportInternalConstruct : public RTCStatsReportInternal {
  1.1299 +public:
  1.1300 +  RTCStatsReportInternalConstruct(const nsString &pcid, DOMHighResTimeStamp now) {
  1.1301 +    mPcid = pcid;
  1.1302 +    mInboundRTPStreamStats.Construct();
  1.1303 +    mOutboundRTPStreamStats.Construct();
  1.1304 +    mMediaStreamTrackStats.Construct();
  1.1305 +    mMediaStreamStats.Construct();
  1.1306 +    mTransportStats.Construct();
  1.1307 +    mIceComponentStats.Construct();
  1.1308 +    mIceCandidatePairStats.Construct();
  1.1309 +    mIceCandidateStats.Construct();
  1.1310 +    mCodecStats.Construct();
  1.1311 +  }
  1.1312 +};
  1.1313 +
  1.1314 +// Specialized helper - push map[key] if specified or all map values onto array
  1.1315 +
  1.1316 +static void
  1.1317 +PushBackSelect(nsTArray<RefPtr<MediaPipeline>>& aDst,
  1.1318 +               const std::map<TrackID, RefPtr<mozilla::MediaPipeline>> & aSrc,
  1.1319 +               TrackID aKey = 0) {
  1.1320 +  auto begin = aKey ? aSrc.find(aKey) : aSrc.begin(), it = begin;
  1.1321 +  for (auto end = (aKey && begin != aSrc.end())? ++begin : aSrc.end();
  1.1322 +       it != end; ++it) {
  1.1323 +    aDst.AppendElement(it->second);
  1.1324 +  }
  1.1325 +}
  1.1326 +#endif
  1.1327 +
  1.1328 +NS_IMETHODIMP
  1.1329 +PeerConnectionImpl::GetStats(MediaStreamTrack *aSelector) {
  1.1330 +  PC_AUTO_ENTER_API_CALL(true);
  1.1331 +
  1.1332 +#ifdef MOZILLA_INTERNAL_API
  1.1333 +  if (!mMedia) {
  1.1334 +    // Since we zero this out before the d'tor, we should check.
  1.1335 +    return NS_ERROR_UNEXPECTED;
  1.1336 +  }
  1.1337 +
  1.1338 +  nsAutoPtr<RTCStatsQuery> query(new RTCStatsQuery(false));
  1.1339 +
  1.1340 +  nsresult rv = BuildStatsQuery_m(aSelector, query.get());
  1.1341 +
  1.1342 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1343 +
  1.1344 +  RUN_ON_THREAD(mSTSThread,
  1.1345 +                WrapRunnableNM(&PeerConnectionImpl::GetStatsForPCObserver_s,
  1.1346 +                               mHandle,
  1.1347 +                               query),
  1.1348 +                NS_DISPATCH_NORMAL);
  1.1349 +#endif
  1.1350 +  return NS_OK;
  1.1351 +}
  1.1352 +
  1.1353 +NS_IMETHODIMP
  1.1354 +PeerConnectionImpl::AddIceCandidate(const char* aCandidate, const char* aMid, unsigned short aLevel) {
  1.1355 +  PC_AUTO_ENTER_API_CALL(true);
  1.1356 +
  1.1357 +  Timecard *tc = mTimeCard;
  1.1358 +  mTimeCard = nullptr;
  1.1359 +  STAMP_TIMECARD(tc, "Add Ice Candidate");
  1.1360 +
  1.1361 +#ifdef MOZILLA_INTERNAL_API
  1.1362 +  // When remote candidates are added before our ICE ctx is up and running
  1.1363 +  // (the transition to New is async through STS, so this is not impossible),
  1.1364 +  // we won't record them as trickle candidates. Is this what we want?
  1.1365 +  if(!mIceStartTime.IsNull()) {
  1.1366 +    TimeDuration timeDelta = TimeStamp::Now() - mIceStartTime;
  1.1367 +    if (mIceConnectionState == PCImplIceConnectionState::Failed) {
  1.1368 +      Telemetry::Accumulate(Telemetry::WEBRTC_ICE_LATE_TRICKLE_ARRIVAL_TIME,
  1.1369 +                            timeDelta.ToMilliseconds());
  1.1370 +    } else {
  1.1371 +      Telemetry::Accumulate(Telemetry::WEBRTC_ICE_ON_TIME_TRICKLE_ARRIVAL_TIME,
  1.1372 +                            timeDelta.ToMilliseconds());
  1.1373 +    }
  1.1374 +  }
  1.1375 +#endif
  1.1376 +
  1.1377 +  mInternal->mCall->addICECandidate(aCandidate, aMid, aLevel, tc);
  1.1378 +  return NS_OK;
  1.1379 +}
  1.1380 +
  1.1381 +NS_IMETHODIMP
  1.1382 +PeerConnectionImpl::CloseStreams() {
  1.1383 +  PC_AUTO_ENTER_API_CALL(false);
  1.1384 +
  1.1385 +  if (mReadyState != PCImplReadyState::Closed)  {
  1.1386 +    ChangeReadyState(PCImplReadyState::Closing);
  1.1387 +  }
  1.1388 +
  1.1389 +  CSFLogInfo(logTag, "%s: Ending associated call", __FUNCTION__);
  1.1390 +
  1.1391 +  mInternal->mCall->endCall();
  1.1392 +  return NS_OK;
  1.1393 +}
  1.1394 +
  1.1395 +NS_IMETHODIMP
  1.1396 +PeerConnectionImpl::AddStream(DOMMediaStream &aMediaStream,
  1.1397 +                              const MediaConstraintsInternal& aConstraints)
  1.1398 +{
  1.1399 +  return AddStream(aMediaStream, MediaConstraintsExternal(aConstraints));
  1.1400 +}
  1.1401 +
  1.1402 +NS_IMETHODIMP
  1.1403 +PeerConnectionImpl::AddStream(DOMMediaStream& aMediaStream,
  1.1404 +                              const MediaConstraintsExternal& aConstraints) {
  1.1405 +  PC_AUTO_ENTER_API_CALL(true);
  1.1406 +
  1.1407 +  uint32_t hints = aMediaStream.GetHintContents();
  1.1408 +
  1.1409 +  // XXX Remove this check once addStream has an error callback
  1.1410 +  // available and/or we have plumbing to handle multiple
  1.1411 +  // local audio streams.
  1.1412 +  if ((hints & DOMMediaStream::HINT_CONTENTS_AUDIO) &&
  1.1413 +      mNumAudioStreams > 0) {
  1.1414 +    CSFLogError(logTag, "%s: Only one local audio stream is supported for now",
  1.1415 +                __FUNCTION__);
  1.1416 +    return NS_ERROR_FAILURE;
  1.1417 +  }
  1.1418 +
  1.1419 +  // XXX Remove this check once addStream has an error callback
  1.1420 +  // available and/or we have plumbing to handle multiple
  1.1421 +  // local video streams.
  1.1422 +  if ((hints & DOMMediaStream::HINT_CONTENTS_VIDEO) &&
  1.1423 +      mNumVideoStreams > 0) {
  1.1424 +    CSFLogError(logTag, "%s: Only one local video stream is supported for now",
  1.1425 +                __FUNCTION__);
  1.1426 +    return NS_ERROR_FAILURE;
  1.1427 +  }
  1.1428 +
  1.1429 +  uint32_t stream_id;
  1.1430 +  nsresult res = mMedia->AddStream(&aMediaStream, &stream_id);
  1.1431 +  if (NS_FAILED(res))
  1.1432 +    return res;
  1.1433 +
  1.1434 +  // TODO(ekr@rtfm.com): these integers should be the track IDs
  1.1435 +  if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) {
  1.1436 +    cc_media_constraints_t* cc_constraints = aConstraints.build();
  1.1437 +    NS_ENSURE_TRUE(cc_constraints, NS_ERROR_UNEXPECTED);
  1.1438 +    mInternal->mCall->addStream(stream_id, 0, AUDIO, cc_constraints);
  1.1439 +    mNumAudioStreams++;
  1.1440 +  }
  1.1441 +
  1.1442 +  if (hints & DOMMediaStream::HINT_CONTENTS_VIDEO) {
  1.1443 +    cc_media_constraints_t* cc_constraints = aConstraints.build();
  1.1444 +    NS_ENSURE_TRUE(cc_constraints, NS_ERROR_UNEXPECTED);
  1.1445 +    mInternal->mCall->addStream(stream_id, 1, VIDEO, cc_constraints);
  1.1446 +    mNumVideoStreams++;
  1.1447 +  }
  1.1448 +
  1.1449 +  return NS_OK;
  1.1450 +}
  1.1451 +
  1.1452 +NS_IMETHODIMP
  1.1453 +PeerConnectionImpl::RemoveStream(DOMMediaStream& aMediaStream) {
  1.1454 +  PC_AUTO_ENTER_API_CALL(true);
  1.1455 +
  1.1456 +  uint32_t stream_id;
  1.1457 +  nsresult res = mMedia->RemoveStream(&aMediaStream, &stream_id);
  1.1458 +
  1.1459 +  if (NS_FAILED(res))
  1.1460 +    return res;
  1.1461 +
  1.1462 +  uint32_t hints = aMediaStream.GetHintContents();
  1.1463 +
  1.1464 +  if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) {
  1.1465 +    mInternal->mCall->removeStream(stream_id, 0, AUDIO);
  1.1466 +    MOZ_ASSERT(mNumAudioStreams > 0);
  1.1467 +    mNumAudioStreams--;
  1.1468 +  }
  1.1469 +
  1.1470 +  if (hints & DOMMediaStream::HINT_CONTENTS_VIDEO) {
  1.1471 +    mInternal->mCall->removeStream(stream_id, 1, VIDEO);
  1.1472 +    MOZ_ASSERT(mNumVideoStreams > 0);
  1.1473 +    mNumVideoStreams--;
  1.1474 +  }
  1.1475 +
  1.1476 +  return NS_OK;
  1.1477 +}
  1.1478 +
  1.1479 +/*
  1.1480 +NS_IMETHODIMP
  1.1481 +PeerConnectionImpl::SetRemoteFingerprint(const char* hash, const char* fingerprint)
  1.1482 +{
  1.1483 +  MOZ_ASSERT(hash);
  1.1484 +  MOZ_ASSERT(fingerprint);
  1.1485 +
  1.1486 +  if (fingerprint != nullptr && (strcmp(hash, "sha-1") == 0)) {
  1.1487 +    mRemoteFingerprint = std::string(fingerprint);
  1.1488 +    CSFLogDebug(logTag, "Setting remote fingerprint to %s", mRemoteFingerprint.c_str());
  1.1489 +    return NS_OK;
  1.1490 +  } else {
  1.1491 +    CSFLogError(logTag, "%s: Invalid Remote Finger Print", __FUNCTION__);
  1.1492 +    return NS_ERROR_FAILURE;
  1.1493 +  }
  1.1494 +}
  1.1495 +*/
  1.1496 +
  1.1497 +NS_IMETHODIMP
  1.1498 +PeerConnectionImpl::GetFingerprint(char** fingerprint)
  1.1499 +{
  1.1500 +  MOZ_ASSERT(fingerprint);
  1.1501 +
  1.1502 +  if (!mIdentity) {
  1.1503 +    return NS_ERROR_FAILURE;
  1.1504 +  }
  1.1505 +
  1.1506 +  char* tmp = new char[mFingerprint.size() + 1];
  1.1507 +  std::copy(mFingerprint.begin(), mFingerprint.end(), tmp);
  1.1508 +  tmp[mFingerprint.size()] = '\0';
  1.1509 +
  1.1510 +  *fingerprint = tmp;
  1.1511 +  return NS_OK;
  1.1512 +}
  1.1513 +
  1.1514 +NS_IMETHODIMP
  1.1515 +PeerConnectionImpl::GetLocalDescription(char** aSDP)
  1.1516 +{
  1.1517 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1518 +  MOZ_ASSERT(aSDP);
  1.1519 +
  1.1520 +  char* tmp = new char[mLocalSDP.size() + 1];
  1.1521 +  std::copy(mLocalSDP.begin(), mLocalSDP.end(), tmp);
  1.1522 +  tmp[mLocalSDP.size()] = '\0';
  1.1523 +
  1.1524 +  *aSDP = tmp;
  1.1525 +  return NS_OK;
  1.1526 +}
  1.1527 +
  1.1528 +NS_IMETHODIMP
  1.1529 +PeerConnectionImpl::GetRemoteDescription(char** aSDP)
  1.1530 +{
  1.1531 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1532 +  MOZ_ASSERT(aSDP);
  1.1533 +
  1.1534 +  char* tmp = new char[mRemoteSDP.size() + 1];
  1.1535 +  std::copy(mRemoteSDP.begin(), mRemoteSDP.end(), tmp);
  1.1536 +  tmp[mRemoteSDP.size()] = '\0';
  1.1537 +
  1.1538 +  *aSDP = tmp;
  1.1539 +  return NS_OK;
  1.1540 +}
  1.1541 +
  1.1542 +NS_IMETHODIMP
  1.1543 +PeerConnectionImpl::ReadyState(PCImplReadyState* aState)
  1.1544 +{
  1.1545 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1546 +  MOZ_ASSERT(aState);
  1.1547 +
  1.1548 +  *aState = mReadyState;
  1.1549 +  return NS_OK;
  1.1550 +}
  1.1551 +
  1.1552 +NS_IMETHODIMP
  1.1553 +PeerConnectionImpl::SignalingState(PCImplSignalingState* aState)
  1.1554 +{
  1.1555 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1556 +  MOZ_ASSERT(aState);
  1.1557 +
  1.1558 +  *aState = mSignalingState;
  1.1559 +  return NS_OK;
  1.1560 +}
  1.1561 +
  1.1562 +NS_IMETHODIMP
  1.1563 +PeerConnectionImpl::SipccState(PCImplSipccState* aState)
  1.1564 +{
  1.1565 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1566 +  MOZ_ASSERT(aState);
  1.1567 +
  1.1568 +  PeerConnectionCtx* pcctx = PeerConnectionCtx::GetInstance();
  1.1569 +  // Avoid B2G error: operands to ?: have different types
  1.1570 +  // 'mozilla::dom::PCImplSipccState' and 'mozilla::dom::PCImplSipccState::Enum'
  1.1571 +  if (pcctx) {
  1.1572 +    *aState = pcctx->sipcc_state();
  1.1573 +  } else {
  1.1574 +    *aState = PCImplSipccState::Idle;
  1.1575 +  }
  1.1576 +  return NS_OK;
  1.1577 +}
  1.1578 +
  1.1579 +NS_IMETHODIMP
  1.1580 +PeerConnectionImpl::IceConnectionState(PCImplIceConnectionState* aState)
  1.1581 +{
  1.1582 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1583 +  MOZ_ASSERT(aState);
  1.1584 +
  1.1585 +  *aState = mIceConnectionState;
  1.1586 +  return NS_OK;
  1.1587 +}
  1.1588 +
  1.1589 +NS_IMETHODIMP
  1.1590 +PeerConnectionImpl::IceGatheringState(PCImplIceGatheringState* aState)
  1.1591 +{
  1.1592 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1593 +  MOZ_ASSERT(aState);
  1.1594 +
  1.1595 +  *aState = mIceGatheringState;
  1.1596 +  return NS_OK;
  1.1597 +}
  1.1598 +
  1.1599 +nsresult
  1.1600 +PeerConnectionImpl::CheckApiState(bool assert_ice_ready) const
  1.1601 +{
  1.1602 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1603 +  MOZ_ASSERT(mTrickle || !assert_ice_ready ||
  1.1604 +             (mIceGatheringState == PCImplIceGatheringState::Complete));
  1.1605 +
  1.1606 +  if (mReadyState == PCImplReadyState::Closed) {
  1.1607 +    CSFLogError(logTag, "%s: called API while closed", __FUNCTION__);
  1.1608 +    return NS_ERROR_FAILURE;
  1.1609 +  }
  1.1610 +  if (!mMedia) {
  1.1611 +    CSFLogError(logTag, "%s: called API with disposed mMedia", __FUNCTION__);
  1.1612 +    return NS_ERROR_FAILURE;
  1.1613 +  }
  1.1614 +  return NS_OK;
  1.1615 +}
  1.1616 +
  1.1617 +NS_IMETHODIMP
  1.1618 +PeerConnectionImpl::Close()
  1.1619 +{
  1.1620 +  CSFLogDebug(logTag, "%s: for %s", __FUNCTION__, mHandle.c_str());
  1.1621 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1622 +
  1.1623 +  nsresult res = CloseInt();
  1.1624 +
  1.1625 +  SetSignalingState_m(PCImplSignalingState::SignalingClosed);
  1.1626 +
  1.1627 +  return res;
  1.1628 +}
  1.1629 +
  1.1630 +
  1.1631 +nsresult
  1.1632 +PeerConnectionImpl::CloseInt()
  1.1633 +{
  1.1634 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1635 +
  1.1636 +  // We do this at the end of the call because we want to make sure we've waited
  1.1637 +  // for all trickle ICE candidates to come in; this can happen well after we've
  1.1638 +  // transitioned to connected. As a bonus, this allows us to detect race
  1.1639 +  // conditions where a stats dispatch happens right as the PC closes.
  1.1640 +  if (!IsClosed()) {
  1.1641 +    RecordLongtermICEStatistics();
  1.1642 +  }
  1.1643 +
  1.1644 +  if (mInternal->mCall) {
  1.1645 +    CSFLogInfo(logTag, "%s: Closing PeerConnectionImpl %s; "
  1.1646 +               "ending call", __FUNCTION__, mHandle.c_str());
  1.1647 +    mInternal->mCall->endCall();
  1.1648 +  }
  1.1649 +#ifdef MOZILLA_INTERNAL_API
  1.1650 +  if (mDataConnection) {
  1.1651 +    CSFLogInfo(logTag, "%s: Destroying DataChannelConnection %p for %s",
  1.1652 +               __FUNCTION__, (void *) mDataConnection.get(), mHandle.c_str());
  1.1653 +    mDataConnection->Destroy();
  1.1654 +    mDataConnection = nullptr; // it may not go away until the runnables are dead
  1.1655 +  }
  1.1656 +#endif
  1.1657 +
  1.1658 +  ShutdownMedia();
  1.1659 +
  1.1660 +  // DataConnection will need to stay alive until all threads/runnables exit
  1.1661 +
  1.1662 +  return NS_OK;
  1.1663 +}
  1.1664 +
  1.1665 +void
  1.1666 +PeerConnectionImpl::ShutdownMedia()
  1.1667 +{
  1.1668 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1669 +
  1.1670 +  if (!mMedia)
  1.1671 +    return;
  1.1672 +
  1.1673 +#ifdef MOZILLA_INTERNAL_API
  1.1674 +  // End of call to be recorded in Telemetry
  1.1675 +  if (!mStartTime.IsNull()){
  1.1676 +    TimeDuration timeDelta = TimeStamp::Now() - mStartTime;
  1.1677 +    Telemetry::Accumulate(Telemetry::WEBRTC_CALL_DURATION, timeDelta.ToSeconds());
  1.1678 +  }
  1.1679 +#endif
  1.1680 +
  1.1681 +  // Forget the reference so that we can transfer it to
  1.1682 +  // SelfDestruct().
  1.1683 +  mMedia.forget().take()->SelfDestruct();
  1.1684 +}
  1.1685 +
  1.1686 +#ifdef MOZILLA_INTERNAL_API
  1.1687 +// If NSS is shutting down, then we need to get rid of the DTLS
  1.1688 +// identity right now; otherwise, we'll cause wreckage when we do
  1.1689 +// finally deallocate it in our destructor.
  1.1690 +void
  1.1691 +PeerConnectionImpl::virtualDestroyNSSReference()
  1.1692 +{
  1.1693 +  destructorSafeDestroyNSSReference();
  1.1694 +}
  1.1695 +
  1.1696 +void
  1.1697 +PeerConnectionImpl::destructorSafeDestroyNSSReference()
  1.1698 +{
  1.1699 +  MOZ_ASSERT(NS_IsMainThread());
  1.1700 +  CSFLogDebug(logTag, "%s: NSS shutting down; freeing our DtlsIdentity.", __FUNCTION__);
  1.1701 +  mIdentity = nullptr;
  1.1702 +}
  1.1703 +#endif
  1.1704 +
  1.1705 +void
  1.1706 +PeerConnectionImpl::onCallEvent(const OnCallEventArgs& args)
  1.1707 +{
  1.1708 +  const ccapi_call_event_e &aCallEvent = args.mCallEvent;
  1.1709 +  const CSF::CC_CallInfoPtr &aInfo = args.mInfo;
  1.1710 +
  1.1711 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1712 +  MOZ_ASSERT(aInfo.get());
  1.1713 +
  1.1714 +  cc_call_state_t event = aInfo->getCallState();
  1.1715 +  std::string statestr = aInfo->callStateToString(event);
  1.1716 +  Timecard *timecard = aInfo->takeTimecard();
  1.1717 +
  1.1718 +  if (timecard) {
  1.1719 +    mTimeCard = timecard;
  1.1720 +    STAMP_TIMECARD(mTimeCard, "Operation Completed");
  1.1721 +  }
  1.1722 +
  1.1723 +  if (CCAPI_CALL_EV_CREATED != aCallEvent && CCAPI_CALL_EV_STATE != aCallEvent) {
  1.1724 +    CSFLogDebug(logTag, "%s: **** CALL HANDLE IS: %s, **** CALL STATE IS: %s",
  1.1725 +      __FUNCTION__, mHandle.c_str(), statestr.c_str());
  1.1726 +    return;
  1.1727 +  }
  1.1728 +
  1.1729 +  switch (event) {
  1.1730 +    case SETLOCALDESCSUCCESS:
  1.1731 +    case UPDATELOCALDESC:
  1.1732 +      mLocalSDP = aInfo->getSDP();
  1.1733 +      break;
  1.1734 +
  1.1735 +    case SETREMOTEDESCSUCCESS:
  1.1736 +    case ADDICECANDIDATE:
  1.1737 +      mRemoteSDP = aInfo->getSDP();
  1.1738 +      break;
  1.1739 +
  1.1740 +    case CONNECTED:
  1.1741 +      CSFLogDebug(logTag, "Setting PeerConnnection state to kActive");
  1.1742 +      ChangeReadyState(PCImplReadyState::Active);
  1.1743 +      break;
  1.1744 +    default:
  1.1745 +      break;
  1.1746 +  }
  1.1747 +
  1.1748 +  nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
  1.1749 +  if (!pco) {
  1.1750 +    return;
  1.1751 +  }
  1.1752 +
  1.1753 +  PeerConnectionObserverDispatch* runnable =
  1.1754 +      new PeerConnectionObserverDispatch(aInfo, this, pco);
  1.1755 +
  1.1756 +  if (mThread) {
  1.1757 +    mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
  1.1758 +    return;
  1.1759 +  }
  1.1760 +  runnable->Run();
  1.1761 +  delete runnable;
  1.1762 +}
  1.1763 +
  1.1764 +void
  1.1765 +PeerConnectionImpl::ChangeReadyState(PCImplReadyState aReadyState)
  1.1766 +{
  1.1767 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1768 +  mReadyState = aReadyState;
  1.1769 +
  1.1770 +  // Note that we are passing an nsRefPtr which keeps the observer live.
  1.1771 +  nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
  1.1772 +  if (!pco) {
  1.1773 +    return;
  1.1774 +  }
  1.1775 +  WrappableJSErrorResult rv;
  1.1776 +  RUN_ON_THREAD(mThread,
  1.1777 +                WrapRunnable(pco,
  1.1778 +                             &PeerConnectionObserver::OnStateChange,
  1.1779 +                             PCObserverStateType::ReadyState,
  1.1780 +                             rv, static_cast<JSCompartment*>(nullptr)),
  1.1781 +                NS_DISPATCH_NORMAL);
  1.1782 +}
  1.1783 +
  1.1784 +void
  1.1785 +PeerConnectionImpl::SetSignalingState_m(PCImplSignalingState aSignalingState)
  1.1786 +{
  1.1787 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1788 +  if (mSignalingState == aSignalingState ||
  1.1789 +      mSignalingState == PCImplSignalingState::SignalingClosed) {
  1.1790 +    return;
  1.1791 +  }
  1.1792 +
  1.1793 +  mSignalingState = aSignalingState;
  1.1794 +  nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
  1.1795 +  if (!pco) {
  1.1796 +    return;
  1.1797 +  }
  1.1798 +  JSErrorResult rv;
  1.1799 +  pco->OnStateChange(PCObserverStateType::SignalingState, rv);
  1.1800 +  MOZ_ASSERT(!rv.Failed());
  1.1801 +}
  1.1802 +
  1.1803 +bool
  1.1804 +PeerConnectionImpl::IsClosed() const
  1.1805 +{
  1.1806 +  return mSignalingState == PCImplSignalingState::SignalingClosed;
  1.1807 +}
  1.1808 +
  1.1809 +bool
  1.1810 +PeerConnectionImpl::HasMedia() const
  1.1811 +{
  1.1812 +  return mMedia;
  1.1813 +}
  1.1814 +
  1.1815 +PeerConnectionWrapper::PeerConnectionWrapper(const std::string& handle)
  1.1816 +    : impl_(nullptr) {
  1.1817 +  if (PeerConnectionCtx::GetInstance()->mPeerConnections.find(handle) ==
  1.1818 +    PeerConnectionCtx::GetInstance()->mPeerConnections.end()) {
  1.1819 +    return;
  1.1820 +  }
  1.1821 +
  1.1822 +  PeerConnectionImpl *impl = PeerConnectionCtx::GetInstance()->mPeerConnections[handle];
  1.1823 +
  1.1824 +  if (!impl->media())
  1.1825 +    return;
  1.1826 +
  1.1827 +  impl_ = impl;
  1.1828 +}
  1.1829 +
  1.1830 +const std::string&
  1.1831 +PeerConnectionImpl::GetHandle()
  1.1832 +{
  1.1833 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1834 +  return mHandle;
  1.1835 +}
  1.1836 +
  1.1837 +const std::string&
  1.1838 +PeerConnectionImpl::GetName()
  1.1839 +{
  1.1840 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.1841 +  return mName;
  1.1842 +}
  1.1843 +
  1.1844 +static mozilla::dom::PCImplIceConnectionState
  1.1845 +toDomIceConnectionState(NrIceCtx::ConnectionState state) {
  1.1846 +  switch (state) {
  1.1847 +    case NrIceCtx::ICE_CTX_INIT:
  1.1848 +      return PCImplIceConnectionState::New;
  1.1849 +    case NrIceCtx::ICE_CTX_CHECKING:
  1.1850 +      return PCImplIceConnectionState::Checking;
  1.1851 +    case NrIceCtx::ICE_CTX_OPEN:
  1.1852 +      return PCImplIceConnectionState::Connected;
  1.1853 +    case NrIceCtx::ICE_CTX_FAILED:
  1.1854 +      return PCImplIceConnectionState::Failed;
  1.1855 +  }
  1.1856 +  MOZ_CRASH();
  1.1857 +}
  1.1858 +
  1.1859 +static mozilla::dom::PCImplIceGatheringState
  1.1860 +toDomIceGatheringState(NrIceCtx::GatheringState state) {
  1.1861 +  switch (state) {
  1.1862 +    case NrIceCtx::ICE_CTX_GATHER_INIT:
  1.1863 +      return PCImplIceGatheringState::New;
  1.1864 +    case NrIceCtx::ICE_CTX_GATHER_STARTED:
  1.1865 +      return PCImplIceGatheringState::Gathering;
  1.1866 +    case NrIceCtx::ICE_CTX_GATHER_COMPLETE:
  1.1867 +      return PCImplIceGatheringState::Complete;
  1.1868 +  }
  1.1869 +  MOZ_CRASH();
  1.1870 +}
  1.1871 +
  1.1872 +#ifdef MOZILLA_INTERNAL_API
  1.1873 +static bool isDone(PCImplIceConnectionState state) {
  1.1874 +  return state != PCImplIceConnectionState::Checking &&
  1.1875 +         state != PCImplIceConnectionState::New;
  1.1876 +}
  1.1877 +
  1.1878 +static bool isSucceeded(PCImplIceConnectionState state) {
  1.1879 +  return state == PCImplIceConnectionState::Connected ||
  1.1880 +         state == PCImplIceConnectionState::Completed;
  1.1881 +}
  1.1882 +
  1.1883 +static bool isFailed(PCImplIceConnectionState state) {
  1.1884 +  return state == PCImplIceConnectionState::Failed ||
  1.1885 +         state == PCImplIceConnectionState::Disconnected;
  1.1886 +}
  1.1887 +#endif
  1.1888 +
  1.1889 +void PeerConnectionImpl::IceConnectionStateChange(
  1.1890 +    NrIceCtx* ctx,
  1.1891 +    NrIceCtx::ConnectionState state) {
  1.1892 +  PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
  1.1893 +
  1.1894 +  CSFLogDebug(logTag, "%s", __FUNCTION__);
  1.1895 +
  1.1896 +  auto domState = toDomIceConnectionState(state);
  1.1897 +
  1.1898 +#ifdef MOZILLA_INTERNAL_API
  1.1899 +  if (!isDone(mIceConnectionState) && isDone(domState)) {
  1.1900 +    // mIceStartTime can be null if going directly from New to Closed, in which
  1.1901 +    // case we don't count it as a success or a failure.
  1.1902 +    if (!mIceStartTime.IsNull()){
  1.1903 +      TimeDuration timeDelta = TimeStamp::Now() - mIceStartTime;
  1.1904 +      if (isSucceeded(domState)) {
  1.1905 +        Telemetry::Accumulate(Telemetry::WEBRTC_ICE_SUCCESS_TIME,
  1.1906 +                              timeDelta.ToMilliseconds());
  1.1907 +      } else if (isFailed(domState)) {
  1.1908 +        Telemetry::Accumulate(Telemetry::WEBRTC_ICE_FAILURE_TIME,
  1.1909 +                              timeDelta.ToMilliseconds());
  1.1910 +      }
  1.1911 +    }
  1.1912 +  }
  1.1913 +#endif
  1.1914 +
  1.1915 +  mIceConnectionState = domState;
  1.1916 +
  1.1917 +  // Would be nice if we had a means of converting one of these dom enums
  1.1918 +  // to a string that wasn't almost as much text as this switch statement...
  1.1919 +  switch (mIceConnectionState) {
  1.1920 +    case PCImplIceConnectionState::New:
  1.1921 +      STAMP_TIMECARD(mTimeCard, "Ice state: new");
  1.1922 +      break;
  1.1923 +    case PCImplIceConnectionState::Checking:
  1.1924 +#ifdef MOZILLA_INTERNAL_API
  1.1925 +      // For telemetry
  1.1926 +      mIceStartTime = TimeStamp::Now();
  1.1927 +#endif
  1.1928 +      STAMP_TIMECARD(mTimeCard, "Ice state: checking");
  1.1929 +      break;
  1.1930 +    case PCImplIceConnectionState::Connected:
  1.1931 +      STAMP_TIMECARD(mTimeCard, "Ice state: connected");
  1.1932 +      break;
  1.1933 +    case PCImplIceConnectionState::Completed:
  1.1934 +      STAMP_TIMECARD(mTimeCard, "Ice state: completed");
  1.1935 +      break;
  1.1936 +    case PCImplIceConnectionState::Failed:
  1.1937 +      STAMP_TIMECARD(mTimeCard, "Ice state: failed");
  1.1938 +      break;
  1.1939 +    case PCImplIceConnectionState::Disconnected:
  1.1940 +      STAMP_TIMECARD(mTimeCard, "Ice state: disconnected");
  1.1941 +      break;
  1.1942 +    case PCImplIceConnectionState::Closed:
  1.1943 +      STAMP_TIMECARD(mTimeCard, "Ice state: closed");
  1.1944 +      break;
  1.1945 +  }
  1.1946 +
  1.1947 +  nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
  1.1948 +  if (!pco) {
  1.1949 +    return;
  1.1950 +  }
  1.1951 +  WrappableJSErrorResult rv;
  1.1952 +  RUN_ON_THREAD(mThread,
  1.1953 +                WrapRunnable(pco,
  1.1954 +                             &PeerConnectionObserver::OnStateChange,
  1.1955 +                             PCObserverStateType::IceConnectionState,
  1.1956 +                             rv, static_cast<JSCompartment*>(nullptr)),
  1.1957 +                NS_DISPATCH_NORMAL);
  1.1958 +}
  1.1959 +
  1.1960 +void
  1.1961 +PeerConnectionImpl::IceGatheringStateChange(
  1.1962 +    NrIceCtx* ctx,
  1.1963 +    NrIceCtx::GatheringState state)
  1.1964 +{
  1.1965 +  PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
  1.1966 +
  1.1967 +  CSFLogDebug(logTag, "%s", __FUNCTION__);
  1.1968 +
  1.1969 +  mIceGatheringState = toDomIceGatheringState(state);
  1.1970 +
  1.1971 +  // Would be nice if we had a means of converting one of these dom enums
  1.1972 +  // to a string that wasn't almost as much text as this switch statement...
  1.1973 +  switch (mIceGatheringState) {
  1.1974 +    case PCImplIceGatheringState::New:
  1.1975 +      STAMP_TIMECARD(mTimeCard, "Ice gathering state: new");
  1.1976 +      break;
  1.1977 +    case PCImplIceGatheringState::Gathering:
  1.1978 +      STAMP_TIMECARD(mTimeCard, "Ice gathering state: gathering");
  1.1979 +      break;
  1.1980 +    case PCImplIceGatheringState::Complete:
  1.1981 +      STAMP_TIMECARD(mTimeCard, "Ice state: complete");
  1.1982 +      break;
  1.1983 +  }
  1.1984 +
  1.1985 +  nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
  1.1986 +  if (!pco) {
  1.1987 +    return;
  1.1988 +  }
  1.1989 +  WrappableJSErrorResult rv;
  1.1990 +  RUN_ON_THREAD(mThread,
  1.1991 +                WrapRunnable(pco,
  1.1992 +                             &PeerConnectionObserver::OnStateChange,
  1.1993 +                             PCObserverStateType::IceGatheringState,
  1.1994 +                             rv, static_cast<JSCompartment*>(nullptr)),
  1.1995 +                NS_DISPATCH_NORMAL);
  1.1996 +}
  1.1997 +
  1.1998 +#ifdef MOZILLA_INTERNAL_API
  1.1999 +nsresult
  1.2000 +PeerConnectionImpl::BuildStatsQuery_m(
  1.2001 +    mozilla::dom::MediaStreamTrack *aSelector,
  1.2002 +    RTCStatsQuery *query) {
  1.2003 +
  1.2004 +  if (!HasMedia()) {
  1.2005 +    return NS_OK;
  1.2006 +  }
  1.2007 +
  1.2008 +  if (!mMedia->ice_ctx() || !mThread) {
  1.2009 +    CSFLogError(logTag, "Could not build stats query, critical components of "
  1.2010 +                        "PeerConnectionImpl not set.");
  1.2011 +    return NS_ERROR_UNEXPECTED;
  1.2012 +  }
  1.2013 +
  1.2014 +  nsresult rv = GetTimeSinceEpoch(&(query->now));
  1.2015 +
  1.2016 +  if (NS_FAILED(rv)) {
  1.2017 +    CSFLogError(logTag, "Could not build stats query, could not get timestamp");
  1.2018 +    return rv;
  1.2019 +  }
  1.2020 +
  1.2021 +  // We do not use the pcHandle here, since that's risky to expose to content.
  1.2022 +  query->report = RTCStatsReportInternalConstruct(
  1.2023 +      NS_ConvertASCIItoUTF16(mName.c_str()),
  1.2024 +      query->now);
  1.2025 +
  1.2026 +  // Gather up pipelines from mMedia so they may be inspected on STS
  1.2027 +  TrackID trackId = aSelector ? aSelector->GetTrackID() : 0;
  1.2028 +
  1.2029 +  for (int i = 0, len = mMedia->LocalStreamsLength(); i < len; i++) {
  1.2030 +    PushBackSelect(query->pipelines,
  1.2031 +                   mMedia->GetLocalStream(i)->GetPipelines(),
  1.2032 +                   trackId);
  1.2033 +  }
  1.2034 +
  1.2035 +  for (int i = 0, len = mMedia->RemoteStreamsLength(); i < len; i++) {
  1.2036 +    PushBackSelect(query->pipelines,
  1.2037 +                   mMedia->GetRemoteStream(i)->GetPipelines(),
  1.2038 +                   trackId);
  1.2039 +  }
  1.2040 +
  1.2041 +  query->iceCtx = mMedia->ice_ctx();
  1.2042 +
  1.2043 +  // From the list of MediaPipelines, determine the set of NrIceMediaStreams
  1.2044 +  // we are interested in.
  1.2045 +  std::set<size_t> levelsToGrab;
  1.2046 +  if (trackId) {
  1.2047 +    for (size_t p = 0; p < query->pipelines.Length(); ++p) {
  1.2048 +      size_t level = query->pipelines[p]->level();
  1.2049 +      MOZ_ASSERT(level);
  1.2050 +      levelsToGrab.insert(level);
  1.2051 +    }
  1.2052 +  } else {
  1.2053 +    // We want to grab all streams, so ignore the pipelines (this also ends up
  1.2054 +    // grabbing DataChannel streams, which is what we want)
  1.2055 +    for (size_t s = 0; s < mMedia->num_ice_media_streams(); ++s) {
  1.2056 +      levelsToGrab.insert(s + 1); // mIceStreams is 0-indexed
  1.2057 +    }
  1.2058 +  }
  1.2059 +
  1.2060 +  for (auto s = levelsToGrab.begin(); s != levelsToGrab.end(); ++s) {
  1.2061 +    // TODO(bcampen@mozilla.com): I may need to revisit this for bundle.
  1.2062 +    // (Bug 786234)
  1.2063 +    RefPtr<NrIceMediaStream> temp(mMedia->ice_media_stream(*s - 1));
  1.2064 +    RefPtr<TransportFlow> flow(mMedia->GetTransportFlow(*s, false));
  1.2065 +    // flow can be null for unused levels, such as unused DataChannels
  1.2066 +    if (temp && flow) {
  1.2067 +      query->streams.AppendElement(temp);
  1.2068 +    }
  1.2069 +  }
  1.2070 +
  1.2071 +  return rv;
  1.2072 +}
  1.2073 +
  1.2074 +static void ToRTCIceCandidateStats(
  1.2075 +    const std::vector<NrIceCandidate>& candidates,
  1.2076 +    RTCStatsType candidateType,
  1.2077 +    const nsString& componentId,
  1.2078 +    DOMHighResTimeStamp now,
  1.2079 +    RTCStatsReportInternal* report) {
  1.2080 +
  1.2081 +  MOZ_ASSERT(report);
  1.2082 +  for (auto c = candidates.begin(); c != candidates.end(); ++c) {
  1.2083 +    RTCIceCandidateStats cand;
  1.2084 +    cand.mType.Construct(candidateType);
  1.2085 +    NS_ConvertASCIItoUTF16 codeword(c->codeword.c_str());
  1.2086 +    cand.mComponentId.Construct(componentId);
  1.2087 +    cand.mId.Construct(codeword);
  1.2088 +    cand.mTimestamp.Construct(now);
  1.2089 +    cand.mCandidateType.Construct(
  1.2090 +        RTCStatsIceCandidateType(c->type));
  1.2091 +    cand.mIpAddress.Construct(
  1.2092 +        NS_ConvertASCIItoUTF16(c->cand_addr.host.c_str()));
  1.2093 +    cand.mPortNumber.Construct(c->cand_addr.port);
  1.2094 +    cand.mTransport.Construct(
  1.2095 +        NS_ConvertASCIItoUTF16(c->cand_addr.transport.c_str()));
  1.2096 +    if (candidateType == RTCStatsType::Localcandidate) {
  1.2097 +      cand.mMozLocalTransport.Construct(
  1.2098 +          NS_ConvertASCIItoUTF16(c->local_addr.transport.c_str()));
  1.2099 +    }
  1.2100 +    report->mIceCandidateStats.Value().AppendElement(cand);
  1.2101 +  }
  1.2102 +}
  1.2103 +
  1.2104 +static void RecordIceStats_s(
  1.2105 +    NrIceMediaStream& mediaStream,
  1.2106 +    bool internalStats,
  1.2107 +    DOMHighResTimeStamp now,
  1.2108 +    RTCStatsReportInternal* report) {
  1.2109 +
  1.2110 +  NS_ConvertASCIItoUTF16 componentId(mediaStream.name().c_str());
  1.2111 +  if (internalStats) {
  1.2112 +    std::vector<NrIceCandidatePair> candPairs;
  1.2113 +    nsresult res = mediaStream.GetCandidatePairs(&candPairs);
  1.2114 +    if (NS_FAILED(res)) {
  1.2115 +      CSFLogError(logTag, "%s: Error getting candidate pairs", __FUNCTION__);
  1.2116 +      return;
  1.2117 +    }
  1.2118 +
  1.2119 +    for (auto p = candPairs.begin(); p != candPairs.end(); ++p) {
  1.2120 +      NS_ConvertASCIItoUTF16 codeword(p->codeword.c_str());
  1.2121 +      NS_ConvertASCIItoUTF16 localCodeword(p->local.codeword.c_str());
  1.2122 +      NS_ConvertASCIItoUTF16 remoteCodeword(p->remote.codeword.c_str());
  1.2123 +      // Only expose candidate-pair statistics to chrome, until we've thought
  1.2124 +      // through the implications of exposing it to content.
  1.2125 +
  1.2126 +      RTCIceCandidatePairStats s;
  1.2127 +      s.mId.Construct(codeword);
  1.2128 +      s.mComponentId.Construct(componentId);
  1.2129 +      s.mTimestamp.Construct(now);
  1.2130 +      s.mType.Construct(RTCStatsType::Candidatepair);
  1.2131 +      s.mLocalCandidateId.Construct(localCodeword);
  1.2132 +      s.mRemoteCandidateId.Construct(remoteCodeword);
  1.2133 +      s.mNominated.Construct(p->nominated);
  1.2134 +      s.mMozPriority.Construct(p->priority);
  1.2135 +      s.mSelected.Construct(p->selected);
  1.2136 +      s.mState.Construct(RTCStatsIceCandidatePairState(p->state));
  1.2137 +      report->mIceCandidatePairStats.Value().AppendElement(s);
  1.2138 +    }
  1.2139 +  }
  1.2140 +
  1.2141 +  std::vector<NrIceCandidate> candidates;
  1.2142 +  if (NS_SUCCEEDED(mediaStream.GetLocalCandidates(&candidates))) {
  1.2143 +    ToRTCIceCandidateStats(candidates,
  1.2144 +                           RTCStatsType::Localcandidate,
  1.2145 +                           componentId,
  1.2146 +                           now,
  1.2147 +                           report);
  1.2148 +  }
  1.2149 +  candidates.clear();
  1.2150 +
  1.2151 +  if (NS_SUCCEEDED(mediaStream.GetRemoteCandidates(&candidates))) {
  1.2152 +    ToRTCIceCandidateStats(candidates,
  1.2153 +                           RTCStatsType::Remotecandidate,
  1.2154 +                           componentId,
  1.2155 +                           now,
  1.2156 +                           report);
  1.2157 +  }
  1.2158 +}
  1.2159 +
  1.2160 +nsresult
  1.2161 +PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
  1.2162 +
  1.2163 +  ASSERT_ON_THREAD(query->iceCtx->thread());
  1.2164 +
  1.2165 +  // Gather stats from pipelines provided (can't touch mMedia + stream on STS)
  1.2166 +
  1.2167 +  for (size_t p = 0; p < query->pipelines.Length(); ++p) {
  1.2168 +    const MediaPipeline& mp = *query->pipelines[p];
  1.2169 +    bool isAudio = (mp.Conduit()->type() == MediaSessionConduit::AUDIO);
  1.2170 +    nsString idstr = isAudio ?
  1.2171 +        NS_LITERAL_STRING("audio_") : NS_LITERAL_STRING("video_");
  1.2172 +    idstr.AppendInt(mp.trackid());
  1.2173 +
  1.2174 +    switch (mp.direction()) {
  1.2175 +      case MediaPipeline::TRANSMIT: {
  1.2176 +        nsString localId = NS_LITERAL_STRING("outbound_rtp_") + idstr;
  1.2177 +        nsString remoteId;
  1.2178 +        nsString ssrc;
  1.2179 +        unsigned int ssrcval;
  1.2180 +        if (mp.Conduit()->GetLocalSSRC(&ssrcval)) {
  1.2181 +          ssrc.AppendInt(ssrcval);
  1.2182 +        }
  1.2183 +        {
  1.2184 +          // First, fill in remote stat with rtcp receiver data, if present.
  1.2185 +          // ReceiverReports have less information than SenderReports,
  1.2186 +          // so fill in what we can.
  1.2187 +          DOMHighResTimeStamp timestamp;
  1.2188 +          uint32_t jitterMs;
  1.2189 +          uint32_t packetsReceived;
  1.2190 +          uint64_t bytesReceived;
  1.2191 +          uint32_t packetsLost;
  1.2192 +          int32_t rtt;
  1.2193 +          if (mp.Conduit()->GetRTCPReceiverReport(&timestamp, &jitterMs,
  1.2194 +                                                  &packetsReceived,
  1.2195 +                                                  &bytesReceived,
  1.2196 +                                                  &packetsLost,
  1.2197 +                                                  &rtt)) {
  1.2198 +            remoteId = NS_LITERAL_STRING("outbound_rtcp_") + idstr;
  1.2199 +            RTCInboundRTPStreamStats s;
  1.2200 +            s.mTimestamp.Construct(timestamp);
  1.2201 +            s.mId.Construct(remoteId);
  1.2202 +            s.mType.Construct(RTCStatsType::Inboundrtp);
  1.2203 +            if (ssrc.Length()) {
  1.2204 +              s.mSsrc.Construct(ssrc);
  1.2205 +            }
  1.2206 +            s.mJitter.Construct(double(jitterMs)/1000);
  1.2207 +            s.mRemoteId.Construct(localId);
  1.2208 +            s.mIsRemote = true;
  1.2209 +            s.mPacketsReceived.Construct(packetsReceived);
  1.2210 +            s.mBytesReceived.Construct(bytesReceived);
  1.2211 +            s.mPacketsLost.Construct(packetsLost);
  1.2212 +            s.mMozRtt.Construct(rtt);
  1.2213 +            query->report.mInboundRTPStreamStats.Value().AppendElement(s);
  1.2214 +          }
  1.2215 +        }
  1.2216 +        // Then, fill in local side (with cross-link to remote only if present)
  1.2217 +        {
  1.2218 +          RTCOutboundRTPStreamStats s;
  1.2219 +          s.mTimestamp.Construct(query->now);
  1.2220 +          s.mId.Construct(localId);
  1.2221 +          s.mType.Construct(RTCStatsType::Outboundrtp);
  1.2222 +          if (ssrc.Length()) {
  1.2223 +            s.mSsrc.Construct(ssrc);
  1.2224 +          }
  1.2225 +          s.mRemoteId.Construct(remoteId);
  1.2226 +          s.mIsRemote = false;
  1.2227 +          s.mPacketsSent.Construct(mp.rtp_packets_sent());
  1.2228 +          s.mBytesSent.Construct(mp.rtp_bytes_sent());
  1.2229 +          query->report.mOutboundRTPStreamStats.Value().AppendElement(s);
  1.2230 +        }
  1.2231 +        break;
  1.2232 +      }
  1.2233 +      case MediaPipeline::RECEIVE: {
  1.2234 +        nsString localId = NS_LITERAL_STRING("inbound_rtp_") + idstr;
  1.2235 +        nsString remoteId;
  1.2236 +        nsString ssrc;
  1.2237 +        unsigned int ssrcval;
  1.2238 +        if (mp.Conduit()->GetRemoteSSRC(&ssrcval)) {
  1.2239 +          ssrc.AppendInt(ssrcval);
  1.2240 +        }
  1.2241 +        {
  1.2242 +          // First, fill in remote stat with rtcp sender data, if present.
  1.2243 +          DOMHighResTimeStamp timestamp;
  1.2244 +          uint32_t packetsSent;
  1.2245 +          uint64_t bytesSent;
  1.2246 +          if (mp.Conduit()->GetRTCPSenderReport(&timestamp,
  1.2247 +                                                &packetsSent, &bytesSent)) {
  1.2248 +            remoteId = NS_LITERAL_STRING("inbound_rtcp_") + idstr;
  1.2249 +            RTCOutboundRTPStreamStats s;
  1.2250 +            s.mTimestamp.Construct(timestamp);
  1.2251 +            s.mId.Construct(remoteId);
  1.2252 +            s.mType.Construct(RTCStatsType::Outboundrtp);
  1.2253 +            if (ssrc.Length()) {
  1.2254 +              s.mSsrc.Construct(ssrc);
  1.2255 +            }
  1.2256 +            s.mRemoteId.Construct(localId);
  1.2257 +            s.mIsRemote = true;
  1.2258 +            s.mPacketsSent.Construct(packetsSent);
  1.2259 +            s.mBytesSent.Construct(bytesSent);
  1.2260 +            query->report.mOutboundRTPStreamStats.Value().AppendElement(s);
  1.2261 +          }
  1.2262 +        }
  1.2263 +        // Then, fill in local side (with cross-link to remote only if present)
  1.2264 +        RTCInboundRTPStreamStats s;
  1.2265 +        s.mTimestamp.Construct(query->now);
  1.2266 +        s.mId.Construct(localId);
  1.2267 +        s.mType.Construct(RTCStatsType::Inboundrtp);
  1.2268 +        if (ssrc.Length()) {
  1.2269 +          s.mSsrc.Construct(ssrc);
  1.2270 +        }
  1.2271 +        unsigned int jitterMs, packetsLost;
  1.2272 +        if (mp.Conduit()->GetRTPStats(&jitterMs, &packetsLost)) {
  1.2273 +          s.mJitter.Construct(double(jitterMs)/1000);
  1.2274 +          s.mPacketsLost.Construct(packetsLost);
  1.2275 +        }
  1.2276 +        if (remoteId.Length()) {
  1.2277 +          s.mRemoteId.Construct(remoteId);
  1.2278 +        }
  1.2279 +        s.mIsRemote = false;
  1.2280 +        s.mPacketsReceived.Construct(mp.rtp_packets_received());
  1.2281 +        s.mBytesReceived.Construct(mp.rtp_bytes_received());
  1.2282 +
  1.2283 +        if (query->internalStats && isAudio) {
  1.2284 +          int32_t jitterBufferDelay;
  1.2285 +          int32_t playoutBufferDelay;
  1.2286 +          int32_t avSyncDelta;
  1.2287 +          if (mp.Conduit()->GetAVStats(&jitterBufferDelay,
  1.2288 +                                       &playoutBufferDelay,
  1.2289 +                                       &avSyncDelta)) {
  1.2290 +            s.mMozJitterBufferDelay.Construct(jitterBufferDelay);
  1.2291 +            s.mMozAvSyncDelay.Construct(avSyncDelta);
  1.2292 +          }
  1.2293 +        }
  1.2294 +        query->report.mInboundRTPStreamStats.Value().AppendElement(s);
  1.2295 +        break;
  1.2296 +      }
  1.2297 +    }
  1.2298 +  }
  1.2299 +
  1.2300 +  // Gather stats from ICE
  1.2301 +  for (size_t s = 0; s != query->streams.Length(); ++s) {
  1.2302 +    RecordIceStats_s(*query->streams[s],
  1.2303 +                     query->internalStats,
  1.2304 +                     query->now,
  1.2305 +                     &(query->report));
  1.2306 +  }
  1.2307 +
  1.2308 +  // NrIceCtx and NrIceMediaStream must be destroyed on STS, so it is not safe
  1.2309 +  // to dispatch them back to main.
  1.2310 +  // We clear streams first to maintain destruction order
  1.2311 +  query->streams.Clear();
  1.2312 +  query->iceCtx = nullptr;
  1.2313 +  return NS_OK;
  1.2314 +}
  1.2315 +
  1.2316 +void PeerConnectionImpl::GetStatsForPCObserver_s(
  1.2317 +    const std::string& pcHandle, // The Runnable holds the memory
  1.2318 +    nsAutoPtr<RTCStatsQuery> query) {
  1.2319 +
  1.2320 +  MOZ_ASSERT(query);
  1.2321 +  MOZ_ASSERT(query->iceCtx);
  1.2322 +  ASSERT_ON_THREAD(query->iceCtx->thread());
  1.2323 +
  1.2324 +  nsresult rv = PeerConnectionImpl::ExecuteStatsQuery_s(query.get());
  1.2325 +
  1.2326 +  NS_DispatchToMainThread(
  1.2327 +      WrapRunnableNM(
  1.2328 +          &PeerConnectionImpl::DeliverStatsReportToPCObserver_m,
  1.2329 +          pcHandle,
  1.2330 +          rv,
  1.2331 +          query),
  1.2332 +      NS_DISPATCH_NORMAL);
  1.2333 +}
  1.2334 +
  1.2335 +void PeerConnectionImpl::DeliverStatsReportToPCObserver_m(
  1.2336 +    const std::string& pcHandle,
  1.2337 +    nsresult result,
  1.2338 +    nsAutoPtr<RTCStatsQuery> query) {
  1.2339 +
  1.2340 +  // Is the PeerConnectionImpl still around?
  1.2341 +  PeerConnectionWrapper pcw(pcHandle);
  1.2342 +  if (pcw.impl()) {
  1.2343 +    nsRefPtr<PeerConnectionObserver> pco =
  1.2344 +        do_QueryObjectReferent(pcw.impl()->mPCObserver);
  1.2345 +    if (pco) {
  1.2346 +      JSErrorResult rv;
  1.2347 +      if (NS_SUCCEEDED(result)) {
  1.2348 +        pco->OnGetStatsSuccess(query->report, rv);
  1.2349 +      } else {
  1.2350 +        pco->OnGetStatsError(kInternalError,
  1.2351 +            ObString("Failed to fetch statistics"),
  1.2352 +            rv);
  1.2353 +      }
  1.2354 +
  1.2355 +      if (rv.Failed()) {
  1.2356 +        CSFLogError(logTag, "Error firing stats observer callback");
  1.2357 +      }
  1.2358 +    }
  1.2359 +  }
  1.2360 +}
  1.2361 +
  1.2362 +#endif
  1.2363 +
  1.2364 +void
  1.2365 +PeerConnectionImpl::RecordLongtermICEStatistics() {
  1.2366 +#ifdef MOZILLA_INTERNAL_API
  1.2367 +  WebrtcGlobalInformation::StoreLongTermICEStatistics(*this);
  1.2368 +#endif
  1.2369 +}
  1.2370 +
  1.2371 +void
  1.2372 +PeerConnectionImpl::IceStreamReady(NrIceMediaStream *aStream)
  1.2373 +{
  1.2374 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.2375 +  MOZ_ASSERT(aStream);
  1.2376 +
  1.2377 +  CSFLogDebug(logTag, "%s: %s", __FUNCTION__, aStream->name().c_str());
  1.2378 +}
  1.2379 +
  1.2380 +void
  1.2381 +PeerConnectionImpl::OnSdpParseError(const char *message) {
  1.2382 +  CSFLogError(logTag, "%s SDP Parse Error: %s", __FUNCTION__, message);
  1.2383 +  // Save the parsing errors in the PC to be delivered with OnSuccess or OnError
  1.2384 +  mSDPParseErrorMessages.push_back(message);
  1.2385 +}
  1.2386 +
  1.2387 +void
  1.2388 +PeerConnectionImpl::ClearSdpParseErrorMessages() {
  1.2389 +  mSDPParseErrorMessages.clear();
  1.2390 +}
  1.2391 +
  1.2392 +const std::vector<std::string> &
  1.2393 +PeerConnectionImpl::GetSdpParseErrors() {
  1.2394 +  return mSDPParseErrorMessages;
  1.2395 +}
  1.2396 +
  1.2397 +#ifdef MOZILLA_INTERNAL_API
  1.2398 +//Telemetry for when calls start
  1.2399 +void
  1.2400 +PeerConnectionImpl::startCallTelem() {
  1.2401 +  // Start time for calls
  1.2402 +  mStartTime = TimeStamp::Now();
  1.2403 +
  1.2404 +  // Increment session call counter
  1.2405 +#ifdef MOZILLA_INTERNAL_API
  1.2406 +  int &cnt = PeerConnectionCtx::GetInstance()->mConnectionCounter;
  1.2407 +  Telemetry::GetHistogramById(Telemetry::WEBRTC_CALL_COUNT)->Subtract(cnt);
  1.2408 +  cnt++;
  1.2409 +  Telemetry::GetHistogramById(Telemetry::WEBRTC_CALL_COUNT)->Add(cnt);
  1.2410 +#endif
  1.2411 +}
  1.2412 +#endif
  1.2413 +
  1.2414 +NS_IMETHODIMP
  1.2415 +PeerConnectionImpl::GetLocalStreams(nsTArray<nsRefPtr<DOMMediaStream > >& result)
  1.2416 +{
  1.2417 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.2418 +#ifdef MOZILLA_INTERNAL_API
  1.2419 +  for(uint32_t i=0; i < media()->LocalStreamsLength(); i++) {
  1.2420 +    LocalSourceStreamInfo *info = media()->GetLocalStream(i);
  1.2421 +    NS_ENSURE_TRUE(info, NS_ERROR_UNEXPECTED);
  1.2422 +    result.AppendElement(info->GetMediaStream());
  1.2423 +  }
  1.2424 +  return NS_OK;
  1.2425 +#else
  1.2426 +  return NS_ERROR_FAILURE;
  1.2427 +#endif
  1.2428 +}
  1.2429 +
  1.2430 +NS_IMETHODIMP
  1.2431 +PeerConnectionImpl::GetRemoteStreams(nsTArray<nsRefPtr<DOMMediaStream > >& result)
  1.2432 +{
  1.2433 +  PC_AUTO_ENTER_API_CALL_NO_CHECK();
  1.2434 +#ifdef MOZILLA_INTERNAL_API
  1.2435 +  for(uint32_t i=0; i < media()->RemoteStreamsLength(); i++) {
  1.2436 +    RemoteSourceStreamInfo *info = media()->GetRemoteStream(i);
  1.2437 +    NS_ENSURE_TRUE(info, NS_ERROR_UNEXPECTED);
  1.2438 +    result.AppendElement(info->GetMediaStream());
  1.2439 +  }
  1.2440 +  return NS_OK;
  1.2441 +#else
  1.2442 +  return NS_ERROR_FAILURE;
  1.2443 +#endif
  1.2444 +}
  1.2445 +
  1.2446 +}  // end sipcc namespace

mercurial