Bug 1266027 part 1 - make the MediaDecoderReaderWrapper as a proxy of requesting media data; r=jwwang
MozReview-Commit-ID: CgTBPmtbNfh
new file mode 100644
--- /dev/null
+++ b/dom/media/MediaCallbackID.cpp
@@ -0,0 +1,50 @@
+#include "MediaCallbackID.h"
+
+namespace mozilla {
+
+char const* CallbackID::INVALID_TAG = "INVALID_TAG";
+int32_t const CallbackID::INVALID_ID = -1;
+
+CallbackID::CallbackID()
+ : mTag(INVALID_TAG), mID(INVALID_ID)
+{
+}
+
+CallbackID::CallbackID(char const* aTag, int32_t aID /* = 0*/)
+ : mTag(aTag), mID(aID)
+{
+}
+
+CallbackID&
+CallbackID::operator++()
+{
+ ++mID;
+ return *this;
+}
+
+CallbackID
+CallbackID::operator++(int)
+{
+ CallbackID ret = *this;
+ ++(*this); // call prefix++
+ return ret;
+}
+
+bool
+CallbackID::operator==(const CallbackID& rhs) const
+{
+ return (strcmp(mTag, rhs.mTag) == 0) && (mID == rhs.mID);
+}
+
+bool
+CallbackID::operator!=(const CallbackID& rhs) const
+{
+ return !(*this == rhs);
+}
+
+CallbackID::operator int() const
+{
+ return mID;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/MediaCallbackID.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MediaCallbackID_h_
+#define MediaCallbackID_h_
+
+namespace mozilla {
+
+struct CallbackID
+{
+ static char const* INVALID_TAG;
+ static int32_t const INVALID_ID;
+
+ CallbackID();
+
+ explicit CallbackID(char const* aTag, int32_t aID = 0);
+
+ CallbackID& operator++(); // prefix++
+
+ CallbackID operator++(int); // postfix++
+
+ bool operator==(const CallbackID& rhs) const;
+
+ bool operator!=(const CallbackID& rhs) const;
+
+ operator int() const;
+
+private:
+ char const* mTag;
+ int32_t mID;
+};
+
+} // namespace mozilla
+
+#endif // MediaCallbackID_h_
--- a/dom/media/MediaDecoderReaderWrapper.cpp
+++ b/dom/media/MediaDecoderReaderWrapper.cpp
@@ -139,16 +139,18 @@ private:
};
MediaDecoderReaderWrapper::MediaDecoderReaderWrapper(bool aIsRealTime,
AbstractThread* aOwnerThread,
MediaDecoderReader* aReader)
: mForceZeroStartTime(aIsRealTime || aReader->ForceZeroStartTime())
, mOwnerThread(aOwnerThread)
, mReader(aReader)
+ , mAudioCallbackID("AudioCallbackID")
+ , mVideoCallbackID("VideoCallbackID")
{}
MediaDecoderReaderWrapper::~MediaDecoderReaderWrapper()
{}
media::TimeUnit
MediaDecoderReaderWrapper::StartTime() const
{
@@ -173,44 +175,76 @@ MediaDecoderReaderWrapper::ReadMetadata(
RefPtr<HaveStartTimePromise>
MediaDecoderReaderWrapper::AwaitStartTime()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
MOZ_ASSERT(!mShutdown);
return mStartTimeRendezvous->AwaitStartTime();
}
-RefPtr<MediaDecoderReaderWrapper::MediaDataPromise>
+void
+MediaDecoderReaderWrapper::CancelAudioCallback(CallbackID aID)
+{
+ MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ MOZ_ASSERT(aID == mAudioCallbackID);
+ ++mAudioCallbackID;
+ mRequestAudioDataCB = nullptr;
+}
+
+void
+MediaDecoderReaderWrapper::CancelVideoCallback(CallbackID aID)
+{
+ MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ MOZ_ASSERT(aID == mVideoCallbackID);
+ ++mVideoCallbackID;
+ mRequestVideoDataCB = nullptr;
+}
+
+void
MediaDecoderReaderWrapper::RequestAudioData()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
MOZ_ASSERT(!mShutdown);
+ MOZ_ASSERT(mRequestAudioDataCB, "Request audio data without callback!");
auto p = InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
&MediaDecoderReader::RequestAudioData);
if (!mStartTimeRendezvous->HaveStartTime()) {
p = p->Then(mOwnerThread, __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<MediaData::AUDIO_DATA>,
&StartTimeRendezvous::FirstSampleRejected<MediaData::AUDIO_DATA>)
->CompletionPromise();
}
- return p->Then(mOwnerThread, __func__, this,
- &MediaDecoderReaderWrapper::OnSampleDecoded,
- &MediaDecoderReaderWrapper::OnNotDecoded)
- ->CompletionPromise();
+ RefPtr<MediaDecoderReaderWrapper> self = this;
+ mAudioDataRequest.Begin(p->Then(mOwnerThread, __func__,
+ [self] (MediaData* aAudioSample) {
+ MOZ_ASSERT(self->mRequestAudioDataCB);
+ self->mAudioDataRequest.Complete();
+ self->OnSampleDecoded(self->mRequestAudioDataCB.get(), aAudioSample, TimeStamp());
+ },
+ [self] (MediaDecoderReader::NotDecodedReason aReason) {
+ MOZ_ASSERT(self->mRequestAudioDataCB);
+ self->mAudioDataRequest.Complete();
+ self->OnNotDecoded(self->mRequestAudioDataCB.get(), aReason);
+ }));
}
-RefPtr<MediaDecoderReaderWrapper::MediaDataPromise>
+void
MediaDecoderReaderWrapper::RequestVideoData(bool aSkipToNextKeyframe,
media::TimeUnit aTimeThreshold)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
MOZ_ASSERT(!mShutdown);
+ MOZ_ASSERT(mRequestVideoDataCB, "Request video data without callback!");
+
+ // Time the video decode and send this value back to callbacks who accept
+ // a TimeStamp as its second parameter.
+ TimeStamp videoDecodeStartTime = TimeStamp::Now();
if (aTimeThreshold.ToMicroseconds() > 0 &&
mStartTimeRendezvous->HaveStartTime()) {
aTimeThreshold += StartTime();
}
auto p = InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
@@ -218,20 +252,42 @@ MediaDecoderReaderWrapper::RequestVideoD
if (!mStartTimeRendezvous->HaveStartTime()) {
p = p->Then(mOwnerThread, __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<MediaData::VIDEO_DATA>,
&StartTimeRendezvous::FirstSampleRejected<MediaData::VIDEO_DATA>)
->CompletionPromise();
}
- return p->Then(mOwnerThread, __func__, this,
- &MediaDecoderReaderWrapper::OnSampleDecoded,
- &MediaDecoderReaderWrapper::OnNotDecoded)
- ->CompletionPromise();
+ RefPtr<MediaDecoderReaderWrapper> self = this;
+ mVideoDataRequest.Begin(p->Then(mOwnerThread, __func__,
+ [self, videoDecodeStartTime] (MediaData* aVideoSample) {
+ MOZ_ASSERT(self->mRequestVideoDataCB);
+ self->mVideoDataRequest.Complete();
+ self->OnSampleDecoded(self->mRequestVideoDataCB.get(), aVideoSample, videoDecodeStartTime);
+ },
+ [self] (MediaDecoderReader::NotDecodedReason aReason) {
+ MOZ_ASSERT(self->mRequestVideoDataCB);
+ self->mVideoDataRequest.Complete();
+ self->OnNotDecoded(self->mRequestVideoDataCB.get(), aReason);
+ }));
+}
+
+bool
+MediaDecoderReaderWrapper::IsRequestingAudioData() const
+{
+ MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ return mAudioDataRequest.Exists();
+}
+
+bool
+MediaDecoderReaderWrapper::IsRequestingVidoeData() const
+{
+ MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ return mVideoDataRequest.Exists();
}
RefPtr<MediaDecoderReader::SeekPromise>
MediaDecoderReaderWrapper::Seek(SeekTarget aTarget, media::TimeUnit aEndTime)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
aTarget.SetTime(aTarget.GetTime() + StartTime());
return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
@@ -272,25 +328,34 @@ MediaDecoderReaderWrapper::SetIdle()
NS_NewRunnableMethod(mReader, &MediaDecoderReader::SetIdle);
mReader->OwnerThread()->Dispatch(r.forget());
}
void
MediaDecoderReaderWrapper::ResetDecode()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+
+ mAudioDataRequest.DisconnectIfExists();
+ mVideoDataRequest.DisconnectIfExists();
+
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode);
mReader->OwnerThread()->Dispatch(r.forget());
}
RefPtr<ShutdownPromise>
MediaDecoderReaderWrapper::Shutdown()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ MOZ_ASSERT(!mRequestAudioDataCB);
+ MOZ_ASSERT(!mRequestVideoDataCB);
+ MOZ_ASSERT(!mAudioDataRequest.Exists());
+ MOZ_ASSERT(!mVideoDataRequest.Exists());
+
mShutdown = true;
if (mStartTimeRendezvous) {
mStartTimeRendezvous->Destroy();
mStartTimeRendezvous = nullptr;
}
return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
&MediaDecoderReader::Shutdown);
}
@@ -318,17 +383,30 @@ MediaDecoderReaderWrapper::OnMetadataRea
},
[] () {
NS_WARNING("Setting start time on reader failed");
});
}
}
void
-MediaDecoderReaderWrapper::OnSampleDecoded(MediaData* aSample)
+MediaDecoderReaderWrapper::OnSampleDecoded(CallbackBase* aCallback,
+ MediaData* aSample,
+ TimeStamp aDecodeStartTime)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
- if (!mShutdown) {
- aSample->AdjustForStartTime(StartTime().ToMicroseconds());
- }
+ MOZ_ASSERT(!mShutdown);
+
+ aSample->AdjustForStartTime(StartTime().ToMicroseconds());
+ aCallback->OnResolved(aSample, aDecodeStartTime);
+}
+
+void
+MediaDecoderReaderWrapper::OnNotDecoded(CallbackBase* aCallback,
+ MediaDecoderReader::NotDecodedReason aReason)
+{
+ MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ MOZ_ASSERT(!mShutdown);
+
+ aCallback->OnRejected(aReason);
}
} // namespace mozilla
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -7,16 +7,17 @@
#ifndef MediaDecoderReaderWrapper_h_
#define MediaDecoderReaderWrapper_h_
#include "mozilla/AbstractThread.h"
#include "mozilla/RefPtr.h"
#include "nsISupportsImpl.h"
#include "MediaDecoderReader.h"
+#include "MediaCallbackID.h"
namespace mozilla {
class StartTimeRendezvous;
typedef MozPromise<bool, bool, /* isExclusive = */ false> HaveStartTimePromise;
/**
@@ -28,27 +29,230 @@ typedef MozPromise<bool, bool, /* isExcl
class MediaDecoderReaderWrapper {
typedef MediaDecoderReader::MetadataPromise MetadataPromise;
typedef MediaDecoderReader::MediaDataPromise MediaDataPromise;
typedef MediaDecoderReader::SeekPromise SeekPromise;
typedef MediaDecoderReader::WaitForDataPromise WaitForDataPromise;
typedef MediaDecoderReader::BufferedUpdatePromise BufferedUpdatePromise;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReaderWrapper);
+ /*
+ * Type 1: void(MediaData*)
+ * void(RefPtr<MediaData>)
+ */
+ template <typename T>
+ class ArgType1CheckHelper {
+ template<typename C, typename... Ts>
+ static TrueType
+ test(void(C::*aMethod)(Ts...),
+ decltype((DeclVal<C>().*aMethod)(DeclVal<MediaData*>()), 0));
+
+ template <typename F>
+ static TrueType
+ test(F&&, decltype(DeclVal<F>()(DeclVal<MediaData*>()), 0));
+
+ static FalseType test(...);
+ public:
+ typedef decltype(test(DeclVal<T>(), 0)) Type;
+ };
+
+ template <typename T>
+ struct ArgType1Check : public ArgType1CheckHelper<T>::Type {};
+
+ /*
+ * Type 2: void(MediaData*, TimeStamp)
+ * void(RefPtr<MediaData>, TimeStamp)
+ * void(MediaData*, TimeStamp&)
+ * void(RefPtr<MediaData>, const TimeStamp&&)
+ */
+ template <typename T>
+ class ArgType2CheckHelper {
+
+ template<typename C, typename... Ts>
+ static TrueType
+ test(void(C::*aMethod)(Ts...),
+ decltype((DeclVal<C>().*aMethod)(DeclVal<MediaData*>(), DeclVal<TimeStamp>()), 0));
+
+ template <typename F>
+ static TrueType
+ test(F&&, decltype(DeclVal<F>()(DeclVal<MediaData*>(), DeclVal<TimeStamp>()), 0));
+
+ static FalseType test(...);
+ public:
+ typedef decltype(test(DeclVal<T>(), 0)) Type;
+ };
+
+ template <typename T>
+ struct ArgType2Check : public ArgType2CheckHelper<T>::Type {};
+
+ struct CallbackBase
+ {
+ virtual ~CallbackBase() {}
+ virtual void OnResolved(MediaData*, TimeStamp) = 0;
+ virtual void OnRejected(MediaDecoderReader::NotDecodedReason) = 0;
+ };
+
+ template<typename ThisType, typename ResolveMethodType, typename RejectMethodType>
+ struct MethodCallback : public CallbackBase
+ {
+ MethodCallback(ThisType* aThis, ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
+ : mThis(aThis), mResolveMethod(aResolveMethod), mRejectMethod(aRejectMethod)
+ {
+ }
+
+ template<typename F>
+ typename EnableIf<ArgType1Check<F>::value, void>::Type
+ CallHelper(MediaData* aSample, TimeStamp)
+ {
+ (mThis->*mResolveMethod)(aSample);
+ }
+
+ template<typename F>
+ typename EnableIf<ArgType2Check<F>::value, void>::Type
+ CallHelper(MediaData* aSample, TimeStamp aDecodeStartTime)
+ {
+ (mThis->*mResolveMethod)(aSample, aDecodeStartTime);
+ }
+
+ void OnResolved(MediaData* aSample, TimeStamp aDecodeStartTime) override
+ {
+ CallHelper<ResolveMethodType>(aSample, aDecodeStartTime);
+ }
+
+ void OnRejected(MediaDecoderReader::NotDecodedReason aReason) override
+ {
+ (mThis->*mRejectMethod)(aReason);
+ }
+
+ RefPtr<ThisType> mThis;
+ ResolveMethodType mResolveMethod;
+ RejectMethodType mRejectMethod;
+ };
+
+ template<typename ResolveFunctionType, typename RejectFunctionType>
+ struct FunctionCallback : public CallbackBase
+ {
+ FunctionCallback(ResolveFunctionType&& aResolveFuntion, RejectFunctionType&& aRejectFunction)
+ : mResolveFuntion(Move(aResolveFuntion)), mRejectFunction(Move(aRejectFunction))
+ {
+ }
+
+ template<typename F>
+ typename EnableIf<ArgType1Check<F>::value, void>::Type
+ CallHelper(MediaData* aSample, TimeStamp)
+ {
+ mResolveFuntion(aSample);
+ }
+
+ template<typename F>
+ typename EnableIf<ArgType2Check<F>::value, void>::Type
+ CallHelper(MediaData* aSample, TimeStamp aDecodeStartTime)
+ {
+ mResolveFuntion(aSample, aDecodeStartTime);
+ }
+
+ void OnResolved(MediaData* aSample, TimeStamp aDecodeStartTime) override
+ {
+ CallHelper<ResolveFunctionType>(aSample, aDecodeStartTime);
+ }
+
+ void OnRejected(MediaDecoderReader::NotDecodedReason aReason) override
+ {
+ mRejectFunction(aReason);
+ }
+
+ ResolveFunctionType mResolveFuntion;
+ RejectFunctionType mRejectFunction;
+ };
+
public:
MediaDecoderReaderWrapper(bool aIsRealTime,
AbstractThread* aOwnerThread,
MediaDecoderReader* aReader);
media::TimeUnit StartTime() const;
RefPtr<MetadataPromise> ReadMetadata();
RefPtr<HaveStartTimePromise> AwaitStartTime();
- RefPtr<MediaDataPromise> RequestAudioData();
- RefPtr<MediaDataPromise> RequestVideoData(bool aSkipToNextKeyframe,
- media::TimeUnit aTimeThreshold);
+
+ template<typename ThisType, typename ResolveMethodType, typename RejectMethodType>
+ CallbackID
+ SetAudioCallback(ThisType* aThisVal,
+ ResolveMethodType aResolveMethod,
+ RejectMethodType aRejectMethod)
+ {
+ MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ MOZ_ASSERT(!mRequestAudioDataCB,
+ "Please cancel the original callback before setting a new one.");
+
+ mRequestAudioDataCB.reset(
+ new MethodCallback<ThisType, ResolveMethodType, RejectMethodType>(
+ aThisVal, aResolveMethod, aRejectMethod));
+
+ return mAudioCallbackID;
+ }
+
+ template<typename ResolveFunction, typename RejectFunction>
+ CallbackID
+ SetAudioCallback(ResolveFunction&& aResolveFunction,
+ RejectFunction&& aRejectFunction)
+ {
+ MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ MOZ_ASSERT(!mRequestAudioDataCB,
+ "Please cancel the original callback before setting a new one.");
+
+ mRequestAudioDataCB.reset(
+ new FunctionCallback<ResolveFunction, RejectFunction>(
+ Move(aResolveFunction), Move(aRejectFunction)));
+
+ return mAudioCallbackID;
+ }
+
+ template<typename ThisType, typename ResolveMethodType, typename RejectMethodType>
+ CallbackID
+ SetVideoCallback(ThisType* aThisVal,
+ ResolveMethodType aResolveMethod,
+ RejectMethodType aRejectMethod)
+ {
+ MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ MOZ_ASSERT(!mRequestVideoDataCB,
+ "Please cancel the original callback before setting a new one.");
+
+ mRequestVideoDataCB.reset(
+ new MethodCallback<ThisType, ResolveMethodType, RejectMethodType>(
+ aThisVal, aResolveMethod, aRejectMethod));
+
+ return mVideoCallbackID;
+ }
+
+ template<typename ResolveFunction, typename RejectFunction>
+ CallbackID
+ SetVideoCallback(ResolveFunction&& aResolveFunction,
+ RejectFunction&& aRejectFunction)
+ {
+ MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ MOZ_ASSERT(!mRequestVideoDataCB,
+ "Please cancel the original callback before setting a new one.");
+
+ mRequestVideoDataCB.reset(
+ new FunctionCallback<ResolveFunction, RejectFunction>(
+ Move(aResolveFunction), Move(aRejectFunction)));
+
+ return mVideoCallbackID;
+ }
+
+ void CancelAudioCallback(CallbackID aID);
+ void CancelVideoCallback(CallbackID aID);
+
+ // NOTE: please set callbacks before requesting audio/video data!
+ void RequestAudioData();
+ void RequestVideoData(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold);
+
+ bool IsRequestingAudioData() const;
+ bool IsRequestingVidoeData() const;
+
RefPtr<SeekPromise> Seek(SeekTarget aTarget, media::TimeUnit aEndTime);
RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType);
RefPtr<BufferedUpdatePromise> UpdateBufferedWithPromise();
RefPtr<ShutdownPromise> Shutdown();
void ReleaseMediaResources();
void SetIdle();
void ResetDecode();
@@ -91,22 +295,35 @@ public:
void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); }
#endif
private:
~MediaDecoderReaderWrapper();
void OnMetadataRead(MetadataHolder* aMetadata);
void OnMetadataNotRead() {}
- void OnSampleDecoded(MediaData* aSample);
- void OnNotDecoded() {}
+ void OnSampleDecoded(CallbackBase* aCallback, MediaData* aSample,
+ TimeStamp aVideoDecodeStartTime);
+ void OnNotDecoded(CallbackBase* aCallback,
+ MediaDecoderReader::NotDecodedReason aReason);
const bool mForceZeroStartTime;
const RefPtr<AbstractThread> mOwnerThread;
const RefPtr<MediaDecoderReader> mReader;
bool mShutdown = false;
RefPtr<StartTimeRendezvous> mStartTimeRendezvous;
+
+ UniquePtr<CallbackBase> mRequestAudioDataCB;
+ UniquePtr<CallbackBase> mRequestVideoDataCB;
+ MozPromiseRequestHolder<MediaDataPromise> mAudioDataRequest;
+ MozPromiseRequestHolder<MediaDataPromise> mVideoDataRequest;
+
+ /*
+ * These callback ids are used to prevent mis-canceling callback.
+ */
+ CallbackID mAudioCallbackID;
+ CallbackID mVideoCallbackID;
};
} // namespace mozilla
#endif // MediaDecoderReaderWrapper_h_
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -103,16 +103,17 @@ EXPORTS += [
'DOMMediaStream.h',
'EncodedBufferCache.h',
'FileBlockCache.h',
'FlushableTaskQueue.h',
'FrameStatistics.h',
'Intervals.h',
'Latency.h',
'MediaCache.h',
+ 'MediaCallbackID.h',
'MediaData.h',
'MediaDataDemuxer.h',
'MediaDecoder.h',
'MediaDecoderOwner.h',
'MediaDecoderReader.h',
'MediaDecoderStateMachine.h',
'MediaEventSource.h',
'MediaFormatReader.h',
@@ -213,16 +214,17 @@ UNIFIED_SOURCES += [
'DOMMediaStream.cpp',
'EncodedBufferCache.cpp',
'FileBlockCache.cpp',
'FlushableTaskQueue.cpp',
'GetUserMediaRequest.cpp',
'GraphDriver.cpp',
'Latency.cpp',
'MediaCache.cpp',
+ 'MediaCallbackID.cpp',
'MediaData.cpp',
'MediaDecoder.cpp',
'MediaDecoderReader.cpp',
'MediaDecoderReaderWrapper.cpp',
'MediaDecoderStateMachine.cpp',
'MediaDeviceInfo.cpp',
'MediaDevices.cpp',
'MediaFormatReader.cpp',
--- a/xpcom/threads/MozPromise.h
+++ b/xpcom/threads/MozPromise.h
@@ -887,17 +887,17 @@ public:
}
void DisconnectIfExists() {
if (Exists()) {
Disconnect();
}
}
- bool Exists() { return !!mRequest; }
+ bool Exists() const { return !!mRequest; }
private:
RefPtr<typename PromiseType::Request> mRequest;
};
// Asynchronous Potentially-Cross-Thread Method Calls.
//
// This machinery allows callers to schedule a promise-returning method to be