gecko-dev/dom/media/MediaDecoder.h
Bryce Van Dyk 939ab2b661 Bug 657791 - Update seekable range handling for cueless WebMs. r=kinetik
MediaDecoder previously had 3 states within GetSeekable(), media is either
seekable, seekable but not supported by transport, or not seekable. Due to
changes to make cueless webms playable, a 4th option is needed: a file that is
not fully seekable, but may support seeking from the transport, such as these
webms, should only be seekable in the buffered range.

MozReview-Commit-ID: ISeFkngtrGU
2016-02-04 17:31:21 +13:00

896 lines
31 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(MediaDecoder_h_)
#define MediaDecoder_h_
#ifdef MOZ_EME
#include "mozilla/CDMProxy.h"
#endif
#include "mozilla/Atomics.h"
#include "mozilla/MozPromise.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/StateMirroring.h"
#include "mozilla/StateWatching.h"
#include "mozilla/dom/AudioChannelBinding.h"
#include "necko-config.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsIObserver.h"
#include "nsISupports.h"
#include "nsITimer.h"
#include "AbstractMediaDecoder.h"
#include "FrameStatistics.h"
#include "MediaDecoderOwner.h"
#include "MediaEventSource.h"
#include "MediaMetadataManager.h"
#include "MediaResource.h"
#include "MediaResourceCallback.h"
#include "MediaStatistics.h"
#include "MediaStreamGraph.h"
#include "TimeUnits.h"
#include "SeekTarget.h"
class nsIStreamListener;
class nsIPrincipal;
namespace mozilla {
class VideoFrameContainer;
class MediaDecoderStateMachine;
enum class MediaEventType : int8_t;
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount() and conflicts with MediaDecoder::GetCurrentTime implementation.
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif
class MediaDecoder : public AbstractMediaDecoder
{
public:
struct SeekResolveValue {
SeekResolveValue(bool aAtEnd, MediaDecoderEventVisibility aEventVisibility)
: mAtEnd(aAtEnd), mEventVisibility(aEventVisibility) {}
bool mAtEnd;
MediaDecoderEventVisibility mEventVisibility;
};
// Used to register with MediaResource to receive notifications which will
// be forwarded to MediaDecoder.
class ResourceCallback : public MediaResourceCallback {
public:
// Start to receive notifications from ResourceCallback.
void Connect(MediaDecoder* aDecoder);
// Called upon shutdown to stop receiving notifications.
void Disconnect();
private:
/* MediaResourceCallback functions */
MediaDecoderOwner* GetMediaOwner() const override;
void SetInfinite(bool aInfinite) override;
void SetMediaSeekable(bool aMediaSeekable) override;
void ResetConnectionState() override;
nsresult FinishDecoderSetup(MediaResource* aResource) override;
void NotifyNetworkError() override;
void NotifyDecodeError() override;
void NotifyDataArrived() override;
void NotifyBytesDownloaded() override;
void NotifyDataEnded(nsresult aStatus) override;
void NotifyPrincipalChanged() override;
void NotifySuspendedStatusChanged() override;
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) override;
// The decoder to send notifications. Main-thread only.
MediaDecoder* mDecoder = nullptr;
};
typedef MozPromise<SeekResolveValue, bool /* aIgnored */, /* IsExclusive = */ true> SeekPromise;
NS_DECL_THREADSAFE_ISUPPORTS
// Enumeration for the valid play states (see mPlayState)
enum PlayState {
PLAY_STATE_START,
PLAY_STATE_LOADING,
PLAY_STATE_PAUSED,
PLAY_STATE_PLAYING,
PLAY_STATE_ENDED,
PLAY_STATE_SHUTDOWN
};
// Must be called exactly once, on the main thread, during startup.
static void InitStatics();
explicit MediaDecoder(MediaDecoderOwner* aOwner);
// Return a callback object used to register with MediaResource to receive
// notifications.
MediaResourceCallback* GetResourceCallback() const;
// Create a new decoder of the same type as this one.
// Subclasses must implement this.
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) = 0;
// Create a new state machine to run this decoder.
// Subclasses must implement this.
virtual MediaDecoderStateMachine* CreateStateMachine() = 0;
// Cleanup internal data structures. Must be called on the main
// thread by the owning object before that object disposes of this object.
virtual RefPtr<ShutdownPromise> Shutdown();
// Start downloading the media. Decode the downloaded data up to the
// point of the first frame of data.
// This is called at most once per decoder, after Init().
virtual nsresult Load(nsIStreamListener** aListener);
// Called in |Load| to open mResource.
nsresult OpenResource(nsIStreamListener** aStreamListener);
// Called if the media file encounters a network error.
void NetworkError();
// Get the current MediaResource being used. Its URI will be returned
// by currentSrc. Returns what was passed to Load(), if Load() has been called.
// Note: The MediaResource is refcounted, but it outlives the MediaDecoder,
// so it's OK to use the reference returned by this function without
// refcounting, *unless* you need to store and use the reference after the
// MediaDecoder has been destroyed. You might need to do this if you're
// wrapping the MediaResource in some kind of byte stream interface to be
// passed to a platform decoder.
MediaResource* GetResource() const final override
{
return mResource;
}
void SetResource(MediaResource* aResource)
{
MOZ_ASSERT(NS_IsMainThread());
mResource = aResource;
}
// Return the principal of the current URI being played or downloaded.
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
// Return the time position in the video stream being
// played measured in seconds.
virtual double GetCurrentTime();
// Seek to the time position in (seconds) from the start of the video.
// If aDoFastSeek is true, we'll seek to the sync point/keyframe preceeding
// the seek target.
virtual nsresult Seek(double aTime, SeekTarget::Type aSeekType);
// Initialize state machine and schedule it.
nsresult InitializeStateMachine();
// Start playback of a video. 'Load' must have previously been
// called.
virtual nsresult Play();
// Notify activity of the decoder owner is changed.
// Based on the activity, dormant state is updated.
// Dormant state is a state to free all scarce media resources
// (like hw video codec), did not decoding and stay dormant.
// It is used to share scarece media resources in system.
virtual void NotifyOwnerActivityChanged();
void UpdateDormantState(bool aDormantTimeout, bool aActivity);
// Pause video playback.
virtual void Pause();
// Adjust the speed of the playback, optionally with pitch correction,
virtual void SetVolume(double aVolume);
virtual void SetPlaybackRate(double aPlaybackRate);
void SetPreservesPitch(bool aPreservesPitch);
// Directs the decoder to not preroll extra samples until the media is
// played. This reduces the memory overhead of media elements that may
// not be played. Note that seeking also doesn't cause us start prerolling.
void SetMinimizePrerollUntilPlaybackStarts();
// All MediaStream-related data is protected by mReentrantMonitor.
// We have at most one DecodedStreamData per MediaDecoder. Its stream
// is used as the input for each ProcessedMediaStream created by calls to
// captureStream(UntilEnded). Seeking creates a new source stream, as does
// replaying after the input as ended. In the latter case, the new source is
// not connected to streams created by captureStreamUntilEnded.
// Add an output stream. All decoder output will be sent to the stream.
// The stream is initially blocked. The decoder is responsible for unblocking
// it while it is playing back.
virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
// Remove an output stream added with AddOutputStream.
virtual void RemoveOutputStream(MediaStream* aStream);
// Return the duration of the video in seconds.
virtual double GetDuration();
// Return true if the stream is infinite (see SetInfinite).
virtual bool IsInfinite();
// Called by MediaResource when some data has been received.
// Call on the main thread only.
virtual void NotifyBytesDownloaded();
// Called as data arrives on the stream and is read into the cache. Called
// on the main thread only.
void NotifyDataArrived();
// Return true if we are currently seeking in the media resource.
// Call on the main thread only.
virtual bool IsSeeking() const;
// Return true if the decoder has reached the end of playback or the decoder
// has shutdown.
// Call on the main thread only.
virtual bool IsEndedOrShutdown() const;
// Return true if the MediaDecoderOwner's error attribute is not null.
// If the MediaDecoder is shutting down, OwnerHasError will return true.
bool OwnerHasError() const;
protected:
// Updates the media duration. This is called while the media is being
// played, calls before the media has reached loaded metadata are ignored.
// The duration is assumed to be an estimate, and so a degree of
// instability is expected; if the incoming duration is not significantly
// different from the existing duration, the change request is ignored.
// If the incoming duration is significantly different, the duration is
// changed, this causes a durationchanged event to fire to the media
// element.
void UpdateEstimatedMediaDuration(int64_t aDuration) override;
public:
// Called from HTMLMediaElement when owner document activity changes
virtual void SetElementVisibility(bool aIsVisible) {}
// Set a flag indicating whether random seeking is supported
void SetMediaSeekable(bool aMediaSeekable);
// Set a flag indicating whether seeking is supported only in buffered ranges
void SetMediaSeekableOnlyInBufferedRanges(bool aMediaSeekableOnlyInBufferedRanges);
// Returns true if this media supports random seeking. False for example with
// chained ogg files.
bool IsMediaSeekable();
// Returns true if this media supports seeking only in buffered ranges. True
// for example in WebMs with no cues
bool IsMediaSeekableOnlyInBufferedRanges();
// Returns true if seeking is supported on a transport level (e.g. the server
// supports range requests, we are playing a file, etc.).
bool IsTransportSeekable();
// Return the time ranges that can be seeked into.
virtual media::TimeIntervals GetSeekable();
// Set the end time of the media resource. When playback reaches
// this point the media pauses. aTime is in seconds.
virtual void SetFragmentEndTime(double aTime);
// Invalidate the frame.
void Invalidate();
void InvalidateWithFlags(uint32_t aFlags);
// Suspend any media downloads that are in progress. Called by the
// media element when it is sent to the bfcache, or when we need
// to throttle the download. Call on the main thread only. This can
// be called multiple times, there's an internal "suspend count".
virtual void Suspend();
// Resume any media downloads that have been suspended. Called by the
// media element when it is restored from the bfcache, or when we need
// to stop throttling the download. Call on the main thread only.
// The download will only actually resume once as many Resume calls
// have been made as Suspend calls.
virtual void Resume();
// Moves any existing channel loads into or out of background. Background
// loads don't block the load event. This is called when we stop or restart
// delaying the load event. This also determines whether any new loads
// initiated (for example to seek) will be in the background. This calls
// SetLoadInBackground() on mResource.
void SetLoadInBackground(bool aLoadInBackground);
MediaDecoderStateMachine* GetStateMachine() const;
void SetStateMachine(MediaDecoderStateMachine* aStateMachine);
// Constructs the time ranges representing what segments of the media
// are buffered and playable.
virtual media::TimeIntervals GetBuffered();
// Returns the size, in bytes, of the heap memory used by the currently
// queued decoded video and audio data.
size_t SizeOfVideoQueue();
size_t SizeOfAudioQueue();
// Helper struct for accumulating resource sizes that need to be measured
// asynchronously. Once all references are dropped the callback will be
// invoked.
struct ResourceSizes
{
typedef MozPromise<size_t, size_t, true> SizeOfPromise;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ResourceSizes)
explicit ResourceSizes(MallocSizeOf aMallocSizeOf)
: mMallocSizeOf(aMallocSizeOf)
, mByteSize(0)
, mCallback()
{
}
mozilla::MallocSizeOf mMallocSizeOf;
mozilla::Atomic<size_t> mByteSize;
RefPtr<SizeOfPromise> Promise()
{
return mCallback.Ensure(__func__);
}
private:
~ResourceSizes()
{
mCallback.ResolveIfExists(mByteSize, __func__);
}
MozPromiseHolder<SizeOfPromise> mCallback;
};
virtual void AddSizeOfResources(ResourceSizes* aSizes);
VideoFrameContainer* GetVideoFrameContainer() final override
{
return mVideoFrameContainer;
}
layers::ImageContainer* GetImageContainer() override;
// Fire timeupdate events if needed according to the time constraints
// outlined in the specification.
void FireTimeUpdate();
// Something has changed that could affect the computed playback rate,
// so recompute it. The monitor must be held.
virtual void UpdatePlaybackRate();
// The actual playback rate computation. The monitor must be held.
void ComputePlaybackRate();
// Returns true if we can play the entire media through without stopping
// to buffer, given the current download and playback rates.
virtual bool CanPlayThrough();
void SetAudioChannel(dom::AudioChannel aChannel) { mAudioChannel = aChannel; }
dom::AudioChannel GetAudioChannel() { return mAudioChannel; }
/******
* The following methods must only be called on the main
* thread.
******/
// Change to a new play state. This updates the mState variable and
// notifies any thread blocking on this object's monitor of the
// change. Call on the main thread only.
virtual void ChangeState(PlayState aState);
// Called from MetadataLoaded(). Creates audio tracks and adds them to its
// owner's audio track list, and implies to video tracks respectively.
// Call on the main thread only.
void ConstructMediaTracks();
// Removes all audio tracks and video tracks that are previously added into
// the track list. Call on the main thread only.
void RemoveMediaTracks();
// Called when the video has completed playing.
// Call on the main thread only.
void PlaybackEnded();
void OnSeekRejected()
{
MOZ_ASSERT(NS_IsMainThread());
mSeekRequest.Complete();
mLogicallySeeking = false;
}
void OnSeekResolved(SeekResolveValue aVal);
void SeekingChanged()
{
// Stop updating the bytes downloaded for progress notifications when
// seeking to prevent wild changes to the progress notification.
MOZ_ASSERT(NS_IsMainThread());
mIgnoreProgressData = mLogicallySeeking;
}
// Seeking has started. Inform the element on the main
// thread.
void SeekingStarted(MediaDecoderEventVisibility aEventVisibility = MediaDecoderEventVisibility::Observable);
void UpdateLogicalPosition(MediaDecoderEventVisibility aEventVisibility);
void UpdateLogicalPosition()
{
MOZ_ASSERT(NS_IsMainThread());
UpdateLogicalPosition(MediaDecoderEventVisibility::Observable);
}
// Find the end of the cached data starting at the current decoder
// position.
int64_t GetDownloadPosition();
// Notifies the element that decoding has failed.
void DecodeError();
// Indicate whether the media is same-origin with the element.
void UpdateSameOriginStatus(bool aSameOrigin);
MediaDecoderOwner* GetOwner() override;
#ifdef MOZ_EME
typedef MozPromise<RefPtr<CDMProxy>, bool /* aIgnored */, /* IsExclusive = */ true> CDMProxyPromise;
// Resolved when a CDMProxy is available and the capabilities are known or
// rejected when this decoder is about to shut down.
RefPtr<CDMProxyPromise> RequestCDMProxy() const;
void SetCDMProxy(CDMProxy* aProxy);
#endif
void EnsureTelemetryReported();
#ifdef MOZ_RAW
static bool IsRawEnabled();
#endif
static bool IsOggEnabled();
static bool IsOpusEnabled();
static bool IsWaveEnabled();
static bool IsWebMEnabled();
#ifdef NECKO_PROTOCOL_rtsp
static bool IsRtspEnabled();
#endif
#ifdef MOZ_OMX_DECODER
static bool IsOmxEnabled();
#endif
#ifdef MOZ_ANDROID_OMX
static bool IsAndroidMediaPluginEnabled();
#endif
#ifdef MOZ_WMF
static bool IsWMFEnabled();
#endif
// Return statistics. This is used for progress events and other things.
// This can be called from any thread. It's only a snapshot of the
// current state, since other threads might be changing the state
// at any time.
MediaStatistics GetStatistics();
// Return the frame decode/paint related statistics.
FrameStatistics& GetFrameStatistics() { return *mFrameStats; }
// Increments the parsed and decoded frame counters by the passed in counts.
// Can be called on any thread.
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
uint32_t aDropped) override
{
GetFrameStatistics().NotifyDecodedFrames(aParsed, aDecoded, aDropped);
}
void UpdateReadyState()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mShuttingDown) {
mOwner->UpdateReadyState();
}
}
virtual MediaDecoderOwner::NextFrameStatus NextFrameStatus() { return mNextFrameStatus; }
virtual MediaDecoderOwner::NextFrameStatus NextFrameBufferedStatus();
// Returns a string describing the state of the media player internal
// data. Used for debugging purposes.
virtual void GetMozDebugReaderData(nsAString& aString) {}
protected:
virtual ~MediaDecoder();
// Called when the first audio and/or video from the media file has been loaded
// by the state machine. Call on the main thread only.
virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
MediaDecoderEventVisibility aEventVisibility);
void SetStateMachineParameters();
static void DormantTimerExpired(nsITimer *aTimer, void *aClosure);
// Start a timer for heuristic dormant.
void StartDormantTimer();
// Cancel a timer for heuristic dormant.
void CancelDormantTimer();
// Return true if the decoder has reached the end of playback
bool IsEnded() const;
// Called by the state machine to notify the decoder that the duration
// has changed.
void DurationChanged();
// State-watching manager.
WatchManager<MediaDecoder> mWatchManager;
// Used by the ogg decoder to watch mStateMachineIsShutdown.
virtual void ShutdownBitChanged() {}
double ExplicitDuration() { return mExplicitDuration.Ref().ref(); }
void SetExplicitDuration(double aValue)
{
mExplicitDuration.Set(Some(aValue));
// We Invoke DurationChanged explicitly, rather than using a watcher, so
// that it takes effect immediately, rather than at the end of the current task.
DurationChanged();
}
/******
* The following members should be accessed with the decoder lock held.
******/
// Whether the decoder implementation supports dormant mode.
bool mDormantSupported;
// The logical playback position of the media resource in units of
// seconds. This corresponds to the "official position" in HTML5. Note that
// we need to store this as a double, rather than an int64_t (like
// mCurrentPosition), so that |v.currentTime = foo; v.currentTime == foo|
// returns true without being affected by rounding errors.
double mLogicalPosition;
// The current playback position of the underlying playback infrastructure.
// This corresponds to the "current position" in HTML5.
// We allow omx subclasses to substitute an alternative current position for
// usage with the audio offload player.
virtual int64_t CurrentPosition() { return mCurrentPosition; }
// Official duration of the media resource as observed by script.
double mDuration;
/******
* The following member variables can be accessed from any thread.
******/
// Media data resource.
RefPtr<MediaResource> mResource;
// Amount of buffered data ahead of current time required to consider that
// the next frame is available.
// An arbitrary value of 250ms is used.
static const int DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED = 250000;
private:
// Called when the metadata from the media file has been loaded by the
// state machine. Call on the main thread only.
void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
nsAutoPtr<MetadataTags> aTags,
MediaDecoderEventVisibility aEventVisibility);
MediaEventSource<void>*
DataArrivedEvent() override { return &mDataArrivedEvent; }
void OnPlaybackEvent(MediaEventType aEvent);
void OnMediaNotSeekable()
{
SetMediaSeekable(false);
}
RefPtr<ShutdownPromise> FinishShutdown();
MediaEventProducer<void> mDataArrivedEvent;
// The state machine object for handling the decoding. It is safe to
// call methods of this object from other threads. Its internal data
// is synchronised on a monitor. The lifetime of this object is
// after mPlayState is LOADING and before mPlayState is SHUTDOWN. It
// is safe to access it during this period.
//
// Explicitly prievate to force access via accessors.
RefPtr<MediaDecoderStateMachine> mDecoderStateMachine;
RefPtr<ResourceCallback> mResourceCallback;
#ifdef MOZ_EME
MozPromiseHolder<CDMProxyPromise> mCDMProxyPromiseHolder;
RefPtr<CDMProxyPromise> mCDMProxyPromise;
#endif
protected:
virtual void CallSeek(const SeekTarget& aTarget);
// Returns true if heuristic dormant is supported.
bool IsHeuristicDormantSupported() const;
MozPromiseRequestHolder<SeekPromise> mSeekRequest;
// True when seeking or otherwise moving the play position around in
// such a manner that progress event data is inaccurate. This is set
// during seek and duration operations to prevent the progress indicator
// from jumping around. Read/Write on the main thread only.
bool mIgnoreProgressData;
// True if the stream is infinite (e.g. a webradio).
bool mInfiniteStream;
// Ensures our media stream has been pinned.
void PinForSeek();
// Ensures our media stream has been unpinned.
void UnpinForSeek();
const char* PlayStateStr();
void OnMetadataUpdate(TimedMetadata&& aMetadata);
// This should only ever be accessed from the main thread.
// It is set in Init and cleared in Shutdown when the element goes away.
// The decoder does not add a reference the element.
MediaDecoderOwner* const mOwner;
// Counters related to decode and presentation of frames.
const RefPtr<FrameStatistics> mFrameStats;
const RefPtr<VideoFrameContainer> mVideoFrameContainer;
// Data needed to estimate playback data rate. The timeline used for
// this estimate is "decode time" (where the "current time" is the
// time of the last decoded video frame).
RefPtr<MediaChannelStatistics> mPlaybackStatistics;
// True when our media stream has been pinned. We pin the stream
// while seeking.
bool mPinnedForSeek;
// True if the decoder is being shutdown. At this point all events that
// are currently queued need to return immediately to prevent javascript
// being run that operates on the element and decoder during shutdown.
// Read/Write from the main thread only.
bool mShuttingDown;
// True if the playback is paused because the playback rate member is 0.0.
bool mPausedForPlaybackRateNull;
// Be assigned from media element during the initialization and pass to
// AudioStream Class.
dom::AudioChannel mAudioChannel;
// True if the decoder has been directed to minimize its preroll before
// playback starts. After the first time playback starts, we don't attempt
// to minimize preroll, as we assume the user is likely to keep playing,
// or play the media again.
bool mMinimizePreroll;
// True if audio tracks and video tracks are constructed and added into the
// track list, false if all tracks are removed from the track list.
bool mMediaTracksConstructed;
// True if we've already fired metadataloaded.
bool mFiredMetadataLoaded;
// Stores media info, including info of audio tracks and video tracks, should
// only be accessed from main thread.
nsAutoPtr<MediaInfo> mInfo;
// True if MediaDecoder is in dormant state.
bool mIsDormant;
// True if MediaDecoder was PLAY_STATE_ENDED state, when entering to dormant.
// When MediaCodec is in dormant during PLAY_STATE_ENDED state, PlayState
// becomes different from PLAY_STATE_ENDED. But the MediaDecoder need to act
// as in PLAY_STATE_ENDED state to MediaDecoderOwner.
bool mWasEndedWhenEnteredDormant;
// True if heuristic dormant is supported.
const bool mIsHeuristicDormantSupported;
// Timeout ms of heuristic dormant timer.
const int mHeuristicDormantTimeout;
// True if MediaDecoder is in dormant by heuristic.
bool mIsHeuristicDormant;
// Timer to schedule updating dormant state.
nsCOMPtr<nsITimer> mDormantTimer;
// A listener to receive metadata updates from MDSM.
MediaEventListener mTimedMetadataListener;
MediaEventListener mMetadataLoadedListener;
MediaEventListener mFirstFrameLoadedListener;
MediaEventListener mOnPlaybackEvent;
MediaEventListener mOnSeekingStart;
MediaEventListener mOnMediaNotSeekable;
protected:
// Whether the state machine is shut down.
Mirror<bool> mStateMachineIsShutdown;
// Buffered range, mirrored from the reader.
Mirror<media::TimeIntervals> mBuffered;
// NextFrameStatus, mirrored from the state machine.
Mirror<MediaDecoderOwner::NextFrameStatus> mNextFrameStatus;
// NB: Don't use mCurrentPosition directly, but rather CurrentPosition().
Mirror<int64_t> mCurrentPosition;
// Duration of the media resource according to the state machine.
Mirror<media::NullableTimeUnit> mStateMachineDuration;
// Current playback position in the stream. This is (approximately)
// where we're up to playing back the stream. This is not adjusted
// during decoder seek operations, but it's updated at the end when we
// start playing back again.
Mirror<int64_t> mPlaybackPosition;
// Used to distiguish whether the audio is producing sound.
Mirror<bool> mIsAudioDataAudible;
// Volume of playback. 0.0 = muted. 1.0 = full volume.
Canonical<double> mVolume;
// PlaybackRate and pitch preservation status we should start at.
Canonical<double> mPlaybackRate;
Canonical<bool> mPreservesPitch;
// Media duration according to the demuxer's current estimate.
// Note that it's quite bizarre for this to live on the main thread - it would
// make much more sense for this to be owned by the demuxer's task queue. But
// currently this is only every changed in NotifyDataArrived, which runs on
// the main thread. That will need to be cleaned up at some point.
Canonical<media::NullableTimeUnit> mEstimatedDuration;
// Media duration set explicitly by JS. At present, this is only ever present
// for MSE.
Canonical<Maybe<double>> mExplicitDuration;
// Set to one of the valid play states.
// This can only be changed on the main thread while holding the decoder
// monitor. Thus, it can be safely read while holding the decoder monitor
// OR on the main thread.
Canonical<PlayState> mPlayState;
// This can only be changed on the main thread while holding the decoder
// monitor. Thus, it can be safely read while holding the decoder monitor
// OR on the main thread.
Canonical<PlayState> mNextState;
// True if the decoder is seeking.
Canonical<bool> mLogicallySeeking;
// True if the media is same-origin with the element. Data can only be
// passed to MediaStreams when this is true.
Canonical<bool> mSameOriginMedia;
// Estimate of the current playback rate (bytes/second).
Canonical<double> mPlaybackBytesPerSecond;
// True if mPlaybackBytesPerSecond is a reliable estimate.
Canonical<bool> mPlaybackRateReliable;
// Current decoding position in the stream. This is where the decoder
// is up to consuming the stream. This is not adjusted during decoder
// seek operations, but it's updated at the end when we start playing
// back again.
Canonical<int64_t> mDecoderPosition;
// True if the media is seekable (i.e. supports random access).
Canonical<bool> mMediaSeekable;
// True if the media is only seekable within its buffered ranges.
Canonical<bool> mMediaSeekableOnlyInBufferedRanges;
public:
AbstractCanonical<media::NullableTimeUnit>* CanonicalDurationOrNull() override;
AbstractCanonical<double>* CanonicalVolume() {
return &mVolume;
}
AbstractCanonical<double>* CanonicalPlaybackRate() {
return &mPlaybackRate;
}
AbstractCanonical<bool>* CanonicalPreservesPitch() {
return &mPreservesPitch;
}
AbstractCanonical<media::NullableTimeUnit>* CanonicalEstimatedDuration() {
return &mEstimatedDuration;
}
AbstractCanonical<Maybe<double>>* CanonicalExplicitDuration() {
return &mExplicitDuration;
}
AbstractCanonical<PlayState>* CanonicalPlayState() {
return &mPlayState;
}
AbstractCanonical<PlayState>* CanonicalNextPlayState() {
return &mNextState;
}
AbstractCanonical<bool>* CanonicalLogicallySeeking() {
return &mLogicallySeeking;
}
AbstractCanonical<bool>* CanonicalSameOriginMedia() {
return &mSameOriginMedia;
}
AbstractCanonical<double>* CanonicalPlaybackBytesPerSecond() {
return &mPlaybackBytesPerSecond;
}
AbstractCanonical<bool>* CanonicalPlaybackRateReliable() {
return &mPlaybackRateReliable;
}
AbstractCanonical<int64_t>* CanonicalDecoderPosition() {
return &mDecoderPosition;
}
AbstractCanonical<bool>* CanonicalMediaSeekable() {
return &mMediaSeekable;
}
AbstractCanonical<bool>* CanonicalMediaSeekableOnlyInBufferedRanges() {
return &mMediaSeekableOnlyInBufferedRanges;
}
private:
// Notify owner when the audible state changed
void NotifyAudibleStateChanged();
/* Functions called by ResourceCallback */
// A media stream is assumed to be infinite if the metadata doesn't
// contain the duration, and range requests are not supported, and
// no headers give a hint of a possible duration (Content-Length,
// Content-Duration, and variants), and we cannot seek in the media
// stream to determine the duration.
//
// When the media stream ends, we can know the duration, thus the stream is
// no longer considered to be infinite.
void SetInfinite(bool aInfinite);
// Reset the decoder and notify the media element that
// server connection is closed.
void ResetConnectionState();
nsresult FinishDecoderSetup(MediaResource* aResource);
// Called by MediaResource when the principal of the resource has
// changed. Called on main thread only.
void NotifyPrincipalChanged();
// Called by MediaResource when the "cache suspended" status changes.
// If MediaResource::IsSuspendedByCache returns true, then the decoder
// should stop buffering or otherwise waiting for download progress and
// start consuming data, if possible, because the cache is full.
void NotifySuspendedStatusChanged();
// Called by the MediaResource to keep track of the number of bytes read
// from the resource. Called on the main by an event runner dispatched
// by the MediaResource read functions.
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset);
// Called by nsChannelToPipeListener or MediaResource when the
// download has ended. Called on the main thread only. aStatus is
// the result from OnStopRequest.
void NotifyDownloadEnded(nsresult aStatus);
bool mTelemetryReported;
};
} // namespace mozilla
#endif