diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index c3845e772ab9..95e01891bd5e 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -7385,6 +7385,8 @@ void HTMLMediaElement::AsyncRejectPendingPlayPromises(nsresult aError) { } void HTMLMediaElement::GetEMEInfo(dom::EMEDebugInfo& aInfo) { + MOZ_ASSERT(NS_IsMainThread(), + "MediaKeys expects to be interacted with on main thread!"); if (!mMediaKeys) { return; } diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 791de742298c..467ca3ff12b1 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -1376,6 +1376,7 @@ MediaDecoderOwner::NextFrameStatus MediaDecoder::NextFrameBufferedStatus() { } void MediaDecoder::GetDebugInfo(dom::MediaDecoderDebugInfo& aInfo) { + MOZ_ASSERT(NS_IsMainThread()); CopyUTF8toUTF16(nsPrintfCString("%p", this), aInfo.mInstance); aInfo.mChannels = mInfo ? mInfo->mAudio.mChannels : 0; aInfo.mRate = mInfo ? mInfo->mAudio.mRate : 0; @@ -1384,27 +1385,28 @@ void MediaDecoder::GetDebugInfo(dom::MediaDecoderDebugInfo& aInfo) { CopyUTF8toUTF16(MakeStringSpan(PlayStateStr()), aInfo.mPlayState); aInfo.mContainerType = NS_ConvertUTF8toUTF16(ContainerType().Type().AsString()); - mReader->GetDebugInfo(aInfo.mReader); } RefPtr MediaDecoder::RequestDebugInfo( MediaDecoderDebugInfo& aInfo) { MOZ_DIAGNOSTIC_ASSERT(!IsShutdown()); + if (!NS_IsMainThread()) { + // Run the request on the main thread if it's not already. + return InvokeAsync(AbstractThread::MainThread(), __func__, + [this, self = RefPtr{this}, &aInfo]() { + return RequestDebugInfo(aInfo); + }); + } GetDebugInfo(aInfo); - if (!GetStateMachine()) { - return GenericPromise::CreateAndResolve(true, __func__); - } - - return GetStateMachine() - ->RequestDebugInfo(aInfo.mStateMachine) - ->Then( - AbstractThread::MainThread(), __func__, - []() { return GenericPromise::CreateAndResolve(true, __func__); }, - []() { - MOZ_ASSERT_UNREACHABLE("Unexpected RequestDebugInfo() rejection"); - return GenericPromise::CreateAndResolve(false, __func__); - }); + return mReader->RequestDebugInfo(aInfo.mReader) + ->Then(AbstractThread::MainThread(), __func__, + [this, self = RefPtr{this}, &aInfo] { + if (!GetStateMachine()) { + return GenericPromise::CreateAndResolve(true, __func__); + } + return GetStateMachine()->RequestDebugInfo(aInfo.mStateMachine); + }); } void MediaDecoder::NotifyAudibleStateChanged() { diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index f02c0e7c84e6..d8170ac01e4d 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -3096,7 +3096,23 @@ layers::ImageContainer* MediaFormatReader::GetImageContainer() { : nullptr; } +RefPtr MediaFormatReader::RequestDebugInfo( + dom::MediaFormatReaderDebugInfo& aInfo) { + if (!OnTaskQueue()) { + // Run the request on the task queue if it's not already. + return InvokeAsync(mTaskQueue, __func__, + [this, self = RefPtr{this}, &aInfo] { + return RequestDebugInfo(aInfo); + }); + } + GetDebugInfo(aInfo); + return GenericPromise::CreateAndResolve(true, __func__); +} + void MediaFormatReader::GetDebugInfo(dom::MediaFormatReaderDebugInfo& aInfo) { + MOZ_ASSERT(OnTaskQueue(), + "Don't call this off the task queue, it's going to touch a lot of " + "data members"); nsCString result; nsAutoCString audioDecoderName("unavailable"); nsAutoCString videoDecoderName = audioDecoderName; @@ -3104,34 +3120,11 @@ void MediaFormatReader::GetDebugInfo(dom::MediaFormatReaderDebugInfo& aInfo) { nsAutoCString videoType("none"); AudioInfo audioInfo; - { - MutexAutoLock lock(mAudio.mMutex); - if (HasAudio()) { - audioInfo = *mAudio.GetWorkingInfo()->GetAsAudioInfo(); - audioDecoderName = mAudio.mDecoder ? mAudio.mDecoder->GetDescriptionName() - : mAudio.mDescription; - audioType = audioInfo.mMimeType; - } - } - - VideoInfo videoInfo; - { - MutexAutoLock lock(mVideo.mMutex); - if (HasVideo()) { - videoInfo = *mVideo.GetWorkingInfo()->GetAsVideoInfo(); - videoDecoderName = mVideo.mDecoder ? mVideo.mDecoder->GetDescriptionName() - : mVideo.mDescription; - videoType = videoInfo.mMimeType; - } - } - - CopyUTF8toUTF16(audioDecoderName, aInfo.mAudioDecoderName); - CopyUTF8toUTF16(audioType, aInfo.mAudioType); - aInfo.mAudioChannels = audioInfo.mChannels; - aInfo.mAudioRate = audioInfo.mRate / 1000.0f; - aInfo.mAudioFramesDecoded = mAudio.mNumSamplesOutputTotal; - if (HasAudio()) { + audioInfo = *mAudio.GetWorkingInfo()->GetAsAudioInfo(); + audioDecoderName = mAudio.mDecoder ? mAudio.mDecoder->GetDescriptionName() + : mAudio.mDescription; + audioType = audioInfo.mMimeType; aInfo.mAudioState.mNeedInput = NeedInput(mAudio); aInfo.mAudioState.mHasPromise = mAudio.HasPromise(); aInfo.mAudioState.mWaitingPromise = !mAudio.mWaitingPromise.IsEmpty(); @@ -3155,18 +3148,18 @@ void MediaFormatReader::GetDebugInfo(dom::MediaFormatReaderDebugInfo& aInfo) { aInfo.mAudioState.mLastStreamSourceID = mAudio.mLastStreamSourceID; } - CopyUTF8toUTF16(videoDecoderName, aInfo.mVideoDecoderName); - CopyUTF8toUTF16(videoType, aInfo.mVideoType); - aInfo.mVideoWidth = - videoInfo.mDisplay.width < 0 ? 0 : videoInfo.mDisplay.width; - aInfo.mVideoHeight = - videoInfo.mDisplay.height < 0 ? 0 : videoInfo.mDisplay.height; - aInfo.mVideoRate = mVideo.mMeanRate.Mean(); - aInfo.mVideoHardwareAccelerated = VideoIsHardwareAccelerated(); - aInfo.mVideoNumSamplesOutputTotal = mVideo.mNumSamplesOutputTotal; - aInfo.mVideoNumSamplesSkippedTotal = mVideo.mNumSamplesSkippedTotal; + CopyUTF8toUTF16(audioDecoderName, aInfo.mAudioDecoderName); + CopyUTF8toUTF16(audioType, aInfo.mAudioType); + aInfo.mAudioChannels = audioInfo.mChannels; + aInfo.mAudioRate = audioInfo.mRate / 1000.0f; + aInfo.mAudioFramesDecoded = mAudio.mNumSamplesOutputTotal; + VideoInfo videoInfo; if (HasVideo()) { + videoInfo = *mVideo.GetWorkingInfo()->GetAsVideoInfo(); + videoDecoderName = mVideo.mDecoder ? mVideo.mDecoder->GetDescriptionName() + : mVideo.mDescription; + videoType = videoInfo.mMimeType; aInfo.mVideoState.mNeedInput = NeedInput(mVideo); aInfo.mVideoState.mHasPromise = mVideo.HasPromise(); aInfo.mVideoState.mWaitingPromise = !mVideo.mWaitingPromise.IsEmpty(); @@ -3190,6 +3183,17 @@ void MediaFormatReader::GetDebugInfo(dom::MediaFormatReaderDebugInfo& aInfo) { aInfo.mVideoState.mLastStreamSourceID = mVideo.mLastStreamSourceID; } + CopyUTF8toUTF16(videoDecoderName, aInfo.mVideoDecoderName); + CopyUTF8toUTF16(videoType, aInfo.mVideoType); + aInfo.mVideoWidth = + videoInfo.mDisplay.width < 0 ? 0 : videoInfo.mDisplay.width; + aInfo.mVideoHeight = + videoInfo.mDisplay.height < 0 ? 0 : videoInfo.mDisplay.height; + aInfo.mVideoRate = mVideo.mMeanRate.Mean(); + aInfo.mVideoHardwareAccelerated = VideoIsHardwareAccelerated(); + aInfo.mVideoNumSamplesOutputTotal = mVideo.mNumSamplesOutputTotal; + aInfo.mVideoNumSamplesSkippedTotal = mVideo.mNumSamplesSkippedTotal; + // Looking at dropped frames FrameStatisticsData stats = mFrameStats->GetFrameStatisticsData(); aInfo.mFrameStats.mDroppedDecodedFrames = stats.mDroppedDecodedFrames; diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 4355f22e0a42..b91077f0cea0 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -16,6 +16,7 @@ # include "SeekTarget.h" # include "mozilla/Atomics.h" # include "mozilla/Maybe.h" +# include "mozilla/MozPromise.h" # include "mozilla/Mutex.h" # include "mozilla/StateMirroring.h" # include "mozilla/StaticPrefs_media.h" @@ -182,9 +183,11 @@ class MediaFormatReader final RefPtr SetCDMProxy(CDMProxy* aProxy); - // Returns a MediaDebugInfo structure - // Used for debugging purposes. - void GetDebugInfo(dom::MediaFormatReaderDebugInfo& aInfo); + // Requests that the MediaFormatReader populates aInfo with debug information. + // This may be done asynchronously, and aInfo should *not* be accessed by the + // caller until the returned promise is resolved or rejected. + RefPtr RequestDebugInfo( + dom::MediaFormatReaderDebugInfo& aInfo); // Switch the video decoder to NullDecoderModule. It might takes effective // since a few samples later depends on how much demuxed samples are already @@ -813,6 +816,8 @@ class MediaFormatReader final MozPromiseHolder mSetCDMPromise; TrackSet mSetCDMForTracks{}; bool IsDecoderWaitingForCDM(TrackType aTrack); + + void GetDebugInfo(dom::MediaFormatReaderDebugInfo& aInfo); }; } // namespace mozilla diff --git a/dom/media/mediasource/MediaSource.cpp b/dom/media/mediasource/MediaSource.cpp index a3609e65e38c..79c8d737c632 100644 --- a/dom/media/mediasource/MediaSource.cpp +++ b/dom/media/mediasource/MediaSource.cpp @@ -629,9 +629,17 @@ already_AddRefed MediaSource::MozDebugReaderData(ErrorResult& aRv) { return nullptr; } MOZ_ASSERT(domPromise); - MediaSourceDecoderDebugInfo info; - mDecoder->GetDebugInfo(info); - domPromise->MaybeResolve(info); + UniquePtr info = + MakeUnique(); + mDecoder->RequestDebugInfo(*info)->Then( + mAbstractMainThread, __func__, + [domPromise, infoPtr = std::move(info)] { + domPromise->MaybeResolve(infoPtr.get()); + }, + [] { + MOZ_ASSERT_UNREACHABLE("Unexpected rejection while getting debug data"); + }); + return domPromise.forget(); } diff --git a/dom/media/mediasource/MediaSourceDecoder.cpp b/dom/media/mediasource/MediaSourceDecoder.cpp index ae3dd55bb465..14008e29107d 100644 --- a/dom/media/mediasource/MediaSourceDecoder.cpp +++ b/dom/media/mediasource/MediaSourceDecoder.cpp @@ -223,11 +223,22 @@ void MediaSourceDecoder::SetMediaSourceDuration(double aDuration) { } } -void MediaSourceDecoder::GetDebugInfo(dom::MediaSourceDecoderDebugInfo& aInfo) { - if (mReader && mDemuxer) { - mReader->GetDebugInfo(aInfo.mReader); - mDemuxer->GetDebugInfo(aInfo.mDemuxer); +RefPtr MediaSourceDecoder::RequestDebugInfo( + dom::MediaSourceDecoderDebugInfo& aInfo) { + // This should be safe to call off main thead, but there's no such usage at + // time of writing. Can be carefully relaxed if needed. + MOZ_ASSERT(NS_IsMainThread(), "Expects to be called on main thread."); + if (mReader) { + return mReader->RequestDebugInfo(aInfo.mReader) + ->Then(GetCurrentSerialEventTarget(), __func__, + [this, self = RefPtr{this}, &aInfo] { + if (mDemuxer) { + mDemuxer->GetDebugInfo(aInfo.mDemuxer); + } + return GenericPromise::CreateAndResolve(true, __func__); + }); } + return GenericPromise::CreateAndResolve(true, __func__); } double MediaSourceDecoder::GetDuration() { diff --git a/dom/media/mediasource/MediaSourceDecoder.h b/dom/media/mediasource/MediaSourceDecoder.h index 0922f070e037..73730ef0730e 100644 --- a/dom/media/mediasource/MediaSourceDecoder.h +++ b/dom/media/mediasource/MediaSourceDecoder.h @@ -54,9 +54,11 @@ class MediaSourceDecoder : public MediaDecoder, bool IsTransportSeekable() override { return true; } - // Returns a structure describing the state of the MediaSource internal - // buffered data. Used for debugging purposes. - void GetDebugInfo(dom::MediaSourceDecoderDebugInfo& aInfo); + // Requests that the MediaSourceDecoder populates aInfo with debug + // information. This may be done asynchronously, and aInfo should *not* be + // accessed by the caller until the returned promise is resolved or rejected. + RefPtr RequestDebugInfo( + dom::MediaSourceDecoderDebugInfo& aInfo); void AddSizeOfResources(ResourceSizes* aSizes) override;