diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp
index 9aed5f82b419..cde458d95cf4 100644
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2804,8 +2804,7 @@ double HTMLMediaElement::CurrentTime() const {
void HTMLMediaElement::FastSeek(double aTime, ErrorResult& aRv) {
LOG(LogLevel::Debug, ("%p FastSeek(%f) called by JS", this, aTime));
- RefPtr tobeDropped =
- Seek(aTime, SeekTarget::PrevSyncPoint, IgnoreErrors());
+ Seek(aTime, SeekTarget::PrevSyncPoint, IgnoreErrors());
}
already_AddRefed HTMLMediaElement::SeekToNextFrame(ErrorResult& aRv) {
@@ -2820,14 +2819,23 @@ already_AddRefed HTMLMediaElement::SeekToNextFrame(ErrorResult& aRv) {
}
}
- return Seek(CurrentTime(), SeekTarget::NextFrame, aRv);
+ Seek(CurrentTime(), SeekTarget::NextFrame, aRv);
+ if (aRv.Failed()) {
+ return nullptr;
+ }
+
+ mSeekDOMPromise = CreateDOMPromise(aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+
+ return do_AddRef(mSeekDOMPromise);
}
void HTMLMediaElement::SetCurrentTime(double aCurrentTime, ErrorResult& aRv) {
LOG(LogLevel::Debug,
("%p SetCurrentTime(%f) called by JS", this, aCurrentTime));
- RefPtr tobeDropped =
- Seek(aCurrentTime, SeekTarget::Accurate, IgnoreErrors());
+ Seek(aCurrentTime, SeekTarget::Accurate, IgnoreErrors());
}
/**
@@ -2857,9 +2865,8 @@ static bool IsInRanges(TimeRanges& aRanges, double aValue,
return false;
}
-already_AddRefed HTMLMediaElement::Seek(double aTime,
- SeekTarget::Type aSeekType,
- ErrorResult& aRv) {
+void HTMLMediaElement::Seek(double aTime, SeekTarget::Type aSeekType,
+ ErrorResult& aRv) {
// Note: Seek is called both by synchronous code that expects errors thrown in
// aRv, as well as asynchronous code that expects a promise. Make sure all
// synchronous errors are returned using aRv, not promise rejections.
@@ -2871,11 +2878,6 @@ already_AddRefed HTMLMediaElement::Seek(double aTime,
// https://html.spec.whatwg.org/multipage/media.html#dom-media-seek
mShowPoster = false;
- RefPtr promise = CreateDOMPromise(aRv);
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
-
// Detect if user has interacted with element by seeking so that
// play will not be blocked when initiated by a script.
if (EventStateManager::IsHandlingUserInput()) {
@@ -2887,7 +2889,7 @@ already_AddRefed HTMLMediaElement::Seek(double aTime,
if (mSrcAttrStream) {
// do nothing since media streams have an empty Seekable range.
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return nullptr;
+ return;
}
if (mPlayed && mCurrentPlayRangeStart != -1.0) {
@@ -2906,28 +2908,28 @@ already_AddRefed HTMLMediaElement::Seek(double aTime,
if (mReadyState == HAVE_NOTHING) {
mDefaultPlaybackStartPosition = aTime;
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return nullptr;
+ return;
}
if (!mDecoder) {
// mDecoder must always be set in order to reach this point.
NS_ASSERTION(mDecoder, "SetCurrentTime failed: no decoder");
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return nullptr;
+ return;
}
// Clamp the seek target to inside the seekable ranges.
media::TimeIntervals seekableIntervals = mDecoder->GetSeekable();
if (seekableIntervals.IsInvalid()) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return nullptr;
+ return;
}
RefPtr seekable =
new TimeRanges(ToSupports(OwnerDoc()), seekableIntervals);
uint32_t length = seekable->Length();
if (length == 0) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return nullptr;
+ return;
}
// If the position we want to seek to is not in a seekable range, we seek
@@ -2988,11 +2990,6 @@ already_AddRefed HTMLMediaElement::Seek(double aTime,
// We changed whether we're seeking so we need to AddRemoveSelfReference.
AddRemoveSelfReference();
-
- // Keep the DOM promise.
- mSeekDOMPromise = promise;
-
- return promise.forget();
}
double HTMLMediaElement::Duration() const {
@@ -5266,6 +5263,24 @@ void HTMLMediaElement::SeekCompleted() {
if (IsAudioTrackCurrentlySilent()) {
UpdateAudioTrackSilenceRange(mIsAudioTrackAudible);
}
+
+ if (mSeekDOMPromise) {
+ mAbstractMainThread->Dispatch(NS_NewRunnableFunction(
+ __func__, [promise = std::move(mSeekDOMPromise)] {
+ promise->MaybeResolveWithUndefined();
+ }));
+ }
+ MOZ_ASSERT(!mSeekDOMPromise);
+}
+
+void HTMLMediaElement::SeekAborted() {
+ if (mSeekDOMPromise) {
+ mAbstractMainThread->Dispatch(NS_NewRunnableFunction(
+ __func__, [promise = std::move(mSeekDOMPromise)] {
+ promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
+ }));
+ }
+ MOZ_ASSERT(!mSeekDOMPromise);
}
void HTMLMediaElement::NotifySuspendedByCache(bool aSuspendedByCache) {
@@ -7235,30 +7250,6 @@ bool HasDebuggerOrTabsPrivilege(JSContext* aCx, JSObject* aObj) {
nsContentUtils::CallerHasPermission(aCx, nsGkAtoms::tabs);
}
-void HTMLMediaElement::AsyncResolveSeekDOMPromiseIfExists() {
- MOZ_ASSERT(NS_IsMainThread());
- if (mSeekDOMPromise) {
- RefPtr promise = mSeekDOMPromise.forget();
- nsCOMPtr r = NS_NewRunnableFunction(
- "dom::HTMLMediaElement::AsyncResolveSeekDOMPromiseIfExists",
- [promise]() { promise->MaybeResolveWithUndefined(); });
- mAbstractMainThread->Dispatch(r.forget());
- mSeekDOMPromise = nullptr;
- }
-}
-
-void HTMLMediaElement::AsyncRejectSeekDOMPromiseIfExists() {
- MOZ_ASSERT(NS_IsMainThread());
- if (mSeekDOMPromise) {
- RefPtr promise = mSeekDOMPromise.forget();
- nsCOMPtr r = NS_NewRunnableFunction(
- "dom::HTMLMediaElement::AsyncRejectSeekDOMPromiseIfExists",
- [promise]() { promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); });
- mAbstractMainThread->Dispatch(r.forget());
- mSeekDOMPromise = nullptr;
- }
-}
-
void HTMLMediaElement::ReportCanPlayTelemetry() {
LOG(LogLevel::Debug, ("%s", __func__));
diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h
index 1df98b4f37a1..e75b653c1205 100644
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -200,6 +200,10 @@ class HTMLMediaElement : public nsGenericHTMLElement,
// 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.
@@ -699,17 +703,6 @@ class HTMLMediaElement : public nsGenericHTMLElement,
already_AddRefed CreateGMPCrashHelper() override;
- // The promise resolving/rejection is queued as a "micro-task" which will be
- // handled immediately after the current JS task and before any pending JS
- // tasks.
- // At the time we are going to resolve/reject a promise, the "seeking" event
- // task should already be queued but might yet be processed, so we queue one
- // more task to file the promise resolving/rejection micro-tasks
- // asynchronously to make sure that the micro-tasks are processed after the
- // "seeking" event task.
- void AsyncResolveSeekDOMPromiseIfExists() override;
- void AsyncRejectSeekDOMPromiseIfExists() override;
-
nsISerialEventTarget* MainThreadEventTarget() {
return mMainThreadEventTarget;
}
@@ -1185,8 +1178,7 @@ class HTMLMediaElement : public nsGenericHTMLElement,
// 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.
- already_AddRefed Seek(double aTime, SeekTarget::Type aSeekType,
- ErrorResult& aRv);
+ void Seek(double aTime, SeekTarget::Type aSeekType, ErrorResult& aRv);
// Update the audio channel playing state
void UpdateAudioChannelPlayingState(bool aForcePlaying = false);
diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp
index d73d5d431ce2..8e3b52c05b80 100644
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -627,7 +627,6 @@ void MediaDecoder::DiscardOngoingSeekIfExists() {
MOZ_ASSERT(NS_IsMainThread());
AbstractThread::AutoEnter context(AbstractMainThread());
mSeekRequest.DisconnectIfExists();
- GetOwner()->AsyncRejectSeekDOMPromiseIfExists();
}
void MediaDecoder::CallSeek(const SeekTarget& aTarget) {
@@ -836,14 +835,14 @@ void MediaDecoder::OnSeekResolved() {
mSeekRequest.Complete();
GetOwner()->SeekCompleted();
- GetOwner()->AsyncResolveSeekDOMPromiseIfExists();
}
void MediaDecoder::OnSeekRejected() {
MOZ_ASSERT(NS_IsMainThread());
mSeekRequest.Complete();
mLogicallySeeking = false;
- GetOwner()->AsyncRejectSeekDOMPromiseIfExists();
+
+ GetOwner()->SeekAborted();
}
void MediaDecoder::SeekingStarted() {
diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h
index 76874a91c493..d5f2c2fa4753 100644
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -497,7 +497,7 @@ class MediaDecoder : public DecoderDoctorLifeLogger {
protected:
void NotifyReaderDataArrived();
void DiscardOngoingSeekIfExists();
- virtual void CallSeek(const SeekTarget& aTarget);
+ void CallSeek(const SeekTarget& aTarget);
// Called by MediaResource when the principal of the resource has
// changed. Called on main thread only.
diff --git a/dom/media/MediaDecoderOwner.h b/dom/media/MediaDecoderOwner.h
index 42f8d4b21aeb..48e14c36c5f6 100644
--- a/dom/media/MediaDecoderOwner.h
+++ b/dom/media/MediaDecoderOwner.h
@@ -94,6 +94,10 @@ class MediaDecoderOwner {
// when the resource has completed seeking.
virtual void SeekCompleted() = 0;
+ // Called by the video decoder object, on the main thread,
+ // when the resource has aborted seeking.
+ virtual void SeekAborted() = 0;
+
// 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.
@@ -144,12 +148,6 @@ class MediaDecoderOwner {
// owner's track list.
virtual void RemoveMediaTracks() = 0;
- // Called by the media decoder to notify the owner to resolve a seek promise.
- virtual void AsyncResolveSeekDOMPromiseIfExists() = 0;
-
- // Called by the media decoder to notify the owner to reject a seek promise.
- virtual void AsyncRejectSeekDOMPromiseIfExists() = 0;
-
// Notified by the decoder that a decryption key is required before emitting
// further output.
virtual void NotifyWaitingForKey() {}
diff --git a/testing/web-platform/meta/media-source/mediasource-seek-beyond-duration.html.ini b/testing/web-platform/meta/media-source/mediasource-seek-beyond-duration.html.ini
deleted file mode 100644
index 52da55863615..000000000000
--- a/testing/web-platform/meta/media-source/mediasource-seek-beyond-duration.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[mediasource-seek-beyond-duration.html]
- disabled:
- if (os == "android") and not e10s: https://bugzilla.mozilla.org/show_bug.cgi?id=1499003
- if (os == "android") and e10s: bug 1550895 (frequently fails on geckoview)
- if (os == "android") and debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1560524
- expected: ERROR
-
diff --git a/testing/web-platform/meta/media-source/mediasource-seek-during-pending-seek.html.ini b/testing/web-platform/meta/media-source/mediasource-seek-during-pending-seek.html.ini
deleted file mode 100644
index f329f6882c0d..000000000000
--- a/testing/web-platform/meta/media-source/mediasource-seek-during-pending-seek.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[mediasource-seek-during-pending-seek.html]
- disabled:
- if (os == "android") and not e10s: https://bugzilla.mozilla.org/show_bug.cgi?id=1499003
- expected: ERROR
- [Test seeking to a new location during a pending seek.]
- disabled:
- if (os == "android"): Frequently failing on geckoview (Bug 1563134), Bug 1553057