Bug 1286723: [MSE] P1. Add support for live seekable attribute. r?gerald,r?bz
See https://github.com/w3c/media-source/issues/5
MozReview-Commit-ID: EP37gRmUAXF
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -361,16 +361,68 @@ MediaSource::IsTypeSupported(const Globa
}
/* static */ bool
MediaSource::Enabled(JSContext* cx, JSObject* aGlobal)
{
return Preferences::GetBool("media.mediasource.enabled");
}
+void
+MediaSource::SetLiveSeekableRange(double aStart, double aEnd, ErrorResult& aRv)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // 1. If the readyState attribute is not "open" then throw an InvalidStateError
+ // exception and abort these steps.
+ // 2. If the updating attribute equals true on any SourceBuffer in
+ // sourceBuffers, then throw an InvalidStateError exception and abort these
+ // steps.
+ if (mReadyState != MediaSourceReadyState::Open ||
+ mSourceBuffers->AnyUpdating()) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+
+ // 3. If start is negative or greater than end, then throw a TypeError
+ // exception and abort these steps.
+ if (aStart < 0 || aStart > aEnd) {
+ aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
+ return;
+ }
+
+ // 4. Set live seekable range to be a new normalized TimeRanges object
+ // containing a single range whose start position is start and end position is
+ // end.
+ mLiveSeekableRange =
+ Some(media::TimeInterval(media::TimeUnit::FromSeconds(aStart),
+ media::TimeUnit::FromSeconds(aEnd)));
+}
+
+void
+MediaSource::ClearLiveSeekableRange(ErrorResult& aRv)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // 1. If the readyState attribute is not "open" then throw an InvalidStateError
+ // exception and abort these steps.
+ // 2. If the updating attribute equals true on any SourceBuffer in
+ // sourceBuffers, then throw an InvalidStateError exception and abort these
+ // steps.
+ if (mReadyState != MediaSourceReadyState::Open ||
+ mSourceBuffers->AnyUpdating()) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+
+ // 3. If live seekable range contains a range, then set live seekable range to
+ // be a new empty TimeRanges object.
+ mLiveSeekableRange.reset();
+}
+
bool
MediaSource::Attach(MediaSourceDecoder* aDecoder)
{
MOZ_ASSERT(NS_IsMainThread());
MSE_DEBUG("Attach(aDecoder=%p) owner=%p", aDecoder, aDecoder->GetOwner());
MOZ_ASSERT(aDecoder);
MOZ_ASSERT(aDecoder->GetOwner());
if (mReadyState != MediaSourceReadyState::Closed) {
--- a/dom/media/mediasource/MediaSource.h
+++ b/dom/media/mediasource/MediaSource.h
@@ -14,16 +14,17 @@
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/MediaSourceBinding.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionNoteChild.h"
#include "nsCycleCollectionParticipant.h"
#include "nsID.h"
#include "nsISupports.h"
#include "nscore.h"
+#include "TimeUnits.h"
struct JSContext;
class JSObject;
class nsPIDOMWindowInner;
namespace mozilla {
class ErrorResult;
@@ -59,16 +60,20 @@ public:
double Duration();
void SetDuration(double aDuration, ErrorResult& aRv);
already_AddRefed<SourceBuffer> AddSourceBuffer(const nsAString& aType, ErrorResult& aRv);
void RemoveSourceBuffer(SourceBuffer& aSourceBuffer, ErrorResult& aRv);
void EndOfStream(const Optional<MediaSourceEndOfStreamError>& aError, ErrorResult& aRv);
+
+ void SetLiveSeekableRange(double aStart, double aEnd, ErrorResult& aRv);
+ void ClearLiveSeekableRange(ErrorResult& aRv);
+
static bool IsTypeSupported(const GlobalObject&, const nsAString& aType);
static bool Enabled(JSContext* cx, JSObject* aGlobal);
/** End WebIDL Methods. */
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaSource, DOMEventTargetHelper)
NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOM_MEDIASOURCE_IMPLEMENTATION_IID)
@@ -94,16 +99,22 @@ public:
{
return mPrincipal;
}
// Returns a string describing the state of the MediaSource internal
// buffered data. Used for debugging purposes.
void GetMozDebugReaderData(nsAString& aString);
+ bool HasLiveSeekableRange() const { return mLiveSeekableRange.isSome(); }
+ media::TimeInterval LiveSeekableRange() const
+ {
+ return mLiveSeekableRange.value();
+ }
+
private:
// MediaSourceDecoder uses DurationChange to set the duration
// without hitting the checks in SetDuration.
friend class mozilla::MediaSourceDecoder;
// SourceBuffer uses SetDuration and SourceBufferIsActive
friend class mozilla::dom::SourceBuffer;
~MediaSource();
@@ -128,16 +139,18 @@ private:
RefPtr<MediaSourceDecoder> mDecoder;
// Ensures the media element remains alive to dispatch progress and
// durationchanged events.
RefPtr<HTMLMediaElement> mMediaElement;
RefPtr<nsIPrincipal> mPrincipal;
MediaSourceReadyState mReadyState;
+
+ Maybe<media::TimeInterval> mLiveSeekableRange;
};
NS_DEFINE_STATIC_IID_ACCESSOR(MediaSource, MOZILLA_DOM_MEDIASOURCE_IMPLEMENTATION_IID)
} // namespace dom
} // namespace mozilla
--- a/dom/media/mediasource/MediaSourceDecoder.cpp
+++ b/dom/media/mediasource/MediaSourceDecoder.cpp
@@ -77,16 +77,31 @@ MediaSourceDecoder::GetSeekable()
}
media::TimeIntervals seekable;
double duration = mMediaSource->Duration();
if (IsNaN(duration)) {
// Return empty range.
} else if (duration > 0 && mozilla::IsInfinite(duration)) {
media::TimeIntervals buffered = GetBuffered();
+
+ // 1. If live seekable range is not empty:
+ if (mMediaSource->HasLiveSeekableRange()) {
+ // 1. Let union ranges be the union of live seekable range and the
+ // HTMLMediaElement.buffered attribute.
+ media::TimeIntervals unionRanges =
+ buffered + mMediaSource->LiveSeekableRange();
+ // 2. Return a single range with a start time equal to the earliest start
+ // time in union ranges and an end time equal to the highest end time in
+ // union ranges and abort these steps.
+ seekable +=
+ media::TimeInterval(unionRanges.GetStart(), unionRanges.GetEnd());
+ return seekable;
+ }
+
if (buffered.Length()) {
seekable +=
media::TimeInterval(media::TimeUnit::FromSeconds(0), buffered.GetEnd());
}
} else {
seekable += media::TimeInterval(media::TimeUnit::FromSeconds(0),
media::TimeUnit::FromSeconds(duration));
}
--- a/dom/webidl/MediaSource.webidl
+++ b/dom/webidl/MediaSource.webidl
@@ -29,12 +29,16 @@ interface MediaSource : EventTarget {
[SetterThrows]
attribute unrestricted double duration;
[NewObject, Throws]
SourceBuffer addSourceBuffer(DOMString type);
[Throws]
void removeSourceBuffer(SourceBuffer sourceBuffer);
[Throws]
void endOfStream(optional MediaSourceEndOfStreamError error);
+ [Throws]
+ void setLiveSeekableRange(double start, double end);
+ [Throws]
+ void clearLiveSeekableRange();
static boolean isTypeSupported(DOMString type);
[ChromeOnly]
readonly attribute DOMString mozDebugReaderData;
};