--- a/dom/media/MediaDecoderReaderWrapper.cpp
+++ b/dom/media/MediaDecoderReaderWrapper.cpp
@@ -49,18 +49,21 @@ MediaDecoderReaderWrapper::RequestAudioD
MOZ_ASSERT(!mShutdown);
int64_t startTime = StartTime().ToMicroseconds();
return InvokeAsync(mReader->OwnerThread(), mReader.get(),
__func__, &MediaDecoderReader::RequestAudioData)
->Then(mOwnerThread, __func__,
[startTime] (AudioData* aAudio) {
aAudio->AdjustForStartTime(startTime);
+ return AudioDataPromise::CreateAndResolve(aAudio, __func__);
},
- [] (const MediaResult& aError) {});
+ [] (const MediaResult& aError) {
+ return AudioDataPromise::CreateAndReject(aError, __func__);
+ });
}
RefPtr<MediaDecoderReaderWrapper::VideoDataPromise>
MediaDecoderReaderWrapper::RequestVideoData(bool aSkipToNextKeyframe,
media::TimeUnit aTimeThreshold)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
MOZ_ASSERT(!mShutdown);
@@ -72,18 +75,21 @@ MediaDecoderReaderWrapper::RequestVideoD
int64_t startTime = StartTime().ToMicroseconds();
return InvokeAsync(
mReader->OwnerThread(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
aSkipToNextKeyframe, aTimeThreshold)
->Then(mOwnerThread, __func__,
[startTime] (VideoData* aVideo) {
aVideo->AdjustForStartTime(startTime);
+ return VideoDataPromise::CreateAndResolve(aVideo, __func__);
},
- [] (const MediaResult& aError) {});
+ [] (const MediaResult& aError) {
+ return VideoDataPromise::CreateAndReject(aError, __func__);
+ });
}
RefPtr<MediaDecoderReader::SeekPromise>
MediaDecoderReaderWrapper::Seek(const SeekTarget& aTarget)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
SeekTarget adjustedTarget = aTarget;
adjustedTarget.SetTime(adjustedTarget.GetTime() + StartTime());
@@ -126,27 +132,35 @@ RefPtr<ShutdownPromise>
MediaDecoderReaderWrapper::Shutdown()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
mShutdown = true;
return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
&MediaDecoderReader::Shutdown);
}
-void
+RefPtr<MediaDecoderReaderWrapper::MetadataPromise>
MediaDecoderReaderWrapper::OnMetadataRead(MetadataHolder* aMetadata)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
if (mShutdown) {
- return;
+ return MetadataPromise::CreateAndReject(
+ NS_ERROR_DOM_MEDIA_ABORT_ERR, __func__);
}
if (mStartTime.isNothing()) {
mStartTime.emplace(aMetadata->mInfo.mStartTime);
}
+ return MetadataPromise::CreateAndResolve(aMetadata, __func__);
+}
+
+RefPtr<MediaDecoderReaderWrapper::MetadataPromise>
+MediaDecoderReaderWrapper::OnMetadataNotRead(const MediaResult& aError)
+{
+ return MetadataPromise::CreateAndReject(aError, __func__);
}
void
MediaDecoderReaderWrapper::SetVideoBlankDecode(bool aIsBlankDecode)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
nsCOMPtr<nsIRunnable> r =
NewRunnableMethod<bool>(mReader, &MediaDecoderReader::SetVideoNullDecode,
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -85,18 +85,18 @@ public:
}
void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); }
void SetVideoBlankDecode(bool aIsBlankDecode);
private:
~MediaDecoderReaderWrapper();
- void OnMetadataRead(MetadataHolder* aMetadata);
- void OnMetadataNotRead() {}
+ RefPtr<MetadataPromise> OnMetadataRead(MetadataHolder* aMetadata);
+ RefPtr<MetadataPromise> OnMetadataNotRead(const MediaResult& aError);
const RefPtr<AbstractThread> mOwnerThread;
const RefPtr<MediaDecoderReader> mReader;
bool mShutdown = false;
Maybe<media::TimeUnit> mStartTime;
};
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -565,18 +565,19 @@ public:
return mDecoder->SupportDecoderRecycling();
}
RefPtr<ShutdownPromise> Shutdown() override
{
RefPtr<MediaDataDecoder> decoder = mDecoder.forget();
RefPtr<Token> token = mToken.forget();
return decoder->Shutdown()->Then(
AbstractThread::GetCurrent(), __func__,
- [token]() {},
- [token]() { MOZ_RELEASE_ASSERT(false, "Can't reach here"); });
+ [token]() {
+ return ShutdownPromise::CreateAndResolve(true, __func__);
+ });
}
private:
RefPtr<MediaDataDecoder> mDecoder;
RefPtr<Token> mToken;
};
void
@@ -884,30 +885,42 @@ public:
RefPtr<SeekPromise> Seek(const TimeUnit& aTime) override
{
RefPtr<Wrapper> self = this;
return InvokeAsync(
mTaskQueue, __func__,
[self, aTime]() { return self->mTrackDemuxer->Seek(aTime); })
->Then(mTaskQueue, __func__,
- [self]() { self->UpdateRandomAccessPoint(); },
- [self]() { self->UpdateRandomAccessPoint(); });
+ [self](const TimeUnit& aTime) {
+ self->UpdateRandomAccessPoint();
+ return SeekPromise::CreateAndResolve(aTime, __func__);
+ },
+ [self](const MediaResult& aError) {
+ self->UpdateRandomAccessPoint();
+ return SeekPromise::CreateAndReject(aError, __func__);
+ });
}
RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples) override
{
RefPtr<Wrapper> self = this;
return InvokeAsync(mTaskQueue, __func__,
[self, aNumSamples]() {
return self->mTrackDemuxer->GetSamples(aNumSamples);
})
->Then(mTaskQueue, __func__,
- [self]() { self->UpdateRandomAccessPoint(); },
- [self]() { self->UpdateRandomAccessPoint(); });
+ [self](RefPtr<SamplesHolder> aSamples) {
+ self->UpdateRandomAccessPoint();
+ return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
+ },
+ [self](const MediaResult& aError) {
+ self->UpdateRandomAccessPoint();
+ return SamplesPromise::CreateAndReject(aError, __func__);
+ });
}
bool GetSamplesMayBlock() const override
{
return mGetSamplesMayBlock;
}
void Reset() override
@@ -933,18 +946,24 @@ public:
RefPtr<Wrapper> self = this;
return InvokeAsync(
mTaskQueue, __func__,
[self, aTimeThreshold]() {
return self->mTrackDemuxer->SkipToNextRandomAccessPoint(
aTimeThreshold);
})
->Then(mTaskQueue, __func__,
- [self]() { self->UpdateRandomAccessPoint(); },
- [self]() { self->UpdateRandomAccessPoint(); });
+ [self](uint32_t aVal) {
+ self->UpdateRandomAccessPoint();
+ return SkipAccessPointPromise::CreateAndResolve(aVal, __func__);
+ },
+ [self](const SkipFailureHolder& aError) {
+ self->UpdateRandomAccessPoint();
+ return SkipAccessPointPromise::CreateAndReject(aError, __func__);
+ });
}
TimeIntervals GetBuffered() override
{
MutexAutoLock lock(mMutex);
return mBuffered;
}
@@ -992,30 +1011,33 @@ private:
MutexAutoLock lock(mMutex);
mBuffered = mTrackDemuxer->GetBuffered();
}
};
RefPtr<MediaDataDemuxer::InitPromise>
MediaFormatReader::DemuxerProxy::Init()
{
+ using InitPromise = MediaDataDemuxer::InitPromise;
+
RefPtr<Data> data = mData;
RefPtr<AutoTaskQueue> taskQueue = mTaskQueue;
return InvokeAsync(mTaskQueue, __func__,
[data, taskQueue]() {
if (!data->mDemuxer) {
- return MediaDataDemuxer::InitPromise::CreateAndReject(
+ return InitPromise::CreateAndReject(
NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
return data->mDemuxer->Init();
})
->Then(taskQueue, __func__,
[data, taskQueue]() {
if (!data->mDemuxer) { // Was shutdown.
- return;
+ return InitPromise::CreateAndReject(
+ NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
data->mNumAudioTrack =
data->mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
if (data->mNumAudioTrack) {
RefPtr<MediaTrackDemuxer> d =
data->mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
if (d) {
RefPtr<Wrapper> wrapper =
@@ -1038,18 +1060,21 @@ MediaFormatReader::DemuxerProxy::Init()
}
data->mCrypto = data->mDemuxer->GetCrypto();
data->mSeekable = data->mDemuxer->IsSeekable();
data->mSeekableOnlyInBufferedRange =
data->mDemuxer->IsSeekableOnlyInBufferedRanges();
data->mShouldComputeStartTime =
data->mDemuxer->ShouldComputeStartTime();
data->mInitDone = true;
+ return InitPromise::CreateAndResolve(NS_OK, __func__);
},
- []() {});
+ [](const MediaResult& aError) {
+ return InitPromise::CreateAndReject(aError, __func__);
+ });
}
RefPtr<MediaFormatReader::NotifyDataArrivedPromise>
MediaFormatReader::DemuxerProxy::NotifyDataArrived()
{
RefPtr<Data> data = mData;
return InvokeAsync(mTaskQueue, __func__, [data]() {
if (!data->mDemuxer) {
@@ -1609,26 +1634,30 @@ MediaFormatReader::OnDemuxFailed(TrackTy
NotifyError(aTrack, aError);
break;
}
}
void
MediaFormatReader::DoDemuxVideo()
{
+ using SamplesPromise = MediaTrackDemuxer::SamplesPromise;
+
auto p = mVideo.mTrackDemuxer->GetSamples(1);
if (mVideo.mFirstDemuxedSampleTime.isNothing()) {
RefPtr<MediaFormatReader> self = this;
p = p->Then(OwnerThread(), __func__,
[self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
self->OnFirstDemuxCompleted(TrackInfo::kVideoTrack, aSamples);
+ return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
},
[self] (const MediaResult& aError) {
self->OnFirstDemuxFailed(TrackInfo::kVideoTrack, aError);
+ return SamplesPromise::CreateAndReject(aError, __func__);
});
}
p->Then(OwnerThread(), __func__, this,
&MediaFormatReader::OnVideoDemuxCompleted,
&MediaFormatReader::OnVideoDemuxFailed)
->Track(mVideo.mDemuxRequest);
}
@@ -1682,26 +1711,30 @@ MediaFormatReader::RequestAudioData()
ScheduleUpdate(TrackInfo::kAudioTrack);
return p;
}
void
MediaFormatReader::DoDemuxAudio()
{
+ using SamplesPromise = MediaTrackDemuxer::SamplesPromise;
+
auto p = mAudio.mTrackDemuxer->GetSamples(1);
if (mAudio.mFirstDemuxedSampleTime.isNothing()) {
RefPtr<MediaFormatReader> self = this;
p = p->Then(OwnerThread(), __func__,
[self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
self->OnFirstDemuxCompleted(TrackInfo::kAudioTrack, aSamples);
+ return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
},
[self] (const MediaResult& aError) {
self->OnFirstDemuxFailed(TrackInfo::kAudioTrack, aError);
+ return SamplesPromise::CreateAndReject(aError, __func__);
});
}
p->Then(OwnerThread(), __func__, this,
&MediaFormatReader::OnAudioDemuxCompleted,
&MediaFormatReader::OnAudioDemuxFailed)
->Track(mAudio.mDemuxRequest);
}
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -643,25 +643,27 @@ GeckoMediaPluginServiceParent::AsyncAddP
nsString dir(aDirectory);
RefPtr<GeckoMediaPluginServiceParent> self = this;
return InvokeAsync(
thread, this, __func__,
&GeckoMediaPluginServiceParent::AddOnGMPThread, dir)
->Then(
mMainThread,
__func__,
- [dir, self]() -> void {
+ [dir, self](bool aVal) {
LOGD(("GeckoMediaPluginServiceParent::AsyncAddPluginDirectory %s succeeded",
NS_ConvertUTF16toUTF8(dir).get()));
MOZ_ASSERT(NS_IsMainThread());
self->UpdateContentProcessGMPCapabilities();
+ return GenericPromise::CreateAndResolve(aVal, __func__);
},
- [dir]() -> void {
+ [dir](nsresult aResult) {
LOGD(("GeckoMediaPluginServiceParent::AsyncAddPluginDirectory %s failed",
NS_ConvertUTF16toUTF8(dir).get()));
+ return GenericPromise::CreateAndReject(aResult, __func__);
});
}
NS_IMETHODIMP
GeckoMediaPluginServiceParent::AddPluginDirectory(const nsAString& aDirectory)
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<GenericPromise> p = AsyncAddPluginDirectory(aDirectory);
@@ -869,25 +871,27 @@ GeckoMediaPluginServiceParent::AddOnGMPT
RefPtr<GMPParent> gmp = CreateGMPParent(mMainThread);
if (!gmp) {
NS_WARNING("Can't Create GMPParent");
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
RefPtr<GeckoMediaPluginServiceParent> self(this);
return gmp->Init(this, directory)->Then(thread, __func__,
- [gmp, self, dir]() -> void {
+ [gmp, self, dir](bool aVal) {
LOGD(("%s::%s: %s Succeeded", __CLASS__, __FUNCTION__, dir.get()));
{
MutexAutoLock lock(self->mMutex);
self->mPlugins.AppendElement(gmp);
}
+ return GenericPromise::CreateAndResolve(aVal, __func__);
},
- [dir]() -> void {
+ [dir](nsresult aResult) {
LOGD(("%s::%s: %s Failed", __CLASS__, __FUNCTION__, dir.get()));
+ return GenericPromise::CreateAndReject(aResult, __func__);
});
}
void
GeckoMediaPluginServiceParent::RemoveOnGMPThread(const nsAString& aDirectory,
const bool aDeleteFromDisk,
const bool aCanDefer)
{
--- a/dom/media/gtest/TestMozPromise.cpp
+++ b/dom/media/gtest/TestMozPromise.cpp
@@ -83,17 +83,17 @@ template<typename FunctionType>
void
RunOnTaskQueue(TaskQueue* aQueue, FunctionType aFun)
{
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(aFun);
aQueue->Dispatch(r.forget());
}
// std::function can't come soon enough. :-(
-#define DO_FAIL []()->void { EXPECT_TRUE(false); }
+#define DO_FAIL []() { EXPECT_TRUE(false); return TestPromise::CreateAndReject(0, __func__); }
TEST(MozPromise, BasicResolve)
{
AutoTaskQueue atq;
RefPtr<TaskQueue> queue = atq.Queue();
RunOnTaskQueue(queue, [queue] () -> void {
TestPromise::CreateAndResolve(42, __func__)->Then(queue, __func__,
[queue] (int aResolveValue) -> void { EXPECT_EQ(aResolveValue, 42); queue->BeginShutdown(); },
@@ -180,17 +180,21 @@ TEST(MozPromise, CompletionPromises)
bool invokedPass = false;
AutoTaskQueue atq;
RefPtr<TaskQueue> queue = atq.Queue();
RunOnTaskQueue(queue, [queue, &invokedPass] () -> void {
TestPromise::CreateAndResolve(40, __func__)
->Then(queue, __func__,
[] (int aVal) -> RefPtr<TestPromise> { return TestPromise::CreateAndResolve(aVal + 10, __func__); },
DO_FAIL)
- ->Then(queue, __func__, [&invokedPass] () -> void { invokedPass = true; }, DO_FAIL)
+ ->Then(queue, __func__,
+ [&invokedPass] (int aVal) {
+ invokedPass = true;
+ return TestPromise::CreateAndResolve(aVal, __func__);
+ }, DO_FAIL)
->Then(queue, __func__,
[queue] (int aVal) -> RefPtr<TestPromise> {
RefPtr<TestPromise::Private> p = new TestPromise::Private(__func__);
nsCOMPtr<nsIRunnable> resolver = new DelayedResolveOrReject(queue, p, RRValue::MakeResolve(aVal - 8), 10);
queue->Dispatch(resolver.forget());
return RefPtr<TestPromise>(p);
},
DO_FAIL)
@@ -217,17 +221,17 @@ TEST(MozPromise, PromiseAllResolve)
TestPromise::All(queue, promises)->Then(queue, __func__,
[queue] (const nsTArray<int>& aResolveValues) -> void {
EXPECT_EQ(aResolveValues.Length(), 3UL);
EXPECT_EQ(aResolveValues[0], 22);
EXPECT_EQ(aResolveValues[1], 32);
EXPECT_EQ(aResolveValues[2], 42);
queue->BeginShutdown();
},
- DO_FAIL
+ []() { EXPECT_TRUE(false); }
);
});
}
TEST(MozPromise, PromiseAllReject)
{
AutoTaskQueue atq;
RefPtr<TaskQueue> queue = atq.Queue();
@@ -236,17 +240,17 @@ TEST(MozPromise, PromiseAllReject)
nsTArray<RefPtr<TestPromise>> promises;
promises.AppendElement(TestPromise::CreateAndResolve(22, __func__));
promises.AppendElement(TestPromise::CreateAndReject(32.0, __func__));
promises.AppendElement(TestPromise::CreateAndResolve(42, __func__));
// Ensure that more than one rejection doesn't cause a crash (bug #1207312)
promises.AppendElement(TestPromise::CreateAndReject(52.0, __func__));
TestPromise::All(queue, promises)->Then(queue, __func__,
- DO_FAIL,
+ []() { EXPECT_TRUE(false); },
[queue] (float aRejectValue) -> void {
EXPECT_EQ(aRejectValue, 32.0);
queue->BeginShutdown();
}
);
});
}
@@ -260,18 +264,21 @@ TEST(MozPromise, Chaining)
RunOnTaskQueue(queue, [queue, &holder] () {
auto p = TestPromise::CreateAndResolve(42, __func__);
const size_t kIterations = 100;
for (size_t i = 0; i < kIterations; ++i) {
p = p->Then(queue, __func__,
[] (int aVal) {
EXPECT_EQ(aVal, 42);
+ return TestPromise::CreateAndResolve(aVal, __func__);
},
- [] () {}
+ [] (double aVal) {
+ return TestPromise::CreateAndReject(aVal, __func__);
+ }
);
if (i == kIterations / 2) {
p->Then(queue, __func__,
[queue, &holder] () {
holder.Disconnect();
queue->BeginShutdown();
},
--- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
@@ -168,18 +168,22 @@ public:
mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
mThroughputLimiter.Flush();
for (auto iter = mDecrypts.Iter(); !iter.Done(); iter.Next()) {
nsAutoPtr<DecryptPromiseRequestHolder>& holder = iter.Data();
holder->DisconnectIfExists();
iter.Remove();
}
RefPtr<SamplesWaitingForKey> k = mSamplesWaitingForKey;
- return mDecoder->Flush()->Then(mTaskQueue, __func__,
- [k]() { k->Flush(); });
+ return mDecoder->Flush()->Then(
+ mTaskQueue, __func__,
+ [k]() {
+ k->Flush();
+ return FlushPromise::CreateAndResolve(true, __func__);
+ });
}
RefPtr<DecodePromise> Drain() override
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
MOZ_ASSERT(!mIsShutdown);
MOZ_ASSERT(mDecodePromise.IsEmpty() && !mDecodeRequest.Exists(),
"Must wait for decoding to complete");
--- a/dom/media/platforms/omx/OmxDataDecoder.cpp
+++ b/dom/media/platforms/omx/OmxDataDecoder.cpp
@@ -236,18 +236,19 @@ OmxDataDecoder::DoAsyncShutdown()
// Flush to all ports, so all buffers can be returned from component.
RefPtr<OmxDataDecoder> self = this;
mOmxLayer->SendCommand(OMX_CommandFlush, OMX_ALL, nullptr)
->Then(mOmxTaskQueue, __func__,
[self] () -> RefPtr<OmxCommandPromise> {
LOGL("DoAsyncShutdown: flush complete");
return self->mOmxLayer->SendCommand(OMX_CommandStateSet, OMX_StateIdle, nullptr);
},
- [self] () {
+ [self] (const OmxCommandFailureHolder& aError) {
self->mOmxLayer->Shutdown();
+ return OmxCommandPromise::CreateAndReject(aError, __func__);
})
->Then(mOmxTaskQueue, __func__,
[self] () -> RefPtr<OmxCommandPromise> {
RefPtr<OmxCommandPromise> p =
self->mOmxLayer->SendCommand(OMX_CommandStateSet, OMX_StateLoaded, nullptr);
// According to spec 3.1.1.2.2.1:
// OMX_StateLoaded needs to be sent before releasing buffers.
@@ -258,18 +259,19 @@ OmxDataDecoder::DoAsyncShutdown()
// in layer, it needs to wait before the layer returns the
// buffers.
LOGL("DoAsyncShutdown: releasing buffers...");
self->ReleaseBuffers(OMX_DirInput);
self->ReleaseBuffers(OMX_DirOutput);
return p;
},
- [self] () {
+ [self] (const OmxCommandFailureHolder& aError) {
self->mOmxLayer->Shutdown();
+ return OmxCommandPromise::CreateAndReject(aError, __func__);
})
->Then(mOmxTaskQueue, __func__,
[self] () {
LOGL("DoAsyncShutdown: OMX_StateLoaded, it is safe to shutdown omx");
self->mOmxLayer->Shutdown();
self->mWatchManager.Shutdown();
self->mOmxLayer = nullptr;
self->mMediaDataHelper = nullptr;
@@ -781,18 +783,19 @@ OmxDataDecoder::PortSettingsChanged()
// Allocate new port buffers.
nsresult rv = self->AllocateBuffers(def.eDir);
if (NS_FAILED(rv)) {
self->NotifyError(OMX_ErrorUndefined, __func__);
}
return p;
},
- [self] () {
+ [self] (const OmxCommandFailureHolder& aError) {
self->NotifyError(OMX_ErrorUndefined, __func__);
+ return OmxCommandPromise::CreateAndReject(aError, __func__);
})
->Then(mOmxTaskQueue, __func__,
[self] () {
LOGL("PortSettingsChanged: port settings changed complete");
// finish port setting changed.
self->mPortSettingsChanged = -1;
self->FillAndEmptyBuffers();
},