diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 542b6cab4c45..33a5a9748719 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -9,9 +9,6 @@ #endif #include "mozilla/dom/HTMLMediaElement.h" - -#include - #include "AudioDeviceInfo.h" #include "AudioStreamTrack.h" #include "AutoplayPolicy.h" @@ -2082,60 +2079,6 @@ double HTMLMediaElement::VideoDecodeSuspendedTime() const { return mDecoder ? mDecoder->GetVideoDecodeSuspendedTimeInSeconds() : -1.0; } -void HTMLMediaElement::SetFormatDiagnosticsReportForMimeType( - const nsAString& aMimeType, DecoderDoctorReportType aType) { - DecoderDoctorDiagnostics diagnostics; - diagnostics.SetDecoderDoctorReportType(aType); - diagnostics.StoreFormatDiagnostics(OwnerDoc(), aMimeType, false /* can play*/, - __func__); -} - -void HTMLMediaElement::SetDecodeError(const nsAString& aError, - ErrorResult& aRv) { - // The reason we use this map-ish structure is because we can't use - // `CR.NS_ERROR.*` directly in test. In order to use them in test, we have to - // add them into `xpc.msg`. As we won't use `CR.NS_ERROR.*` in the production - // code, adding them to `xpc.msg` seems an overdesign and adding maintenance - // effort (exposing them in CR also needs to add a description, which is - // useless because we won't show them to users) - static struct { - const char* mName; - nsresult mResult; - } kSupportedErrorList[] = { - {"NS_ERROR_DOM_MEDIA_ABORT_ERR", NS_ERROR_DOM_MEDIA_ABORT_ERR}, - {"NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR", - NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR}, - {"NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR", - NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR}, - {"NS_ERROR_DOM_MEDIA_DECODE_ERR", NS_ERROR_DOM_MEDIA_DECODE_ERR}, - {"NS_ERROR_DOM_MEDIA_FATAL_ERR", NS_ERROR_DOM_MEDIA_FATAL_ERR}, - {"NS_ERROR_DOM_MEDIA_METADATA_ERR", NS_ERROR_DOM_MEDIA_METADATA_ERR}, - {"NS_ERROR_DOM_MEDIA_OVERFLOW_ERR", NS_ERROR_DOM_MEDIA_OVERFLOW_ERR}, - {"NS_ERROR_DOM_MEDIA_MEDIASINK_ERR", NS_ERROR_DOM_MEDIA_MEDIASINK_ERR}, - {"NS_ERROR_DOM_MEDIA_DEMUXER_ERR", NS_ERROR_DOM_MEDIA_DEMUXER_ERR}, - {"NS_ERROR_DOM_MEDIA_CDM_ERR", NS_ERROR_DOM_MEDIA_CDM_ERR}, - {"NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR", - NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR} - }; - for (auto& error : kSupportedErrorList) { - if (strcmp(error.mName, NS_ConvertUTF16toUTF8(aError).get()) == 0) { - DecoderDoctorDiagnostics diagnostics; - diagnostics.StoreDecodeError(OwnerDoc(), error.mResult, u""_ns, __func__); - return; - } - } - aRv.Throw(NS_ERROR_FAILURE); - return; -} - -void HTMLMediaElement::SetAudioSinkFailedStartup() { - DecoderDoctorDiagnostics diagnostics; - diagnostics.StoreEvent(OwnerDoc(), - {DecoderDoctorEvent::eAudioSinkStartup, - NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR}, - __func__); -} - already_AddRefed HTMLMediaElement::GetCurrentImage() { MarkAsTainted(); diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h index fbe1094195d4..3401ae8d0c72 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -22,7 +22,6 @@ #include "mozilla/Attributes.h" #include "mozilla/StateWatching.h" #include "mozilla/WeakPtr.h" -#include "mozilla/dom/DecoderDoctorNotificationBinding.h" #include "mozilla/dom/HTMLMediaElementBinding.h" #include "mozilla/dom/MediaDebugInfoBinding.h" #include "mozilla/dom/MediaKeys.h" @@ -655,12 +654,6 @@ class HTMLMediaElement : public nsGenericHTMLElement, double InvisiblePlayTime() const; double VideoDecodeSuspendedTime() const; - // Test methods for decoder doctor. - void SetFormatDiagnosticsReportForMimeType(const nsAString& aMimeType, - DecoderDoctorReportType aType); - void SetDecodeError(const nsAString& aError, ErrorResult& aRv); - void SetAudioSinkFailedStartup(); - // Synchronously, return the next video frame and mark the element unable to // participate in decode suspending. // diff --git a/dom/media/doctor/DecoderDoctorDiagnostics.cpp b/dom/media/doctor/DecoderDoctorDiagnostics.cpp index a51ad31a1c5a..bf9c6a4c1535 100644 --- a/dom/media/doctor/DecoderDoctorDiagnostics.cpp +++ b/dom/media/doctor/DecoderDoctorDiagnostics.cpp @@ -6,13 +6,11 @@ #include "DecoderDoctorDiagnostics.h" -#include - #include "VideoUtils.h" #include "mozilla/Logging.h" #include "mozilla/Preferences.h" #include "mozilla/TimeStamp.h" -#include "mozilla/StaticPrefs_media.h" +#include "mozilla/dom/DecoderDoctorNotificationBinding.h" #include "mozilla/dom/Document.h" #include "nsContentUtils.h" #include "nsGkAtoms.h" @@ -256,7 +254,7 @@ static const NotificationAndReportStringId sMediaWMFNeeded = { dom::DecoderDoctorNotificationType::Platform_decoder_not_found, "MediaWMFNeeded", {ReportParam::Formats}}; -static const NotificationAndReportStringId sMediaFFMpegNotFound = { +static const NotificationAndReportStringId sMediaPlatformDecoderNotFound = { dom::DecoderDoctorNotificationType::Platform_decoder_not_found, "MediaPlatformDecoderNotFound", {ReportParam::Formats}}; @@ -286,12 +284,15 @@ static const NotificationAndReportStringId sMediaDecodeWarning = { {ReportParam::ResourceURL, ReportParam::DecodeIssue}}; static const NotificationAndReportStringId* const - sAllNotificationsAndReportStringIds[] = { - &sMediaWidevineNoWMF, &sMediaWMFNeeded, - &sMediaFFMpegNotFound, &sMediaCannotPlayNoDecoders, - &sMediaNoDecoders, &sCannotInitializePulseAudio, - &sUnsupportedLibavcodec, &sMediaDecodeError, - &sMediaDecodeWarning}; + sAllNotificationsAndReportStringIds[] = {&sMediaWidevineNoWMF, + &sMediaWMFNeeded, + &sMediaPlatformDecoderNotFound, + &sMediaCannotPlayNoDecoders, + &sMediaNoDecoders, + &sCannotInitializePulseAudio, + &sUnsupportedLibavcodec, + &sMediaDecodeError, + &sMediaDecodeWarning}; // Create a webcompat-friendly description of a MediaResult. static nsString MediaResultDescription(const MediaResult& aResult, @@ -305,55 +306,6 @@ static nsString MediaResultDescription(const MediaResult& aResult, aResult.Message().get())); } -static bool IsNotificationAllowedOnPlatform( - const NotificationAndReportStringId& aNotification) { - // Allow all notifications during testing. - if (StaticPrefs::media_decoder_doctor_testing()) { - return true; - } - // These notifications are platform independent. - if (aNotification.mNotificationType == - dom::DecoderDoctorNotificationType::Cannot_play || - aNotification.mNotificationType == - dom::DecoderDoctorNotificationType:: - Can_play_but_some_missing_decoders || - aNotification.mNotificationType == - dom::DecoderDoctorNotificationType::Decode_error || - aNotification.mNotificationType == - dom::DecoderDoctorNotificationType::Decode_warning) { - return true; - } -#if defined(XP_WIN) - if (aNotification.mNotificationType == - dom::DecoderDoctorNotificationType::Platform_decoder_not_found) { - return strcmp(sMediaWMFNeeded.mReportStringId, - aNotification.mReportStringId) == 0 || - strcmp(sMediaWidevineNoWMF.mReportStringId, - aNotification.mReportStringId) == 0; - } -#endif -#if defined(MOZ_FFMPEG) - if (aNotification.mNotificationType == - dom::DecoderDoctorNotificationType::Platform_decoder_not_found) { - return strcmp(sMediaFFMpegNotFound.mReportStringId, - aNotification.mReportStringId) == 0; - } - if (aNotification.mNotificationType == - dom::DecoderDoctorNotificationType::Unsupported_libavcodec) { - return strcmp(sUnsupportedLibavcodec.mReportStringId, - aNotification.mReportStringId) == 0; - } -#endif -#ifdef MOZ_PULSEAUDIO - if (aNotification.mNotificationType == - dom::DecoderDoctorNotificationType::Cannot_initialize_pulseaudio) { - return strcmp(sCannotInitializePulseAudio.mReportStringId, - aNotification.mReportStringId) == 0; - } -#endif - return false; -} - static void DispatchNotification( nsISupports* aSubject, const NotificationAndReportStringId& aNotification, bool aIsSolved, const nsAString& aFormats, const nsAString& aDecodeIssue, @@ -413,11 +365,6 @@ static void ReportToConsole(dom::Document* aDocument, ? "" : NS_ConvertUTF16toUTF8(aParams[0]).get(), aParams.Length() < 2 ? "" : ", ..."); - if (StaticPrefs::media_decoder_doctor_testing()) { - Unused << nsContentUtils::DispatchTrustedEvent( - aDocument, ToSupports(aDocument), u"mozreportmediaerror"_ns, - CanBubble::eNo, Cancelable::eNo); - } nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "Media"_ns, aDocument, nsContentUtils::eDOM_PROPERTIES, aConsoleStringId, aParams); @@ -477,13 +424,6 @@ static void ReportAnalysis(dom::Document* aDocument, return; } - // Some errors should only appear on the specific platform. Eg. WMF related - // error only happens on Windows. - if (!IsNotificationAllowedOnPlatform(aNotification)) { - DD_WARN("Platform doesn't support '%s'!", aNotification.mReportStringId); - return; - } - nsString decodeIssueDescription; if (aDecodeIssue != NS_OK) { decodeIssueDescription.Assign( @@ -519,15 +459,8 @@ static void ReportAnalysis(dom::Document* aDocument, ReportToConsole(aDocument, aNotification.mReportStringId, params); } - const bool allowNotification = AllowNotification(aNotification); - const bool allowDecodeIssue = - AllowDecodeIssue(aDecodeIssue, aDecodeIssueIsError); - DD_INFO( - "ReportAnalysis for %s (decodeResult=%s) [AllowNotification=%d, " - "AllowDecodeIssue=%d]", - aNotification.mReportStringId, aDecodeIssue.ErrorName().get(), - allowNotification, allowDecodeIssue); - if (allowNotification && allowDecodeIssue) { + if (AllowNotification(aNotification) && + AllowDecodeIssue(aDecodeIssue, aDecodeIssueIsError)) { DispatchNotification(aDocument->GetInnerWindow(), aNotification, aIsSolved, aFormats, decodeIssueDescription, aDocURL, aResourceURL); @@ -556,31 +489,18 @@ static bool FormatsListContains(const nsAString& aList, return StringListContains(aList, CleanItemForFormatsList(aItem)); } -static const char* GetLinkStatusLibraryName() { -#if defined(MOZ_FFMPEG) - return FFmpegRuntimeLinker::LinkStatusLibraryName(); -#else - return "no library (ffmpeg disabled during build)"; -#endif -} - -static const char* GetLinkStatusString() { -#if defined(MOZ_FFMPEG) - return FFmpegRuntimeLinker::LinkStatusString(); -#else - return "no link (ffmpeg disabled during build)"; -#endif -} - void DecoderDoctorDocumentWatcher::SynthesizeAnalysis() { MOZ_ASSERT(NS_IsMainThread()); nsAutoString playableFormats; nsAutoString unplayableFormats; // Subsets of unplayableFormats that require a specific platform decoder: +#if defined(XP_WIN) nsAutoString formatsRequiringWMF; +#endif +#if defined(MOZ_FFMPEG) nsAutoString formatsRequiringFFMpeg; - nsAutoString formatsLibAVCodecUnsupported; +#endif nsAutoString supportedKeySystems; nsAutoString unsupportedKeySystems; DecoderDoctorDiagnostics::KeySystemIssue lastKeySystemIssue = @@ -601,16 +521,18 @@ void DecoderDoctorDocumentWatcher::SynthesizeAnalysis() { } else { AppendToFormatsList(unplayableFormats, diag.mDecoderDoctorDiagnostics.Format()); +#if defined(XP_WIN) if (diag.mDecoderDoctorDiagnostics.DidWMFFailToLoad()) { AppendToFormatsList(formatsRequiringWMF, diag.mDecoderDoctorDiagnostics.Format()); - } else if (diag.mDecoderDoctorDiagnostics.DidFFmpegNotFound()) { + } +#endif +#if defined(MOZ_FFMPEG) + if (diag.mDecoderDoctorDiagnostics.DidFFmpegFailToLoad()) { AppendToFormatsList(formatsRequiringFFMpeg, diag.mDecoderDoctorDiagnostics.Format()); - } else if (diag.mDecoderDoctorDiagnostics.IsLibAVCodecUnsupported()) { - AppendToFormatsList(formatsLibAVCodecUnsupported, - diag.mDecoderDoctorDiagnostics.Format()); } +#endif } break; case DecoderDoctorDiagnostics::eMediaKeySystemAccessRequest: @@ -733,6 +655,7 @@ void DecoderDoctorDocumentWatcher::SynthesizeAnalysis() { if (playableFormats.IsEmpty()) { // No requested formats can be played. See if we can help the user, by // going through expected decoders from most to least desirable. +#if defined(XP_WIN) if (!formatsRequiringWMF.IsEmpty()) { DD_INFO( "DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - " @@ -742,32 +665,46 @@ void DecoderDoctorDocumentWatcher::SynthesizeAnalysis() { ReportAnalysis(mDocument, sMediaWMFNeeded, false, formatsRequiringWMF); return; } +#endif +#if defined(MOZ_FFMPEG) if (!formatsRequiringFFMpeg.IsEmpty()) { - MOZ_DIAGNOSTIC_ASSERT(formatsLibAVCodecUnsupported.IsEmpty()); - DD_INFO( - "DecoderDoctorDocumentWatcher[%p, " - "doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> " - "Cannot play media because ffmpeg was not found (Reason: %s)", - this, mDocument, - NS_ConvertUTF16toUTF8(formatsRequiringFFMpeg).get(), - GetLinkStatusString()); - ReportAnalysis(mDocument, sMediaFFMpegNotFound, false, - formatsRequiringFFMpeg); - return; - } - if (!formatsLibAVCodecUnsupported.IsEmpty()) { - MOZ_DIAGNOSTIC_ASSERT(formatsRequiringFFMpeg.IsEmpty()); - DD_INFO( - "DecoderDoctorDocumentWatcher[%p, " - "doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> " - "Cannot play media because of unsupported %s (Reason: %s)", - this, mDocument, - NS_ConvertUTF16toUTF8(formatsLibAVCodecUnsupported).get(), - GetLinkStatusLibraryName(), GetLinkStatusString()); - ReportAnalysis(mDocument, sUnsupportedLibavcodec, false, - formatsLibAVCodecUnsupported); - return; + switch (FFmpegRuntimeLinker::LinkStatusCode()) { + case FFmpegRuntimeLinker::LinkStatus_INVALID_FFMPEG_CANDIDATE: + case FFmpegRuntimeLinker::LinkStatus_UNUSABLE_LIBAV57: + case FFmpegRuntimeLinker::LinkStatus_INVALID_LIBAV_CANDIDATE: + case FFmpegRuntimeLinker::LinkStatus_OBSOLETE_FFMPEG: + case FFmpegRuntimeLinker::LinkStatus_OBSOLETE_LIBAV: + case FFmpegRuntimeLinker::LinkStatus_INVALID_CANDIDATE: + DD_INFO( + "DecoderDoctorDocumentWatcher[%p, " + "doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> " + "Cannot play media because of unsupported %s (Reason: %s)", + this, mDocument, + NS_ConvertUTF16toUTF8(formatsRequiringFFMpeg).get(), + FFmpegRuntimeLinker::LinkStatusLibraryName(), + FFmpegRuntimeLinker::LinkStatusString()); + ReportAnalysis(mDocument, sUnsupportedLibavcodec, false, + formatsRequiringFFMpeg); + return; + case FFmpegRuntimeLinker::LinkStatus_INIT: + MOZ_FALLTHROUGH_ASSERT("Unexpected LinkStatus_INIT"); + case FFmpegRuntimeLinker::LinkStatus_SUCCEEDED: + MOZ_FALLTHROUGH_ASSERT("Unexpected LinkStatus_SUCCEEDED"); + case FFmpegRuntimeLinker::LinkStatus_NOT_FOUND: + DD_INFO( + "DecoderDoctorDocumentWatcher[%p, " + "doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> " + "Cannot play media because platform decoder was not found " + "(Reason: %s)", + this, mDocument, + NS_ConvertUTF16toUTF8(formatsRequiringFFMpeg).get(), + FFmpegRuntimeLinker::LinkStatusString()); + ReportAnalysis(mDocument, sMediaPlatformDecoderNotFound, false, + formatsRequiringFFMpeg); + return; + } } +#endif DD_INFO( "DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - " "Cannot play media, unplayable formats: %s", @@ -1030,6 +967,7 @@ void DecoderDoctorDiagnostics::StoreEvent(dom::Document* aDocument, } // Don't keep events for later processing, just handle them now. +#ifdef MOZ_PULSEAUDIO switch (aEvent.mDomain) { case DecoderDoctorEvent::eAudioSinkStartup: if (aEvent.mResult == NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR) { @@ -1047,6 +985,7 @@ void DecoderDoctorDiagnostics::StoreEvent(dom::Document* aDocument, } break; } +#endif // MOZ_PULSEAUDIO } void DecoderDoctorDiagnostics::StoreDecodeError(dom::Document* aDocument, @@ -1176,8 +1115,8 @@ nsCString DecoderDoctorDiagnostics::GetDescription() const { if (mFlags.contains(Flags::WMFFailedToLoad)) { s += ", Windows platform decoder failed to load"; } - if (mFlags.contains(Flags::FFmpegNotFound)) { - s += ", Linux platform decoder not found"; + if (mFlags.contains(Flags::FFmpegFailedToLoad)) { + s += ", Linux platform decoder failed to load"; } if (mFlags.contains(Flags::GMPPDMFailedToStartup)) { s += ", GMP PDM failed to startup"; @@ -1226,56 +1165,4 @@ nsCString DecoderDoctorDiagnostics::GetDescription() const { return s; } -static const char* ToDecoderDoctorReportTypeStr( - const dom::DecoderDoctorReportType& aType) { - switch (aType) { - case dom::DecoderDoctorReportType::Mediawidevinenowmf: - return sMediaWidevineNoWMF.mReportStringId; - case dom::DecoderDoctorReportType::Mediawmfneeded: - return sMediaWMFNeeded.mReportStringId; - case dom::DecoderDoctorReportType::Mediaplatformdecodernotfound: - return sMediaFFMpegNotFound.mReportStringId; - case dom::DecoderDoctorReportType::Mediacannotplaynodecoders: - return sMediaCannotPlayNoDecoders.mReportStringId; - case dom::DecoderDoctorReportType::Medianodecoders: - return sMediaNoDecoders.mReportStringId; - case dom::DecoderDoctorReportType::Mediacannotinitializepulseaudio: - return sCannotInitializePulseAudio.mReportStringId; - case dom::DecoderDoctorReportType::Mediaunsupportedlibavcodec: - return sUnsupportedLibavcodec.mReportStringId; - case dom::DecoderDoctorReportType::Mediadecodeerror: - return sMediaDecodeError.mReportStringId; - case dom::DecoderDoctorReportType::Mediadecodewarning: - return sMediaDecodeWarning.mReportStringId; - default: - DD_DEBUG("Invalid report type to str"); - return "invalid-report-type"; - } -} - -void DecoderDoctorDiagnostics::SetDecoderDoctorReportType( - const dom::DecoderDoctorReportType& aType) { - DD_INFO("Set report type %s", ToDecoderDoctorReportTypeStr(aType)); - switch (aType) { - case dom::DecoderDoctorReportType::Mediawmfneeded: - SetWMFFailedToLoad(); - return; - case dom::DecoderDoctorReportType::Mediaplatformdecodernotfound: - SetFFmpegNotFound(); - return; - case dom::DecoderDoctorReportType::Mediaunsupportedlibavcodec: - SetLibAVCodecUnsupported(); - return; - case dom::DecoderDoctorReportType::Mediacannotplaynodecoders: - case dom::DecoderDoctorReportType::Medianodecoders: - // Do nothing, because these type are related with can-play, which would - // be handled in `StoreFormatDiagnostics()` when sending `false` in the - // parameter for the canplay. - return; - default: - DD_DEBUG("Not supported type"); - return; - } -} - } // namespace mozilla diff --git a/dom/media/doctor/DecoderDoctorDiagnostics.h b/dom/media/doctor/DecoderDoctorDiagnostics.h index dee63a6f1ad4..5c5cb547fa29 100644 --- a/dom/media/doctor/DecoderDoctorDiagnostics.h +++ b/dom/media/doctor/DecoderDoctorDiagnostics.h @@ -11,7 +11,6 @@ #include "mozilla/DefineEnum.h" #include "mozilla/EnumSet.h" #include "mozilla/EnumTypeTraits.h" -#include "mozilla/dom/DecoderDoctorNotificationBinding.h" #include "nsString.h" namespace mozilla { @@ -84,7 +83,7 @@ class DecoderDoctorDiagnostics { // Methods to record diagnostic information: MOZ_DEFINE_ENUM_CLASS_AT_CLASS_SCOPE( - Flags, (CanPlay, WMFFailedToLoad, FFmpegNotFound, LibAVCodecUnsupported, + Flags, (CanPlay, WMFFailedToLoad, FFmpegFailedToLoad, GMPPDMFailedToStartup, VideoNotSupported, AudioNotSupported)); using FlagsSet = mozilla::EnumSet; @@ -97,14 +96,9 @@ class DecoderDoctorDiagnostics { return mFlags.contains(Flags::WMFFailedToLoad); } - void SetFFmpegNotFound() { mFlags += Flags::FFmpegNotFound; } - bool DidFFmpegNotFound() const { - return mFlags.contains(Flags::FFmpegNotFound); - } - - void SetLibAVCodecUnsupported() { mFlags += Flags::LibAVCodecUnsupported; } - bool IsLibAVCodecUnsupported() const { - return mFlags.contains(Flags::LibAVCodecUnsupported); + void SetFFmpegFailedToLoad() { mFlags += Flags::FFmpegFailedToLoad; } + bool DidFFmpegFailToLoad() const { + return mFlags.contains(Flags::FFmpegFailedToLoad); } void SetGMPPDMFailedToStartup() { mFlags += Flags::GMPPDMFailedToStartup; } @@ -131,9 +125,6 @@ class DecoderDoctorDiagnostics { const MediaResult& DecodeIssue() const { return mDecodeIssue; } const nsString& DecodeIssueMediaSrc() const { return mDecodeIssueMediaSrc; } - // This method is only used for testing. - void SetDecoderDoctorReportType(const dom::DecoderDoctorReportType& aType); - private: // Currently-known type of diagnostics. Set from one of the 'Store...' // methods. This helps ensure diagnostics are only stored once, and makes it diff --git a/dom/media/doctor/test/browser/browser.ini b/dom/media/doctor/test/browser/browser.ini index a73320eb9a30..292289f59448 100644 --- a/dom/media/doctor/test/browser/browser.ini +++ b/dom/media/doctor/test/browser/browser.ini @@ -3,4 +3,3 @@ tags = decoderdoctor support-files = [browser_decoderDoctor.js] -[browser_doctor_notification.js] diff --git a/dom/media/doctor/test/browser/browser_doctor_notification.js b/dom/media/doctor/test/browser/browser_doctor_notification.js deleted file mode 100644 index 5789622e2332..000000000000 --- a/dom/media/doctor/test/browser/browser_doctor_notification.js +++ /dev/null @@ -1,265 +0,0 @@ -/** - * This test is used to test whether the decoder doctor would report the error - * on the notification banner (checking that by observing message) or on the web - * console (checking that by listening to the test event). - * Error should be reported after calling `DecoderDoctorDiagnostics::StoreXXX` - * methods. - * - StoreFormatDiagnostics() [for checking if type is supported] - * - StoreDecodeError() [when decode error occurs] - * - StoreEvent() [for reporting audio sink error] - */ - -// Only types being listed here would be allowed to display on a -// notification banner. Otherwise, the error would only be showed on the -// web console. -var gAllowedNotificationTypes = - "MediaWMFNeeded,MediaFFMpegNotFound,MediaUnsupportedLibavcodec,MediaDecodeError,MediaCannotInitializePulseAudio,"; - -// Used to check if the mime type in the notification is equal to what we set -// before. This mime type doesn't reflect the real world siutation, i.e. not -// every error listed in this test would happen on this type. An example, ffmpeg -// not found would only happen on H264/AAC media. -const gMimeType = "video/mp4"; - -add_task(async function setupTestingPref() { - await SpecialPowers.pushPrefEnv({ - set: [ - ["media.decoder-doctor.testing", true], - ["media.decoder-doctor.verbose", true], - ["media.decoder-doctor.notifications-allowed", gAllowedNotificationTypes], - ], - }); - // transfer types to lower cases in order to match with `DecoderDoctorReportType` - gAllowedNotificationTypes = gAllowedNotificationTypes.toLowerCase(); -}); - -add_task(async function testWMFIsNeeded() { - const tab = await createTab("about:blank"); - await setFormatDiagnosticsReportForMimeType(tab, { - type: "platform-decoder-not-found", - decoderDoctorReportId: "mediawmfneeded", - formats: gMimeType, - }); - BrowserTestUtils.removeTab(tab); -}); - -add_task(async function testFFMpegNotFound() { - const tab = await createTab("about:blank"); - await setFormatDiagnosticsReportForMimeType(tab, { - type: "platform-decoder-not-found", - decoderDoctorReportId: "mediaplatformdecodernotfound", - formats: gMimeType, - }); - BrowserTestUtils.removeTab(tab); -}); - -add_task(async function testLibAVCodecUnsupported() { - const tab = await createTab("about:blank"); - await setFormatDiagnosticsReportForMimeType(tab, { - type: "unsupported-libavcodec", - decoderDoctorReportId: "mediaunsupportedlibavcodec", - formats: gMimeType, - }); - BrowserTestUtils.removeTab(tab); -}); - -add_task(async function testCanNotPlayNoDecoder() { - const tab = await createTab("about:blank"); - await setFormatDiagnosticsReportForMimeType(tab, { - type: "cannot-play", - decoderDoctorReportId: "mediacannotplaynodecoders", - formats: gMimeType, - }); - BrowserTestUtils.removeTab(tab); -}); - -add_task(async function testNoDecoder() { - const tab = await createTab("about:blank"); - await setFormatDiagnosticsReportForMimeType(tab, { - type: "can-play-but-some-missing-decoders", - decoderDoctorReportId: "medianodecoders", - formats: gMimeType, - }); - BrowserTestUtils.removeTab(tab); -}); - -const gErrorList = [ - "NS_ERROR_DOM_MEDIA_ABORT_ERR", - "NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR", - "NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR", - "NS_ERROR_DOM_MEDIA_DECODE_ERR", - "NS_ERROR_DOM_MEDIA_FATAL_ERR", - "NS_ERROR_DOM_MEDIA_METADATA_ERR", - "NS_ERROR_DOM_MEDIA_OVERFLOW_ERR", - "NS_ERROR_DOM_MEDIA_MEDIASINK_ERR", - "NS_ERROR_DOM_MEDIA_DEMUXER_ERR", - "NS_ERROR_DOM_MEDIA_CDM_ERR", - "NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR", -]; - -add_task(async function testDecodeError() { - const type = "decode-error"; - const decoderDoctorReportId = "mediadecodeerror"; - for (let error of gErrorList) { - const tab = await createTab("about:blank"); - info(`first to try if the error is not allowed to be reported`); - // No error is allowed to be reported in the notification banner. - await SpecialPowers.pushPrefEnv({ - set: [["media.decoder-doctor.decode-errors-allowed", ""]], - }); - await setDecodeError(tab, { - type, - decoderDoctorReportId, - error, - shouldReportNotification: false, - }); - - // If the notification type is `MediaDecodeError` and the error type is - // listed in the pref, then the error would be reported to the - // notification banner. - info(`Then to try if the error is allowed to be reported`); - await SpecialPowers.pushPrefEnv({ - set: [["media.decoder-doctor.decode-errors-allowed", error]], - }); - await setDecodeError(tab, { - type, - decoderDoctorReportId, - error, - shouldReportNotification: true, - }); - BrowserTestUtils.removeTab(tab); - } -}); - -add_task(async function testAudioSinkFailedStartup() { - const tab = await createTab("about:blank"); - await setAudioSinkFailedStartup(tab, { - type: "cannot-initialize-pulseaudio", - decoderDoctorReportId: "mediacannotinitializepulseaudio", - // This error comes with `*`, see `DecoderDoctorDiagnostics::StoreEvent` - formats: "*", - }); - BrowserTestUtils.removeTab(tab); -}); - -/** - * Following are helper functions - */ -async function createTab(url) { - let tab = await BrowserTestUtils.openNewForegroundTab(window.gBrowser, url); - // Create observer in the content process in order to check the decoder - // doctor's notification that would be sent when an error occurs. - await SpecialPowers.spawn(tab.linkedBrowser, [], _ => { - content._notificationName = "decoder-doctor-notification"; - content._obs = { - observe(subject, topic, data) { - let { type, decoderDoctorReportId, formats } = JSON.parse(data); - decoderDoctorReportId = decoderDoctorReportId.toLowerCase(); - info(`received '${type}:${decoderDoctorReportId}:${formats}'`); - if (!this._resolve) { - ok(false, "receive unexpected notification?"); - } - if ( - type == this._type && - decoderDoctorReportId == this._decoderDoctorReportId && - formats == this._formats - ) { - ok(true, `received correct notification`); - Services.obs.removeObserver(content._obs, content._notificationName); - this._resolve(); - this._resolve = null; - } - }, - // Return a promise that will be resolved once receiving a notification - // which has equal data with the input parameters. - waitFor({ type, decoderDoctorReportId, formats }) { - if (this._resolve) { - ok(false, "already has a pending promise!"); - return Promise.reject(); - } - Services.obs.addObserver(content._obs, content._notificationName); - return new Promise(resolve => { - info(`waiting for '${type}:${decoderDoctorReportId}:${formats}'`); - this._resolve = resolve; - this._type = type; - this._decoderDoctorReportId = decoderDoctorReportId; - this._formats = formats; - }); - }, - }; - content._waitForReport = (params, shouldReportNotification) => { - const reportToConsolePromise = new Promise(r => { - content.document.addEventListener( - "mozreportmediaerror", - _ => { - r(); - }, - { once: true } - ); - }); - const reportToNotificationBannerPromise = shouldReportNotification - ? content._obs.waitFor(params) - : Promise.resolve(); - info( - `waitForConsole=true, waitForNotificationBanner=${shouldReportNotification}` - ); - return Promise.all([ - reportToConsolePromise, - reportToNotificationBannerPromise, - ]); - }; - }); - return tab; -} - -async function setFormatDiagnosticsReportForMimeType(tab, params) { - const shouldReportNotification = gAllowedNotificationTypes.includes( - params.decoderDoctorReportId - ); - await SpecialPowers.spawn( - tab.linkedBrowser, - [params, shouldReportNotification], - async (params, shouldReportNotification) => { - const video = content.document.createElement("video"); - SpecialPowers.wrap(video).setFormatDiagnosticsReportForMimeType( - params.formats, - params.decoderDoctorReportId - ); - await content._waitForReport(params, shouldReportNotification); - } - ); - ok(true, `finished check for ${params.decoderDoctorReportId}`); -} - -async function setDecodeError(tab, params) { - info(`start check for ${params.error}`); - await SpecialPowers.spawn( - tab.linkedBrowser, - [params], - async (params, shouldReportNotification) => { - const video = content.document.createElement("video"); - SpecialPowers.wrap(video).setDecodeError(params.error); - await content._waitForReport(params, params.shouldReportNotification); - } - ); - ok(true, `finished check for ${params.error}`); -} - -async function setAudioSinkFailedStartup(tab, params) { - const shouldReportNotification = gAllowedNotificationTypes.includes( - params.decoderDoctorReportId - ); - await SpecialPowers.spawn( - tab.linkedBrowser, - [params, shouldReportNotification], - async (params, shouldReportNotification) => { - const video = content.document.createElement("video"); - const waitPromise = content._waitForReport( - params, - shouldReportNotification - ); - SpecialPowers.wrap(video).setAudioSinkFailedStartup(); - await waitPromise; - } - ); -} diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index 0bc45a98d08f..ee8b0a1ee0c4 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -450,26 +450,6 @@ void PDMFactory::CreateGpuPDMs() { #endif } -#if defined(MOZ_FFMPEG) -static DecoderDoctorDiagnostics::Flags GetFailureFlagBasedOnFFmpegStatus( - const FFmpegRuntimeLinker::LinkStatus& aStatus) { - switch (aStatus) { - case FFmpegRuntimeLinker::LinkStatus_INVALID_FFMPEG_CANDIDATE: - case FFmpegRuntimeLinker::LinkStatus_UNUSABLE_LIBAV57: - case FFmpegRuntimeLinker::LinkStatus_INVALID_LIBAV_CANDIDATE: - case FFmpegRuntimeLinker::LinkStatus_OBSOLETE_FFMPEG: - case FFmpegRuntimeLinker::LinkStatus_OBSOLETE_LIBAV: - case FFmpegRuntimeLinker::LinkStatus_INVALID_CANDIDATE: - return DecoderDoctorDiagnostics::Flags::LibAVCodecUnsupported; - default: - MOZ_DIAGNOSTIC_ASSERT( - aStatus == FFmpegRuntimeLinker::LinkStatus_NOT_FOUND, - "Only call this method when linker fails."); - return DecoderDoctorDiagnostics::Flags::FFmpegNotFound; - } -} -#endif - void PDMFactory::CreateRddPDMs() { #ifdef XP_WIN if (StaticPrefs::media_wmf_enabled() && @@ -492,8 +472,9 @@ void PDMFactory::CreateRddPDMs() { if (StaticPrefs::media_ffmpeg_enabled() && StaticPrefs::media_rdd_ffmpeg_enabled() && !CreateAndStartupPDM()) { - mFailureFlags += GetFailureFlagBasedOnFFmpegStatus( - FFmpegRuntimeLinker::LinkStatusCode()); + mFailureFlags += DecoderDoctorDiagnostics::Flags::FFmpegFailedToLoad; + } else { + mFailureFlags -= DecoderDoctorDiagnostics::Flags::FFmpegFailedToLoad; } #endif CreateAndStartupPDM(); @@ -534,8 +515,7 @@ void PDMFactory::CreateContentPDMs() { #ifdef MOZ_FFMPEG if (StaticPrefs::media_ffmpeg_enabled() && !CreateAndStartupPDM()) { - mFailureFlags += GetFailureFlagBasedOnFFmpegStatus( - FFmpegRuntimeLinker::LinkStatusCode()); + mFailureFlags += DecoderDoctorDiagnostics::Flags::FFmpegFailedToLoad; } #endif #ifdef MOZ_WIDGET_ANDROID @@ -580,8 +560,7 @@ void PDMFactory::CreateDefaultPDMs() { #ifdef MOZ_FFMPEG if (StaticPrefs::media_ffmpeg_enabled() && !CreateAndStartupPDM()) { - mFailureFlags += GetFailureFlagBasedOnFFmpegStatus( - FFmpegRuntimeLinker::LinkStatusCode()); + mFailureFlags += DecoderDoctorDiagnostics::Flags::FFmpegFailedToLoad; } #endif #ifdef MOZ_WIDGET_ANDROID diff --git a/dom/webidl/DecoderDoctorNotification.webidl b/dom/webidl/DecoderDoctorNotification.webidl index 6c6ad6835e46..911531c992bd 100644 --- a/dom/webidl/DecoderDoctorNotification.webidl +++ b/dom/webidl/DecoderDoctorNotification.webidl @@ -14,18 +14,6 @@ enum DecoderDoctorNotificationType { "decode-warning", }; -enum DecoderDoctorReportType { - "mediawidevinenowmf", - "mediawmfneeded", - "mediaplatformdecodernotfound", - "mediacannotplaynodecoders", - "medianodecoders", - "mediacannotinitializepulseaudio", - "mediaunsupportedlibavcodec", - "mediadecodeerror", - "mediadecodewarning", -}; - [GenerateToJSON] dictionary DecoderDoctorNotification { required DecoderDoctorNotificationType type; diff --git a/dom/webidl/HTMLMediaElement.webidl b/dom/webidl/HTMLMediaElement.webidl index 601d651f9485..d7b52b8e79cf 100644 --- a/dom/webidl/HTMLMediaElement.webidl +++ b/dom/webidl/HTMLMediaElement.webidl @@ -204,18 +204,18 @@ partial interface HTMLMediaElement { Promise seekToNextFrame(); }; -/* Internal testing only API */ +/* + * These APIs are testing only, they are used to simulate visibility changes to help debug and write + * tests about suspend-video-decoding. + * + * - SetVisible() is for simulating visibility changes. + * - HasSuspendTaint() is for querying that the element's decoder cannot suspend + * video decoding because it has been tainted by an operation, such as + * drawImage(). + * - isVisible is a boolean value which indicate whether media element is visible. + * - isVideoDecodingSuspended() is used to know whether video decoding has suspended. + */ partial interface HTMLMediaElement { - // These APIs are used to simulate visibility changes to help debug and write - // tests about suspend-video-decoding. - // - SetVisible() is for simulating visibility changes. - // - HasSuspendTaint() is for querying that the element's decoder cannot suspend - // video decoding because it has been tainted by an operation, such as - // drawImage(). - // - isInViewPort is a boolean value which indicate whether media element is - // in view port. - // - isVideoDecodingSuspended() is used to know whether video decoding has - // suspended. [Pref="media.test.video-suspend"] void setVisible(boolean aVisible); @@ -236,16 +236,6 @@ partial interface HTMLMediaElement { [ChromeOnly] readonly attribute double videoDecodeSuspendedTime; - - // These APIs are used for decoder doctor tests. - [ChromeOnly] - void setFormatDiagnosticsReportForMimeType(DOMString mimeType, DecoderDoctorReportType error); - - [Throws, ChromeOnly] - void setDecodeError(DOMString error); - - [ChromeOnly] - void setAudioSinkFailedStartup(); }; /* Audio Output Devices API */ diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 4a2930381403..46778e1355f6 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -7516,11 +7516,6 @@ #endif # MOZ_WMF -- name: media.decoder-doctor.testing - type: bool - value: false - mirror: always - - name: media.hardware-video-decoding.force-enabled type: bool value: false diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 451c4fb9829f..bd6aa8ea764d 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -395,9 +395,9 @@ pref("media.gmp.storage.version.expected", 1); // Filter what triggers user notifications. // See DecoderDoctorDocumentWatcher::ReportAnalysis for details. #ifdef NIGHTLY_BUILD - pref("media.decoder-doctor.notifications-allowed", "MediaWMFNeeded,MediaWidevineNoWMF,MediaCannotInitializePulseAudio,MediaCannotPlayNoDecoders,MediaUnsupportedLibavcodec,MediaPlatformDecoderNotFound,MediaDecodeError"); + pref("media.decoder-doctor.notifications-allowed", "MediaWMFNeeded,MediaWidevineNoWMF,MediaCannotInitializePulseAudio,MediaCannotPlayNoDecoders,MediaUnsupportedLibavcodec,MediaDecodeError"); #else - pref("media.decoder-doctor.notifications-allowed", "MediaWMFNeeded,MediaWidevineNoWMF,MediaCannotInitializePulseAudio,MediaCannotPlayNoDecoders,MediaUnsupportedLibavcodec,MediaPlatformDecoderNotFound"); + pref("media.decoder-doctor.notifications-allowed", "MediaWMFNeeded,MediaWidevineNoWMF,MediaCannotInitializePulseAudio,MediaCannotPlayNoDecoders,MediaUnsupportedLibavcodec"); #endif pref("media.decoder-doctor.decode-errors-allowed", ""); pref("media.decoder-doctor.decode-warnings-allowed", "");