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/MediaTrackSettingsBinding.h"
15 #include "mozilla/media/MediaUtils.h"
16 #include "mozilla/WeakPtr.h"
19 #include "nsIPrincipal.h"
24 class MediaEnginePhotoCallback
;
27 class MediaTrackGraph
;
28 class MediaTrackGraphImpl
;
29 class MediaTrackListener
;
30 class DirectMediaTrackListener
;
31 class PeerConnectionImpl
;
33 class ProcessedMediaTrack
;
34 class RemoteSourceStreamInfo
;
35 class SourceStreamInfo
;
40 class AudioStreamTrack
;
41 class VideoStreamTrack
;
42 enum class CallerType
: uint32_t;
45 * Common interface through which a MediaStreamTrack can communicate with its
46 * producer on the main thread.
48 * Kept alive by a strong ref in all MediaStreamTracks (original and clones)
49 * sharing this source.
51 class MediaStreamTrackSource
: public nsISupports
{
52 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
53 NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackSource
)
56 class Sink
: public SupportsWeakPtr
{
59 * Must be constant throughout the Sink's lifetime.
61 * Return true to keep the MediaStreamTrackSource where this sink is
63 * Return false to allow the source to stop.
65 * Typically MediaStreamTrack::Sink returns true and other Sinks
66 * (like HTMLMediaElement::StreamCaptureTrackSource) return false.
68 virtual bool KeepsSourceAlive() const = 0;
71 * Return true to ensure that the MediaStreamTrackSource where this Sink is
72 * registered is kept turned on and active.
73 * Return false to allow the source to pause, and any underlying devices to
76 * When the underlying enabled state of the sink changes,
77 * call MediaStreamTrackSource::SinkEnabledStateChanged().
79 * Typically MediaStreamTrack returns the track's enabled state and other
80 * Sinks (like HTMLMediaElement::StreamCaptureTrackSource) return false so
81 * control over device state remains with tracks and their enabled state.
83 virtual bool Enabled() const = 0;
86 * Called when the principal of the MediaStreamTrackSource where this sink
87 * is registered has changed.
89 virtual void PrincipalChanged() = 0;
92 * Called when the muted state of the MediaStreamTrackSource where this sink
93 * is registered has changed.
95 virtual void MutedChanged(bool aNewState
) = 0;
98 * Called when the MediaStreamTrackSource where this sink is registered has
99 * stopped producing data for good, i.e., it has ended.
101 virtual void OverrideEnded() = 0;
104 virtual ~Sink() = default;
107 MediaStreamTrackSource(nsIPrincipal
* aPrincipal
, const nsString
& aLabel
)
108 : mPrincipal(aPrincipal
), mLabel(aLabel
), mStopped(false) {}
111 * Use to clean up any resources that have to be cleaned before the
112 * destructor is called. It is often too late in the destructor because
113 * of garbage collection having removed the members already.
115 virtual void Destroy() {}
118 * Gets the source's MediaSourceEnum for usage by PeerConnections.
120 virtual MediaSourceEnum
GetMediaSource() const = 0;
123 * Get this TrackSource's principal.
125 nsIPrincipal
* GetPrincipal() const { return mPrincipal
; }
128 * This is used in WebRTC. A peerIdentity constrained MediaStreamTrack cannot
129 * be sent across the network to anything other than a peer with the provided
130 * identity. If this is set, then GetPrincipal() should return an instance of
133 * A track's PeerIdentity is immutable and will not change during the track's
136 virtual const PeerIdentity
* GetPeerIdentity() const { return nullptr; }
139 * MediaStreamTrack::GetLabel (see spec) calls through to here.
141 void GetLabel(nsAString
& aLabel
) { aLabel
.Assign(mLabel
); }
144 * Whether this TrackSource provides video frames with an alpha channel. Only
145 * applies to video sources. Used by HTMLVideoElement.
147 virtual bool HasAlpha() const { return false; }
150 * Forwards a photo request to backends that support it. Other backends return
151 * NS_ERROR_NOT_IMPLEMENTED to indicate that a MediaTrackGraph-based fallback
154 virtual nsresult
TakePhoto(MediaEnginePhotoCallback
*) const {
155 return NS_ERROR_NOT_IMPLEMENTED
;
158 typedef MozPromise
<bool /* aIgnored */, RefPtr
<MediaMgrError
>, true>
159 ApplyConstraintsPromise
;
162 * We provide a fallback solution to ApplyConstraints() here.
163 * Sources that support ApplyConstraints() will have to override it.
165 virtual RefPtr
<ApplyConstraintsPromise
> ApplyConstraints(
166 const dom::MediaTrackConstraints
& aConstraints
, CallerType aCallerType
);
169 * Same for GetSettings (no-op).
171 virtual void GetSettings(dom::MediaTrackSettings
& aResult
){};
174 * Called by the source interface when all registered sinks with
175 * KeepsSourceAlive() == true have unregistered.
177 virtual void Stop() = 0;
180 * Called by the source interface when all registered sinks with
181 * KeepsSourceAlive() == true become disabled.
183 virtual void Disable() = 0;
186 * Called by the source interface when at least one registered sink with
187 * KeepsSourceAlive() == true become enabled.
189 virtual void Enable() = 0;
192 * Called when a Sink's Enabled() state changed. Will iterate through all
193 * sinks and notify the source of the aggregated enabled state.
195 * Note that a Sink with KeepsSourceAlive() == false counts as disabled.
197 void SinkEnabledStateChanged() {
206 * Called by each MediaStreamTrack clone on initialization.
208 void RegisterSink(Sink
* aSink
) {
209 MOZ_ASSERT(NS_IsMainThread());
213 mSinks
.AppendElement(aSink
);
214 while (mSinks
.RemoveElement(nullptr)) {
215 MOZ_ASSERT_UNREACHABLE("Sink was not explicitly removed");
220 * Called by each MediaStreamTrack clone on Stop() if supported by the
221 * source (us) or destruction.
223 void UnregisterSink(Sink
* aSink
) {
224 MOZ_ASSERT(NS_IsMainThread());
225 while (mSinks
.RemoveElement(nullptr)) {
226 MOZ_ASSERT_UNREACHABLE("Sink was not explicitly removed");
228 if (mSinks
.RemoveElement(aSink
) && !IsActive()) {
229 MOZ_ASSERT(!aSink
->KeepsSourceAlive() || !mStopped
,
230 "When the last sink keeping the source alive is removed, "
231 "we should still be live");
236 SinkEnabledStateChanged();
241 virtual ~MediaStreamTrackSource() = default;
244 for (const WeakPtr
<Sink
>& sink
: mSinks
) {
245 if (sink
&& sink
->KeepsSourceAlive()) {
253 for (const WeakPtr
<Sink
>& sink
: mSinks
) {
254 if (sink
&& sink
->KeepsSourceAlive() && sink
->Enabled()) {
262 * Called by a sub class when the principal has changed.
263 * Notifies all sinks.
265 void PrincipalChanged() {
266 MOZ_ASSERT(NS_IsMainThread());
267 for (auto& sink
: mSinks
.Clone()) {
269 DebugOnly
<bool> removed
= mSinks
.RemoveElement(sink
);
270 MOZ_ASSERT(!removed
, "Sink was not explicitly removed");
273 sink
->PrincipalChanged();
278 * Called by a sub class when the source's muted state has changed. Note that
279 * the source is responsible for making the content black/silent during mute.
280 * Notifies all sinks.
282 void MutedChanged(bool aNewState
) {
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
->MutedChanged(aNewState
);
295 * Called by a sub class when the source has stopped producing data for good,
296 * i.e., it has ended. Notifies all sinks.
298 void OverrideEnded() {
299 MOZ_ASSERT(NS_IsMainThread());
300 for (auto& sink
: mSinks
.Clone()) {
302 DebugOnly
<bool> removed
= mSinks
.RemoveElement(sink
);
303 MOZ_ASSERT(!removed
, "Sink was not explicitly removed");
306 sink
->OverrideEnded();
310 // Principal identifying who may access the contents of this source.
311 RefPtr
<nsIPrincipal
> mPrincipal
;
313 // Currently registered sinks.
314 nsTArray
<WeakPtr
<Sink
>> mSinks
;
316 // The label of the track we are the source of per the MediaStreamTrack spec.
317 const nsString mLabel
;
319 // True if all MediaStreamTrack users have unregistered from this source and
320 // Stop() has been called.
325 * Basic implementation of MediaStreamTrackSource that doesn't forward Stop().
327 class BasicTrackSource
: public MediaStreamTrackSource
{
329 explicit BasicTrackSource(
330 nsIPrincipal
* aPrincipal
,
331 const MediaSourceEnum aMediaSource
= MediaSourceEnum::Other
)
332 : MediaStreamTrackSource(aPrincipal
, nsString()),
333 mMediaSource(aMediaSource
) {}
335 MediaSourceEnum
GetMediaSource() const override
{ return mMediaSource
; }
337 void Stop() override
{}
338 void Disable() override
{}
339 void Enable() override
{}
342 ~BasicTrackSource() = default;
344 const MediaSourceEnum mMediaSource
;
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 GetConstraints(dom::MediaTrackConstraints
& aResult
);
445 void GetSettings(dom::MediaTrackSettings
& aResult
, CallerType aCallerType
);
447 already_AddRefed
<Promise
> ApplyConstraints(
448 const dom::MediaTrackConstraints
& aConstraints
, CallerType aCallerType
,
450 already_AddRefed
<MediaStreamTrack
> Clone();
451 MediaStreamTrackState
ReadyState() { return mReadyState
; }
453 IMPL_EVENT_HANDLER(mute
)
454 IMPL_EVENT_HANDLER(unmute
)
455 IMPL_EVENT_HANDLER(ended
)
458 * Convenience (and legacy) method for when ready state is "ended".
460 bool Ended() const { return mReadyState
== MediaStreamTrackState::Ended
; }
463 * Get this track's principal.
465 nsIPrincipal
* GetPrincipal() const { return mPrincipal
; }
468 * Get this track's PeerIdentity.
470 const PeerIdentity
* GetPeerIdentity() const {
471 return GetSource().GetPeerIdentity();
474 ProcessedMediaTrack
* GetTrack() const;
475 MediaTrackGraph
* Graph() const;
476 MediaTrackGraphImpl
* GraphImpl() const;
478 MediaStreamTrackSource
& GetSource() const {
479 MOZ_RELEASE_ASSERT(mSource
,
480 "The track source is only removed on destruction");
484 // Webrtc allows the remote side to name tracks whatever it wants, and we
485 // need to surface this to content.
486 void AssignId(const nsAString
& aID
) { mID
= aID
; }
489 * Add a PrincipalChangeObserver to this track.
491 * Returns true if it was successfully added.
493 * Ownership of the PrincipalChangeObserver remains with the caller, and it's
494 * the caller's responsibility to remove the observer before it dies.
496 bool AddPrincipalChangeObserver(
497 PrincipalChangeObserver
<MediaStreamTrack
>* aObserver
);
500 * Remove an added PrincipalChangeObserver from this track.
502 * Returns true if it was successfully removed.
504 bool RemovePrincipalChangeObserver(
505 PrincipalChangeObserver
<MediaStreamTrack
>* aObserver
);
508 * Add a MediaStreamTrackConsumer to this track.
510 * Adding the same consumer multiple times is prohibited.
512 void AddConsumer(MediaStreamTrackConsumer
* aConsumer
);
515 * Remove an added MediaStreamTrackConsumer from this track.
517 void RemoveConsumer(MediaStreamTrackConsumer
* aConsumer
);
520 * Adds a MediaTrackListener to the MediaTrackGraph representation of
523 virtual void AddListener(MediaTrackListener
* aListener
);
526 * Removes a MediaTrackListener from the MediaTrackGraph representation
529 void RemoveListener(MediaTrackListener
* aListener
);
532 * Attempts to add a direct track listener to this track.
533 * Callers must listen to the NotifyInstalled event to know if installing
534 * the listener succeeded (tracks originating from SourceMediaTracks) or
535 * failed (e.g., WebAudio originated tracks).
537 virtual void AddDirectListener(DirectMediaTrackListener
* aListener
);
538 void RemoveDirectListener(DirectMediaTrackListener
* aListener
);
541 * Sets up a MediaInputPort from the underlying track that this
542 * MediaStreamTrack represents, to aTrack, and returns it.
544 already_AddRefed
<MediaInputPort
> ForwardTrackContentsTo(
545 ProcessedMediaTrack
* aTrack
);
548 virtual ~MediaStreamTrack();
551 * Forces the ready state to a particular value, for instance when we're
552 * cloning an already ended track.
554 virtual void SetReadyState(MediaStreamTrackState aState
);
557 * Notified by the MediaTrackGraph, through our owning MediaStream on the
560 * Note that this sets the track to ended and raises the "ended" event
563 void OverrideEnded();
566 * Called by the MTGListener when this track's PrincipalHandle changes on
567 * the MediaTrackGraph thread. When the PrincipalHandle matches the pending
568 * principal we know that the principal change has propagated to consumers.
570 void NotifyPrincipalHandleChanged(const PrincipalHandle
& aNewPrincipalHandle
);
573 * Called when this track's readyState transitions to "ended".
574 * Notifies all MediaStreamTrackConsumers that this track ended.
579 * Called when this track's enabled state has changed.
580 * Notifies all MediaStreamTrackConsumers.
582 void NotifyEnabledChanged();
585 * Called when mSource's principal has changed.
587 void PrincipalChanged();
590 * Called when mSource's muted state has changed.
592 void MutedChanged(bool aNewState
);
595 * Sets this track's muted state without raising any events.
596 * Only really set by cloning. See MutedChanged for runtime changes.
598 void SetMuted(bool aMuted
) { mMuted
= aMuted
; }
600 virtual void Destroy();
603 * Sets the principal and notifies PrincipalChangeObservers if it changes.
605 void SetPrincipal(nsIPrincipal
* aPrincipal
);
608 * Creates a new MediaStreamTrack with the same kind, input track, input
609 * track ID and source as this MediaStreamTrack.
611 virtual already_AddRefed
<MediaStreamTrack
> CloneInternal() = 0;
613 nsTArray
<PrincipalChangeObserver
<MediaStreamTrack
>*>
614 mPrincipalChangeObservers
;
616 nsTArray
<WeakPtr
<MediaStreamTrackConsumer
>> mConsumers
;
618 // We need this to track our parent object.
619 nsCOMPtr
<nsPIDOMWindowInner
> mWindow
;
621 // The input MediaTrack assigned us by the data producer.
622 // Owned by the producer.
623 const RefPtr
<mozilla::MediaTrack
> mInputTrack
;
624 // The MediaTrack representing this MediaStreamTrack in the MediaTrackGraph.
625 // Set on construction if we're live. Valid until we end. Owned by us.
626 RefPtr
<ProcessedMediaTrack
> mTrack
;
627 // The MediaInputPort connecting mInputTrack to mTrack. Set on construction
628 // if mInputTrack is non-destroyed and we're live. Valid until we end. Owned
630 RefPtr
<MediaInputPort
> mPort
;
631 RefPtr
<MediaStreamTrackSource
> mSource
;
632 const UniquePtr
<TrackSink
> mSink
;
633 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
634 nsCOMPtr
<nsIPrincipal
> mPendingPrincipal
;
635 RefPtr
<MTGListener
> mMTGListener
;
636 // Keep tracking MediaTrackListener and DirectMediaTrackListener,
637 // so we can remove them in |Destory|.
638 nsTArray
<RefPtr
<MediaTrackListener
>> mTrackListeners
;
639 nsTArray
<RefPtr
<DirectMediaTrackListener
>> mDirectTrackListeners
;
641 MediaStreamTrackState mReadyState
;
644 dom::MediaTrackConstraints mConstraints
;
648 } // namespace mozilla
650 #endif /* MEDIASTREAMTRACK_H_ */