/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef _PEER_CONNECTION_IMPL_H_ #define _PEER_CONNECTION_IMPL_H_ #include #include #include #include #include "prlock.h" #include "mozilla/RefPtr.h" #include "nsComponentManagerUtils.h" #include "nsPIDOMWindow.h" #include "nsIUUIDGenerator.h" #include "nsIThread.h" #include "mozilla/Mutex.h" #include "mozilla/Attributes.h" // Work around nasty macro in webrtc/voice_engine/voice_engine_defines.h #ifdef GetLastError # undef GetLastError #endif #include "jsep/JsepSession.h" #include "jsep/JsepSessionImpl.h" #include "sdp/SdpMediaSection.h" #include "mozilla/ErrorResult.h" #include "jsapi/PacketDumper.h" #include "mozilla/dom/RTCPeerConnectionBinding.h" // mozPacketDumpType, maybe move? #include "mozilla/dom/PeerConnectionImplBinding.h" // ChainedOperation #include "mozilla/dom/RTCRtpCapabilitiesBinding.h" #include "mozilla/dom/RTCRtpTransceiverBinding.h" #include "mozilla/dom/RTCConfigurationBinding.h" #include "PrincipalChangeObserver.h" #include "mozilla/dom/PromiseNativeHandler.h" #include "mozilla/TimeStamp.h" #include "mozilla/net/DataChannel.h" #include "VideoUtils.h" #include "VideoSegment.h" #include "mozilla/dom/RTCStatsReportBinding.h" #include "mozilla/PeerIdentity.h" #include "RTCStatsIdGenerator.h" #include "RTCStatsReport.h" #include "mozilla/net/StunAddrsRequestChild.h" #include "MediaTransportHandler.h" #include "nsIHttpChannelInternal.h" #include "RTCDtlsTransport.h" #include "RTCRtpTransceiver.h" namespace test { #ifdef USE_FAKE_PCOBSERVER class AFakePCObserver; #endif } // namespace test class nsDOMDataChannel; class nsIPrincipal; namespace mozilla { struct CandidateInfo; class DataChannel; class DtlsIdentity; class MediaPipeline; class MediaPipelineReceive; class MediaPipelineTransmit; enum class PrincipalPrivacy : uint8_t; class SharedWebrtcState; namespace dom { class RTCCertificate; struct RTCConfiguration; struct RTCRtpSourceEntry; struct RTCIceServer; struct RTCOfferOptions; struct RTCRtpParameters; class RTCRtpSender; class MediaStreamTrack; #ifdef USE_FAKE_PCOBSERVER typedef test::AFakePCObserver PeerConnectionObserver; typedef const char* PCObserverString; #else class PeerConnectionObserver; typedef NS_ConvertUTF8toUTF16 PCObserverString; #endif } // namespace dom } // namespace mozilla #if defined(__cplusplus) && __cplusplus >= 201103L typedef struct Timecard Timecard; #else # include "common/time_profiling/timecard.h" #endif // To preserve blame, convert nsresult to ErrorResult with wrappers. These // macros help declare wrappers w/function being wrapped when there are no // differences. #define NS_IMETHODIMP_TO_ERRORRESULT(func, rv, ...) \ NS_IMETHODIMP func(__VA_ARGS__); \ void func(__VA_ARGS__, rv) #define NS_IMETHODIMP_TO_ERRORRESULT_RETREF(resulttype, func, rv, ...) \ NS_IMETHODIMP func(__VA_ARGS__, resulttype** result); \ already_AddRefed func(__VA_ARGS__, rv) namespace mozilla { using mozilla::DtlsIdentity; using mozilla::ErrorResult; using mozilla::PeerIdentity; using mozilla::dom::PeerConnectionObserver; using mozilla::dom::RTCConfiguration; using mozilla::dom::RTCIceServer; using mozilla::dom::RTCOfferOptions; class PeerConnectionWrapper; class RemoteSourceStreamInfo; // Uuid Generator class PCUuidGenerator : public mozilla::JsepUuidGenerator { public: virtual bool Generate(std::string* idp) override; virtual mozilla::JsepUuidGenerator* Clone() const override { return new PCUuidGenerator(*this); } private: nsCOMPtr mGenerator; }; // This is a variation of Telemetry::AutoTimer that keeps a reference // count and records the elapsed time when the count falls to zero. The // elapsed time is recorded in seconds. struct PeerConnectionAutoTimer { PeerConnectionAutoTimer() : mRefCnt(0), mStart(TimeStamp::Now()), mUsedAV(false){}; void RegisterConnection(); void UnregisterConnection(bool aContainedAV); bool IsStopped(); private: int64_t mRefCnt; TimeStamp mStart; bool mUsedAV; }; // Enter an API call and check that the state is OK, // the PC isn't closed, etc. #define PC_AUTO_ENTER_API_CALL(assert_ice_ready) \ do { \ /* do/while prevents res from conflicting with locals */ \ nsresult res = CheckApiState(assert_ice_ready); \ if (NS_FAILED(res)) return res; \ } while (0) #define PC_AUTO_ENTER_API_CALL_VOID_RETURN(assert_ice_ready) \ do { \ /* do/while prevents res from conflicting with locals */ \ nsresult res = CheckApiState(assert_ice_ready); \ if (NS_FAILED(res)) return; \ } while (0) #define PC_AUTO_ENTER_API_CALL_NO_CHECK() CheckThread() class PeerConnectionImpl final : public nsISupports, public nsWrapperCache, public mozilla::DataChannelConnection::DataConnectionListener { struct Internal; // Avoid exposing c includes to bindings public: explicit PeerConnectionImpl( const mozilla::dom::GlobalObject* aGlobal = nullptr); NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(PeerConnectionImpl) struct RtpExtensionHeader { JsepMediaType mMediaType; SdpDirectionAttribute::Direction direction; std::string extensionname; }; JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; nsPIDOMWindowInner* GetParentObject() const; static already_AddRefed Constructor( const mozilla::dom::GlobalObject& aGlobal); // DataConnection observers void NotifyDataChannel(already_AddRefed aChannel) // PeerConnectionImpl only inherits from mozilla::DataChannelConnection // inside libxul. override; void NotifyDataChannelOpen(DataChannel*) override; void NotifyDataChannelClosed(DataChannel*) override; void NotifySctpConnected() override; void NotifySctpClosed() override; const RefPtr GetTransportHandler() const; // Handle system to allow weak references to be passed through C code virtual const std::string& GetHandle(); // Name suitable for exposing to content virtual const std::string& GetName(); // ICE events void IceConnectionStateChange(dom::RTCIceConnectionState state); void IceGatheringStateChange(dom::RTCIceGatheringState state); void OnCandidateFound(const std::string& aTransportId, const CandidateInfo& aCandidateInfo); void UpdateDefaultCandidate(const std::string& defaultAddr, uint16_t defaultPort, const std::string& defaultRtcpAddr, uint16_t defaultRtcpPort, const std::string& transportId); static void ListenThread(void* aData); static void ConnectThread(void* aData); // Get the STS thread nsISerialEventTarget* GetSTSThread() { PC_AUTO_ENTER_API_CALL_NO_CHECK(); return mSTSThread; } nsresult Initialize(PeerConnectionObserver& aObserver, nsGlobalWindowInner* aWindow); // Initialize PeerConnection from an RTCConfiguration object (JS entrypoint) void Initialize(PeerConnectionObserver& aObserver, nsGlobalWindowInner& aWindow, ErrorResult& rv); void SetCertificate(mozilla::dom::RTCCertificate& aCertificate); const RefPtr& Certificate() const; // This is a hack to support external linkage. RefPtr Identity() const; NS_IMETHODIMP_TO_ERRORRESULT(CreateOffer, ErrorResult& rv, const RTCOfferOptions& aOptions) { rv = CreateOffer(aOptions); } NS_IMETHODIMP CreateAnswer(); void CreateAnswer(ErrorResult& rv) { rv = CreateAnswer(); } NS_IMETHODIMP CreateOffer(const mozilla::JsepOfferOptions& aConstraints); NS_IMETHODIMP SetLocalDescription(int32_t aAction, const char* aSDP); void SetLocalDescription(int32_t aAction, const nsAString& aSDP, ErrorResult& rv) { rv = SetLocalDescription(aAction, NS_ConvertUTF16toUTF8(aSDP).get()); } NS_IMETHODIMP SetRemoteDescription(int32_t aAction, const char* aSDP); void SetRemoteDescription(int32_t aAction, const nsAString& aSDP, ErrorResult& rv) { rv = SetRemoteDescription(aAction, NS_ConvertUTF16toUTF8(aSDP).get()); } already_AddRefed GetStats(dom::MediaStreamTrack* aSelector); void GetRemoteStreams(nsTArray>& aStreamsOut) const; NS_IMETHODIMP AddIceCandidate(const char* aCandidate, const char* aMid, const char* aUfrag, const dom::Nullable& aLevel); void AddIceCandidate(const nsAString& aCandidate, const nsAString& aMid, const nsAString& aUfrag, const dom::Nullable& aLevel, ErrorResult& rv) { rv = AddIceCandidate(NS_ConvertUTF16toUTF8(aCandidate).get(), NS_ConvertUTF16toUTF8(aMid).get(), NS_ConvertUTF16toUTF8(aUfrag).get(), aLevel); } void UpdateNetworkState(bool online); NS_IMETHODIMP CloseStreams(); void CloseStreams(ErrorResult& rv) { rv = CloseStreams(); } already_AddRefed AddTransceiver( const dom::RTCRtpTransceiverInit& aInit, const nsAString& aKind, dom::MediaStreamTrack* aSendTrack, bool aAddTrackMagic, ErrorResult& aRv); bool CheckNegotiationNeeded(); bool CreatedSender(const dom::RTCRtpSender& aSender) const; // test-only NS_IMETHODIMP_TO_ERRORRESULT(EnablePacketDump, ErrorResult& rv, unsigned long level, dom::mozPacketDumpType type, bool sending) { rv = EnablePacketDump(level, type, sending); } // test-only NS_IMETHODIMP_TO_ERRORRESULT(DisablePacketDump, ErrorResult& rv, unsigned long level, dom::mozPacketDumpType type, bool sending) { rv = DisablePacketDump(level, type, sending); } void GetPeerIdentity(nsAString& peerIdentity) { if (mPeerIdentity) { peerIdentity = mPeerIdentity->ToString(); return; } peerIdentity.SetIsVoid(true); } const PeerIdentity* GetPeerIdentity() const { return mPeerIdentity; } NS_IMETHODIMP_TO_ERRORRESULT(SetPeerIdentity, ErrorResult& rv, const nsAString& peerIdentity) { rv = SetPeerIdentity(peerIdentity); } const std::string& GetIdAsAscii() const { return mName; } void GetId(nsAString& id) { id = NS_ConvertASCIItoUTF16(mName.c_str()); } void SetId(const nsAString& id) { mName = NS_ConvertUTF16toUTF8(id).get(); } // this method checks to see if we've made a promise to protect media. bool PrivacyRequested() const { return mRequestedPrivacy.valueOr(PrincipalPrivacy::NonPrivate) == PrincipalPrivacy::Private; } NS_IMETHODIMP GetFingerprint(char** fingerprint); void GetFingerprint(nsAString& fingerprint) { char* tmp; nsresult rv = GetFingerprint(&tmp); NS_ENSURE_SUCCESS_VOID(rv); fingerprint.AssignASCII(tmp); delete[] tmp; } void GetCurrentLocalDescription(nsAString& aSDP) const; void GetPendingLocalDescription(nsAString& aSDP) const; void GetCurrentRemoteDescription(nsAString& aSDP) const; void GetPendingRemoteDescription(nsAString& aSDP) const; dom::Nullable GetCurrentOfferer() const; dom::Nullable GetPendingOfferer() const; NS_IMETHODIMP SignalingState(mozilla::dom::RTCSignalingState* aState); mozilla::dom::RTCSignalingState SignalingState() { mozilla::dom::RTCSignalingState state; SignalingState(&state); return state; } NS_IMETHODIMP IceConnectionState(mozilla::dom::RTCIceConnectionState* aState); mozilla::dom::RTCIceConnectionState IceConnectionState() { mozilla::dom::RTCIceConnectionState state; IceConnectionState(&state); return state; } NS_IMETHODIMP IceGatheringState(mozilla::dom::RTCIceGatheringState* aState); mozilla::dom::RTCIceGatheringState IceGatheringState() { return mIceGatheringState; } NS_IMETHODIMP ConnectionState(mozilla::dom::RTCPeerConnectionState* aState); mozilla::dom::RTCPeerConnectionState ConnectionState() { mozilla::dom::RTCPeerConnectionState state; ConnectionState(&state); return state; } NS_IMETHODIMP Close(); void Close(ErrorResult& rv) { rv = Close(); } // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230) MOZ_CAN_RUN_SCRIPT_BOUNDARY bool PluginCrash(uint32_t aPluginID, const nsAString& aPluginName); NS_IMETHODIMP_TO_ERRORRESULT(SetConfiguration, ErrorResult& rv, const RTCConfiguration& aConfiguration) { rv = SetConfiguration(aConfiguration); } dom::RTCSctpTransport* GetSctp() const; void RestartIce(); void RestartIceNoRenegotiationNeeded(); void RecordEndOfCallTelemetry(); nsresult InitializeDataChannel(); NS_IMETHODIMP_TO_ERRORRESULT_RETREF(nsDOMDataChannel, CreateDataChannel, ErrorResult& rv, const nsAString& aLabel, const nsAString& aProtocol, uint16_t aType, bool outOfOrderAllowed, uint16_t aMaxTime, uint16_t aMaxNum, bool aExternalNegotiated, uint16_t aStream); // Base class for chained operations. Necessary right now because some // operations come from JS (in the form of dom::ChainedOperation), and others // come from c++ (dom::ChainedOperation is very unwieldy and arcane to build // in c++). Once we stop using JSImpl, we should be able to simplify this. class Operation : public dom::PromiseNativeHandler { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS(Operation) Operation(PeerConnectionImpl* aPc, ErrorResult& aError); MOZ_CAN_RUN_SCRIPT void Call(ErrorResult& aError); dom::Promise* GetPromise() { return mPromise; } MOZ_CAN_RUN_SCRIPT void ResolvedCallback(JSContext* aCx, JS::Handle aValue, ErrorResult& aRv) override; MOZ_CAN_RUN_SCRIPT void RejectedCallback(JSContext* aCx, JS::Handle aValue, ErrorResult& aRv) override; protected: MOZ_CAN_RUN_SCRIPT virtual RefPtr CallImpl(ErrorResult& aError) = 0; virtual ~Operation(); // This is the promise p from https://w3c.github.io/webrtc-pc/#dfn-chain // This will be a content promise, since we return this to the caller of // Chain. RefPtr mPromise; RefPtr mPc; }; class JSOperation final : public Operation { public: JSOperation(PeerConnectionImpl* aPc, dom::ChainedOperation& aOp, ErrorResult& aError); NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(JSOperation, Operation) private: MOZ_CAN_RUN_SCRIPT RefPtr CallImpl(ErrorResult& aError) override; ~JSOperation() = default; RefPtr mOperation; }; MOZ_CAN_RUN_SCRIPT already_AddRefed Chain(dom::ChainedOperation& aOperation, ErrorResult& aError); MOZ_CAN_RUN_SCRIPT already_AddRefed Chain(const RefPtr& aOperation, ErrorResult& aError); already_AddRefed MakePromise(ErrorResult& aError) const; void UpdateNegotiationNeeded(); void GetTransceivers( nsTArray>& aTransceiversOut) { aTransceiversOut = mTransceivers.Clone(); } // Gets the RTC Signaling State of the JSEP session dom::RTCSignalingState GetSignalingState() const; already_AddRefed OnSetDescriptionSuccess( dom::RTCSdpType aSdpType, bool aRemote, ErrorResult& aError); void OnSetDescriptionError(); bool IsClosed() const; // called when DTLS connects; we only need this once nsresult OnAlpnNegotiated(bool aPrivacyRequested); void OnDtlsStateChange(const std::string& aTransportId, TransportLayer::State aState); void UpdateConnectionState(); dom::RTCPeerConnectionState GetNewConnectionState() const; // initialize telemetry for when calls start void StartCallTelem(); // Gets all codec stats for all transports, coalesced to transport level. nsTArray GetCodecStats(DOMHighResTimeStamp aNow); RefPtr GetStats(dom::MediaStreamTrack* aSelector, bool aInternalStats); void CollectConduitTelemetryData(); void OnMediaError(const std::string& aError); void DumpPacket_m(size_t level, dom::mozPacketDumpType type, bool sending, UniquePtr& packet, size_t size); const dom::RTCStatsTimestampMaker& GetTimestampMaker() const { return mTimestampMaker; } // Utility function, given a string pref and an URI, returns whether or not // the URI occurs in the pref. Wildcards are supported (e.g. *.example.com) // and multiple hostnames can be present, separated by commas. static bool HostnameInPref(const char* aPrefList, const nsCString& aHostName); void StampTimecard(const char* aEvent); bool RelayOnly() const { return mJsConfiguration.mIceTransportPolicy.WasPassed() && mJsConfiguration.mIceTransportPolicy.Value() == dom::RTCIceTransportPolicy::Relay; } RefPtr GetPacketDumper() { if (!mPacketDumper) { mPacketDumper = new PacketDumper(mHandle); } return mPacketDumper; } nsString GenerateUUID() const { std::string result; if (!mUuidGen->Generate(&result)) { MOZ_CRASH(); } return NS_ConvertUTF8toUTF16(result.c_str()); } bool ShouldAllowOldSetParameters() const { return mAllowOldSetParameters; } nsCString GetHostname() const { return mHostname; } nsCString GetEffectiveTLDPlus1() const { return mEffectiveTLDPlus1; } void SendWarningToConsole(const nsCString& aWarning); const UniquePtr& GetFinalStats() const { return mFinalStats; } void DisableLongTermStats() { mDisableLongTermStats = true; } bool LongTermStatsIsDisabled() const { return mDisableLongTermStats; } static void GetDefaultVideoCodecs( std::vector>& aSupportedCodecs, bool aUseRtx); static void GetDefaultAudioCodecs( std::vector>& aSupportedCodecs); static void GetDefaultRtpExtensions( std::vector& aRtpExtensions); static void GetCapabilities(const nsAString& aKind, dom::Nullable& aResult, sdp::Direction aDirection); static void SetupPreferredCodecs( std::vector>& aPreferredCodecs); static void SetupPreferredRtpExtensions( std::vector& aPreferredheaders); private: virtual ~PeerConnectionImpl(); PeerConnectionImpl(const PeerConnectionImpl& rhs); PeerConnectionImpl& operator=(PeerConnectionImpl); RefPtr GetDataChannelStats( const RefPtr& aDataChannelConnection, const DOMHighResTimeStamp aTimestamp); nsresult CalculateFingerprint(const std::string& algorithm, std::vector* fingerprint) const; nsresult ConfigureJsepSessionCodecs(); NS_IMETHODIMP EnsureDataConnection(uint16_t aLocalPort, uint16_t aNumstreams, uint32_t aMaxMessageSize, bool aMMSSet); nsresult CheckApiState(bool assert_ice_ready) const; void StoreFinalStats(UniquePtr&& report); void CheckThread() const { MOZ_ASSERT(NS_IsMainThread(), "Wrong thread"); } // test-only: called from AddRIDExtension and AddRIDFilter // for simulcast mochitests. RefPtr GetMediaPipelineForTrack( dom::MediaStreamTrack& aRecvTrack); void CandidateReady(const std::string& candidate, const std::string& transportId, const std::string& ufrag); void SendLocalIceCandidateToContent(uint16_t level, const std::string& mid, const std::string& candidate, const std::string& ufrag); nsresult GetDatachannelParameters(uint32_t* channels, uint16_t* localport, uint16_t* remoteport, uint32_t* maxmessagesize, bool* mmsset, std::string* transportId, bool* client) const; nsresult AddRtpTransceiverToJsepSession(JsepTransceiver& transceiver); void RecordIceRestartStatistics(JsepSdpType type); void StoreConfigurationForAboutWebrtc(const RTCConfiguration& aConfig); dom::Sequence GetLastSdpParsingErrors() const; MOZ_CAN_RUN_SCRIPT void RunNextOperation(ErrorResult& aError); void SyncToJsep(); void SyncFromJsep(); void DoSetDescriptionSuccessPostProcessing(dom::RTCSdpType aSdpType, bool aRemote, const RefPtr& aP); // Timecard used to measure processing time. This should be the first class // attribute so that we accurately measure the time required to instantiate // any other attributes of this class. Timecard* mTimeCard; // Configuration used to initialize the PeerConnection dom::RTCConfigurationInternal mJsConfiguration; mozilla::dom::RTCSignalingState mSignalingState; // ICE State mozilla::dom::RTCIceConnectionState mIceConnectionState; mozilla::dom::RTCIceGatheringState mIceGatheringState; mozilla::dom::RTCPeerConnectionState mConnectionState; RefPtr mPCObserver; nsCOMPtr mWindow; // The SDP sent in from JS std::string mLocalRequestedSDP; std::string mRemoteRequestedSDP; // Only accessed from main mozilla::dom::Sequence mSdpHistory; std::string mPendingLocalDescription; std::string mPendingRemoteDescription; std::string mCurrentLocalDescription; std::string mCurrentRemoteDescription; Maybe mPendingOfferer; Maybe mCurrentOfferer; // DTLS fingerprint std::string mFingerprint; std::string mRemoteFingerprint; // identity-related fields // The entity on the other end of the peer-to-peer connection; // void if they are not yet identified, and no identity setting has been set RefPtr mPeerIdentity; // The certificate we are using. RefPtr mCertificate; // Whether an app should be prevented from accessing media produced by the PC // If this is true, then media will not be sent until mPeerIdentity matches // local streams PeerIdentity; and remote streams are protected from content // // This can be false if mPeerIdentity is set, in the case where identity is // provided, but the media is not protected from the app on either side Maybe mRequestedPrivacy; // A handle to refer to this PC with std::string mHandle; // A name for this PC that we are willing to expose to content. std::string mName; nsCString mHostname; nsCString mEffectiveTLDPlus1; // The target to run stuff on nsCOMPtr mSTSThread; // DataConnection that's used to get all the DataChannels RefPtr mDataConnection; unsigned int mDataChannelsOpened = 0; unsigned int mDataChannelsClosed = 0; bool mForceIceTcp; RefPtr mTransportHandler; // The JSEP negotiation session. mozilla::UniquePtr mUuidGen; mozilla::UniquePtr mJsepSession; // There are lots of error cases where we want to abandon an sRD/sLD _after_ // it has already been applied to the JSEP engine, and revert back to the // previous state. We also want to ensure that the various modifications // to the JSEP engine are not exposed to JS until the sRD/sLD completes, // which is why we have a new "uncommitted" JSEP engine. mozilla::UniquePtr mUncommittedJsepSession; unsigned long mIceRestartCount; unsigned long mIceRollbackCount; // The following are used for Telemetry: bool mCallTelemStarted = false; bool mCallTelemEnded = false; // We _could_ make mFinalStatsQuery be an RTCStatsReportPromise, but that // would require RTCStatsReportPromise to no longer be exclusive, which is // a bit of a hassle, and not very performant. RefPtr mFinalStatsQuery; UniquePtr mFinalStats; bool mDisableLongTermStats = false; // Start time of ICE. mozilla::TimeStamp mIceStartTime; // Hold PeerConnectionAutoTimer instances for each window. static std::map sCallDurationTimers; bool mHaveConfiguredCodecs; bool mTrickle; bool mPrivateWindow; // Whether this PeerConnection is being counted as active by mWindow bool mActiveOnWindow; // storage for Telemetry data uint16_t mMaxReceiving[SdpMediaSection::kMediaTypes]; uint16_t mMaxSending[SdpMediaSection::kMediaTypes]; // used to store the raw trickle candidate string for display // on the about:webrtc raw candidates table. std::vector mRawTrickledCandidates; dom::RTCStatsTimestampMaker mTimestampMaker; RefPtr mIdGenerator; // Ordinarily, I would use a std::map here, but this used to be a JS Map // which iterates in insertion order, and I want to avoid changing this. nsTArray> mReceiveStreams; DOMMediaStream* GetReceiveStream(const std::string& aId) const; DOMMediaStream* CreateReceiveStream(const std::string& aId); void InitLocalAddrs(); // for stun local address IPC request bool ShouldForceProxy() const; std::unique_ptr GetProxyConfig() const; class StunAddrsHandler : public net::StunAddrsListener { public: explicit StunAddrsHandler(PeerConnectionImpl* aPc) : mPcHandle(aPc->GetHandle()) {} void OnMDNSQueryComplete(const nsCString& hostname, const Maybe& address) override; void OnStunAddrsAvailable( const mozilla::net::NrIceStunAddrArray& addrs) override; private: // This class is not cycle-collected, so we must avoid grabbing a strong // reference. const std::string mPcHandle; virtual ~StunAddrsHandler() {} }; // Manage ICE transports. void UpdateTransport(const JsepTransceiver& aTransceiver, bool aForceIceTcp); void GatherIfReady(); void FlushIceCtxOperationQueueIfReady(); void PerformOrEnqueueIceCtxOperation(nsIRunnable* runnable); nsresult SetTargetForDefaultLocalAddressLookup(); void EnsureIceGathering(bool aDefaultRouteOnly, bool aObfuscateHostAddresses); bool GetPrefDefaultAddressOnly() const; bool GetPrefObfuscateHostAddresses() const; bool IsIceCtxReady() const { return mLocalAddrsRequestState == STUN_ADDR_REQUEST_COMPLETE; } // Ensure ICE transports exist that we might need when offer/answer concludes void EnsureTransports(const JsepSession& aSession); void UpdateRTCDtlsTransports(bool aMarkAsStable); void RollbackRTCDtlsTransports(); void RemoveRTCDtlsTransportsExcept( const std::set& aTransportIds); // Activate ICE transports at the conclusion of offer/answer, // or when rollback occurs. nsresult UpdateTransports(const JsepSession& aSession, const bool forceIceTcp); void ResetStunAddrsForIceRestart() { mStunAddrs.Clear(); } // Start ICE checks. void StartIceChecks(const JsepSession& session); // Process a trickle ICE candidate. void AddIceCandidate(const std::string& candidate, const std::string& aTransportId, const std::string& aUFrag); // Handle complete media pipelines. // This updates codec parameters, starts/stops send/receive, and other // stuff that doesn't necessarily require negotiation. This can be called at // any time, not just when an offer/answer exchange completes. nsresult UpdateMediaPipelines(); already_AddRefed CreateTransceiver( const std::string& aId, bool aIsVideo, const dom::RTCRtpTransceiverInit& aInit, dom::MediaStreamTrack* aSendTrack, bool aAddTrackMagic, ErrorResult& aRv); std::string GetTransportIdMatchingSendTrack( const dom::MediaStreamTrack& aTrack) const; // this determines if any track is peerIdentity constrained bool AnyLocalTrackHasPeerIdentity() const; bool AnyCodecHasPluginID(uint64_t aPluginID); already_AddRefed GetChannel() const; void BreakCycles(); bool HasPendingSetParameters() const; void InvalidateLastReturnedParameters(); RefPtr mCall; // See Bug 1642419, this can be removed when all sites are working with RTX. bool mRtxIsAllowed = true; nsTArray> mOperations; bool mChainingOperation = false; bool mUpdateNegotiationNeededFlagOnEmptyChain = false; bool mNegotiationNeeded = false; std::set> mLocalIceCredentialsToReplace; nsTArray> mTransceivers; std::map> mTransportIdToRTCDtlsTransport; RefPtr mSctpTransport; // Used whenever we need to dispatch a runnable to STS to tweak something // on our ICE ctx, but are not ready to do so at the moment (eg; we are // waiting to get a callback with our http proxy config before we start // gathering or start checking) std::vector> mQueuedIceCtxOperations; // Set if prefs dictate that we should force the use of a web proxy. bool mForceProxy = false; // Used to cancel incoming stun addrs response RefPtr mStunAddrsRequest; enum StunAddrRequestState { STUN_ADDR_REQUEST_NONE, STUN_ADDR_REQUEST_PENDING, STUN_ADDR_REQUEST_COMPLETE }; // Used to track the state of the stun addr IPC request StunAddrRequestState mLocalAddrsRequestState = STUN_ADDR_REQUEST_NONE; // Used to store the result of the stun addr IPC request nsTArray mStunAddrs; // Used to ensure the target for default local address lookup is only set // once. bool mTargetForDefaultLocalAddressLookupIsSet = false; // Keep track of local hostnames to register. Registration is deferred // until StartIceChecks has run. Accessed on main thread only. std::map mMDNSHostnamesToRegister; bool mCanRegisterMDNSHostnamesDirectly = false; // Used to store the mDNS hostnames that we have registered std::set mRegisteredMDNSHostnames; // web-compat stopgap bool mAllowOldSetParameters = false; // Used to store the mDNS hostnames that we have queried struct PendingIceCandidate { std::vector mTokenizedCandidate; std::string mTransportId; std::string mUfrag; }; std::map> mQueriedMDNSHostnames; // Connecting PCImpl to sigslot is not safe, because sigslot takes strong // references without any reference counting, and JS holds refcounted strong // references to PCImpl (meaning JS can cause PCImpl to be destroyed). This // is not ref-counted (since sigslot holds onto non-refcounted strong refs) // Must be destroyed on STS. Holds a weak reference to PCImpl. class SignalHandler : public sigslot::has_slots<> { public: SignalHandler(PeerConnectionImpl* aPc, MediaTransportHandler* aSource); virtual ~SignalHandler(); void ConnectSignals(); // ICE events void IceGatheringStateChange_s(dom::RTCIceGatheringState aState); void IceConnectionStateChange_s(dom::RTCIceConnectionState aState); void OnCandidateFound_s(const std::string& aTransportId, const CandidateInfo& aCandidateInfo); void AlpnNegotiated_s(const std::string& aAlpn, bool aPrivacyRequested); void ConnectionStateChange_s(const std::string& aTransportId, TransportLayer::State aState); private: const std::string mHandle; RefPtr mSource; RefPtr mSTSThread; }; mozilla::UniquePtr mSignalHandler; // Make absolutely sure our refcount does not go to 0 before Close() is called // This is because Close does a stats query, which needs the // PeerConnectionImpl to stick around until the query is done. RefPtr mKungFuDeathGrip; RefPtr mPacketDumper; public: // these are temporary until the DataChannel Listen/Connect API is removed unsigned short listenPort; unsigned short connectPort; char* connectStr; // XXX ownership/free }; // This is what is returned when you acquire on a handle class PeerConnectionWrapper { public: explicit PeerConnectionWrapper(const std::string& handle); PeerConnectionImpl* impl() { return impl_; } private: RefPtr impl_; }; } // namespace mozilla #undef NS_IMETHODIMP_TO_ERRORRESULT #undef NS_IMETHODIMP_TO_ERRORRESULT_RETREF #endif // _PEER_CONNECTION_IMPL_H_