diff options
Diffstat (limited to 'media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h')
-rw-r--r-- | media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h | 586 |
1 files changed, 586 insertions, 0 deletions
diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h new file mode 100644 index 000000000..c0001a5e5 --- /dev/null +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h @@ -0,0 +1,586 @@ +/* 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_MEDIA_H_ +#define _PEER_CONNECTION_MEDIA_H_ + +#include <string> +#include <vector> +#include <map> + +#include "nspr.h" +#include "prlock.h" + +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" +#include "nsComponentManagerUtils.h" +#include "nsIProtocolProxyCallback.h" + +#include "signaling/src/jsep/JsepSession.h" +#include "AudioSegment.h" + +#if !defined(MOZILLA_EXTERNAL_LINKAGE) +#include "Layers.h" +#include "VideoUtils.h" +#include "ImageLayers.h" +#include "VideoSegment.h" +#include "MediaStreamTrack.h" +#endif + +class nsIPrincipal; + +namespace mozilla { +class DataChannel; +class PeerIdentity; +class MediaPipelineFactory; +namespace dom { +struct RTCInboundRTPStreamStats; +struct RTCOutboundRTPStreamStats; +} +} + +#include "nricectxhandler.h" +#include "nriceresolver.h" +#include "nricemediastream.h" +#include "MediaPipeline.h" + +namespace mozilla { + +class PeerConnectionImpl; +class PeerConnectionMedia; +class PCUuidGenerator; + +class SourceStreamInfo { +public: + SourceStreamInfo(DOMMediaStream* aMediaStream, + PeerConnectionMedia *aParent, + const std::string& aId) + : mMediaStream(aMediaStream), + mParent(aParent), + mId(aId) { + MOZ_ASSERT(mMediaStream); + } + + SourceStreamInfo(already_AddRefed<DOMMediaStream>& aMediaStream, + PeerConnectionMedia *aParent, + const std::string& aId) + : mMediaStream(aMediaStream), + mParent(aParent), + mId(aId) { + MOZ_ASSERT(mMediaStream); + } + + virtual ~SourceStreamInfo() {} + + DOMMediaStream* GetMediaStream() const { + return mMediaStream; + } + + nsresult StorePipeline(const std::string& trackId, + const RefPtr<MediaPipeline>& aPipeline); + + virtual void AddTrack(const std::string& trackId, + const RefPtr<dom::MediaStreamTrack>& aTrack) + { + mTracks.insert(std::make_pair(trackId, aTrack)); + } + virtual void RemoveTrack(const std::string& trackId); + bool HasTrack(const std::string& trackId) const + { + return !!mTracks.count(trackId); + } + size_t GetTrackCount() const { return mTracks.size(); } + + // This method exists for stats and the unittests. + // It allows visibility into the pipelines and flows. + const std::map<std::string, RefPtr<MediaPipeline>>& + GetPipelines() const { return mPipelines; } + RefPtr<MediaPipeline> GetPipelineByTrackId_m(const std::string& trackId); + // This is needed so PeerConnectionImpl can unregister itself as + // PrincipalChangeObserver from each track. + const std::map<std::string, RefPtr<dom::MediaStreamTrack>>& + GetMediaStreamTracks() const { return mTracks; } + dom::MediaStreamTrack* GetTrackById(const std::string& trackId) const + { + auto it = mTracks.find(trackId); + if (it == mTracks.end()) { + return nullptr; + } + + return it->second; + } + const std::string& GetId() const { return mId; } + + void DetachTransport_s(); + virtual void DetachMedia_m(); + bool AnyCodecHasPluginID(uint64_t aPluginID); +protected: + void EndTrack(MediaStream* stream, dom::MediaStreamTrack* track); + RefPtr<DOMMediaStream> mMediaStream; + PeerConnectionMedia *mParent; + const std::string mId; + // These get set up before we generate our local description, the pipelines + // and conduits are set up once offer/answer completes. + std::map<std::string, RefPtr<dom::MediaStreamTrack>> mTracks; + std::map<std::string, RefPtr<MediaPipeline>> mPipelines; +}; + +// TODO(ekr@rtfm.com): Refactor {Local,Remote}SourceStreamInfo +// bug 837539. +class LocalSourceStreamInfo : public SourceStreamInfo { + ~LocalSourceStreamInfo() { + mMediaStream = nullptr; + } +public: + LocalSourceStreamInfo(DOMMediaStream *aMediaStream, + PeerConnectionMedia *aParent, + const std::string& aId) + : SourceStreamInfo(aMediaStream, aParent, aId) {} + + nsresult TakePipelineFrom(RefPtr<LocalSourceStreamInfo>& info, + const std::string& oldTrackId, + dom::MediaStreamTrack& aNewTrack, + const std::string& newTrackId); + +#if !defined(MOZILLA_EXTERNAL_LINKAGE) + void UpdateSinkIdentity_m(dom::MediaStreamTrack* aTrack, + nsIPrincipal* aPrincipal, + const PeerIdentity* aSinkIdentity); +#endif + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LocalSourceStreamInfo) + +private: + already_AddRefed<MediaPipeline> ForgetPipelineByTrackId_m( + const std::string& trackId); +}; + +#if !defined(MOZILLA_EXTERNAL_LINKAGE) +class RemoteTrackSource : public dom::MediaStreamTrackSource +{ +public: + explicit RemoteTrackSource(nsIPrincipal* aPrincipal, const nsString& aLabel) + : dom::MediaStreamTrackSource(aPrincipal, aLabel) {} + + dom::MediaSourceEnum GetMediaSource() const override + { + return dom::MediaSourceEnum::Other; + } + + already_AddRefed<PledgeVoid> + ApplyConstraints(nsPIDOMWindowInner* aWindow, + const dom::MediaTrackConstraints& aConstraints) override; + + void Stop() override + { + // XXX (Bug 1314270): Implement rejection logic if necessary when we have + // clarity in the spec. + } + + void SetPrincipal(nsIPrincipal* aPrincipal) + { + mPrincipal = aPrincipal; + PrincipalChanged(); + } + +protected: + virtual ~RemoteTrackSource() {} +}; +#endif + +class RemoteSourceStreamInfo : public SourceStreamInfo { + ~RemoteSourceStreamInfo() {} + public: + RemoteSourceStreamInfo(already_AddRefed<DOMMediaStream> aMediaStream, + PeerConnectionMedia *aParent, + const std::string& aId) + : SourceStreamInfo(aMediaStream, aParent, aId), + mReceiving(false) + { + } + + void DetachMedia_m() override; + void RemoveTrack(const std::string& trackId) override; + void SyncPipeline(RefPtr<MediaPipelineReceive> aPipeline); + +#if !defined(MOZILLA_EXTERNAL_LINKAGE) + void UpdatePrincipal_m(nsIPrincipal* aPrincipal); +#endif + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteSourceStreamInfo) + + void AddTrack(const std::string& trackId, + const RefPtr<dom::MediaStreamTrack>& aTrack) override + { + SourceStreamInfo::AddTrack(trackId, aTrack); + } + + TrackID GetNumericTrackId(const std::string& trackId) const + { + dom::MediaStreamTrack* track = GetTrackById(trackId); + if (!track) { + return TRACK_INVALID; + } + return track->mTrackID; + } + + void StartReceiving(); + + private: + // True iff SetPullEnabled(true) has been called on the DOMMediaStream. This + // happens when offer/answer concludes. + bool mReceiving; +}; + +class PeerConnectionMedia : public sigslot::has_slots<> { + ~PeerConnectionMedia() + { + MOZ_RELEASE_ASSERT(!mMainThread); + } + + public: + explicit PeerConnectionMedia(PeerConnectionImpl *parent); + + enum IceRestartState { ICE_RESTART_NONE, + ICE_RESTART_PROVISIONAL, + ICE_RESTART_COMMITTED + }; + + PeerConnectionImpl* GetPC() { return mParent; } + nsresult Init(const std::vector<NrIceStunServer>& stun_servers, + const std::vector<NrIceTurnServer>& turn_servers, + NrIceCtx::Policy policy); + // WARNING: This destroys the object! + void SelfDestruct(); + + RefPtr<NrIceCtxHandler> ice_ctx_hdlr() const { return mIceCtxHdlr; } + RefPtr<NrIceCtx> ice_ctx() const { return mIceCtxHdlr->ctx(); } + + RefPtr<NrIceMediaStream> ice_media_stream(size_t i) const { + return mIceCtxHdlr->ctx()->GetStream(i); + } + + size_t num_ice_media_streams() const { + return mIceCtxHdlr->ctx()->GetStreamCount(); + } + + // Ensure ICE transports exist that we might need when offer/answer concludes + void EnsureTransports(const JsepSession& aSession); + + // Activate or remove ICE transports at the conclusion of offer/answer, + // or when rollback occurs. + void ActivateOrRemoveTransports(const JsepSession& aSession); + + // Start ICE checks. + void StartIceChecks(const JsepSession& session); + + bool IsIceRestarting() const; + IceRestartState GetIceRestartState() const; + + // Begin ICE restart + void BeginIceRestart(const std::string& ufrag, + const std::string& pwd); + // Commit ICE Restart - offer/answer complete, no rollback possible + void CommitIceRestart(); + // Finalize ICE restart + void FinalizeIceRestart(); + // Abort ICE restart + void RollbackIceRestart(); + + // Process a trickle ICE candidate. + void AddIceCandidate(const std::string& candidate, const std::string& mid, + uint32_t aMLine); + + // Handle complete media pipelines. + nsresult UpdateMediaPipelines(const JsepSession& session); + + // Add a track (main thread only) + nsresult AddTrack(DOMMediaStream& aMediaStream, + const std::string& streamId, + dom::MediaStreamTrack& aTrack, + const std::string& trackId); + + nsresult RemoveLocalTrack(const std::string& streamId, + const std::string& trackId); + nsresult RemoveRemoteTrack(const std::string& streamId, + const std::string& trackId); + + // Get a specific local stream + uint32_t LocalStreamsLength() + { + return mLocalSourceStreams.Length(); + } + LocalSourceStreamInfo* GetLocalStreamByIndex(int index); + LocalSourceStreamInfo* GetLocalStreamById(const std::string& id); + LocalSourceStreamInfo* GetLocalStreamByTrackId(const std::string& id); + + // Get a specific remote stream + uint32_t RemoteStreamsLength() + { + return mRemoteSourceStreams.Length(); + } + + RemoteSourceStreamInfo* GetRemoteStreamByIndex(size_t index); + RemoteSourceStreamInfo* GetRemoteStreamById(const std::string& id); + RemoteSourceStreamInfo* GetRemoteStreamByTrackId(const std::string& id); + + // Add a remote stream. + nsresult AddRemoteStream(RefPtr<RemoteSourceStreamInfo> aInfo); + + nsresult ReplaceTrack(const std::string& aOldStreamId, + const std::string& aOldTrackId, + dom::MediaStreamTrack& aNewTrack, + const std::string& aNewStreamId, + const std::string& aNewTrackId); + +#if !defined(MOZILLA_EXTERNAL_LINKAGE) + // In cases where the peer isn't yet identified, we disable the pipeline (not + // the stream, that would potentially affect others), so that it sends + // black/silence. Once the peer is identified, re-enable those streams. + // aTrack will be set if this update came from a principal change on aTrack. + void UpdateSinkIdentity_m(dom::MediaStreamTrack* aTrack, + nsIPrincipal* aPrincipal, + const PeerIdentity* aSinkIdentity); + // this determines if any track is peerIdentity constrained + bool AnyLocalTrackHasPeerIdentity() const; + // When we finally learn who is on the other end, we need to change the ownership + // on streams + void UpdateRemoteStreamPrincipals_m(nsIPrincipal* aPrincipal); +#endif + + bool AnyCodecHasPluginID(uint64_t aPluginID); + + const nsCOMPtr<nsIThread>& GetMainThread() const { return mMainThread; } + const nsCOMPtr<nsIEventTarget>& GetSTSThread() const { return mSTSThread; } + + static size_t GetTransportFlowIndex(int aStreamIndex, bool aRtcp) + { + return aStreamIndex * 2 + (aRtcp ? 1 : 0); + } + + // Get a transport flow either RTP/RTCP for a particular stream + // A stream can be of audio/video/datachannel/budled(?) types + RefPtr<TransportFlow> GetTransportFlow(int aStreamIndex, bool aIsRtcp) { + int index_inner = GetTransportFlowIndex(aStreamIndex, aIsRtcp); + + if (mTransportFlows.find(index_inner) == mTransportFlows.end()) + return nullptr; + + return mTransportFlows[index_inner]; + } + + // Add a transport flow + void AddTransportFlow(int aIndex, bool aRtcp, + const RefPtr<TransportFlow> &aFlow); + void RemoveTransportFlow(int aIndex, bool aRtcp); + void ConnectDtlsListener_s(const RefPtr<TransportFlow>& aFlow); + void DtlsConnected_s(TransportLayer* aFlow, + TransportLayer::State state); + static void DtlsConnected_m(const std::string& aParentHandle, + bool aPrivacyRequested); + + RefPtr<AudioSessionConduit> GetAudioConduit(size_t level) { + auto it = mConduits.find(level); + if (it == mConduits.end()) { + return nullptr; + } + + if (it->second.first) { + MOZ_ASSERT(false, "In GetAudioConduit, we found a video conduit!"); + return nullptr; + } + + return RefPtr<AudioSessionConduit>( + static_cast<AudioSessionConduit*>(it->second.second.get())); + } + + RefPtr<VideoSessionConduit> GetVideoConduit(size_t level) { + auto it = mConduits.find(level); + if (it == mConduits.end()) { + return nullptr; + } + + if (!it->second.first) { + MOZ_ASSERT(false, "In GetVideoConduit, we found an audio conduit!"); + return nullptr; + } + + return RefPtr<VideoSessionConduit>( + static_cast<VideoSessionConduit*>(it->second.second.get())); + } + + // Add a conduit + void AddAudioConduit(size_t level, const RefPtr<AudioSessionConduit> &aConduit) { + mConduits[level] = std::make_pair(false, aConduit); + } + + void AddVideoConduit(size_t level, const RefPtr<VideoSessionConduit> &aConduit) { + mConduits[level] = std::make_pair(true, aConduit); + } + + // ICE state signals + sigslot::signal2<NrIceCtx*, NrIceCtx::GatheringState> + SignalIceGatheringStateChange; + sigslot::signal2<NrIceCtx*, NrIceCtx::ConnectionState> + SignalIceConnectionStateChange; + // This passes a candidate:... attribute and level + sigslot::signal2<const std::string&, uint16_t> SignalCandidate; + // This passes address, port, level of the default candidate. + sigslot::signal5<const std::string&, uint16_t, + const std::string&, uint16_t, uint16_t> + SignalUpdateDefaultCandidate; + sigslot::signal1<uint16_t> + SignalEndOfLocalCandidates; + + private: + nsresult InitProxy(); + class ProtocolProxyQueryHandler : public nsIProtocolProxyCallback { + public: + explicit ProtocolProxyQueryHandler(PeerConnectionMedia *pcm) : + pcm_(pcm) {} + + NS_IMETHOD OnProxyAvailable(nsICancelable *request, + nsIChannel *aChannel, + nsIProxyInfo *proxyinfo, + nsresult result) override; + NS_DECL_ISUPPORTS + + private: + void SetProxyOnPcm(nsIProxyInfo& proxyinfo); + RefPtr<PeerConnectionMedia> pcm_; + virtual ~ProtocolProxyQueryHandler() {} + }; + + // Shutdown media transport. Must be called on STS thread. + void ShutdownMediaTransport_s(); + + // Final destruction of the media stream. Must be called on the main + // thread. + void SelfDestruct_m(); + + // Manage ICE transports. + void EnsureTransport_s(size_t aLevel, size_t aComponentCount); + void ActivateOrRemoveTransport_s( + size_t aMLine, + size_t aComponentCount, + const std::string& aUfrag, + const std::string& aPassword, + const std::vector<std::string>& aCandidateList); + void RemoveTransportsAtOrAfter_s(size_t aMLine); + + void GatherIfReady(); + void FlushIceCtxOperationQueueIfReady(); + void PerformOrEnqueueIceCtxOperation(nsIRunnable* runnable); + void EnsureIceGathering_s(bool aDefaultRouteOnly, bool aProxyOnly); + void StartIceChecks_s(bool aIsControlling, + bool aIsIceLite, + const std::vector<std::string>& aIceOptionsList); + + void BeginIceRestart_s(RefPtr<NrIceCtx> new_ctx); + void FinalizeIceRestart_s(); + void RollbackIceRestart_s(); + bool GetPrefDefaultAddressOnly() const; + bool GetPrefProxyOnly() const; + + void ConnectSignals(NrIceCtx *aCtx, NrIceCtx *aOldCtx=nullptr); + + // Process a trickle ICE candidate. + void AddIceCandidate_s(const std::string& aCandidate, const std::string& aMid, + uint32_t aMLine); + + + // ICE events + void IceGatheringStateChange_s(NrIceCtx* ctx, + NrIceCtx::GatheringState state); + void IceConnectionStateChange_s(NrIceCtx* ctx, + NrIceCtx::ConnectionState state); + void IceStreamReady_s(NrIceMediaStream *aStream); + void OnCandidateFound_s(NrIceMediaStream *aStream, + const std::string& aCandidate); + void EndOfLocalCandidates(const std::string& aDefaultAddr, + uint16_t aDefaultPort, + const std::string& aDefaultRtcpAddr, + uint16_t aDefaultRtcpPort, + uint16_t aMLine); + void GetDefaultCandidates(const NrIceMediaStream& aStream, + NrIceCandidate* aCandidate, + NrIceCandidate* aRtcpCandidate); + + void IceGatheringStateChange_m(NrIceCtx* ctx, + NrIceCtx::GatheringState state); + void IceConnectionStateChange_m(NrIceCtx* ctx, + NrIceCtx::ConnectionState state); + void OnCandidateFound_m(const std::string& aCandidateLine, + const std::string& aDefaultAddr, + uint16_t aDefaultPort, + const std::string& aDefaultRtcpAddr, + uint16_t aDefaultRtcpPort, + uint16_t aMLine); + void EndOfLocalCandidates_m(const std::string& aDefaultAddr, + uint16_t aDefaultPort, + const std::string& aDefaultRtcpAddr, + uint16_t aDefaultRtcpPort, + uint16_t aMLine); + bool IsIceCtxReady() const { + return mProxyResolveCompleted; + } + + // The parent PC + PeerConnectionImpl *mParent; + // and a loose handle on it for event driven stuff + std::string mParentHandle; + std::string mParentName; + + // A list of streams returned from GetUserMedia + // This is only accessed on the main thread (with one special exception) + nsTArray<RefPtr<LocalSourceStreamInfo> > mLocalSourceStreams; + + // A list of streams provided by the other side + // This is only accessed on the main thread (with one special exception) + nsTArray<RefPtr<RemoteSourceStreamInfo> > mRemoteSourceStreams; + + std::map<size_t, std::pair<bool, RefPtr<MediaSessionConduit>>> mConduits; + + // ICE objects + RefPtr<NrIceCtxHandler> mIceCtxHdlr; + + // DNS + RefPtr<NrIceResolver> mDNSResolver; + + // Transport flows: even is RTP, odd is RTCP + std::map<int, RefPtr<TransportFlow> > mTransportFlows; + + // UUID Generator + UniquePtr<PCUuidGenerator> mUuidGen; + + // The main thread. + nsCOMPtr<nsIThread> mMainThread; + + // The STS thread. + nsCOMPtr<nsIEventTarget> mSTSThread; + + // 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<nsCOMPtr<nsIRunnable>> mQueuedIceCtxOperations; + + // Used to cancel any ongoing proxy request. + nsCOMPtr<nsICancelable> mProxyRequest; + + // Used to track the state of the request. + bool mProxyResolveCompleted; + + // Used to store the result of the request. + UniquePtr<NrIceProxyServer> mProxyServer; + + // Used to track the state of ice restart + IceRestartState mIceRestartState; + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PeerConnectionMedia) +}; + +} // namespace mozilla + +#endif |