Bug 1280613 - P1. Add experimental SourceBuffer.appendBufferAsync. r?bz
The aim of those changes is to be incubated in the WICG.
MozReview-Commit-ID: 5wEUnWz8i7kBug 1280613
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -201,16 +201,42 @@ SourceBuffer::AppendBuffer(const ArrayBu
{
MOZ_ASSERT(NS_IsMainThread());
MSE_API("AppendBuffer(ArrayBufferView)");
aData.ComputeLengthAndData();
DDLOG(DDLogCategory::API, "AppendBuffer", aData.Length());
AppendData(aData.Data(), aData.Length(), aRv);
}
+already_AddRefed<Promise>
+SourceBuffer::AppendBufferAsync(const ArrayBuffer& aData,
+ ErrorResult& aRv)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ MSE_API("AppendBufferAsync(ArrayBuffer)");
+ aData.ComputeLengthAndData();
+ DDLOG(DDLogCategory::API, "AppendBufferAsync", aData.Length());
+
+ return AppendDataAsync(aData.Data(), aData.Length(), aRv);
+}
+
+already_AddRefed<Promise>
+SourceBuffer::AppendBufferAsync(const ArrayBufferView& aData,
+ ErrorResult& aRv)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ MSE_API("AppendBufferAsync(ArrayBufferView)");
+ aData.ComputeLengthAndData();
+ DDLOG(DDLogCategory::API, "AppendBufferAsync", aData.Length());
+
+ return AppendDataAsync(aData.Data(), aData.Length(), aRv);
+}
+
void
SourceBuffer::Abort(ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MSE_API("Abort()");
if (!IsAttached()) {
DDLOG(DDLogCategory::API, "Abort", NS_ERROR_DOM_INVALID_STATE_ERR);
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
@@ -454,25 +480,33 @@ SourceBuffer::StopUpdating()
if (!mUpdating) {
// The buffer append or range removal algorithm has been interrupted by
// abort().
return;
}
mUpdating = false;
QueueAsyncSimpleEvent("update");
QueueAsyncSimpleEvent("updateend");
+ if (mDOMPromise) {
+ mDOMPromise->MaybeResolveWithUndefined();
+ mDOMPromise = nullptr;
+ }
}
void
SourceBuffer::AbortUpdating()
{
MOZ_ASSERT(NS_IsMainThread());
mUpdating = false;
QueueAsyncSimpleEvent("abort");
QueueAsyncSimpleEvent("updateend");
+ if (mDOMPromise) {
+ mDOMPromise->MaybeReject(NS_ERROR_DOM_MEDIA_ABORT_ERR);
+ mDOMPromise = nullptr;
+ }
}
void
SourceBuffer::CheckEndTime()
{
MOZ_ASSERT(NS_IsMainThread());
// Check if we need to update mMediaSource duration
double endTime = mCurrentAttributes.GetGroupEndTimestamp().ToSeconds();
@@ -480,33 +514,69 @@ SourceBuffer::CheckEndTime()
if (endTime > duration) {
mMediaSource->SetDuration(endTime);
}
}
void
SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
{
+ MOZ_ASSERT(NS_IsMainThread());
MSE_DEBUG("AppendData(aLength=%u)", aLength);
RefPtr<MediaByteBuffer> data = PrepareAppend(aData, aLength, aRv);
if (!data) {
return;
}
StartUpdating();
mTrackBuffersManager->AppendData(data.forget(), mCurrentAttributes)
->Then(mAbstractMainThread, __func__, this,
&SourceBuffer::AppendDataCompletedWithSuccess,
&SourceBuffer::AppendDataErrored)
->Track(mPendingAppend);
}
+already_AddRefed<Promise>
+SourceBuffer::AppendDataAsync(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!IsAttached()) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIGlobalObject> parentObject =
+ do_QueryInterface(mMediaSource->GetParentObject());
+ if (!parentObject) {
+ aRv.Throw(NS_ERROR_UNEXPECTED);
+ return nullptr;
+ }
+
+ RefPtr<Promise> promise = Promise::Create(parentObject, aRv);
+ if (aRv.Failed()) {
+ return nullptr;
+ }
+
+ AppendData(aData, aLength, aRv);
+
+ if (aRv.Failed()) {
+ return nullptr;
+ }
+
+ MOZ_ASSERT(!mDOMPromise, "Can't have a pending operation going");
+ mDOMPromise = promise;
+
+ return promise.forget();
+}
+
void
-SourceBuffer::AppendDataCompletedWithSuccess(const SourceBufferTask::AppendBufferResult& aResult)
+SourceBuffer::AppendDataCompletedWithSuccess(
+ const SourceBufferTask::AppendBufferResult& aResult)
{
MOZ_ASSERT(mUpdating);
mPendingAppend.Complete();
DDLOG(DDLogCategory::API, "AppendBuffer-completed", NS_OK);
if (aResult.first()) {
if (!mActive) {
mActive = true;
@@ -565,20 +635,27 @@ SourceBuffer::AppendError(const MediaRes
mUpdating = false;
QueueAsyncSimpleEvent("error");
QueueAsyncSimpleEvent("updateend");
MOZ_ASSERT(NS_FAILED(aDecodeError));
mMediaSource->EndOfStream(aDecodeError);
+
+ if (mDOMPromise) {
+ mDOMPromise->MaybeReject(aDecodeError);
+ mDOMPromise = nullptr;
+ }
}
already_AddRefed<MediaByteBuffer>
-SourceBuffer::PrepareAppend(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
+SourceBuffer::PrepareAppend(const uint8_t* aData,
+ uint32_t aLength,
+ ErrorResult& aRv)
{
typedef TrackBuffersManager::EvictDataResult Result;
if (!IsAttached() || mUpdating) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
@@ -655,22 +732,24 @@ SourceBuffer::HighestEndTime()
}
NS_IMPL_CYCLE_COLLECTION_CLASS(SourceBuffer)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SourceBuffer)
tmp->Detach();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBuffered)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMPromise)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SourceBuffer,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBuffered)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMPromise)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(SourceBuffer, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(SourceBuffer, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SourceBuffer)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -83,16 +83,21 @@ public:
return mCurrentAttributes.GetAppendWindowEnd();
}
void SetAppendWindowEnd(double aAppendWindowEnd, ErrorResult& aRv);
void AppendBuffer(const ArrayBuffer& aData, ErrorResult& aRv);
void AppendBuffer(const ArrayBufferView& aData, ErrorResult& aRv);
+ already_AddRefed<Promise> AppendBufferAsync(const ArrayBuffer& aData,
+ ErrorResult& aRv);
+ already_AddRefed<Promise> AppendBufferAsync(const ArrayBufferView& aData,
+ ErrorResult& aRv);
+
void Abort(ErrorResult& aRv);
void AbortBufferAppend();
void Remove(double aStart, double aEnd, ErrorResult& aRv);
void ChangeType(const nsAString& aType, ErrorResult& aRv);
IMPL_EVENT_HANDLER(updatestart);
@@ -152,16 +157,18 @@ private:
// If the media segment contains data beyond the current duration,
// then run the duration change algorithm with new duration set to the
// maximum of the current duration and the group end timestamp.
void CheckEndTime();
// Shared implementation of AppendBuffer overloads.
void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
+ // Shared implementation of AppendBufferAsync overloads.
+ already_AddRefed<Promise> AppendDataAsync(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
// Implement the "Append Error Algorithm".
// Will call endOfStream() with "decode" error if aDecodeError is true.
// 3.5.3 Append Error Algorithm
// http://w3c.github.io/media-source/#sourcebuffer-append-error
void AppendError(const MediaResult& aDecodeError);
// Implements the "Prepare Append Algorithm". Returns MediaByteBuffer object
@@ -185,15 +192,20 @@ private:
MozPromiseRequestHolder<SourceBufferTask::AppendPromise> mPendingAppend;
MozPromiseRequestHolder<SourceBufferTask::RangeRemovalPromise> mPendingRemoval;
MediaContainerType mType;
RefPtr<TimeRanges> mBuffered;
MozPromiseRequestHolder<MediaSource::ActiveCompletionPromise> mCompletionPromise;
+
+ // Only used if MSE v2 experimental mode is active.
+ // Contains the current Promise to be resolved following use of
+ // appendBufferAsync and removeAsync. Not set of no operation is pending.
+ RefPtr<Promise> mDOMPromise;
};
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_SourceBuffer_h_ */
--- a/dom/webidl/SourceBuffer.webidl
+++ b/dom/webidl/SourceBuffer.webidl
@@ -35,16 +35,22 @@ interface SourceBuffer : EventTarget {
attribute EventHandler onupdate;
attribute EventHandler onupdateend;
attribute EventHandler onerror;
attribute EventHandler onabort;
[Throws]
void appendBuffer(ArrayBuffer data);
[Throws]
void appendBuffer(ArrayBufferView data);
+ // Experimental function as proposed in:
+ // https://github.com/w3c/media-source/issues/100 for promise proposal.
+ [Throws, Func="mozilla::dom::MediaSource::ExperimentalEnabled"]
+ Promise<void> appendBufferAsync(ArrayBuffer data);
+ [Throws, Func="mozilla::dom::MediaSource::ExperimentalEnabled"]
+ Promise<void> appendBufferAsync(ArrayBufferView data);
//[Throws]
//void appendStream(Stream stream, [EnforceRange] optional unsigned long long maxSize);
[Throws]
void abort();
[Throws]
void remove(double start, unrestricted double end);
// Experimental function as proposed in:
// https://github.com/w3c/media-source/issues/155