diff options
Diffstat (limited to 'dom/media/MediaStreamTrack.h')
-rw-r--r-- | dom/media/MediaStreamTrack.h | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/dom/media/MediaStreamTrack.h b/dom/media/MediaStreamTrack.h new file mode 100644 index 000000000..bf092e4b2 --- /dev/null +++ b/dom/media/MediaStreamTrack.h @@ -0,0 +1,481 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ +/* 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 MEDIASTREAMTRACK_H_ +#define MEDIASTREAMTRACK_H_ + +#include "mozilla/DOMEventTargetHelper.h" +#include "nsError.h" +#include "nsID.h" +#include "nsIPrincipal.h" +#include "StreamTracks.h" +#include "MediaTrackConstraints.h" +#include "mozilla/CORSMode.h" +#include "PrincipalChangeObserver.h" +#include "mozilla/dom/MediaStreamTrackBinding.h" +#include "mozilla/dom/MediaTrackSettingsBinding.h" +#include "mozilla/media/MediaUtils.h" + +namespace mozilla { + +class DOMMediaStream; +class MediaEnginePhotoCallback; +class MediaInputPort; +class MediaStream; +class MediaStreamGraph; +class MediaStreamGraphImpl; +class MediaStreamTrackListener; +class DirectMediaStreamTrackListener; +class PeerConnectionImpl; +class PeerConnectionMedia; +class PeerIdentity; +class ProcessedMediaStream; +class RemoteSourceStreamInfo; +class SourceStreamInfo; + +namespace dom { + +class AudioStreamTrack; +class VideoStreamTrack; +class MediaStreamError; + +/** + * Common interface through which a MediaStreamTrack can communicate with its + * producer on the main thread. + * + * Kept alive by a strong ref in all MediaStreamTracks (original and clones) + * sharing this source. + */ +class MediaStreamTrackSource : public nsISupports +{ + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackSource) + +public: + class Sink + { + public: + virtual void PrincipalChanged() = 0; + }; + + MediaStreamTrackSource(nsIPrincipal* aPrincipal, + const nsString& aLabel) + : mPrincipal(aPrincipal), + mLabel(aLabel), + mStopped(false) + { + MOZ_COUNT_CTOR(MediaStreamTrackSource); + } + + /** + * Use to clean up any resources that have to be cleaned before the + * destructor is called. It is often too late in the destructor because + * of garbage collection having removed the members already. + */ + virtual void Destroy() {} + + /** + * Gets the source's MediaSourceEnum for usage by PeerConnections. + */ + virtual MediaSourceEnum GetMediaSource() const = 0; + + /** + * Get this TrackSource's principal. + */ + nsIPrincipal* GetPrincipal() const { return mPrincipal; } + + /** + * Get the source's current CORSMode. If not applicable CORS_NONE is returned. + * The sink will be notified of changes to our CORSMode through + * PrincipalChanged(). + */ + virtual CORSMode GetCORSMode() const { return CORS_NONE; } + + /** + * This is used in WebRTC. A peerIdentity constrained MediaStreamTrack cannot + * be sent across the network to anything other than a peer with the provided + * identity. If this is set, then GetPrincipal() should return an instance of + * nsNullPrincipal. + * + * A track's PeerIdentity is immutable and will not change during the track's + * lifetime. + */ + virtual const PeerIdentity* GetPeerIdentity() const { return nullptr; } + + /** + * MediaStreamTrack::GetLabel (see spec) calls through to here. + */ + void GetLabel(nsAString& aLabel) { aLabel.Assign(mLabel); } + + /** + * Forwards a photo request to backends that support it. Other backends return + * NS_ERROR_NOT_IMPLEMENTED to indicate that a MediaStreamGraph-based fallback + * should be used. + */ + virtual nsresult TakePhoto(MediaEnginePhotoCallback*) const { return NS_ERROR_NOT_IMPLEMENTED; } + + typedef media::Pledge<bool, dom::MediaStreamError*> PledgeVoid; + + /** + * We provide a fallback solution to ApplyConstraints() here. + * Sources that support ApplyConstraints() will have to override it. + */ + virtual already_AddRefed<PledgeVoid> + ApplyConstraints(nsPIDOMWindowInner* aWindow, + const dom::MediaTrackConstraints& aConstraints); + + /** + * Same for GetSettings (no-op). + */ + virtual void + GetSettings(dom::MediaTrackSettings& aResult) {}; + + /** + * Called by the source interface when all registered sinks have unregistered. + */ + virtual void Stop() = 0; + + /** + * Called by each MediaStreamTrack clone on initialization. + */ + void RegisterSink(Sink* aSink) + { + MOZ_ASSERT(NS_IsMainThread()); + if (mStopped) { + return; + } + mSinks.AppendElement(aSink); + } + + /** + * Called by each MediaStreamTrack clone on Stop() if supported by the + * source (us) or destruction. + */ + void UnregisterSink(Sink* aSink) + { + MOZ_ASSERT(NS_IsMainThread()); + if (mSinks.RemoveElement(aSink) && mSinks.IsEmpty()) { + MOZ_ASSERT(!mStopped); + Stop(); + mStopped = true; + } + } + +protected: + virtual ~MediaStreamTrackSource() + { + MOZ_COUNT_DTOR(MediaStreamTrackSource); + } + + /** + * Called by a sub class when the principal has changed. + * Notifies all sinks. + */ + void PrincipalChanged() + { + for (Sink* sink : mSinks) { + sink->PrincipalChanged(); + } + } + + // Principal identifying who may access the contents of this source. + nsCOMPtr<nsIPrincipal> mPrincipal; + + // Currently registered sinks. + nsTArray<Sink*> mSinks; + + // The label of the track we are the source of per the MediaStreamTrack spec. + const nsString mLabel; + + // True if all MediaStreamTrack users have unregistered from this source and + // Stop() has been called. + bool mStopped; +}; + +/** + * Basic implementation of MediaStreamTrackSource that doesn't forward Stop(). + */ +class BasicTrackSource : public MediaStreamTrackSource +{ +public: + explicit BasicTrackSource(nsIPrincipal* aPrincipal, + const MediaSourceEnum aMediaSource = + MediaSourceEnum::Other) + : MediaStreamTrackSource(aPrincipal, nsString()) + , mMediaSource(aMediaSource) + {} + + MediaSourceEnum GetMediaSource() const override { return mMediaSource; } + + void Stop() override {} + +protected: + ~BasicTrackSource() {} + + const MediaSourceEnum mMediaSource; +}; + +/** + * Base class that consumers of a MediaStreamTrack can use to get notifications + * about state changes in the track. + */ +class MediaStreamTrackConsumer : public nsISupports +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackConsumer) + + /** + * Called when the track's readyState transitions to "ended". + * Unlike the "ended" event exposed to script this is called for any reason, + * including MediaStreamTrack::Stop(). + */ + virtual void NotifyEnded(MediaStreamTrack* aTrack) {}; + +protected: + virtual ~MediaStreamTrackConsumer() {} +}; + +/** + * Class representing a track in a DOMMediaStream. + */ +class MediaStreamTrack : public DOMEventTargetHelper, + public MediaStreamTrackSource::Sink +{ + // DOMMediaStream owns MediaStreamTrack instances, and requires access to + // some internal state, e.g., GetInputStream(), GetOwnedStream(). + friend class mozilla::DOMMediaStream; + + // PeerConnection and friends need to know our owning DOMStream and track id. + friend class mozilla::PeerConnectionImpl; + friend class mozilla::PeerConnectionMedia; + friend class mozilla::SourceStreamInfo; + friend class mozilla::RemoteSourceStreamInfo; + + class PrincipalHandleListener; + +public: + /** + * aTrackID is the MediaStreamGraph track ID for the track in the + * MediaStream owned by aStream. + */ + MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID, + TrackID aInputTrackID, + MediaStreamTrackSource* aSource, + const MediaTrackConstraints& aConstraints = MediaTrackConstraints()); + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamTrack, + DOMEventTargetHelper) + + nsPIDOMWindowInner* GetParentObject() const; + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override = 0; + + virtual AudioStreamTrack* AsAudioStreamTrack() { return nullptr; } + virtual VideoStreamTrack* AsVideoStreamTrack() { return nullptr; } + + virtual const AudioStreamTrack* AsAudioStreamTrack() const { return nullptr; } + virtual const VideoStreamTrack* AsVideoStreamTrack() const { return nullptr; } + + // WebIDL + virtual void GetKind(nsAString& aKind) = 0; + void GetId(nsAString& aID) const; + void GetLabel(nsAString& aLabel) { GetSource().GetLabel(aLabel); } + bool Enabled() { return mEnabled; } + void SetEnabled(bool aEnabled); + void Stop(); + void GetConstraints(dom::MediaTrackConstraints& aResult); + void GetSettings(dom::MediaTrackSettings& aResult); + + already_AddRefed<Promise> + ApplyConstraints(const dom::MediaTrackConstraints& aConstraints, ErrorResult &aRv); + already_AddRefed<MediaStreamTrack> Clone(); + MediaStreamTrackState ReadyState() { return mReadyState; } + + IMPL_EVENT_HANDLER(ended) + + /** + * Convenience (and legacy) method for when ready state is "ended". + */ + bool Ended() const { return mReadyState == MediaStreamTrackState::Ended; } + + /** + * Forces the ready state to a particular value, for instance when we're + * cloning an already ended track. + */ + void SetReadyState(MediaStreamTrackState aState); + + /** + * Notified by the MediaStreamGraph, through our owning MediaStream on the + * main thread. + * + * Note that this sets the track to ended and raises the "ended" event + * synchronously. + */ + void OverrideEnded(); + + /** + * Get this track's principal. + */ + nsIPrincipal* GetPrincipal() const { return mPrincipal; } + + /** + * Called by the PrincipalHandleListener when this track's PrincipalHandle changes on + * the MediaStreamGraph thread. When the PrincipalHandle matches the pending + * principal we know that the principal change has propagated to consumers. + */ + void NotifyPrincipalHandleChanged(const PrincipalHandle& aPrincipalHandle); + + /** + * Called when this track's readyState transitions to "ended". + * Notifies all MediaStreamTrackConsumers that this track ended. + */ + void NotifyEnded(); + + /** + * Get this track's CORS mode. + */ + CORSMode GetCORSMode() const { return GetSource().GetCORSMode(); } + + /** + * Get this track's PeerIdentity. + */ + const PeerIdentity* GetPeerIdentity() const { return GetSource().GetPeerIdentity(); } + + MediaStreamGraph* Graph(); + MediaStreamGraphImpl* GraphImpl(); + + MediaStreamTrackSource& GetSource() const + { + MOZ_RELEASE_ASSERT(mSource, "The track source is only removed on destruction"); + return *mSource; + } + + // Webrtc allows the remote side to name tracks whatever it wants, and we + // need to surface this to content. + void AssignId(const nsAString& aID) { mID = aID; } + + // Implementation of MediaStreamTrackSource::Sink + void PrincipalChanged() override; + + /** + * Add a PrincipalChangeObserver to this track. + * + * Returns true if it was successfully added. + * + * Ownership of the PrincipalChangeObserver remains with the caller, and it's + * the caller's responsibility to remove the observer before it dies. + */ + bool AddPrincipalChangeObserver(PrincipalChangeObserver<MediaStreamTrack>* aObserver); + + /** + * Remove an added PrincipalChangeObserver from this track. + * + * Returns true if it was successfully removed. + */ + bool RemovePrincipalChangeObserver(PrincipalChangeObserver<MediaStreamTrack>* aObserver); + + /** + * Add a MediaStreamTrackConsumer to this track. + * + * Adding the same consumer multiple times is prohibited. + */ + void AddConsumer(MediaStreamTrackConsumer* aConsumer); + + /** + * Remove an added MediaStreamTrackConsumer from this track. + */ + void RemoveConsumer(MediaStreamTrackConsumer* aConsumer); + + /** + * Adds a MediaStreamTrackListener to the MediaStreamGraph representation of + * this track. + */ + void AddListener(MediaStreamTrackListener* aListener); + + /** + * Removes a MediaStreamTrackListener from the MediaStreamGraph representation + * of this track. + */ + void RemoveListener(MediaStreamTrackListener* aListener); + + /** + * Attempts to add a direct track listener to this track. + * Callers must listen to the NotifyInstalled event to know if installing + * the listener succeeded (tracks originating from SourceMediaStreams) or + * failed (e.g., WebAudio originated tracks). + */ + void AddDirectListener(DirectMediaStreamTrackListener *aListener); + void RemoveDirectListener(DirectMediaStreamTrackListener *aListener); + + /** + * Sets up a MediaInputPort from the underlying track that this + * MediaStreamTrack represents, to aStream, and returns it. + */ + already_AddRefed<MediaInputPort> ForwardTrackContentsTo(ProcessedMediaStream* aStream, + TrackID aDestinationTrackID = TRACK_ANY); + + /** + * Returns true if this track is connected to aPort and forwarded to aPort's + * output stream. + */ + bool IsForwardedThrough(MediaInputPort* aPort); + + void SetMediaStreamSizeListener(DirectMediaStreamTrackListener* aListener); + +protected: + virtual ~MediaStreamTrack(); + + void Destroy(); + + // Returns the original DOMMediaStream's underlying input stream. + MediaStream* GetInputStream(); + + // Returns the owning DOMMediaStream's underlying owned stream. + ProcessedMediaStream* GetOwnedStream(); + + // Returns the original DOMMediaStream. If this track is a clone, + // the original track's owning DOMMediaStream is returned. + DOMMediaStream* GetInputDOMStream(); + + /** + * Sets the principal and notifies PrincipalChangeObservers if it changes. + */ + void SetPrincipal(nsIPrincipal* aPrincipal); + + /** + * Creates a new MediaStreamTrack with the same type, input track ID and + * source as this MediaStreamTrack. + * aTrackID is the TrackID the new track will have in its owned stream. + */ + virtual already_AddRefed<MediaStreamTrack> CloneInternal(DOMMediaStream* aOwningStream, + TrackID aTrackID) = 0; + + nsTArray<PrincipalChangeObserver<MediaStreamTrack>*> mPrincipalChangeObservers; + + nsTArray<RefPtr<MediaStreamTrackConsumer>> mConsumers; + + RefPtr<DOMMediaStream> mOwningStream; + TrackID mTrackID; + TrackID mInputTrackID; + RefPtr<MediaStreamTrackSource> mSource; + RefPtr<MediaStreamTrack> mOriginalTrack; + nsCOMPtr<nsIPrincipal> mPrincipal; + nsCOMPtr<nsIPrincipal> mPendingPrincipal; + RefPtr<PrincipalHandleListener> mPrincipalHandleListener; + // Keep tracking MediaStreamTrackListener and DirectMediaStreamTrackListener, + // so we can remove them in |Destory|. + nsTArray<RefPtr<MediaStreamTrackListener>> mTrackListeners; + nsTArray<RefPtr<DirectMediaStreamTrackListener>> mDirectTrackListeners; + nsString mID; + MediaStreamTrackState mReadyState; + bool mEnabled; + dom::MediaTrackConstraints mConstraints; +}; + +} // namespace dom +} // namespace mozilla + +#endif /* MEDIASTREAMTRACK_H_ */ |