summaryrefslogtreecommitdiffstats
path: root/dom/html/HTMLMediaElement.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/html/HTMLMediaElement.h')
-rw-r--r--dom/html/HTMLMediaElement.h1941
1 files changed, 1941 insertions, 0 deletions
diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h
new file mode 100644
index 0000000000..0d35fcc85c
--- /dev/null
+++ b/dom/html/HTMLMediaElement.h
@@ -0,0 +1,1941 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 mozilla_dom_HTMLMediaElement_h
+#define mozilla_dom_HTMLMediaElement_h
+
+#include "nsGenericHTMLElement.h"
+#include "AudioChannelService.h"
+#include "MediaEventSource.h"
+#include "SeekTarget.h"
+#include "MediaDecoderOwner.h"
+#include "MediaElementEventRunners.h"
+#include "MediaPlaybackDelayPolicy.h"
+#include "MediaPromiseDefs.h"
+#include "TelemetryProbesReporter.h"
+#include "nsCycleCollectionParticipant.h"
+#include "Visibility.h"
+#include "mozilla/CORSMode.h"
+#include "DecoderTraits.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/StateWatching.h"
+#include "mozilla/WeakPtr.h"
+#include "mozilla/dom/DecoderDoctorNotificationBinding.h"
+#include "mozilla/dom/HTMLMediaElementBinding.h"
+#include "mozilla/dom/MediaDebugInfoBinding.h"
+#include "mozilla/dom/MediaKeys.h"
+#include "mozilla/dom/TextTrackManager.h"
+#include "nsGkAtoms.h"
+#include "PrincipalChangeObserver.h"
+#include "nsStubMutationObserver.h"
+#include "MediaSegment.h" // for PrincipalHandle, GraphTime
+
+#include <utility>
+
+// X.h on Linux #defines CurrentTime as 0L, so we have to #undef it here.
+#ifdef CurrentTime
+# undef CurrentTime
+#endif
+
+// Define to output information on decoding and painting framerate
+/* #define DEBUG_FRAME_RATE 1 */
+
+using nsMediaNetworkState = uint16_t;
+using nsMediaReadyState = uint16_t;
+using SuspendTypes = uint32_t;
+using AudibleChangedReasons = uint32_t;
+
+class nsIStreamListener;
+
+namespace mozilla {
+class AbstractThread;
+class ChannelMediaDecoder;
+class DecoderDoctorDiagnostics;
+class DOMMediaStream;
+class ErrorResult;
+class FirstFrameVideoOutput;
+class MediaResource;
+class MediaDecoder;
+class MediaInputPort;
+class MediaTrack;
+class MediaTrackGraph;
+class MediaStreamWindowCapturer;
+struct SharedDummyTrack;
+class VideoFrameContainer;
+class VideoOutput;
+namespace dom {
+class HTMLSourceElement;
+class MediaKeys;
+class TextTrack;
+class TimeRanges;
+class WakeLock;
+class MediaStreamTrack;
+class MediaStreamTrackSource;
+class MediaTrack;
+class VideoStreamTrack;
+} // namespace dom
+} // namespace mozilla
+
+class AudioDeviceInfo;
+class nsIChannel;
+class nsIHttpChannel;
+class nsILoadGroup;
+class nsIRunnable;
+class nsISerialEventTarget;
+class nsITimer;
+class nsRange;
+
+namespace mozilla::dom {
+
+// Number of milliseconds between timeupdate events as defined by spec
+#define TIMEUPDATE_MS 250
+
+class MediaError;
+class MediaSource;
+class PlayPromise;
+class Promise;
+class TextTrackList;
+class AudioTrackList;
+class VideoTrackList;
+
+enum class StreamCaptureType : uint8_t { CAPTURE_ALL_TRACKS, CAPTURE_AUDIO };
+
+enum class StreamCaptureBehavior : uint8_t {
+ CONTINUE_WHEN_ENDED,
+ FINISH_WHEN_ENDED
+};
+
+class HTMLMediaElement : public nsGenericHTMLElement,
+ public MediaDecoderOwner,
+ public PrincipalChangeObserver<MediaStreamTrack>,
+ public SupportsWeakPtr,
+ public nsStubMutationObserver,
+ public TelemetryProbesReporterOwner {
+ public:
+ using TimeStamp = mozilla::TimeStamp;
+ using ImageContainer = mozilla::layers::ImageContainer;
+ using VideoFrameContainer = mozilla::VideoFrameContainer;
+ using MediaResource = mozilla::MediaResource;
+ using MediaDecoderOwner = mozilla::MediaDecoderOwner;
+ using MetadataTags = mozilla::MetadataTags;
+
+ // Helper struct to keep track of the MediaStreams returned by
+ // mozCaptureStream(). For each OutputMediaStream, dom::MediaTracks get
+ // captured into MediaStreamTracks which get added to
+ // OutputMediaStream::mStream.
+ struct OutputMediaStream {
+ OutputMediaStream(RefPtr<DOMMediaStream> aStream, bool aCapturingAudioOnly,
+ bool aFinishWhenEnded);
+ ~OutputMediaStream();
+
+ RefPtr<DOMMediaStream> mStream;
+ nsTArray<RefPtr<MediaStreamTrack>> mLiveTracks;
+ const bool mCapturingAudioOnly;
+ const bool mFinishWhenEnded;
+ // If mFinishWhenEnded is true, this is the URI of the first resource
+ // mStream got tracks for.
+ nsCOMPtr<nsIURI> mFinishWhenEndedLoadingSrc;
+ // If mFinishWhenEnded is true, this is the first MediaStream mStream got
+ // tracks for.
+ RefPtr<DOMMediaStream> mFinishWhenEndedAttrStream;
+ // If mFinishWhenEnded is true, this is the MediaSource being played.
+ RefPtr<MediaSource> mFinishWhenEndedMediaSource;
+ };
+
+ NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
+
+ CORSMode GetCORSMode() { return mCORSMode; }
+
+ explicit HTMLMediaElement(
+ already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
+ void Init();
+
+ // `eMandatory`: `timeupdate` occurs according to the spec requirement.
+ // Eg.
+ // https://html.spec.whatwg.org/multipage/media.html#seeking:event-media-timeupdate
+ // `ePeriodic` : `timeupdate` occurs regularly and should follow the rule
+ // of not dispatching that event within 250 ms. Eg.
+ // https://html.spec.whatwg.org/multipage/media.html#offsets-into-the-media-resource:event-media-timeupdate
+ enum class TimeupdateType : bool {
+ eMandatory = false,
+ ePeriodic = true,
+ };
+
+ // This is used for event runner creation. Currently only timeupdate needs
+ // that, but it can be used to extend for other events in the future if
+ // necessary.
+ enum class EventFlag : uint8_t {
+ eNone = 0,
+ eMandatory = 1,
+ };
+
+ /**
+ * This is used when the browser is constructing a video element to play
+ * a channel that we've already started loading. The src attribute and
+ * <source> children are ignored.
+ * @param aChannel the channel to use
+ * @param aListener returns a stream listener that should receive
+ * notifications for the stream
+ */
+ nsresult LoadWithChannel(nsIChannel* aChannel, nsIStreamListener** aListener);
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLMediaElement,
+ nsGenericHTMLElement)
+ NS_IMPL_FROMNODE_HELPER(HTMLMediaElement,
+ IsAnyOfHTMLElements(nsGkAtoms::video,
+ nsGkAtoms::audio))
+
+ NS_DECL_ADDSIZEOFEXCLUDINGTHIS
+
+ // EventTarget
+ void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
+
+ void NodeInfoChanged(Document* aOldDoc) override;
+
+ virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
+ const nsAString& aValue,
+ nsIPrincipal* aMaybeScriptedPrincipal,
+ nsAttrValue& aResult) override;
+
+ virtual nsresult BindToTree(BindContext&, nsINode& aParent) override;
+ virtual void UnbindFromTree(bool aNullParent = true) override;
+ virtual void DoneCreatingElement() override;
+
+ virtual bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+ int32_t* aTabIndex) override;
+ virtual int32_t TabIndexDefault() override;
+
+ // Called by the video decoder object, on the main thread,
+ // when it has read the metadata containing video dimensions,
+ // etc.
+ virtual void MetadataLoaded(const MediaInfo* aInfo,
+ UniquePtr<const MetadataTags> aTags) final;
+
+ // Called by the decoder object, on the main thread,
+ // when it has read the first frame of the video or audio.
+ void FirstFrameLoaded() final;
+
+ // Called by the video decoder object, on the main thread,
+ // when the resource has a network error during loading.
+ void NetworkError(const MediaResult& aError) final;
+
+ // Called by the video decoder object, on the main thread, when the
+ // resource has a decode error during metadata loading or decoding.
+ void DecodeError(const MediaResult& aError) final;
+
+ // Called by the decoder object, on the main thread, when the
+ // resource has a decode issue during metadata loading or decoding, but can
+ // continue decoding.
+ void DecodeWarning(const MediaResult& aError) final;
+
+ // Return true if error attribute is not null.
+ bool HasError() const final;
+
+ // Called by the video decoder object, on the main thread, when the
+ // resource load has been cancelled.
+ void LoadAborted() final;
+
+ // Called by the video decoder object, on the main thread,
+ // when the video playback has ended.
+ void PlaybackEnded() final;
+
+ // Called by the video decoder object, on the main thread,
+ // when the resource has started seeking.
+ void SeekStarted() final;
+
+ // Called by the video decoder object, on the main thread,
+ // when the resource has completed seeking.
+ void SeekCompleted() final;
+
+ // Called by the video decoder object, on the main thread,
+ // when the resource has aborted seeking.
+ void SeekAborted() final;
+
+ // Called by the media stream, on the main thread, when the download
+ // has been suspended by the cache or because the element itself
+ // asked the decoder to suspend the download.
+ void DownloadSuspended() final;
+
+ // Called by the media stream, on the main thread, when the download
+ // has been resumed by the cache or because the element itself
+ // asked the decoder to resumed the download.
+ void DownloadResumed();
+
+ // Called to indicate the download is progressing.
+ void DownloadProgressed() final;
+
+ // Called by the media decoder to indicate whether the media cache has
+ // suspended the channel.
+ void NotifySuspendedByCache(bool aSuspendedByCache) final;
+
+ // Return true if the media element is actually invisible to users.
+ bool IsActuallyInvisible() const override;
+
+ // Return true if the element is in the view port.
+ bool IsInViewPort() const;
+
+ // Called by the media decoder and the video frame to get the
+ // ImageContainer containing the video data.
+ VideoFrameContainer* GetVideoFrameContainer() final;
+ layers::ImageContainer* GetImageContainer();
+
+ /**
+ * Call this to reevaluate whether we should start/stop due to our owner
+ * document being active, inactive, visible or hidden.
+ */
+ void NotifyOwnerDocumentActivityChanged();
+
+ // Called when the media element enters or leaves the fullscreen.
+ void NotifyFullScreenChanged();
+
+ bool IsInFullScreen() const;
+
+ // From PrincipalChangeObserver<MediaStreamTrack>.
+ void PrincipalChanged(MediaStreamTrack* aTrack) override;
+
+ void UpdateSrcStreamVideoPrincipal(const PrincipalHandle& aPrincipalHandle);
+
+ // Called after the MediaStream we're playing rendered a frame to aContainer
+ // with a different principalHandle than the previous frame.
+ void PrincipalHandleChangedForVideoFrameContainer(
+ VideoFrameContainer* aContainer,
+ const PrincipalHandle& aNewPrincipalHandle) override;
+
+ // Dispatch events
+ void DispatchAsyncEvent(const nsAString& aName) final;
+ void DispatchAsyncEvent(RefPtr<nsMediaEventRunner> aRunner);
+
+ // Triggers a recomputation of readyState.
+ void UpdateReadyState() override {
+ mWatchManager.ManualNotify(&HTMLMediaElement::UpdateReadyStateInternal);
+ }
+
+ // Dispatch events that were raised while in the bfcache
+ nsresult DispatchPendingMediaEvents();
+
+ // Return true if we can activate autoplay assuming enough data has arrived.
+ // https://html.spec.whatwg.org/multipage/media.html#eligible-for-autoplay
+ bool IsEligibleForAutoplay();
+
+ // Notify that state has changed that might cause an autoplay element to
+ // start playing.
+ // If the element is 'autoplay' and is ready to play back (not paused,
+ // autoplay pref enabled, etc), it should start playing back.
+ void CheckAutoplayDataReady();
+
+ void RunAutoplay();
+
+ // Check if the media element had crossorigin set when loading started
+ bool ShouldCheckAllowOrigin();
+
+ // Returns true if the currently loaded resource is CORS same-origin with
+ // respect to the document.
+ bool IsCORSSameOrigin();
+
+ // Is the media element potentially playing as defined by the HTML 5
+ // specification.
+ // http://www.whatwg.org/specs/web-apps/current-work/#potentially-playing
+ bool IsPotentiallyPlaying() const;
+
+ // Has playback ended as defined by the HTML 5 specification.
+ // http://www.whatwg.org/specs/web-apps/current-work/#ended
+ bool IsPlaybackEnded() const;
+
+ // principal of the currently playing resource. Anything accessing the
+ // contents of this element must have a principal that subsumes this
+ // principal. Returns null if nothing is playing.
+ already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
+
+ // Return true if the loading of this resource required cross-origin
+ // redirects.
+ bool HadCrossOriginRedirects();
+
+ bool ShouldResistFingerprinting(RFPTarget aTarget) const override;
+
+ // Principal of the currently playing video resource. Anything accessing the
+ // image container of this element must have a principal that subsumes this
+ // principal. If there are no live video tracks but content has been rendered
+ // to the image container, we return the last video principal we had. Should
+ // the image container be empty with no live video tracks, we return nullptr.
+ already_AddRefed<nsIPrincipal> GetCurrentVideoPrincipal();
+
+ // called to notify that the principal of the decoder's media resource has
+ // changed.
+ void NotifyDecoderPrincipalChanged() final;
+
+ void GetEMEInfo(dom::EMEDebugInfo& aInfo);
+
+ // Update the visual size of the media. Called from the decoder on the
+ // main thread when/if the size changes.
+ virtual void UpdateMediaSize(const nsIntSize& aSize);
+
+ void Invalidate(ImageSizeChanged aImageSizeChanged,
+ const Maybe<nsIntSize>& aNewIntrinsicSize,
+ ForceInvalidate aForceInvalidate) override;
+
+ // Returns the CanPlayStatus indicating if we can handle the
+ // full MIME type including the optional codecs parameter.
+ static CanPlayStatus GetCanPlay(const nsAString& aType,
+ DecoderDoctorDiagnostics* aDiagnostics);
+
+ /**
+ * Called when a child source element is added to this media element. This
+ * may queue a task to run the select resource algorithm if appropriate.
+ */
+ void NotifyAddedSource();
+
+ /**
+ * Called when there's been an error fetching the resource. This decides
+ * whether it's appropriate to fire an error event.
+ */
+ void NotifyLoadError(const nsACString& aErrorDetails = nsCString());
+
+ /**
+ * Called by one of our associated MediaTrackLists (audio/video) when a
+ * MediaTrack is added.
+ */
+ void NotifyMediaTrackAdded(dom::MediaTrack* aTrack);
+
+ /**
+ * Called by one of our associated MediaTrackLists (audio/video) when a
+ * MediaTrack is removed.
+ */
+ void NotifyMediaTrackRemoved(dom::MediaTrack* aTrack);
+
+ /**
+ * Called by one of our associated MediaTrackLists (audio/video) when an
+ * AudioTrack is enabled or a VideoTrack is selected.
+ */
+ void NotifyMediaTrackEnabled(dom::MediaTrack* aTrack);
+
+ /**
+ * Called by one of our associated MediaTrackLists (audio/video) when an
+ * AudioTrack is disabled or a VideoTrack is unselected.
+ */
+ void NotifyMediaTrackDisabled(dom::MediaTrack* aTrack);
+
+ /**
+ * Returns the current load ID. Asynchronous events store the ID that was
+ * current when they were enqueued, and if it has changed when they come to
+ * fire, they consider themselves cancelled, and don't fire.
+ */
+ uint32_t GetCurrentLoadID() const { return mCurrentLoadID; }
+
+ /**
+ * Returns the load group for this media element's owner document.
+ * XXX XBL2 issue.
+ */
+ already_AddRefed<nsILoadGroup> GetDocumentLoadGroup();
+
+ /**
+ * Returns true if the media has played or completed a seek.
+ * Used by video frame to determine whether to paint the poster.
+ */
+ bool GetPlayedOrSeeked() const { return mHasPlayedOrSeeked; }
+
+ nsresult CopyInnerTo(Element* aDest);
+
+ /**
+ * Sets the Accept header on the HTTP channel to the required
+ * video or audio MIME types.
+ */
+ virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel) = 0;
+
+ /**
+ * Sets the required request headers on the HTTP channel for
+ * video or audio requests.
+ */
+ void SetRequestHeaders(nsIHttpChannel* aChannel);
+
+ /**
+ * Asynchronously awaits a stable state, whereupon aRunnable runs on the main
+ * thread. This adds an event which run aRunnable to the appshell's list of
+ * sections synchronous the next time control returns to the event loop.
+ */
+ void RunInStableState(nsIRunnable* aRunnable);
+
+ /**
+ * Fires a timeupdate event. If aPeriodic is true, the event will only
+ * be fired if we've not fired a timeupdate event (for any reason) in the
+ * last 250ms, as required by the spec when the current time is periodically
+ * increasing during playback.
+ */
+ void FireTimeUpdate(TimeupdateType aType);
+
+ void MaybeQueueTimeupdateEvent() final {
+ FireTimeUpdate(TimeupdateType::ePeriodic);
+ }
+
+ const TimeStamp& LastTimeupdateDispatchTime() const;
+ void UpdateLastTimeupdateDispatchTime();
+
+ // WebIDL
+
+ MediaError* GetError() const;
+
+ void GetSrc(nsAString& aSrc) { GetURIAttr(nsGkAtoms::src, nullptr, aSrc); }
+ void SetSrc(const nsAString& aSrc, ErrorResult& aError) {
+ SetHTMLAttr(nsGkAtoms::src, aSrc, aError);
+ }
+ void SetSrc(const nsAString& aSrc, nsIPrincipal* aTriggeringPrincipal,
+ ErrorResult& aError) {
+ SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aError);
+ }
+
+ void GetCurrentSrc(nsAString& aCurrentSrc);
+
+ void GetCrossOrigin(nsAString& aResult) {
+ // Null for both missing and invalid defaults is ok, since we
+ // always parse to an enum value, so we don't need an invalid
+ // default, and we _want_ the missing default to be null.
+ GetEnumAttr(nsGkAtoms::crossorigin, nullptr, aResult);
+ }
+ void SetCrossOrigin(const nsAString& aCrossOrigin, ErrorResult& aError) {
+ SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError);
+ }
+
+ uint16_t NetworkState() const { return mNetworkState; }
+
+ void NotifyXPCOMShutdown() final;
+
+ // Called by media decoder when the audible state changed or when input is
+ // a media stream.
+ void SetAudibleState(bool aAudible) final;
+
+ // Notify agent when the MediaElement changes its audible state.
+ void NotifyAudioPlaybackChanged(AudibleChangedReasons aReason);
+
+ void GetPreload(nsAString& aValue) {
+ if (mSrcAttrStream) {
+ nsGkAtoms::none->ToString(aValue);
+ return;
+ }
+ GetEnumAttr(nsGkAtoms::preload, nullptr, aValue);
+ }
+ void SetPreload(const nsAString& aValue, ErrorResult& aRv) {
+ if (mSrcAttrStream) {
+ return;
+ }
+ SetHTMLAttr(nsGkAtoms::preload, aValue, aRv);
+ }
+
+ already_AddRefed<TimeRanges> Buffered() const;
+
+ void Load();
+
+ void CanPlayType(const nsAString& aType, nsAString& aResult);
+
+ uint16_t ReadyState() const { return mReadyState; }
+
+ bool Seeking() const;
+
+ double CurrentTime() const;
+
+ void SetCurrentTime(double aCurrentTime, ErrorResult& aRv);
+ void SetCurrentTime(double aCurrentTime) {
+ SetCurrentTime(aCurrentTime, IgnoreErrors());
+ }
+
+ void FastSeek(double aTime, ErrorResult& aRv);
+
+ already_AddRefed<Promise> SeekToNextFrame(ErrorResult& aRv);
+
+ double Duration() const;
+
+ bool HasAudio() const { return mMediaInfo.HasAudio(); }
+
+ virtual bool IsVideo() const { return false; }
+
+ bool HasVideo() const { return mMediaInfo.HasVideo(); }
+
+ bool IsEncrypted() const override { return mIsEncrypted; }
+
+#ifdef MOZ_WMF_CDM
+ bool IsUsingWMFCDM() const override;
+#endif
+
+ bool Paused() const { return mPaused; }
+
+ double DefaultPlaybackRate() const {
+ if (mSrcAttrStream) {
+ return 1.0;
+ }
+ return mDefaultPlaybackRate;
+ }
+
+ void SetDefaultPlaybackRate(double aDefaultPlaybackRate, ErrorResult& aRv);
+
+ double PlaybackRate() const {
+ if (mSrcAttrStream) {
+ return 1.0;
+ }
+ return mPlaybackRate;
+ }
+
+ void SetPlaybackRate(double aPlaybackRate, ErrorResult& aRv);
+
+ already_AddRefed<TimeRanges> Played();
+
+ already_AddRefed<TimeRanges> Seekable() const;
+
+ bool Ended();
+
+ bool Autoplay() const { return GetBoolAttr(nsGkAtoms::autoplay); }
+
+ void SetAutoplay(bool aValue, ErrorResult& aRv) {
+ SetHTMLBoolAttr(nsGkAtoms::autoplay, aValue, aRv);
+ }
+
+ bool Loop() const { return GetBoolAttr(nsGkAtoms::loop); }
+
+ void SetLoop(bool aValue, ErrorResult& aRv) {
+ SetHTMLBoolAttr(nsGkAtoms::loop, aValue, aRv);
+ }
+
+ already_AddRefed<Promise> Play(ErrorResult& aRv);
+ void Play() {
+ IgnoredErrorResult dummy;
+ RefPtr<Promise> toBeIgnored = Play(dummy);
+ }
+
+ void Pause(ErrorResult& aRv);
+ void Pause() { Pause(IgnoreErrors()); }
+
+ bool Controls() const { return GetBoolAttr(nsGkAtoms::controls); }
+
+ void SetControls(bool aValue, ErrorResult& aRv) {
+ SetHTMLBoolAttr(nsGkAtoms::controls, aValue, aRv);
+ }
+
+ double Volume() const { return mVolume; }
+
+ void SetVolume(double aVolume, ErrorResult& aRv);
+
+ bool Muted() const { return mMuted & MUTED_BY_CONTENT; }
+ void SetMuted(bool aMuted);
+
+ bool DefaultMuted() const { return GetBoolAttr(nsGkAtoms::muted); }
+
+ void SetDefaultMuted(bool aMuted, ErrorResult& aRv) {
+ SetHTMLBoolAttr(nsGkAtoms::muted, aMuted, aRv);
+ }
+
+ bool MozAllowCasting() const { return mAllowCasting; }
+
+ void SetMozAllowCasting(bool aShow) { mAllowCasting = aShow; }
+
+ bool MozIsCasting() const { return mIsCasting; }
+
+ void SetMozIsCasting(bool aShow) { mIsCasting = aShow; }
+
+ // Returns whether a call to Play() would be rejected with NotAllowedError.
+ // This assumes "worst case" for unknowns. So if prompting for permission is
+ // enabled and no permission is stored, this behaves as if the user would
+ // opt to block.
+ bool AllowedToPlay() const;
+
+ already_AddRefed<MediaSource> GetMozMediaSourceObject() const;
+
+ // Returns a promise which will be resolved after collecting debugging
+ // data from decoder/reader/MDSM. Used for debugging purposes.
+ already_AddRefed<Promise> MozRequestDebugInfo(ErrorResult& aRv);
+
+ // Enables DecoderDoctorLogger logging. Used for debugging purposes.
+ static void MozEnableDebugLog(const GlobalObject&);
+
+ // Returns a promise which will be resolved after collecting debugging
+ // log associated with this element. Used for debugging purposes.
+ already_AddRefed<Promise> MozRequestDebugLog(ErrorResult& aRv);
+
+ // For use by mochitests. Enabling pref "media.test.video-suspend"
+ void SetVisible(bool aVisible);
+
+ // For use by mochitests. Enabling pref "media.test.video-suspend"
+ bool HasSuspendTaint() const;
+
+ // For use by mochitests.
+ bool IsVideoDecodingSuspended() const;
+
+ // These functions return accumulated time, which are used for the telemetry
+ // usage. Return -1 for error.
+ double TotalVideoPlayTime() const;
+ double TotalVideoHDRPlayTime() const;
+ double VisiblePlayTime() const;
+ double InvisiblePlayTime() const;
+ double VideoDecodeSuspendedTime() const;
+ double TotalAudioPlayTime() const;
+ double AudiblePlayTime() const;
+ double InaudiblePlayTime() const;
+ double MutedPlayTime() const;
+
+ // Test methods for decoder doctor.
+ void SetFormatDiagnosticsReportForMimeType(const nsAString& aMimeType,
+ DecoderDoctorReportType aType);
+ void SetDecodeError(const nsAString& aError, ErrorResult& aRv);
+ void SetAudioSinkFailedStartup();
+
+ // Synchronously, return the next video frame and mark the element unable to
+ // participate in decode suspending.
+ //
+ // This function is synchronous for cases where decoding has been suspended
+ // and JS needs a frame to use in, eg., nsLayoutUtils::SurfaceFromElement()
+ // via drawImage().
+ already_AddRefed<layers::Image> GetCurrentImage();
+
+ already_AddRefed<DOMMediaStream> GetSrcObject() const;
+ void SetSrcObject(DOMMediaStream& aValue);
+ void SetSrcObject(DOMMediaStream* aValue);
+
+ bool PreservesPitch() const { return mPreservesPitch; }
+ void SetPreservesPitch(bool aPreservesPitch);
+
+ MediaKeys* GetMediaKeys() const;
+
+ already_AddRefed<Promise> SetMediaKeys(MediaKeys* mediaKeys,
+ ErrorResult& aRv);
+
+ mozilla::dom::EventHandlerNonNull* GetOnencrypted();
+ void SetOnencrypted(mozilla::dom::EventHandlerNonNull* aCallback);
+
+ mozilla::dom::EventHandlerNonNull* GetOnwaitingforkey();
+ void SetOnwaitingforkey(mozilla::dom::EventHandlerNonNull* aCallback);
+
+ void DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
+ const nsAString& aInitDataType) override;
+
+ bool IsEventAttributeNameInternal(nsAtom* aName) override;
+
+ bool ContainsRestrictedContent() const;
+
+ void NotifyWaitingForKey() override;
+
+ already_AddRefed<DOMMediaStream> CaptureAudio(ErrorResult& aRv,
+ MediaTrackGraph* aGraph);
+
+ already_AddRefed<DOMMediaStream> MozCaptureStream(ErrorResult& aRv);
+
+ already_AddRefed<DOMMediaStream> MozCaptureStreamUntilEnded(ErrorResult& aRv);
+
+ bool MozAudioCaptured() const { return mAudioCaptured; }
+
+ void MozGetMetadata(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
+ ErrorResult& aRv);
+
+ double MozFragmentEnd();
+
+ AudioTrackList* AudioTracks();
+
+ VideoTrackList* VideoTracks();
+
+ TextTrackList* GetTextTracks();
+
+ already_AddRefed<TextTrack> AddTextTrack(TextTrackKind aKind,
+ const nsAString& aLabel,
+ const nsAString& aLanguage);
+
+ void AddTextTrack(TextTrack* aTextTrack) {
+ GetOrCreateTextTrackManager()->AddTextTrack(aTextTrack);
+ }
+
+ void RemoveTextTrack(TextTrack* aTextTrack, bool aPendingListOnly = false) {
+ if (mTextTrackManager) {
+ mTextTrackManager->RemoveTextTrack(aTextTrack, aPendingListOnly);
+ }
+ }
+
+ void NotifyCueAdded(TextTrackCue& aCue) {
+ if (mTextTrackManager) {
+ mTextTrackManager->NotifyCueAdded(aCue);
+ }
+ }
+ void NotifyCueRemoved(TextTrackCue& aCue) {
+ if (mTextTrackManager) {
+ mTextTrackManager->NotifyCueRemoved(aCue);
+ }
+ }
+ void NotifyCueUpdated(TextTrackCue* aCue) {
+ if (mTextTrackManager) {
+ mTextTrackManager->NotifyCueUpdated(aCue);
+ }
+ }
+
+ void NotifyCueDisplayStatesChanged();
+
+ bool IsBlessed() const { return mIsBlessed; }
+
+ // A method to check whether we are currently playing.
+ bool IsCurrentlyPlaying() const;
+
+ // Returns true if the media element is being destroyed. Used in
+ // dormancy checks to prevent dormant processing for an element
+ // that will soon be gone.
+ bool IsBeingDestroyed();
+
+ virtual void OnVisibilityChange(Visibility aNewVisibility);
+
+ // Begin testing only methods
+ float ComputedVolume() const;
+ bool ComputedMuted() const;
+
+ // Return true if the media has been suspended media due to an inactive
+ // document or prohibiting by the docshell.
+ bool IsSuspendedByInactiveDocOrDocShell() const;
+ // End testing only methods
+
+ void SetMediaInfo(const MediaInfo& aInfo);
+ MediaInfo GetMediaInfo() const override;
+
+ // Gives access to the decoder's frame statistics, if present.
+ FrameStatistics* GetFrameStatistics() const override;
+
+ void DispatchAsyncTestingEvent(const nsAString& aName) override;
+
+ AbstractThread* AbstractMainThread() const final;
+
+ // Log the usage of a {visible / invisible} video element as
+ // the source of {drawImage(), createPattern(), createImageBitmap() and
+ // captureStream()} APIs. This function can be used to collect telemetries for
+ // bug 1352007.
+ enum class CallerAPI {
+ DRAW_IMAGE,
+ CREATE_PATTERN,
+ CREATE_IMAGEBITMAP,
+ CAPTURE_STREAM,
+ CREATE_VIDEOFRAME,
+ };
+ void LogVisibility(CallerAPI aAPI);
+
+ Document* GetDocument() const override;
+
+ already_AddRefed<GMPCrashHelper> CreateGMPCrashHelper() override;
+
+ // Set the sink id (of the output device) that the audio will play. If aSinkId
+ // is empty the default device will be set.
+ already_AddRefed<Promise> SetSinkId(const nsAString& aSinkId,
+ ErrorResult& aRv);
+ // Get the sink id of the device that audio is being played. Initial value is
+ // empty and the default device is being used.
+ void GetSinkId(nsString& aSinkId) const {
+ MOZ_ASSERT(NS_IsMainThread());
+ aSinkId = mSink.first;
+ }
+
+ // This is used to notify MediaElementAudioSourceNode that media element is
+ // allowed to play when media element is used as a source for web audio, so
+ // that we can start AudioContext if it was not allowed to start.
+ RefPtr<GenericNonExclusivePromise> GetAllowedToPlayPromise();
+
+ bool GetShowPosterFlag() const { return mShowPoster; }
+
+ bool IsAudible() const;
+
+ // Return key system in use if we have one, otherwise return nothing.
+ Maybe<nsAutoString> GetKeySystem() const override;
+
+ protected:
+ virtual ~HTMLMediaElement();
+
+ class AudioChannelAgentCallback;
+ class ChannelLoader;
+ class ErrorSink;
+ class MediaElementTrackSource;
+ class MediaLoadListener;
+ class MediaStreamRenderer;
+ class MediaStreamTrackListener;
+ class ShutdownObserver;
+ class TitleChangeObserver;
+ class MediaControlKeyListener;
+
+ MediaDecoderOwner::NextFrameStatus NextFrameStatus();
+
+ void SetDecoder(MediaDecoder* aDecoder);
+
+ void PlayInternal(bool aHandlingUserInput);
+
+ // See spec, https://html.spec.whatwg.org/#internal-pause-steps
+ void PauseInternal();
+
+ /** Use this method to change the mReadyState member, so required
+ * events can be fired.
+ */
+ void ChangeReadyState(nsMediaReadyState aState);
+
+ /**
+ * Use this method to change the mNetworkState member, so required
+ * actions will be taken during the transition.
+ */
+ void ChangeNetworkState(nsMediaNetworkState aState);
+
+ /**
+ * The MediaElement will be responsible for creating and releasing the audio
+ * wakelock depending on the playing and audible state.
+ */
+ virtual void WakeLockRelease();
+ virtual void UpdateWakeLock();
+
+ void CreateAudioWakeLockIfNeeded();
+ void ReleaseAudioWakeLockIfExists();
+ RefPtr<WakeLock> mWakeLock;
+
+ /**
+ * Logs a warning message to the web console to report various failures.
+ * aMsg is the localized message identifier, aParams is the parameters to
+ * be substituted into the localized message, and aParamCount is the number
+ * of parameters in aParams.
+ */
+ void ReportLoadError(const char* aMsg, const nsTArray<nsString>& aParams =
+ nsTArray<nsString>());
+
+ /**
+ * Log message to web console.
+ */
+ void ReportToConsole(
+ uint32_t aErrorFlags, const char* aMsg,
+ const nsTArray<nsString>& aParams = nsTArray<nsString>()) const;
+
+ /**
+ * Changes mHasPlayedOrSeeked to aValue. If mHasPlayedOrSeeked changes
+ * we'll force a reflow so that the video frame gets reflowed to reflect
+ * the poster hiding or showing immediately.
+ */
+ void SetPlayedOrSeeked(bool aValue);
+
+ /**
+ * Initialize the media element for playback of aStream
+ */
+ void SetupSrcMediaStreamPlayback(DOMMediaStream* aStream);
+ /**
+ * Stop playback on mSrcStream.
+ */
+ void EndSrcMediaStreamPlayback();
+ /**
+ * Ensure we're playing mSrcStream if and only if we're not paused.
+ */
+ enum { REMOVING_SRC_STREAM = 0x1 };
+ void UpdateSrcMediaStreamPlaying(uint32_t aFlags = 0);
+
+ /**
+ * Ensure currentTime progresses if and only if we're potentially playing
+ * mSrcStream. Called by the watch manager while we're playing mSrcStream, and
+ * one of the inputs to the potentially playing algorithm changes.
+ */
+ void UpdateSrcStreamPotentiallyPlaying();
+
+ /**
+ * mSrcStream's graph's CurrentTime() has been updated. It might be time to
+ * fire "timeupdate".
+ */
+ void UpdateSrcStreamTime();
+
+ /**
+ * Called after a tail dispatch when playback of mSrcStream ended, to comply
+ * with the spec where we must start reporting true for the ended attribute
+ * after the event loop returns to step 1. A MediaStream could otherwise be
+ * manipulated to end a HTMLMediaElement synchronously.
+ */
+ void UpdateSrcStreamReportPlaybackEnded();
+
+ /**
+ * Called by our DOMMediaStream::TrackListener when a new MediaStreamTrack has
+ * been added to the playback stream of |mSrcStream|.
+ */
+ void NotifyMediaStreamTrackAdded(const RefPtr<MediaStreamTrack>& aTrack);
+
+ /**
+ * Called by our DOMMediaStream::TrackListener when a MediaStreamTrack in
+ * |mSrcStream|'s playback stream has ended.
+ */
+ void NotifyMediaStreamTrackRemoved(const RefPtr<MediaStreamTrack>& aTrack);
+
+ /**
+ * Convenience method to get in a single list all enabled AudioTracks and, if
+ * this is a video element, the selected VideoTrack.
+ */
+ void GetAllEnabledMediaTracks(nsTArray<RefPtr<MediaTrack>>& aTracks);
+
+ /**
+ * Enables or disables all tracks forwarded from mSrcStream to all
+ * OutputMediaStreams. We do this for muting the tracks when pausing,
+ * and unmuting when playing the media element again.
+ */
+ void SetCapturedOutputStreamsEnabled(bool aEnabled);
+
+ /**
+ * Returns true if output tracks should be muted, based on the state of this
+ * media element.
+ */
+ enum class OutputMuteState { Muted, Unmuted };
+ OutputMuteState OutputTracksMuted();
+
+ /**
+ * Sets the muted state of all output track sources. They are muted when we're
+ * paused and unmuted otherwise.
+ */
+ void UpdateOutputTracksMuting();
+
+ /**
+ * Create a new MediaStreamTrack for the TrackSource corresponding to aTrack
+ * and add it to the DOMMediaStream in aOutputStream. This automatically sets
+ * the output track to enabled or disabled depending on our current playing
+ * state.
+ */
+ enum class AddTrackMode { ASYNC, SYNC };
+ void AddOutputTrackSourceToOutputStream(
+ MediaElementTrackSource* aSource, OutputMediaStream& aOutputStream,
+ AddTrackMode aMode = AddTrackMode::ASYNC);
+
+ /**
+ * Creates output track sources when this media element is captured, tracks
+ * exist, playback is not ended and readyState is >= HAVE_METADATA.
+ */
+ void UpdateOutputTrackSources();
+
+ /**
+ * Returns an DOMMediaStream containing the played contents of this
+ * element. When aBehavior is FINISH_WHEN_ENDED, when this element ends
+ * playback we will finish the stream and not play any more into it. When
+ * aType is CONTINUE_WHEN_ENDED, ending playback does not finish the stream.
+ * The stream will never finish.
+ *
+ * When aType is CAPTURE_AUDIO, we stop playout of audio and instead route it
+ * to the DOMMediaStream. Volume and mute state will be applied to the audio
+ * reaching the stream. No video tracks will be captured in this case.
+ *
+ * aGraph may be null if the stream's tracks do not need to use a
+ * specific graph.
+ */
+ already_AddRefed<DOMMediaStream> CaptureStreamInternal(
+ StreamCaptureBehavior aFinishBehavior,
+ StreamCaptureType aStreamCaptureType, MediaTrackGraph* aGraph);
+
+ /**
+ * Initialize a decoder as a clone of an existing decoder in another
+ * element.
+ * mLoadingSrc must already be set.
+ */
+ nsresult InitializeDecoderAsClone(ChannelMediaDecoder* aOriginal);
+
+ /**
+ * Call Load() and FinishDecoderSetup() on the decoder. It also handle
+ * resource cloning if DecoderType is ChannelMediaDecoder.
+ */
+ template <typename DecoderType, typename... LoadArgs>
+ nsresult SetupDecoder(DecoderType* aDecoder, LoadArgs&&... aArgs);
+
+ /**
+ * Initialize a decoder to load the given channel. The decoder's stream
+ * listener is returned via aListener.
+ * mLoadingSrc must already be set.
+ */
+ nsresult InitializeDecoderForChannel(nsIChannel* aChannel,
+ nsIStreamListener** aListener);
+
+ /**
+ * Finish setting up the decoder after Load() has been called on it.
+ * Called by InitializeDecoderForChannel/InitializeDecoderAsClone.
+ */
+ nsresult FinishDecoderSetup(MediaDecoder* aDecoder);
+
+ /**
+ * Call this after setting up mLoadingSrc and mDecoder.
+ */
+ void AddMediaElementToURITable();
+ /**
+ * Call this before modifying mLoadingSrc.
+ */
+ void RemoveMediaElementFromURITable();
+ /**
+ * Call this to find a media element with the same NodePrincipal and
+ * mLoadingSrc set to aURI, and with a decoder on which Load() has been
+ * called.
+ */
+ HTMLMediaElement* LookupMediaElementURITable(nsIURI* aURI);
+
+ /**
+ * Shutdown and clear mDecoder and maintain associated invariants.
+ */
+ void ShutdownDecoder();
+ /**
+ * Execute the initial steps of the load algorithm that ensure existing
+ * loads are aborted, the element is emptied, and a new load ID is
+ * created.
+ */
+ void AbortExistingLoads();
+
+ /**
+ * This is the dedicated media source failure steps.
+ * Called when all potential resources are exhausted. Changes network
+ * state to NETWORK_NO_SOURCE, and sends error event with code
+ * MEDIA_ERR_SRC_NOT_SUPPORTED.
+ */
+ void NoSupportedMediaSourceError(
+ const nsACString& aErrorDetails = nsCString());
+
+ /**
+ * Per spec, Failed with elements: Queue a task, using the DOM manipulation
+ * task source, to fire a simple event named error at the candidate element.
+ * So dispatch |QueueLoadFromSourceTask| to main thread to make sure the task
+ * will be executed later than loadstart event.
+ */
+ void DealWithFailedElement(nsIContent* aSourceElement);
+
+ /**
+ * Attempts to load resources from the <source> children. This is a
+ * substep of the resource selection algorithm. Do not call this directly,
+ * call QueueLoadFromSourceTask() instead.
+ */
+ void LoadFromSourceChildren();
+
+ /**
+ * Asynchronously awaits a stable state, and then causes
+ * LoadFromSourceChildren() to be called on the main threads' event loop.
+ */
+ void QueueLoadFromSourceTask();
+
+ /**
+ * Runs the media resource selection algorithm.
+ */
+ void SelectResource();
+
+ /**
+ * A wrapper function that allows us to cleanly reset flags after a call
+ * to SelectResource()
+ */
+ void SelectResourceWrapper();
+
+ /**
+ * Asynchronously awaits a stable state, and then causes SelectResource()
+ * to be run on the main thread's event loop.
+ */
+ void QueueSelectResourceTask();
+
+ /**
+ * When loading a new source on an existing media element, make sure to reset
+ * everything that is accessible using the media element API.
+ */
+ void ResetState();
+
+ /**
+ * The resource-fetch algorithm step of the load algorithm.
+ */
+ MediaResult LoadResource();
+
+ /**
+ * Selects the next <source> child from which to load a resource. Called
+ * during the resource selection algorithm. Stores the return value in
+ * mSourceLoadCandidate before returning.
+ */
+ HTMLSourceElement* GetNextSource();
+
+ /**
+ * Changes mDelayingLoadEvent, and will call BlockOnLoad()/UnblockOnLoad()
+ * on the owning document, so it can delay the load event firing.
+ */
+ void ChangeDelayLoadStatus(bool aDelay);
+
+ /**
+ * If we suspended downloading after the first frame, unsuspend now.
+ */
+ void StopSuspendingAfterFirstFrame();
+
+ /**
+ * Called when our channel is redirected to another channel.
+ * Updates our mChannel reference to aNewChannel.
+ */
+ nsresult OnChannelRedirect(nsIChannel* aChannel, nsIChannel* aNewChannel,
+ uint32_t aFlags);
+
+ /**
+ * Call this to reevaluate whether we should be holding a self-reference.
+ */
+ void AddRemoveSelfReference();
+
+ /**
+ * Called when "xpcom-shutdown" event is received.
+ */
+ void NotifyShutdownEvent();
+
+ /**
+ * Possible values of the 'preload' attribute.
+ */
+ enum PreloadAttrValue : uint8_t {
+ PRELOAD_ATTR_EMPTY, // set to ""
+ PRELOAD_ATTR_NONE, // set to "none"
+ PRELOAD_ATTR_METADATA, // set to "metadata"
+ PRELOAD_ATTR_AUTO // set to "auto"
+ };
+
+ /**
+ * The preloading action to perform. These dictate how we react to the
+ * preload attribute. See mPreloadAction.
+ */
+ enum PreloadAction {
+ PRELOAD_UNDEFINED = 0, // not determined - used only for initialization
+ PRELOAD_NONE = 1, // do not preload
+ PRELOAD_METADATA = 2, // preload only the metadata (and first frame)
+ PRELOAD_ENOUGH = 3 // preload enough data to allow uninterrupted
+ // playback
+ };
+
+ /**
+ * The guts of Load(). Load() acts as a wrapper around this which sets
+ * mIsDoingExplicitLoad to true so that when script calls 'load()'
+ * preload-none will be automatically upgraded to preload-metadata.
+ */
+ void DoLoad();
+
+ /**
+ * Suspends the load of mLoadingSrc, so that it can be resumed later
+ * by ResumeLoad(). This is called when we have a media with a 'preload'
+ * attribute value of 'none', during the resource selection algorithm.
+ */
+ void SuspendLoad();
+
+ /**
+ * Resumes a previously suspended load (suspended by SuspendLoad(uri)).
+ * Will continue running the resource selection algorithm.
+ * Sets mPreloadAction to aAction.
+ */
+ void ResumeLoad(PreloadAction aAction);
+
+ /**
+ * Handle a change to the preload attribute. Should be called whenever the
+ * value (or presence) of the preload attribute changes. The change in
+ * attribute value may cause a change in the mPreloadAction of this
+ * element. If there is a change then this method will initiate any
+ * behaviour that is necessary to implement the action.
+ */
+ void UpdatePreloadAction();
+
+ /**
+ * Fire progress events if needed according to the time and byte constraints
+ * outlined in the specification. aHaveNewProgress is true if progress has
+ * just been detected. Otherwise the method is called as a result of the
+ * progress timer.
+ */
+ void CheckProgress(bool aHaveNewProgress);
+ static void ProgressTimerCallback(nsITimer* aTimer, void* aClosure);
+ /**
+ * Start timer to update download progress.
+ */
+ void StartProgressTimer();
+ /**
+ * Start sending progress and/or stalled events.
+ */
+ void StartProgress();
+ /**
+ * Stop progress information timer and events.
+ */
+ void StopProgress();
+
+ /**
+ * Dispatches an error event to a child source element.
+ */
+ void DispatchAsyncSourceError(nsIContent* aSourceElement);
+
+ /**
+ * Resets the media element for an error condition as per aErrorCode.
+ * aErrorCode must be one of WebIDL HTMLMediaElement error codes.
+ */
+ void Error(uint16_t aErrorCode,
+ const nsACString& aErrorDetails = nsCString());
+
+ /**
+ * Returns the URL spec of the currentSrc.
+ **/
+ void GetCurrentSpec(nsCString& aString);
+
+ /**
+ * Process any media fragment entries in the URI
+ */
+ void ProcessMediaFragmentURI();
+
+ /**
+ * Mute or unmute the audio and change the value that the |muted| map.
+ */
+ void SetMutedInternal(uint32_t aMuted);
+ /**
+ * Update the volume of the output audio stream to match the element's
+ * current mMuted/mVolume/mAudioChannelFaded state.
+ */
+ void SetVolumeInternal();
+
+ /**
+ * Suspend or resume element playback and resource download. When we suspend
+ * playback, event delivery would also be suspended (and events queued) until
+ * the element is resumed.
+ */
+ void SuspendOrResumeElement(bool aSuspendElement);
+
+ // Get the HTMLMediaElement object if the decoder is being used from an
+ // HTML media element, and null otherwise.
+ HTMLMediaElement* GetMediaElement() final { return this; }
+
+ // Return true if decoding should be paused
+ bool GetPaused() final { return Paused(); }
+
+ // Seeks to aTime seconds. aSeekType can be Exact to seek to exactly the
+ // seek target, or PrevSyncPoint if a quicker but less precise seek is
+ // desired, and we'll seek to the sync point (keyframe and/or start of the
+ // next block of audio samples) preceeding seek target.
+ void Seek(double aTime, SeekTarget::Type aSeekType, ErrorResult& aRv);
+
+ // Update the audio channel playing state
+ void UpdateAudioChannelPlayingState();
+
+ // Adds to the element's list of pending text tracks each text track
+ // in the element's list of text tracks whose text track mode is not disabled
+ // and whose text track readiness state is loading.
+ void PopulatePendingTextTrackList();
+
+ // Gets a reference to the MediaElement's TextTrackManager. If the
+ // MediaElement doesn't yet have one then it will create it.
+ TextTrackManager* GetOrCreateTextTrackManager();
+
+ // Recomputes ready state and fires events as necessary based on current
+ // state.
+ void UpdateReadyStateInternal();
+
+ // Create or destroy the captured stream.
+ void AudioCaptureTrackChange(bool aCapture);
+
+ // If the network state is empty and then we would trigger DoLoad().
+ void MaybeDoLoad();
+
+ // Anything we need to check after played success and not related with spec.
+ void UpdateCustomPolicyAfterPlayed();
+
+ // Returns a StreamCaptureType populated with the right bits, depending on the
+ // tracks this HTMLMediaElement has.
+ StreamCaptureType CaptureTypeForElement();
+
+ // True if this element can be captured, false otherwise.
+ bool CanBeCaptured(StreamCaptureType aCaptureType);
+
+ using nsGenericHTMLElement::DispatchEvent;
+ // For nsAsyncEventRunner.
+ nsresult DispatchEvent(const nsAString& aName);
+
+ already_AddRefed<nsMediaEventRunner> GetEventRunner(
+ const nsAString& aName, EventFlag aFlag = EventFlag::eNone);
+
+ // This method moves the mPendingPlayPromises into a temperate object. So the
+ // mPendingPlayPromises is cleared after this method call.
+ nsTArray<RefPtr<PlayPromise>> TakePendingPlayPromises();
+
+ // This method snapshots the mPendingPlayPromises by TakePendingPlayPromises()
+ // and queues a task to resolve them.
+ void AsyncResolvePendingPlayPromises();
+
+ // This method snapshots the mPendingPlayPromises by TakePendingPlayPromises()
+ // and queues a task to reject them.
+ void AsyncRejectPendingPlayPromises(nsresult aError);
+
+ // This method snapshots the mPendingPlayPromises by TakePendingPlayPromises()
+ // and queues a task to resolve them also to dispatch a "playing" event.
+ void NotifyAboutPlaying();
+
+ already_AddRefed<Promise> CreateDOMPromise(ErrorResult& aRv) const;
+
+ // Pass information for deciding the video decode mode to decoder.
+ void NotifyDecoderActivityChanges() const;
+
+ // Constructs an AudioTrack in mAudioTrackList if aInfo reports that audio is
+ // available, and a VideoTrack in mVideoTrackList if aInfo reports that video
+ // is available.
+ void ConstructMediaTracks(const MediaInfo* aInfo);
+
+ // Removes all MediaTracks from mAudioTrackList and mVideoTrackList and fires
+ // "removetrack" on the lists accordingly.
+ // Note that by spec, this should not fire "removetrack". However, it appears
+ // other user agents do, per
+ // https://wpt.fyi/results/media-source/mediasource-avtracks.html.
+ void RemoveMediaTracks();
+
+ // Mark the decoder owned by the element as tainted so that the
+ // suspend-video-decoder is disabled.
+ void MarkAsTainted();
+
+ virtual void AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ nsIPrincipal* aMaybeScriptedPrincipal,
+ bool aNotify) override;
+ virtual void OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify) override;
+
+ bool DetachExistingMediaKeys();
+ bool TryRemoveMediaKeysAssociation();
+ void RemoveMediaKeys();
+ bool AttachNewMediaKeys();
+ bool TryMakeAssociationWithCDM(CDMProxy* aProxy);
+ void MakeAssociationWithCDMResolved();
+ void SetCDMProxyFailure(const MediaResult& aResult);
+ void ResetSetMediaKeysTempVariables();
+
+ void PauseIfShouldNotBePlaying();
+
+ WatchManager<HTMLMediaElement> mWatchManager;
+
+ // When the play is not allowed, dispatch related events which are used for
+ // testing or changing control UI.
+ void DispatchEventsWhenPlayWasNotAllowed();
+
+ // When the doc is blocked permanantly, we would dispatch event to notify
+ // front-end side to show blocking icon.
+ void MaybeNotifyAutoplayBlocked();
+
+ // Dispatch event for video control when video gets blocked in order to show
+ // the click-to-play icon.
+ void DispatchBlockEventForVideoControl();
+
+ // When playing state change, we have to notify MediaControl in the chrome
+ // process in order to keep its playing state correct.
+ void NotifyMediaControlPlaybackStateChanged();
+
+ // Clear the timer when we want to continue listening to the media control
+ // key events.
+ void ClearStopMediaControlTimerIfNeeded();
+
+ // Sets a secondary renderer for mSrcStream, so this media element can be
+ // rendered in Picture-in-Picture mode when playing a MediaStream. A null
+ // aContainer will unset the secondary renderer. aFirstFrameOutput allows
+ // for injecting a listener of the callers choice for rendering the first
+ // frame.
+ void SetSecondaryMediaStreamRenderer(
+ VideoFrameContainer* aContainer,
+ FirstFrameVideoOutput* aFirstFrameOutput = nullptr);
+
+ // This function is used to update the status of media control when the media
+ // changes its status of being used in the Picture-in-Picture mode.
+ void UpdateMediaControlAfterPictureInPictureModeChanged();
+
+ // The current decoder. Load() has been called on this decoder.
+ // At most one of mDecoder and mSrcStream can be non-null.
+ RefPtr<MediaDecoder> mDecoder;
+
+ // A reference to the VideoFrameContainer which contains the current frame
+ // of video to display.
+ RefPtr<VideoFrameContainer> mVideoFrameContainer;
+
+ // Holds a reference to the MediaStream that has been set in the src
+ // attribute.
+ RefPtr<DOMMediaStream> mSrcAttrStream;
+
+ // Holds the triggering principal for the src attribute.
+ nsCOMPtr<nsIPrincipal> mSrcAttrTriggeringPrincipal;
+
+ // Holds a reference to the MediaStream that we're actually playing.
+ // At most one of mDecoder and mSrcStream can be non-null.
+ RefPtr<DOMMediaStream> mSrcStream;
+
+ // The MediaStreamRenderer handles rendering of our selected video track, and
+ // enabled audio tracks, while mSrcStream is set.
+ RefPtr<MediaStreamRenderer> mMediaStreamRenderer;
+
+ // The secondary MediaStreamRenderer handles rendering of our selected video
+ // track to a secondary VideoFrameContainer, while mSrcStream is set.
+ RefPtr<MediaStreamRenderer> mSecondaryMediaStreamRenderer;
+
+ // True once PlaybackEnded() is called and we're playing a MediaStream.
+ // Reset to false if we start playing mSrcStream again.
+ Watchable<bool> mSrcStreamPlaybackEnded = {
+ false, "HTMLMediaElement::mSrcStreamPlaybackEnded"};
+
+ // Mirrors mSrcStreamPlaybackEnded after a tail dispatch when set to true,
+ // but may be be forced to false directly. To accomodate when an application
+ // ends playback synchronously by manipulating mSrcStream or its tracks,
+ // e.g., through MediaStream.removeTrack(), or MediaStreamTrack.stop().
+ bool mSrcStreamReportPlaybackEnded = false;
+
+ // Holds a reference to the stream connecting this stream to the window
+ // capture sink.
+ UniquePtr<MediaStreamWindowCapturer> mStreamWindowCapturer;
+
+ // Holds references to the DOM wrappers for the MediaStreams that we're
+ // writing to.
+ nsTArray<OutputMediaStream> mOutputStreams;
+
+ // Mapping for output tracks, from dom::MediaTrack ids to the
+ // MediaElementTrackSource that represents the source of all corresponding
+ // MediaStreamTracks captured from this element.
+ nsRefPtrHashtable<nsStringHashKey, MediaElementTrackSource>
+ mOutputTrackSources;
+
+ // The currently selected video stream track.
+ RefPtr<VideoStreamTrack> mSelectedVideoStreamTrack;
+
+ const RefPtr<ShutdownObserver> mShutdownObserver;
+
+ const RefPtr<TitleChangeObserver> mTitleChangeObserver;
+
+ // Holds a reference to the MediaSource, if any, referenced by the src
+ // attribute on the media element.
+ RefPtr<MediaSource> mSrcMediaSource;
+
+ // Holds a reference to the MediaSource supplying data for playback. This
+ // may either match mSrcMediaSource or come from Source element children.
+ // This is set when and only when mLoadingSrc corresponds to an object url
+ // that resolved to a MediaSource.
+ RefPtr<MediaSource> mMediaSource;
+
+ RefPtr<ChannelLoader> mChannelLoader;
+
+ // Points to the child source elements, used to iterate through the children
+ // when selecting a resource to load. This is the previous sibling of the
+ // child considered the current 'candidate' in:
+ // https://html.spec.whatwg.org/multipage/media.html#concept-media-load-algorithm
+ //
+ // mSourcePointer == nullptr, we will next try to load |GetFirstChild()|.
+ // mSourcePointer == GetLastChild(), we've exhausted all sources, waiting
+ // for new elements to be appended.
+ nsCOMPtr<nsIContent> mSourcePointer;
+
+ // Points to the document whose load we're blocking. This is the document
+ // we're bound to when loading starts.
+ nsCOMPtr<Document> mLoadBlockedDoc;
+
+ // This is used to help us block/resume the event delivery.
+ class EventBlocker;
+ RefPtr<EventBlocker> mEventBlocker;
+
+ // Media loading flags. See:
+ // http://www.whatwg.org/specs/web-apps/current-work/#video)
+ nsMediaNetworkState mNetworkState = HTMLMediaElement_Binding::NETWORK_EMPTY;
+ Watchable<nsMediaReadyState> mReadyState = {
+ HTMLMediaElement_Binding::HAVE_NOTHING, "HTMLMediaElement::mReadyState"};
+
+ enum LoadAlgorithmState {
+ // No load algorithm instance is waiting for a source to be added to the
+ // media in order to continue loading.
+ NOT_WAITING,
+ // We've run the load algorithm, and we tried all source children of the
+ // media element, and failed to load any successfully. We're waiting for
+ // another source element to be added to the media element, and will try
+ // to load any such element when its added.
+ WAITING_FOR_SOURCE
+ };
+
+ // The current media load ID. This is incremented every time we start a
+ // new load. Async events note the ID when they're first sent, and only fire
+ // if the ID is unchanged when they come to fire.
+ uint32_t mCurrentLoadID = 0;
+
+ // Denotes the waiting state of a load algorithm instance. When the load
+ // algorithm is waiting for a source element child to be added, this is set
+ // to WAITING_FOR_SOURCE, otherwise it's NOT_WAITING.
+ LoadAlgorithmState mLoadWaitStatus = NOT_WAITING;
+
+ // Current audio volume
+ double mVolume = 1.0;
+
+ // True if the audio track is not silent.
+ bool mIsAudioTrackAudible = false;
+
+ enum MutedReasons {
+ MUTED_BY_CONTENT = 0x01,
+ MUTED_BY_INVALID_PLAYBACK_RATE = 0x02,
+ MUTED_BY_AUDIO_CHANNEL = 0x04,
+ MUTED_BY_AUDIO_TRACK = 0x08
+ };
+
+ uint32_t mMuted = 0;
+
+ UniquePtr<const MetadataTags> mTags;
+
+ // URI of the resource we're attempting to load. This stores the value we
+ // return in the currentSrc attribute. Use GetCurrentSrc() to access the
+ // currentSrc attribute.
+ // This is always the original URL we're trying to load --- before
+ // redirects etc.
+ nsCOMPtr<nsIURI> mLoadingSrc;
+
+ // The triggering principal for the current source.
+ nsCOMPtr<nsIPrincipal> mLoadingSrcTriggeringPrincipal;
+
+ // Stores the current preload action for this element. Initially set to
+ // PRELOAD_UNDEFINED, its value is changed by calling
+ // UpdatePreloadAction().
+ PreloadAction mPreloadAction = PRELOAD_UNDEFINED;
+
+ // Time that the last timeupdate event was queued. Read/Write from the
+ // main thread only.
+ TimeStamp mQueueTimeUpdateRunnerTime;
+
+ // Time that the last timeupdate event was fired. Read/Write from the
+ // main thread only.
+ TimeStamp mLastTimeUpdateDispatchTime;
+
+ // Time that the last progress event was fired. Read/Write from the
+ // main thread only.
+ TimeStamp mProgressTime;
+
+ // Time that data was last read from the media resource. Used for
+ // computing if the download has stalled and to rate limit progress events
+ // when data is arriving slower than PROGRESS_MS.
+ // Read/Write from the main thread only.
+ TimeStamp mDataTime;
+
+ // Media 'currentTime' value when the last timeupdate event was queued.
+ // Read/Write from the main thread only.
+ double mLastCurrentTime = 0.0;
+
+ // Logical start time of the media resource in seconds as obtained
+ // from any media fragments. A negative value indicates that no
+ // fragment time has been set. Read/Write from the main thread only.
+ double mFragmentStart = -1.0;
+
+ // Logical end time of the media resource in seconds as obtained
+ // from any media fragments. A negative value indicates that no
+ // fragment time has been set. Read/Write from the main thread only.
+ double mFragmentEnd = -1.0;
+
+ // The defaultPlaybackRate attribute gives the desired speed at which the
+ // media resource is to play, as a multiple of its intrinsic speed.
+ double mDefaultPlaybackRate = 1.0;
+
+ // The playbackRate attribute gives the speed at which the media resource
+ // plays, as a multiple of its intrinsic speed. If it is not equal to the
+ // defaultPlaybackRate, then the implication is that the user is using a
+ // feature such as fast forward or slow motion playback.
+ double mPlaybackRate = 1.0;
+
+ // True if pitch correction is applied when playbackRate is set to a
+ // non-intrinsic value.
+ bool mPreservesPitch = true;
+
+ // Reference to the source element last returned by GetNextSource().
+ // This is the child source element which we're trying to load from.
+ nsCOMPtr<nsIContent> mSourceLoadCandidate;
+
+ // Range of time played.
+ RefPtr<TimeRanges> mPlayed;
+
+ // Timer used for updating progress events.
+ nsCOMPtr<nsITimer> mProgressTimer;
+
+ // Encrypted Media Extension media keys.
+ RefPtr<MediaKeys> mMediaKeys;
+ RefPtr<MediaKeys> mIncomingMediaKeys;
+ // The dom promise is used for HTMLMediaElement::SetMediaKeys.
+ RefPtr<DetailedPromise> mSetMediaKeysDOMPromise;
+ // Used to indicate if the MediaKeys attaching operation is on-going or not.
+ bool mAttachingMediaKey = false;
+ MozPromiseRequestHolder<SetCDMPromise> mSetCDMRequest;
+
+ // Stores the time at the start of the current 'played' range.
+ double mCurrentPlayRangeStart = 1.0;
+
+ // True if loadeddata has been fired.
+ bool mLoadedDataFired = false;
+
+ // One of the factors determines whether a media element with 'autoplay'
+ // attribute is allowed to start playing.
+ // https://html.spec.whatwg.org/multipage/media.html#can-autoplay-flag
+ bool mCanAutoplayFlag = true;
+
+ // Playback of the video is paused either due to calling the
+ // 'Pause' method, or playback not yet having started.
+ Watchable<bool> mPaused = {true, "HTMLMediaElement::mPaused"};
+
+ // The following two fields are here for the private storage of the builtin
+ // video controls, and control 'casting' of the video to external devices
+ // (TVs, projectors etc.)
+ // True if casting is currently allowed
+ bool mAllowCasting = false;
+ // True if currently casting this video
+ bool mIsCasting = false;
+
+ // Set while there are some OutputMediaStreams this media element's enabled
+ // and selected tracks are captured into. When set, all tracks are captured
+ // into the graph of this dummy track.
+ // NB: This is a SharedDummyTrack to allow non-default graphs (AudioContexts
+ // with an explicit sampleRate defined) to capture this element. When
+ // cross-graph tracks are supported, this can become a bool.
+ Watchable<RefPtr<SharedDummyTrack>> mTracksCaptured;
+
+ // True if the sound is being captured.
+ bool mAudioCaptured = false;
+
+ // If TRUE then the media element was actively playing before the currently
+ // in progress seeking. If FALSE then the media element is either not seeking
+ // or was not actively playing before the current seek. Used to decide whether
+ // to raise the 'waiting' event as per 4.7.1.8 in HTML 5 specification.
+ bool mPlayingBeforeSeek = false;
+
+ // True if this element is suspended because the document is inactive or the
+ // inactive docshell is not allowing media to play.
+ bool mSuspendedByInactiveDocOrDocshell = false;
+
+ // True if we're running the "load()" method.
+ bool mIsRunningLoadMethod = false;
+
+ // True if we're running or waiting to run queued tasks due to an explicit
+ // call to "load()".
+ bool mIsDoingExplicitLoad = false;
+
+ // True if we're loading the resource from the child source elements.
+ bool mIsLoadingFromSourceChildren = false;
+
+ // True if we're delaying the "load" event. They are delayed until either
+ // an error occurs, or the first frame is loaded.
+ bool mDelayingLoadEvent = false;
+
+ // True when we've got a task queued to call SelectResource(),
+ // or while we're running SelectResource().
+ bool mIsRunningSelectResource = false;
+
+ // True when we already have select resource call queued
+ bool mHaveQueuedSelectResource = false;
+
+ // True if we suspended the decoder because we were paused,
+ // preloading metadata is enabled, autoplay was not enabled, and we loaded
+ // the first frame.
+ bool mSuspendedAfterFirstFrame = false;
+
+ // True if we are allowed to suspend the decoder because we were paused,
+ // preloading metdata was enabled, autoplay was not enabled, and we loaded
+ // the first frame.
+ bool mAllowSuspendAfterFirstFrame = true;
+
+ // True if we've played or completed a seek. We use this to determine
+ // when the poster frame should be shown.
+ bool mHasPlayedOrSeeked = false;
+
+ // True if we've added a reference to ourselves to keep the element
+ // alive while no-one is referencing it but the element may still fire
+ // events of its own accord.
+ bool mHasSelfReference = false;
+
+ // True if we've received a notification that the engine is shutting
+ // down.
+ bool mShuttingDown = false;
+
+ // True if we've suspended a load in the resource selection algorithm
+ // due to loading a preload:none media. When true, the resource we'll
+ // load when the user initiates either playback or an explicit load is
+ // stored in mPreloadURI.
+ bool mSuspendedForPreloadNone = false;
+
+ // True if we've connected mSrcStream to the media element output.
+ bool mSrcStreamIsPlaying = false;
+
+ // True if we should set nsIClassOfService::UrgentStart to the channel to
+ // get the response ASAP for better user responsiveness.
+ bool mUseUrgentStartForChannel = false;
+
+ // The CORS mode when loading the media element
+ CORSMode mCORSMode = CORS_NONE;
+
+ // Info about the played media.
+ MediaInfo mMediaInfo;
+
+ // True if the media has encryption information.
+ bool mIsEncrypted = false;
+
+ enum WaitingForKeyState {
+ NOT_WAITING_FOR_KEY = 0,
+ WAITING_FOR_KEY = 1,
+ WAITING_FOR_KEY_DISPATCHED = 2
+ };
+
+ // True when the CDM cannot decrypt the current block due to lacking a key.
+ // Note: the "waitingforkey" event is not dispatched until all decoded data
+ // has been rendered.
+ WaitingForKeyState mWaitingForKey = NOT_WAITING_FOR_KEY;
+
+ // Listens for waitingForKey events from the owned decoder.
+ MediaEventListener mWaitingForKeyListener;
+
+ // Init Data that needs to be sent in 'encrypted' events in MetadataLoaded().
+ EncryptionInfo mPendingEncryptedInitData;
+
+ // True if the media's channel's download has been suspended.
+ Watchable<bool> mDownloadSuspendedByCache = {
+ false, "HTMLMediaElement::mDownloadSuspendedByCache"};
+
+ // Disable the video playback by track selection. This flag might not be
+ // enough if we ever expand the ability of supporting multi-tracks video
+ // playback.
+ bool mDisableVideo = false;
+
+ RefPtr<TextTrackManager> mTextTrackManager;
+
+ RefPtr<AudioTrackList> mAudioTrackList;
+
+ RefPtr<VideoTrackList> mVideoTrackList;
+
+ UniquePtr<MediaStreamTrackListener> mMediaStreamTrackListener;
+
+ // The principal guarding mVideoFrameContainer access when playing a
+ // MediaStream.
+ nsCOMPtr<nsIPrincipal> mSrcStreamVideoPrincipal;
+
+ // True if the autoplay media was blocked because it hadn't loaded metadata
+ // yet.
+ bool mBlockedAsWithoutMetadata = false;
+
+ // This promise is used to notify MediaElementAudioSourceNode that media
+ // element is allowed to play when MediaElement is used as a source for web
+ // audio.
+ MozPromiseHolder<GenericNonExclusivePromise> mAllowedToPlayPromise;
+
+ // True if media has ever been blocked for autoplay, it's used to notify front
+ // end to show the correct blocking icon when the document goes back from
+ // bfcache.
+ bool mHasEverBeenBlockedForAutoplay = false;
+
+ // True if we have dispatched a task for text track changed, will be unset
+ // when we starts processing text track changed.
+ // https://html.spec.whatwg.org/multipage/media.html#pending-text-track-change-notification-flag
+ bool mPendingTextTrackChanged = false;
+
+ public:
+ // This function will be called whenever a text track that is in a media
+ // element's list of text tracks has its text track mode change value
+ void NotifyTextTrackModeChanged();
+
+ private:
+ friend class nsMediaEventRunner;
+ friend class nsResolveOrRejectPendingPlayPromisesRunner;
+
+ already_AddRefed<PlayPromise> CreatePlayPromise(ErrorResult& aRv) const;
+
+ virtual void MaybeBeginCloningVisually(){};
+
+ uint32_t GetPreloadDefault() const;
+ uint32_t GetPreloadDefaultAuto() const;
+
+ /**
+ * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
+ * It will not be called if the value is being unset.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aNotify Whether we plan to notify document observers.
+ */
+ void AfterMaybeChangeAttr(int32_t aNamespaceID, nsAtom* aName, bool aNotify);
+
+ // True if Init() has been called after construction
+ bool mInitialized = false;
+
+ // True if user has called load(), seek() or element has started playing
+ // before. It's *only* use for `click-to-play` blocking autoplay policy.
+ // In addition, we would reset this once media aborts current load.
+ bool mIsBlessed = false;
+
+ // True if the first frame has been successfully loaded.
+ Watchable<bool> mFirstFrameLoaded = {false,
+ "HTMLMediaElement::mFirstFrameLoaded"};
+
+ // Media elements also have a default playback start position, which must
+ // initially be set to zero seconds. This time is used to allow the element to
+ // be seeked even before the media is loaded.
+ double mDefaultPlaybackStartPosition = 0.0;
+
+ // True if media element has been marked as 'tainted' and can't
+ // participate in video decoder suspending.
+ bool mHasSuspendTaint = false;
+
+ // True if media element has been forced into being considered 'hidden'.
+ // For use by mochitests. Enabling pref "media.test.video-suspend"
+ bool mForcedHidden = false;
+
+ Visibility mVisibilityState = Visibility::Untracked;
+
+ UniquePtr<ErrorSink> mErrorSink;
+
+ // This wrapper will handle all audio channel related stuffs, eg. the
+ // operations of tab audio indicator, Fennec's media control. Note:
+ // mAudioChannelWrapper might be null after GC happened.
+ RefPtr<AudioChannelAgentCallback> mAudioChannelWrapper;
+
+ // A list of pending play promises. The elements are pushed during the play()
+ // method call and are resolved/rejected during further playback steps.
+ nsTArray<RefPtr<PlayPromise>> mPendingPlayPromises;
+
+ // A list of already-dispatched but not yet run
+ // nsResolveOrRejectPendingPlayPromisesRunners.
+ // Runners whose Run() method is called remove themselves from this list.
+ // We keep track of these because the load algorithm resolves/rejects all
+ // already-dispatched pending play promises.
+ nsTArray<nsResolveOrRejectPendingPlayPromisesRunner*>
+ mPendingPlayPromisesRunners;
+
+ // A pending seek promise which is created at Seek() method call and is
+ // resolved/rejected at AsyncResolveSeekDOMPromiseIfExists()/
+ // AsyncRejectSeekDOMPromiseIfExists() methods.
+ RefPtr<dom::Promise> mSeekDOMPromise;
+
+ // Return true if the docshell is inactive and explicitly wants to stop media
+ // playing in that shell.
+ bool ShouldBeSuspendedByInactiveDocShell() const;
+
+ // For debugging bug 1407148.
+ void AssertReadyStateIsNothing();
+
+ // Contains the unique id of the sink device and the device info.
+ // The initial value is ("", nullptr) and the default output device is used.
+ // It can contain an invalid id and info if the device has been
+ // unplugged. It can be set to ("", nullptr). It follows the spec attribute:
+ // https://w3c.github.io/mediacapture-output/#htmlmediaelement-extensions
+ // Read/Write from the main thread only.
+ std::pair<nsString, RefPtr<AudioDeviceInfo>> mSink;
+
+ // This flag is used to control when the user agent is to show a poster frame
+ // for a video element instead of showing the video contents.
+ // https://html.spec.whatwg.org/multipage/media.html#show-poster-flag
+ bool mShowPoster;
+
+ // We may delay starting playback of a media for an unvisited tab until it's
+ // going to foreground. We would create ResumeDelayedMediaPlaybackAgent to
+ // handle related operations at the time whenever delaying media playback is
+ // needed.
+ void CreateResumeDelayedMediaPlaybackAgentIfNeeded();
+ void ClearResumeDelayedMediaPlaybackAgentIfNeeded();
+ RefPtr<ResumeDelayedPlaybackAgent> mResumeDelayedPlaybackAgent;
+ MozPromiseRequestHolder<ResumeDelayedPlaybackAgent::ResumePromise>
+ mResumePlaybackRequest;
+
+ // Return true if we have already a decoder or a src stream and don't have any
+ // error.
+ bool IsPlayable() const;
+
+ // Return true if the media qualifies for being controlled by media control
+ // keys.
+ bool ShouldStartMediaControlKeyListener() const;
+
+ // Start the listener if media fits the requirement of being able to be
+ // controlled be media control keys.
+ void StartMediaControlKeyListenerIfNeeded();
+
+ // It's used to listen media control key, by which we would play or pause
+ // media element.
+ RefPtr<MediaControlKeyListener> mMediaControlKeyListener;
+
+ // Method to update audio stream name
+ void UpdateStreamName();
+
+ // Return true if the media element is being used in picture in picture mode.
+ bool IsBeingUsedInPictureInPictureMode() const;
+
+ // Return true if we should queue a 'timeupdate' event runner to main thread.
+ bool ShouldQueueTimeupdateAsyncTask(TimeupdateType aType) const;
+
+#ifdef MOZ_WMF_CDM
+ // It's used to record telemetry probe for WMFCDM playback.
+ bool mIsUsingWMFCDM = false;
+#endif
+};
+
+// Check if the context is chrome or has the debugger or tabs permission
+bool HasDebuggerOrTabsPrivilege(JSContext* aCx, JSObject* aObj);
+
+} // namespace mozilla::dom
+
+#endif // mozilla_dom_HTMLMediaElement_h