Skip to content

Commit

Permalink
[MSE] Add support for live seekable attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
trav90 authored and janekptacijarabaci committed Jul 30, 2017
1 parent f3bfd1d commit 8a1820b
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 0 deletions.
52 changes: 52 additions & 0 deletions dom/media/mediasource/MediaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,58 @@ 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)
{
Expand Down
13 changes: 13 additions & 0 deletions dom/media/mediasource/MediaSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "nsID.h"
#include "nsISupports.h"
#include "nscore.h"
#include "TimeUnits.h"

struct JSContext;
class JSObject;
Expand Down Expand Up @@ -64,6 +65,10 @@ class MediaSource final : public DOMEventTargetHelper
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);
Expand Down Expand Up @@ -118,6 +123,12 @@ class MediaSource final : public DOMEventTargetHelper
// 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.
Expand Down Expand Up @@ -154,6 +165,8 @@ class MediaSource final : public DOMEventTargetHelper
nsRefPtr<nsIPrincipal> mPrincipal;

MediaSourceReadyState mReadyState;

Maybe<media::TimeInterval> mLiveSeekableRange;

bool mFirstSourceBufferInitialized;
};
Expand Down
15 changes: 15 additions & 0 deletions dom/media/mediasource/MediaSourceDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,21 @@ MediaSourceDecoder::GetSeekable()
// Return empty range.
} else if (duration > 0 && mozilla::IsInfinite(duration)) {
media::TimeIntervals buffered = mReader->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());
Expand Down
4 changes: 4 additions & 0 deletions dom/webidl/MediaSource.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ interface MediaSource : EventTarget {
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;
Expand Down

0 comments on commit 8a1820b

Please sign in to comment.