1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef MEDIASTREAMTRACK_H_
7 #define MEDIASTREAMTRACK_H_
9 #include "MediaTrackConstraints.h"
10 #include "PrincipalChangeObserver.h"
11 #include "PrincipalHandle.h"
12 #include "mozilla/DOMEventTargetHelper.h"
13 #include "mozilla/dom/MediaStreamTrackBinding.h"
14 #include "mozilla/dom/MediaTrackCapabilitiesBinding.h"
15 #include "mozilla/dom/MediaTrackSettingsBinding.h"
16 #include "mozilla/media/MediaUtils.h"
17 #include "mozilla/WeakPtr.h"
20 #include "nsIPrincipal.h"
21 #include "PerformanceRecorder.h"
26 class MediaEnginePhotoCallback
;
29 class MediaTrackGraph
;
30 class MediaTrackGraphImpl
;
31 class MediaTrackListener
;
32 class DirectMediaTrackListener
;
33 class PeerConnectionImpl
;
35 class ProcessedMediaTrack
;
36 class RemoteSourceStreamInfo
;
37 class SourceStreamInfo
;
42 class AudioStreamTrack
;
43 class VideoStreamTrack
;
44 class RTCStatsTimestampMaker
;
45 enum class CallerType
: uint32_t;
48 * Common interface through which a MediaStreamTrack can communicate with its
49 * producer on the main thread.
51 * Kept alive by a strong ref in all MediaStreamTracks (original and clones)
52 * sharing this source.
54 class MediaStreamTrackSource
: public nsISupports
{
55 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
56 NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackSource
)
59 class Sink
: public SupportsWeakPtr
{
62 * Must be constant throughout the Sink's lifetime.
64 * Return true to keep the MediaStreamTrackSource where this sink is
66 * Return false to allow the source to stop.
68 * Typically MediaStreamTrack::Sink returns true and other Sinks
69 * (like HTMLMediaElement::StreamCaptureTrackSource) return false.
71 virtual bool KeepsSourceAlive() const = 0;
74 * Return true to ensure that the MediaStreamTrackSource where this Sink is
75 * registered is kept turned on and active.
76 * Return false to allow the source to pause, and any underlying devices to
79 * When the underlying enabled state of the sink changes,
80 * call MediaStreamTrackSource::SinkEnabledStateChanged().
82 * Typically MediaStreamTrack returns the track's enabled state and other
83 * Sinks (like HTMLMediaElement::StreamCaptureTrackSource) return false so
84 * control over device state remains with tracks and their enabled state.
86 virtual bool Enabled() const = 0;
89 * Called when the principal of the MediaStreamTrackSource where this sink
90 * is registered has changed.
92 virtual void PrincipalChanged() = 0;
95 * Called when the muted state of the MediaStreamTrackSource where this sink
96 * is registered has changed.
98 virtual void MutedChanged(bool aNewState
) = 0;
101 * Called when the MediaStreamTrackSource where this sink is registered has
102 * stopped producing data for good, i.e., it has ended.
104 virtual void OverrideEnded() = 0;
107 virtual ~Sink() = default;
110 MediaStreamTrackSource(nsIPrincipal
* aPrincipal
, const nsString
& aLabel
,
111 TrackingId aTrackingId
)
112 : mPrincipal(aPrincipal
),
114 mTrackingId(std::move(aTrackingId
)),
118 * Use to clean up any resources that have to be cleaned before the
119 * destructor is called. It is often too late in the destructor because
120 * of garbage collection having removed the members already.
122 virtual void Destroy() {}
125 * Gets the source's MediaSourceEnum for usage by PeerConnections.
127 virtual MediaSourceEnum
GetMediaSource() const = 0;
130 * Get this TrackSource's principal.
132 nsIPrincipal
* GetPrincipal() const { return mPrincipal
; }
135 * This is used in WebRTC. A peerIdentity constrained MediaStreamTrack cannot
136 * be sent across the network to anything other than a peer with the provided
137 * identity. If this is set, then GetPrincipal() should return an instance of
140 * A track's PeerIdentity is immutable and will not change during the track's
143 virtual const PeerIdentity
* GetPeerIdentity() const { return nullptr; }
146 * This is used in WebRTC. The timestampMaker can convert between different
147 * timestamp types used during the session.
149 virtual const RTCStatsTimestampMaker
* GetTimestampMaker() const {
154 * MediaStreamTrack::GetLabel (see spec) calls through to here.
156 void GetLabel(nsAString
& aLabel
) { aLabel
.Assign(mLabel
); }
159 * Whether this TrackSource provides video frames with an alpha channel. Only
160 * applies to video sources. Used by HTMLVideoElement.
162 virtual bool HasAlpha() const { return false; }
165 * Forwards a photo request to backends that support it. Other backends return
166 * NS_ERROR_NOT_IMPLEMENTED to indicate that a MediaTrackGraph-based fallback
169 virtual nsresult
TakePhoto(MediaEnginePhotoCallback
*) const {
170 return NS_ERROR_NOT_IMPLEMENTED
;
173 typedef MozPromise
<bool /* aIgnored */, RefPtr
<MediaMgrError
>, true>
174 ApplyConstraintsPromise
;
177 * We provide a fallback solution to ApplyConstraints() here.
178 * Sources that support ApplyConstraints() will have to override it.
180 virtual RefPtr
<ApplyConstraintsPromise
> ApplyConstraints(
181 const dom::MediaTrackConstraints
& aConstraints
, CallerType aCallerType
);
184 * Same for GetSettings (no-op).
186 virtual void GetSettings(dom::MediaTrackSettings
& aResult
) {};
188 virtual void GetCapabilities(dom::MediaTrackCapabilities
& aResult
) {};
191 * Called by the source interface when all registered sinks with
192 * KeepsSourceAlive() == true have unregistered.
194 virtual void Stop() = 0;
197 * Called by the source interface when all registered sinks with
198 * KeepsSourceAlive() == true become disabled.
200 virtual void Disable() = 0;
203 * Called by the source interface when at least one registered sink with
204 * KeepsSourceAlive() == true become enabled.
206 virtual void Enable() = 0;
209 * Called when a Sink's Enabled() state changed. Will iterate through all
210 * sinks and notify the source of the aggregated enabled state.
212 * Note that a Sink with KeepsSourceAlive() == false counts as disabled.
214 void SinkEnabledStateChanged() {
223 * Called by each MediaStreamTrack clone on initialization.
225 void RegisterSink(Sink
* aSink
) {
226 MOZ_ASSERT(NS_IsMainThread());
230 mSinks
.AppendElement(aSink
);
231 while (mSinks
.RemoveElement(nullptr)) {
232 MOZ_ASSERT_UNREACHABLE("Sink was not explicitly removed");
237 * Called by each MediaStreamTrack clone on Stop() if supported by the
238 * source (us) or destruction.
240 void UnregisterSink(Sink
* aSink
) {
241 MOZ_ASSERT(NS_IsMainThread());
242 while (mSinks
.RemoveElement(nullptr)) {
243 MOZ_ASSERT_UNREACHABLE("Sink was not explicitly removed");
245 if (mSinks
.RemoveElement(aSink
) && !IsActive()) {
246 MOZ_ASSERT(!aSink
->KeepsSourceAlive() || !mStopped
,
247 "When the last sink keeping the source alive is removed, "
248 "we should still be live");
253 SinkEnabledStateChanged();
258 virtual ~MediaStreamTrackSource() = default;
261 for (const WeakPtr
<Sink
>& sink
: mSinks
) {
262 if (sink
&& sink
->KeepsSourceAlive()) {
270 for (const WeakPtr
<Sink
>& sink
: mSinks
) {
271 if (sink
&& sink
->KeepsSourceAlive() && sink
->Enabled()) {
279 * Called by a sub class when the principal has changed.
280 * Notifies all sinks.
282 void PrincipalChanged() {
283 MOZ_ASSERT(NS_IsMainThread());
284 for (auto& sink
: mSinks
.Clone()) {
286 DebugOnly
<bool> removed
= mSinks
.RemoveElement(sink
);
287 MOZ_ASSERT(!removed
, "Sink was not explicitly removed");
290 sink
->PrincipalChanged();
295 * Called by a sub class when the source's muted state has changed. Note that
296 * the source is responsible for making the content black/silent during mute.
297 * Notifies all sinks.
299 void MutedChanged(bool aNewState
) {
300 MOZ_ASSERT(NS_IsMainThread());
301 for (auto& sink
: mSinks
.Clone()) {
303 DebugOnly
<bool> removed
= mSinks
.RemoveElement(sink
);
304 MOZ_ASSERT(!removed
, "Sink was not explicitly removed");
307 sink
->MutedChanged(aNewState
);
312 * Called by a sub class when the source has stopped producing data for good,
313 * i.e., it has ended. Notifies all sinks.
315 void OverrideEnded() {
316 MOZ_ASSERT(NS_IsMainThread());
317 for (auto& sink
: mSinks
.Clone()) {
319 DebugOnly
<bool> removed
= mSinks
.RemoveElement(sink
);
320 MOZ_ASSERT(!removed
, "Sink was not explicitly removed");
323 sink
->OverrideEnded();
327 // Principal identifying who may access the contents of this source.
328 RefPtr
<nsIPrincipal
> mPrincipal
;
330 // Currently registered sinks.
331 nsTArray
<WeakPtr
<Sink
>> mSinks
;
334 // The label of the track we are the source of per the MediaStreamTrack spec.
335 const nsString mLabel
;
337 // Set for all video sources; an id for tracking the source of the video
338 // frames for this track.
339 const TrackingId mTrackingId
;
342 // True if all MediaStreamTrack users have unregistered from this source and
343 // Stop() has been called.
348 * Base class that consumers of a MediaStreamTrack can use to get notifications
349 * about state changes in the track.
351 class MediaStreamTrackConsumer
: public SupportsWeakPtr
{
354 * Called when the track's readyState transitions to "ended".
355 * Unlike the "ended" event exposed to script this is called for any reason,
356 * including MediaStreamTrack::Stop().
358 virtual void NotifyEnded(MediaStreamTrack
* aTrack
) {};
361 * Called when the track's enabled state changes.
363 virtual void NotifyEnabledChanged(MediaStreamTrack
* aTrack
, bool aEnabled
) {};
368 * DOM wrapper for MediaTrackGraph-MediaTracks.
370 * To account for cloning, a MediaStreamTrack wraps two internal (and chained)
373 * - Controlled by the producer of the data in the track. The producer
374 * decides on lifetime of the MediaTrack and the track inside it.
375 * - It can be any type of MediaTrack.
376 * - Contains one track only.
378 * - A ForwardedInputTrack representing this MediaStreamTrack.
379 * - Its data is piped from mInputTrack through mPort.
380 * - Contains one track only.
381 * - When this MediaStreamTrack is enabled/disabled this is reflected in
382 * the chunks in the track in mTrack.
383 * - When this MediaStreamTrack has ended, mTrack gets destroyed.
384 * Note that mInputTrack is unaffected, such that any clones of mTrack
385 * can live on. When all clones are ended, this is signaled to the
386 * producer via our MediaStreamTrackSource. It is then likely to destroy
389 * A graphical representation of how tracks are connected when cloned follows:
396 * MediaStreamTrack B \ (clone of A)
397 * mInputTrack \ mTrack
400 * (*) is a copy of A's mInputTrack
403 class MediaStreamTrack
: public DOMEventTargetHelper
, public SupportsWeakPtr
{
404 // PeerConnection and friends need to know our owning DOMStream and track id.
405 friend class mozilla::PeerConnectionImpl
;
406 friend class mozilla::SourceStreamInfo
;
407 friend class mozilla::RemoteSourceStreamInfo
;
414 nsPIDOMWindowInner
* aWindow
, mozilla::MediaTrack
* aInputTrack
,
415 MediaStreamTrackSource
* aSource
,
416 MediaStreamTrackState aReadyState
= MediaStreamTrackState::Live
,
418 const MediaTrackConstraints
& aConstraints
= MediaTrackConstraints());
420 NS_DECL_ISUPPORTS_INHERITED
421 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamTrack
,
422 DOMEventTargetHelper
)
424 nsPIDOMWindowInner
* GetParentObject() const { return mWindow
; }
425 JSObject
* WrapObject(JSContext
* aCx
,
426 JS::Handle
<JSObject
*> aGivenProto
) override
;
428 virtual AudioStreamTrack
* AsAudioStreamTrack() { return nullptr; }
429 virtual VideoStreamTrack
* AsVideoStreamTrack() { return nullptr; }
431 virtual const AudioStreamTrack
* AsAudioStreamTrack() const { return nullptr; }
432 virtual const VideoStreamTrack
* AsVideoStreamTrack() const { return nullptr; }
435 virtual void GetKind(nsAString
& aKind
) = 0;
436 void GetId(nsAString
& aID
) const;
437 virtual void GetLabel(nsAString
& aLabel
, CallerType
/* aCallerType */) {
438 GetSource().GetLabel(aLabel
);
440 bool Enabled() const { return mEnabled
; }
441 void SetEnabled(bool aEnabled
);
442 bool Muted() { return mMuted
; }
444 void GetCapabilities(MediaTrackCapabilities
& aResult
, CallerType aCallerType
);
445 void GetConstraints(dom::MediaTrackConstraints
& aResult
);
446 void GetSettings(dom::MediaTrackSettings
& aResult
, CallerType aCallerType
);
448 already_AddRefed
<Promise
> ApplyConstraints(
449 const dom::MediaTrackConstraints
& aConstraints
, CallerType aCallerType
,
451 already_AddRefed
<MediaStreamTrack
> Clone();
452 MediaStreamTrackState
ReadyState() { return mReadyState
; }
454 IMPL_EVENT_HANDLER(mute
)
455 IMPL_EVENT_HANDLER(unmute
)
456 IMPL_EVENT_HANDLER(ended
)
459 * Convenience (and legacy) method for when ready state is "ended".
461 bool Ended() const { return mReadyState
== MediaStreamTrackState::Ended
; }
464 * Get this track's principal.
466 nsIPrincipal
* GetPrincipal() const { return mPrincipal
; }
469 * Get this track's PeerIdentity.
471 const PeerIdentity
* GetPeerIdentity() const {
472 return GetSource().GetPeerIdentity();
476 * Get this track's RTCStatsTimestampMaker.
478 const RTCStatsTimestampMaker
* GetTimestampMaker() const {
479 return GetSource().GetTimestampMaker();
482 ProcessedMediaTrack
* GetTrack() const;
483 MediaTrackGraph
* Graph() const;
484 MediaTrackGraphImpl
* GraphImpl() const;
486 MediaStreamTrackSource
& GetSource() const {
487 MOZ_RELEASE_ASSERT(mSource
,
488 "The track source is only removed on destruction");
492 // Webrtc allows the remote side to name tracks whatever it wants, and we
493 // need to surface this to content.
494 void AssignId(const nsAString
& aID
) { mID
= aID
; }
497 * Add a PrincipalChangeObserver to this track.
499 * Returns true if it was successfully added.
501 * Ownership of the PrincipalChangeObserver remains with the caller, and it's
502 * the caller's responsibility to remove the observer before it dies.
504 bool AddPrincipalChangeObserver(
505 PrincipalChangeObserver
<MediaStreamTrack
>* aObserver
);
508 * Remove an added PrincipalChangeObserver from this track.
510 * Returns true if it was successfully removed.
512 bool RemovePrincipalChangeObserver(
513 PrincipalChangeObserver
<MediaStreamTrack
>* aObserver
);
516 * Add a MediaStreamTrackConsumer to this track.
518 * Adding the same consumer multiple times is prohibited.
520 void AddConsumer(MediaStreamTrackConsumer
* aConsumer
);
523 * Remove an added MediaStreamTrackConsumer from this track.
525 void RemoveConsumer(MediaStreamTrackConsumer
* aConsumer
);
528 * Adds a MediaTrackListener to the MediaTrackGraph representation of
531 virtual void AddListener(MediaTrackListener
* aListener
);
534 * Removes a MediaTrackListener from the MediaTrackGraph representation
537 void RemoveListener(MediaTrackListener
* aListener
);
540 * Attempts to add a direct track listener to this track.
541 * Callers must listen to the NotifyInstalled event to know if installing
542 * the listener succeeded (tracks originating from SourceMediaTracks) or
543 * failed (e.g., WebAudio originated tracks).
545 virtual void AddDirectListener(DirectMediaTrackListener
* aListener
);
546 void RemoveDirectListener(DirectMediaTrackListener
* aListener
);
549 * Sets up a MediaInputPort from the underlying track that this
550 * MediaStreamTrack represents, to aTrack, and returns it.
552 already_AddRefed
<MediaInputPort
> ForwardTrackContentsTo(
553 ProcessedMediaTrack
* aTrack
);
556 virtual ~MediaStreamTrack();
559 * Forces the ready state to a particular value, for instance when we're
560 * cloning an already ended track.
562 void SetReadyState(MediaStreamTrackState aState
);
565 * Notified by the MediaTrackGraph, through our owning MediaStream on the
568 * Note that this sets the track to ended and raises the "ended" event
571 void OverrideEnded();
574 * Called by the MTGListener when this track's PrincipalHandle changes on
575 * the MediaTrackGraph thread. When the PrincipalHandle matches the pending
576 * principal we know that the principal change has propagated to consumers.
578 void NotifyPrincipalHandleChanged(const PrincipalHandle
& aNewPrincipalHandle
);
581 * Called when this track's readyState transitions to "ended".
582 * Notifies all MediaStreamTrackConsumers that this track ended.
587 * Called when this track's enabled state has changed.
588 * Notifies all MediaStreamTrackConsumers.
590 void NotifyEnabledChanged();
593 * Called when mSource's principal has changed.
595 void PrincipalChanged();
598 * Called when mSource's muted state has changed.
600 void MutedChanged(bool aNewState
);
603 * Sets this track's muted state without raising any events.
604 * Only really set by cloning. See MutedChanged for runtime changes.
606 void SetMuted(bool aMuted
) { mMuted
= aMuted
; }
608 virtual void Destroy();
611 * Sets the principal and notifies PrincipalChangeObservers if it changes.
613 void SetPrincipal(nsIPrincipal
* aPrincipal
);
616 * Creates a new MediaStreamTrack with the same kind, input track, input
617 * track ID and source as this MediaStreamTrack.
619 virtual already_AddRefed
<MediaStreamTrack
> CloneInternal() = 0;
621 nsTArray
<PrincipalChangeObserver
<MediaStreamTrack
>*>
622 mPrincipalChangeObservers
;
624 nsTArray
<WeakPtr
<MediaStreamTrackConsumer
>> mConsumers
;
626 // We need this to track our parent object.
627 nsCOMPtr
<nsPIDOMWindowInner
> mWindow
;
629 // The input MediaTrack assigned us by the data producer.
630 // Owned by the producer.
631 const RefPtr
<mozilla::MediaTrack
> mInputTrack
;
632 // The MediaTrack representing this MediaStreamTrack in the MediaTrackGraph.
633 // Set on construction if we're live. Valid until we end. Owned by us.
634 RefPtr
<ProcessedMediaTrack
> mTrack
;
635 // The MediaInputPort connecting mInputTrack to mTrack. Set on construction
636 // if mInputTrack is non-destroyed and we're live. Valid until we end. Owned
638 RefPtr
<MediaInputPort
> mPort
;
639 RefPtr
<MediaStreamTrackSource
> mSource
;
640 const UniquePtr
<TrackSink
> mSink
;
641 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
642 nsCOMPtr
<nsIPrincipal
> mPendingPrincipal
;
643 RefPtr
<MTGListener
> mMTGListener
;
644 // Keep tracking MediaTrackListener and DirectMediaTrackListener,
645 // so we can remove them in |Destory|.
646 nsTArray
<RefPtr
<MediaTrackListener
>> mTrackListeners
;
647 nsTArray
<RefPtr
<DirectMediaTrackListener
>> mDirectTrackListeners
;
649 MediaStreamTrackState mReadyState
;
652 dom::MediaTrackConstraints mConstraints
;
656 } // namespace mozilla
658 #endif /* MEDIASTREAMTRACK_H_ */