mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 00:32:11 +00:00
608d91f684
Differential Revision: https://phabricator.services.mozilla.com/D189750
1941 lines
69 KiB
C++
1941 lines
69 KiB
C++
/* -*- 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; }
|
|
|
|
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;
|
|
|
|
nsISerialEventTarget* MainThreadEventTarget() {
|
|
return mMainThreadEventTarget;
|
|
}
|
|
|
|
// 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.
|
|
*/
|
|
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;
|
|
|
|
// The DocGroup-specific nsISerialEventTarget of this HTML element on the main
|
|
// thread.
|
|
nsCOMPtr<nsISerialEventTarget> mMainThreadEventTarget;
|
|
|
|
// The DocGroup-specific AbstractThread::MainThread() of this HTML element.
|
|
RefPtr<AbstractThread> mAbstractMainThread;
|
|
|
|
// 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;
|
|
};
|
|
|
|
// 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
|