Backed out 8 changesets (bug 1691578) for bc failures on browser_decoderDoctor.js. CLOSED TREE

Backed out changeset c535dd429ada (bug 1691578)
Backed out changeset 518eadda7826 (bug 1691578)
Backed out changeset c181e29b13f2 (bug 1691578)
Backed out changeset 23f6dcc3ceb5 (bug 1691578)
Backed out changeset bfd3e4878545 (bug 1691578)
Backed out changeset 214ab3a2f00b (bug 1691578)
Backed out changeset 71a17ff3322c (bug 1691578)
Backed out changeset 6aa662e8d06e (bug 1691578)
This commit is contained in:
Cosmin Sabou 2021-02-25 21:08:07 +02:00
parent a38e77b0db
commit 424d49d43e
11 changed files with 88 additions and 588 deletions

View File

@ -9,9 +9,6 @@
#endif
#include "mozilla/dom/HTMLMediaElement.h"
#include <unordered_map>
#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<layers::Image> HTMLMediaElement::GetCurrentImage() {
MarkAsTainted();

View File

@ -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.
//

View File

@ -6,13 +6,11 @@
#include "DecoderDoctorDiagnostics.h"
#include <string.h>
#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

View File

@ -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<Flags>;
@ -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

View File

@ -3,4 +3,3 @@ tags = decoderdoctor
support-files =
[browser_decoderDoctor.js]
[browser_doctor_notification.js]

View File

@ -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;
}
);
}

View File

@ -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<FFmpegRuntimeLinker>()) {
mFailureFlags += GetFailureFlagBasedOnFFmpegStatus(
FFmpegRuntimeLinker::LinkStatusCode());
mFailureFlags += DecoderDoctorDiagnostics::Flags::FFmpegFailedToLoad;
} else {
mFailureFlags -= DecoderDoctorDiagnostics::Flags::FFmpegFailedToLoad;
}
#endif
CreateAndStartupPDM<AgnosticDecoderModule>();
@ -534,8 +515,7 @@ void PDMFactory::CreateContentPDMs() {
#ifdef MOZ_FFMPEG
if (StaticPrefs::media_ffmpeg_enabled() &&
!CreateAndStartupPDM<FFmpegRuntimeLinker>()) {
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<FFmpegRuntimeLinker>()) {
mFailureFlags += GetFailureFlagBasedOnFFmpegStatus(
FFmpegRuntimeLinker::LinkStatusCode());
mFailureFlags += DecoderDoctorDiagnostics::Flags::FFmpegFailedToLoad;
}
#endif
#ifdef MOZ_WIDGET_ANDROID

View File

@ -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;

View File

@ -204,18 +204,18 @@ partial interface HTMLMediaElement {
Promise<void> 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 */

View File

@ -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

View File

@ -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", "");