summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/wmf/MFMediaSource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/platforms/wmf/MFMediaSource.cpp')
-rw-r--r--dom/media/platforms/wmf/MFMediaSource.cpp605
1 files changed, 605 insertions, 0 deletions
diff --git a/dom/media/platforms/wmf/MFMediaSource.cpp b/dom/media/platforms/wmf/MFMediaSource.cpp
new file mode 100644
index 0000000000..ace3c7988c
--- /dev/null
+++ b/dom/media/platforms/wmf/MFMediaSource.cpp
@@ -0,0 +1,605 @@
+/* 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/. */
+
+#include "MFMediaSource.h"
+
+#include <mfapi.h>
+#include <mfidl.h>
+#include <stdint.h>
+
+#include "MFCDMProxy.h"
+#include "MFMediaEngineAudioStream.h"
+#include "MFMediaEngineUtils.h"
+#include "MFMediaEngineVideoStream.h"
+#include "VideoUtils.h"
+#include "WMF.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/StaticPrefs_media.h"
+#include "mozilla/TaskQueue.h"
+
+namespace mozilla {
+
+#define LOG(msg, ...) \
+ MOZ_LOG(gMFMediaEngineLog, LogLevel::Debug, \
+ ("MFMediaSource=%p, " msg, this, ##__VA_ARGS__))
+
+using Microsoft::WRL::ComPtr;
+
+MFMediaSource::MFMediaSource()
+ : mPresentationEnded(false), mIsAudioEnded(false), mIsVideoEnded(false) {
+ MOZ_COUNT_CTOR(MFMediaSource);
+}
+
+MFMediaSource::~MFMediaSource() {
+ // TODO : notify cdm about the last key id?
+ MOZ_COUNT_DTOR(MFMediaSource);
+}
+
+HRESULT MFMediaSource::RuntimeClassInitialize(
+ const Maybe<AudioInfo>& aAudio, const Maybe<VideoInfo>& aVideo,
+ nsISerialEventTarget* aManagerThread) {
+ // On manager thread.
+ MutexAutoLock lock(mMutex);
+
+ static uint64_t streamId = 1;
+
+ mTaskQueue = TaskQueue::Create(
+ GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER), "MFMediaSource");
+ mManagerThread = aManagerThread;
+ MOZ_ASSERT(mManagerThread, "manager thread shouldn't be nullptr!");
+
+ if (aAudio) {
+ mAudioStream.Attach(
+ MFMediaEngineAudioStream::Create(streamId++, *aAudio, this));
+ if (!mAudioStream) {
+ NS_WARNING("Failed to create audio stream");
+ return E_FAIL;
+ }
+ mAudioStreamEndedListener = mAudioStream->EndedEvent().Connect(
+ mManagerThread, this, &MFMediaSource::HandleStreamEnded);
+ } else {
+ mIsAudioEnded = true;
+ }
+
+ if (aVideo) {
+ mVideoStream.Attach(
+ MFMediaEngineVideoStream::Create(streamId++, *aVideo, this));
+ if (!mVideoStream) {
+ NS_WARNING("Failed to create video stream");
+ return E_FAIL;
+ }
+ mVideoStreamEndedListener = mVideoStream->EndedEvent().Connect(
+ mManagerThread, this, &MFMediaSource::HandleStreamEnded);
+ } else {
+ mIsVideoEnded = true;
+ }
+
+ RETURN_IF_FAILED(wmf::MFCreateEventQueue(&mMediaEventQueue));
+
+ LOG("Initialized a media source");
+ return S_OK;
+}
+
+IFACEMETHODIMP MFMediaSource::GetCharacteristics(DWORD* aCharacteristics) {
+ // This could be run on both mf thread pool and manager thread.
+ {
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return MF_E_SHUTDOWN;
+ }
+ }
+ // https://docs.microsoft.com/en-us/windows/win32/api/mfidl/ne-mfidl-mfmediasource_characteristics
+ *aCharacteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE;
+ return S_OK;
+}
+
+IFACEMETHODIMP MFMediaSource::CreatePresentationDescriptor(
+ IMFPresentationDescriptor** aPresentationDescriptor) {
+ AssertOnMFThreadPool();
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return MF_E_SHUTDOWN;
+ }
+
+ LOG("CreatePresentationDescriptor");
+ // See steps of creating the presentation descriptor
+ // https://docs.microsoft.com/en-us/windows/win32/medfound/writing-a-custom-media-source#creating-the-presentation-descriptor
+ ComPtr<IMFPresentationDescriptor> presentationDescriptor;
+ nsTArray<ComPtr<IMFStreamDescriptor>> streamDescriptors;
+
+ DWORD audioDescriptorId = 0, videoDescriptorId = 0;
+ if (mAudioStream) {
+ ComPtr<IMFStreamDescriptor>* descriptor = streamDescriptors.AppendElement();
+ RETURN_IF_FAILED(
+ mAudioStream->GetStreamDescriptor(descriptor->GetAddressOf()));
+ audioDescriptorId = mAudioStream->DescriptorId();
+ }
+
+ if (mVideoStream) {
+ ComPtr<IMFStreamDescriptor>* descriptor = streamDescriptors.AppendElement();
+ RETURN_IF_FAILED(
+ mVideoStream->GetStreamDescriptor(descriptor->GetAddressOf()));
+ videoDescriptorId = mVideoStream->DescriptorId();
+ }
+
+ const DWORD descCount = static_cast<DWORD>(streamDescriptors.Length());
+ MOZ_ASSERT(descCount <= 2);
+ RETURN_IF_FAILED(wmf::MFCreatePresentationDescriptor(
+ descCount,
+ reinterpret_cast<IMFStreamDescriptor**>(streamDescriptors.Elements()),
+ &presentationDescriptor));
+
+ // Select default streams for the presentation descriptor.
+ for (DWORD idx = 0; idx < descCount; idx++) {
+ ComPtr<IMFStreamDescriptor> streamDescriptor;
+ BOOL selected;
+ RETURN_IF_FAILED(presentationDescriptor->GetStreamDescriptorByIndex(
+ idx, &selected, &streamDescriptor));
+ if (selected) {
+ continue;
+ }
+ RETURN_IF_FAILED(presentationDescriptor->SelectStream(idx));
+ DWORD streamId;
+ streamDescriptor->GetStreamIdentifier(&streamId);
+ LOG(" Select stream (id=%lu)", streamId);
+ }
+
+ LOG("Created a presentation descriptor (a=%lu,v=%lu)", audioDescriptorId,
+ videoDescriptorId);
+ *aPresentationDescriptor = presentationDescriptor.Detach();
+ return S_OK;
+}
+
+IFACEMETHODIMP MFMediaSource::Start(
+ IMFPresentationDescriptor* aPresentationDescriptor,
+ const GUID* aGuidTimeFormat, const PROPVARIANT* aStartPosition) {
+ AssertOnMFThreadPool();
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return MF_E_SHUTDOWN;
+ }
+
+ // See detailed steps in following documents.
+ // https://docs.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-imfmediasource-start
+ // https://docs.microsoft.com/en-us/windows/win32/medfound/writing-a-custom-media-source#starting-the-media-source
+
+ // A call to Start results in a seek if the previous state was started or
+ // paused, and the new starting position is not VT_EMPTY.
+ const bool isSeeking =
+ IsSeekable() && ((mState == State::Started || mState == State::Paused) &&
+ aStartPosition->vt != VT_EMPTY);
+ nsAutoCString startPosition;
+ if (aStartPosition->vt == VT_I8) {
+ startPosition.AppendInt(aStartPosition->hVal.QuadPart);
+ } else if (aStartPosition->vt == VT_EMPTY) {
+ startPosition.AppendLiteral("empty");
+ }
+ LOG("Start, start position=%s, isSeeking=%d", startPosition.get(), isSeeking);
+
+ // Ask IMFMediaStream to send stream events.
+ DWORD streamDescCount = 0;
+ RETURN_IF_FAILED(
+ aPresentationDescriptor->GetStreamDescriptorCount(&streamDescCount));
+
+ // TODO : should event orders be exactly same as msdn's order?
+ for (DWORD idx = 0; idx < streamDescCount; idx++) {
+ ComPtr<IMFStreamDescriptor> streamDescriptor;
+ BOOL selected;
+ RETURN_IF_FAILED(aPresentationDescriptor->GetStreamDescriptorByIndex(
+ idx, &selected, &streamDescriptor));
+
+ DWORD streamId;
+ RETURN_IF_FAILED(streamDescriptor->GetStreamIdentifier(&streamId));
+
+ ComPtr<MFMediaEngineStream> stream;
+ if (mAudioStream && mAudioStream->DescriptorId() == streamId) {
+ stream = mAudioStream;
+ } else if (mVideoStream && mVideoStream->DescriptorId() == streamId) {
+ stream = mVideoStream;
+ }
+ NS_ENSURE_TRUE(stream, MF_E_INVALIDREQUEST);
+
+ if (selected) {
+ RETURN_IF_FAILED(mMediaEventQueue->QueueEventParamUnk(
+ stream->IsSelected() ? MEUpdatedStream : MENewStream, GUID_NULL, S_OK,
+ stream.Get()));
+ // Need to select stream first before doing other operations.
+ stream->SetSelected(true);
+ if (isSeeking) {
+ RETURN_IF_FAILED(stream->Seek(aStartPosition));
+ } else {
+ RETURN_IF_FAILED(stream->Start(aStartPosition));
+ }
+ } else {
+ stream->SetSelected(false);
+ }
+ }
+
+ // Send source event.
+ RETURN_IF_FAILED(QueueEvent(isSeeking ? MESourceSeeked : MESourceStarted,
+ GUID_NULL, S_OK, aStartPosition));
+ mState = State::Started;
+ mPresentationEnded = false;
+ if (mAudioStream && mAudioStream->IsSelected()) {
+ mIsAudioEnded = false;
+ }
+ if (mVideoStream && mVideoStream->IsSelected()) {
+ mIsVideoEnded = false;
+ }
+ LOG("Started media source");
+ return S_OK;
+}
+
+IFACEMETHODIMP MFMediaSource::Stop() {
+ AssertOnMFThreadPool();
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return MF_E_SHUTDOWN;
+ }
+
+ LOG("Stop");
+ RETURN_IF_FAILED(QueueEvent(MESourceStopped, GUID_NULL, S_OK, nullptr));
+ if (mAudioStream) {
+ RETURN_IF_FAILED(mAudioStream->Stop());
+ }
+ if (mVideoStream) {
+ RETURN_IF_FAILED(mVideoStream->Stop());
+ }
+
+ mState = State::Stopped;
+ LOG("Stopped media source");
+ return S_OK;
+}
+
+IFACEMETHODIMP MFMediaSource::Pause() {
+ AssertOnMFThreadPool();
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return MF_E_SHUTDOWN;
+ }
+ if (mState != State::Started) {
+ return MF_E_INVALID_STATE_TRANSITION;
+ }
+
+ LOG("Pause");
+ RETURN_IF_FAILED(QueueEvent(MESourcePaused, GUID_NULL, S_OK, nullptr));
+ if (mAudioStream) {
+ RETURN_IF_FAILED(mAudioStream->Pause());
+ }
+ if (mVideoStream) {
+ RETURN_IF_FAILED(mVideoStream->Pause());
+ }
+
+ mState = State::Paused;
+ LOG("Paused media source");
+ return S_OK;
+}
+
+IFACEMETHODIMP MFMediaSource::Shutdown() {
+ // Could be called on either manager thread or MF thread pool.
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return MF_E_SHUTDOWN;
+ }
+
+ LOG("Shutdown");
+ // After this method is called, all IMFMediaEventQueue methods return
+ // MF_E_SHUTDOWN.
+ RETURN_IF_FAILED(mMediaEventQueue->Shutdown());
+ mState = State::Shutdowned;
+ LOG("Shutdowned media source");
+ return S_OK;
+}
+
+void MFMediaSource::ShutdownTaskQueue() {
+ AssertOnManagerThread();
+ LOG("ShutdownTaskQueue");
+ MutexAutoLock lock(mMutex);
+ if (mAudioStream) {
+ mAudioStream->Shutdown();
+ mAudioStream = nullptr;
+ mAudioStreamEndedListener.DisconnectIfExists();
+ }
+ if (mVideoStream) {
+ mVideoStream->Shutdown();
+ mVideoStream = nullptr;
+ mVideoStreamEndedListener.DisconnectIfExists();
+ }
+ Unused << mTaskQueue->BeginShutdown();
+ mTaskQueue = nullptr;
+}
+
+IFACEMETHODIMP MFMediaSource::GetEvent(DWORD aFlags, IMFMediaEvent** aEvent) {
+ MOZ_ASSERT(mMediaEventQueue);
+ return mMediaEventQueue->GetEvent(aFlags, aEvent);
+}
+
+IFACEMETHODIMP MFMediaSource::BeginGetEvent(IMFAsyncCallback* aCallback,
+ IUnknown* aState) {
+ MOZ_ASSERT(mMediaEventQueue);
+ return mMediaEventQueue->BeginGetEvent(aCallback, aState);
+}
+
+IFACEMETHODIMP MFMediaSource::EndGetEvent(IMFAsyncResult* aResult,
+ IMFMediaEvent** aEvent) {
+ MOZ_ASSERT(mMediaEventQueue);
+ return mMediaEventQueue->EndGetEvent(aResult, aEvent);
+}
+
+IFACEMETHODIMP MFMediaSource::QueueEvent(MediaEventType aType,
+ REFGUID aExtendedType, HRESULT aStatus,
+ const PROPVARIANT* aValue) {
+ MOZ_ASSERT(mMediaEventQueue);
+ RETURN_IF_FAILED(mMediaEventQueue->QueueEventParamVar(aType, aExtendedType,
+ aStatus, aValue));
+ LOG("Queued event %s", MediaEventTypeToStr(aType));
+ PROFILER_MARKER_TEXT("MFMediaSource::QueueEvent", MEDIA_PLAYBACK, {},
+ nsPrintfCString("%s", MediaEventTypeToStr(aType)));
+ return S_OK;
+}
+
+bool MFMediaSource::IsSeekable() const {
+ // TODO : check seekable from info.
+ return true;
+}
+
+void MFMediaSource::NotifyEndOfStream(TrackInfo::TrackType aType) {
+ AssertOnManagerThread();
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return;
+ }
+ if (aType == TrackInfo::TrackType::kAudioTrack) {
+ MOZ_ASSERT(mAudioStream);
+ mAudioStream->NotifyEndOfStream();
+ } else if (aType == TrackInfo::TrackType::kVideoTrack) {
+ MOZ_ASSERT(mVideoStream);
+ mVideoStream->NotifyEndOfStream();
+ }
+}
+
+void MFMediaSource::HandleStreamEnded(TrackInfo::TrackType aType) {
+ AssertOnManagerThread();
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return;
+ }
+ if (mPresentationEnded) {
+ LOG("Presentation is ended already");
+ RETURN_VOID_IF_FAILED(
+ QueueEvent(MEEndOfPresentation, GUID_NULL, S_OK, nullptr));
+ return;
+ }
+
+ LOG("Handle %s stream ended", TrackTypeToStr(aType));
+ if (aType == TrackInfo::TrackType::kAudioTrack) {
+ mIsAudioEnded = true;
+ } else if (aType == TrackInfo::TrackType::kVideoTrack) {
+ mIsVideoEnded = true;
+ } else {
+ MOZ_ASSERT_UNREACHABLE("Incorrect track type!");
+ }
+ mPresentationEnded = mIsAudioEnded && mIsVideoEnded;
+ LOG("PresentationEnded=%d, audioEnded=%d, videoEnded=%d",
+ !!mPresentationEnded, mIsAudioEnded, mIsVideoEnded);
+ PROFILER_MARKER_TEXT(
+ " MFMediaSource::HandleStreamEnded", MEDIA_PLAYBACK, {},
+ nsPrintfCString("PresentationEnded=%d, audioEnded=%d, videoEnded=%d",
+ !!mPresentationEnded, mIsAudioEnded, mIsVideoEnded));
+ if (mPresentationEnded) {
+ RETURN_VOID_IF_FAILED(
+ QueueEvent(MEEndOfPresentation, GUID_NULL, S_OK, nullptr));
+ }
+}
+
+void MFMediaSource::SetDCompSurfaceHandle(HANDLE aDCompSurfaceHandle,
+ gfx::IntSize aDisplay) {
+ AssertOnManagerThread();
+ MutexAutoLock lock(mMutex);
+ if (mVideoStream) {
+ mVideoStream->AsVideoStream()->SetDCompSurfaceHandle(aDCompSurfaceHandle,
+ aDisplay);
+ }
+}
+
+IFACEMETHODIMP MFMediaSource::GetService(REFGUID aGuidService, REFIID aRiid,
+ LPVOID* aResult) {
+ if (!IsEqualGUID(aGuidService, MF_RATE_CONTROL_SERVICE)) {
+ return MF_E_UNSUPPORTED_SERVICE;
+ }
+ return QueryInterface(aRiid, aResult);
+}
+
+IFACEMETHODIMP MFMediaSource::GetSlowestRate(MFRATE_DIRECTION aDirection,
+ BOOL aSupportsThinning,
+ float* aRate) {
+ AssertOnMFThreadPool();
+ MOZ_ASSERT(aRate);
+ *aRate = 0.0f;
+ {
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return MF_E_SHUTDOWN;
+ }
+ }
+ if (aDirection == MFRATE_REVERSE) {
+ return MF_E_REVERSE_UNSUPPORTED;
+ }
+ return S_OK;
+}
+
+IFACEMETHODIMP MFMediaSource::GetFastestRate(MFRATE_DIRECTION aDirection,
+ BOOL aSupportsThinning,
+ float* aRate) {
+ AssertOnMFThreadPool();
+ MOZ_ASSERT(aRate);
+ {
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ *aRate = 0.0f;
+ return MF_E_SHUTDOWN;
+ }
+ }
+ if (aDirection == MFRATE_REVERSE) {
+ return MF_E_REVERSE_UNSUPPORTED;
+ }
+ *aRate = 16.0f;
+ return S_OK;
+}
+
+IFACEMETHODIMP MFMediaSource::IsRateSupported(BOOL aSupportsThinning,
+ float aNewRate,
+ float* aSupportedRate) {
+ AssertOnMFThreadPool();
+ {
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return MF_E_SHUTDOWN;
+ }
+ }
+
+ if (aSupportedRate) {
+ *aSupportedRate = 0.0f;
+ }
+
+ MFRATE_DIRECTION direction = aNewRate >= 0 ? MFRATE_FORWARD : MFRATE_REVERSE;
+ float fastestRate = 0.0f, slowestRate = 0.0f;
+ GetFastestRate(direction, aSupportsThinning, &fastestRate);
+ GetSlowestRate(direction, aSupportsThinning, &slowestRate);
+
+ if (aSupportsThinning) {
+ return MF_E_THINNING_UNSUPPORTED;
+ } else if (aNewRate < slowestRate) {
+ return MF_E_REVERSE_UNSUPPORTED;
+ } else if (aNewRate > fastestRate) {
+ return MF_E_UNSUPPORTED_RATE;
+ }
+
+ if (aSupportedRate) {
+ *aSupportedRate = aNewRate;
+ }
+ return S_OK;
+}
+
+IFACEMETHODIMP MFMediaSource::SetRate(BOOL aSupportsThinning, float aRate) {
+ AssertOnMFThreadPool();
+ {
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return MF_E_SHUTDOWN;
+ }
+ }
+
+ HRESULT hr = IsRateSupported(aSupportsThinning, aRate, &mPlaybackRate);
+ if (FAILED(hr)) {
+ LOG("Unsupported playback rate %f, error=%lX", aRate, hr);
+ return hr;
+ }
+
+ PROPVARIANT varRate;
+ varRate.vt = VT_R4;
+ varRate.fltVal = mPlaybackRate;
+ LOG("Set playback rate %f", mPlaybackRate);
+ return QueueEvent(MESourceRateChanged, GUID_NULL, S_OK, &varRate);
+}
+
+IFACEMETHODIMP MFMediaSource::GetRate(BOOL* aSupportsThinning, float* aRate) {
+ AssertOnMFThreadPool();
+ {
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return MF_E_SHUTDOWN;
+ }
+ }
+ *aSupportsThinning = FALSE;
+ *aRate = mPlaybackRate;
+ return S_OK;
+}
+
+HRESULT MFMediaSource::GetInputTrustAuthority(DWORD aStreamId, REFIID aRiid,
+ IUnknown** aITAOut) {
+ // TODO : add threading assertion, not sure what thread it would be running on
+ // now.
+ {
+ MutexAutoLock lock(mMutex);
+ if (mState == State::Shutdowned) {
+ return MF_E_SHUTDOWN;
+ }
+ }
+#ifdef MOZ_WMF_CDM
+ if (!mCDMProxy) {
+ return MF_E_NOT_PROTECTED;
+ }
+
+ // TODO : verify if this aStreamId is really matching our stream id or not.
+ ComPtr<MFMediaEngineStream> stream = GetStreamByIndentifier(aStreamId);
+ if (!stream) {
+ return E_INVALIDARG;
+ }
+
+ if (!stream->IsEncrypted()) {
+ return MF_E_NOT_PROTECTED;
+ }
+
+ RETURN_IF_FAILED(
+ mCDMProxy->GetInputTrustAuthority(aStreamId, nullptr, 0, aRiid, aITAOut));
+#endif
+ return S_OK;
+}
+
+MFMediaSource::State MFMediaSource::GetState() const {
+ MutexAutoLock lock(mMutex);
+ return mState;
+}
+
+MFMediaEngineStream* MFMediaSource::GetAudioStream() {
+ MutexAutoLock lock(mMutex);
+ return mAudioStream.Get();
+}
+MFMediaEngineStream* MFMediaSource::GetVideoStream() {
+ MutexAutoLock lock(mMutex);
+ return mVideoStream.Get();
+}
+
+MFMediaEngineStream* MFMediaSource::GetStreamByIndentifier(
+ DWORD aStreamId) const {
+ MutexAutoLock lock(mMutex);
+ if (mAudioStream && mAudioStream->DescriptorId() == aStreamId) {
+ return mAudioStream.Get();
+ }
+ if (mVideoStream && mVideoStream->DescriptorId() == aStreamId) {
+ return mVideoStream.Get();
+ }
+ return nullptr;
+}
+
+#ifdef MOZ_WMF_CDM
+void MFMediaSource::SetCDMProxy(MFCDMProxy* aCDMProxy) {
+ // TODO : add threading assertion, not sure what thread it would be running on
+ // now.
+ mCDMProxy = aCDMProxy;
+ // TODO : ask cdm proxy to refresh trusted input
+}
+#endif
+
+bool MFMediaSource::IsEncrypted() const {
+ MutexAutoLock lock(mMutex);
+ return (mAudioStream && mAudioStream->IsEncrypted()) ||
+ (mVideoStream && mVideoStream->IsEncrypted());
+}
+
+void MFMediaSource::AssertOnManagerThread() const {
+ MOZ_ASSERT(mManagerThread->IsOnCurrentThread());
+}
+
+void MFMediaSource::AssertOnMFThreadPool() const {
+ // We can't really assert the thread id from thread pool, because it would
+ // change any time. So we just assert this is not the manager thread, and use
+ // the explicit function name to indicate what thread we should run on.
+ MOZ_ASSERT(!mManagerThread->IsOnCurrentThread());
+}
+
+#undef LOG
+
+} // namespace mozilla