--- a/dom/media/DecoderDoctorDiagnostics.cpp
+++ b/dom/media/DecoderDoctorDiagnostics.cpp
@@ -298,32 +298,49 @@ DecoderDoctorDocumentWatcher::Synthesize
{
MOZ_ASSERT(NS_IsMainThread());
bool canPlay = false;
#if defined(MOZ_FFMPEG)
bool FFMpegNeeded = false;
#endif
nsAutoString unplayableFormats;
+ nsAutoString unsupportedKeySystems;
for (auto& diag : mDiagnosticsSequence) {
- if (!diag.mDecoderDoctorDiagnostics.Format().IsEmpty()) {
+ switch (diag.mDecoderDoctorDiagnostics.Type()) {
+ case DecoderDoctorDiagnostics::eFormatSupportCheck:
if (diag.mDecoderDoctorDiagnostics.CanPlay()) {
canPlay = true;
} else {
#if defined(MOZ_FFMPEG)
if (diag.mDecoderDoctorDiagnostics.DidFFmpegFailToLoad()) {
FFMpegNeeded = true;
}
#endif
if (!unplayableFormats.IsEmpty()) {
unplayableFormats += NS_LITERAL_STRING(", ");
}
unplayableFormats += diag.mDecoderDoctorDiagnostics.Format();
}
+ break;
+ case DecoderDoctorDiagnostics::eMediaKeySystemAccessRequest:
+ if (!diag.mDecoderDoctorDiagnostics.IsKeySystemSupported()) {
+ if (!unsupportedKeySystems.IsEmpty()) {
+ unsupportedKeySystems += NS_LITERAL_STRING(", ");
+ }
+ unsupportedKeySystems += diag.mDecoderDoctorDiagnostics.KeySystem();
+ }
+ break;
+ default:
+ MOZ_ASSERT(diag.mDecoderDoctorDiagnostics.Type()
+ == DecoderDoctorDiagnostics::eFormatSupportCheck
+ || diag.mDecoderDoctorDiagnostics.Type()
+ == DecoderDoctorDiagnostics::eMediaKeySystemAccessRequest);
+ break;
}
}
if (!canPlay) {
#if defined(MOZ_FFMPEG)
if (FFMpegNeeded) {
DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> Cannot play media because platform decoder was not found",
this, mDocument, NS_ConvertUTF16toUTF8(unplayableFormats).get());
@@ -405,16 +422,20 @@ DecoderDoctorDocumentWatcher::Notify(nsI
void
DecoderDoctorDiagnostics::StoreFormatDiagnostics(nsIDocument* aDocument,
const nsAString& aFormat,
bool aCanPlay,
const char* aCallSite)
{
MOZ_ASSERT(NS_IsMainThread());
+ // Make sure we only store once.
+ MOZ_ASSERT(mDiagnosticsType == eUnsaved);
+ mDiagnosticsType = eFormatSupportCheck;
+
if (NS_WARN_IF(!aDocument)) {
DD_WARN("DecoderDoctorDiagnostics[%p]::StoreFormatDiagnostics(nsIDocument* aDocument=nullptr, format='%s', can-play=%d, call site '%s')",
this, NS_ConvertUTF16toUTF8(aFormat).get(), aCanPlay, aCallSite);
return;
}
if (NS_WARN_IF(aFormat.IsEmpty())) {
DD_WARN("DecoderDoctorDiagnostics[%p]::StoreFormatDiagnostics(nsIDocument* aDocument=%p, format=<empty>, can-play=%d, call site '%s')",
this, aDocument, aCanPlay, aCallSite);
@@ -431,31 +452,96 @@ DecoderDoctorDiagnostics::StoreFormatDia
}
mFormat = aFormat;
mCanPlay = aCanPlay;
// StoreDiagnostics should only be called once, after all data is available,
// so it is safe to Move() from this object.
watcher->AddDiagnostics(Move(*this), aCallSite);
+ // Even though it's moved-from, the type should stay set
+ // (Only used to ensure that we do store only once.)
+ MOZ_ASSERT(mDiagnosticsType == eFormatSupportCheck);
+}
+
+void
+DecoderDoctorDiagnostics::StoreMediaKeySystemAccess(nsIDocument* aDocument,
+ const nsAString& aKeySystem,
+ bool aIsSupported,
+ const char* aCallSite)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ // Make sure we only store once.
+ MOZ_ASSERT(mDiagnosticsType == eUnsaved);
+ mDiagnosticsType = eMediaKeySystemAccessRequest;
+
+ if (NS_WARN_IF(!aDocument)) {
+ DD_WARN("DecoderDoctorDiagnostics[%p]::StoreMediaKeySystemAccess(nsIDocument* aDocument=nullptr, keysystem='%s', supported=%d, call site '%s')",
+ this, NS_ConvertUTF16toUTF8(aKeySystem).get(), aIsSupported, aCallSite);
+ return;
+ }
+ if (NS_WARN_IF(aKeySystem.IsEmpty())) {
+ DD_WARN("DecoderDoctorDiagnostics[%p]::StoreMediaKeySystemAccess(nsIDocument* aDocument=%p, keysystem=<empty>, supported=%d, call site '%s')",
+ this, aDocument, aIsSupported, aCallSite);
+ return;
+ }
+
+ RefPtr<DecoderDoctorDocumentWatcher> watcher =
+ DecoderDoctorDocumentWatcher::RetrieveOrCreate(aDocument);
+
+ if (NS_WARN_IF(!watcher)) {
+ DD_WARN("DecoderDoctorDiagnostics[%p]::StoreMediaKeySystemAccess(nsIDocument* aDocument=%p, keysystem='%s', supported=%d, call site '%s') - Could not create document watcher",
+ this, NS_ConvertUTF16toUTF8(aKeySystem).get(), aIsSupported, aCallSite);
+ return;
+ }
+
+ mKeySystem = aKeySystem;
+ mIsKeySystemSupported = aIsSupported;
+
+ // StoreDiagnostics should only be called once, after all data is available,
+ // so it is safe to Move() from this object.
+ watcher->AddDiagnostics(Move(*this), aCallSite);
+ // Even though it's moved-from, the type should stay set
+ // (Only used to ensure that we do store only once.)
+ MOZ_ASSERT(mDiagnosticsType == eMediaKeySystemAccessRequest);
}
nsCString
DecoderDoctorDiagnostics::GetDescription() const
{
+ MOZ_ASSERT(mDiagnosticsType == eFormatSupportCheck
+ || mDiagnosticsType == eMediaKeySystemAccessRequest);
nsCString s;
- if (!mFormat.IsEmpty()) {
+ switch (mDiagnosticsType) {
+ case eUnsaved:
+ s = "Unsaved diagnostics, cannot get accurate description";
+ break;
+ case eFormatSupportCheck:
s = "format='";
s += NS_ConvertUTF16toUTF8(mFormat).get();
s += mCanPlay ? "', can play" : "', cannot play";
if (mWMFFailedToLoad) {
s += ", Windows platform decoder failed to load";
}
if (mFFmpegFailedToLoad) {
s += ", Linux platform decoder failed to load";
}
- } else {
- s = "?";
+ break;
+ case eMediaKeySystemAccessRequest:
+ s = "key system='";
+ s += NS_ConvertUTF16toUTF8(mKeySystem).get();
+ s += mIsKeySystemSupported ? "', supported" : "', not supported";
+ switch (mKeySystemIssue) {
+ case eUnset:
+ break;
+ case eWidevineWithNoWMF:
+ s += ", Widevine with no WMF";
+ break;
+ }
+ break;
+ default:
+ s = "?";
+ break;
}
return s;
}
} // namespace mozilla
--- a/dom/media/DecoderDoctorDiagnostics.h
+++ b/dom/media/DecoderDoctorDiagnostics.h
@@ -2,18 +2,19 @@
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DecoderDoctorDiagnostics_h_
#define DecoderDoctorDiagnostics_h_
+#include "nsString.h"
+
class nsIDocument;
-class nsAString;
namespace mozilla {
// DecoderDoctorDiagnostics class, used to gather data from PDMs/DecoderTraits,
// and then notify the user about issues preventing (or worsening) playback.
//
// The expected usage is:
// 1. Instantiate a DecoderDoctorDiagnostics in a function (close to the point
@@ -35,34 +36,70 @@ public:
// given format. All diagnostics for a document will be analyzed together
// within a short timeframe.
// Should only be called once.
void StoreFormatDiagnostics(nsIDocument* aDocument,
const nsAString& aFormat,
bool aCanPlay,
const char* aCallSite);
- // Description string, for logging purposes.
+ void StoreMediaKeySystemAccess(nsIDocument* aDocument,
+ const nsAString& aKeySystem,
+ bool aIsSupported,
+ const char* aCallSite);
+
+ enum DiagnosticsType {
+ eUnsaved,
+ eFormatSupportCheck,
+ eMediaKeySystemAccessRequest
+ };
+ DiagnosticsType Type() const { return mDiagnosticsType; }
+
+ // Description string, for logging purposes; only call on stored diags.
nsCString GetDescription() const;
// Methods to record diagnostic information:
const nsAString& Format() const { return mFormat; }
bool CanPlay() const { return mCanPlay; }
void SetWMFFailedToLoad() { mWMFFailedToLoad = true; }
bool DidWMFFailToLoad() const { return mWMFFailedToLoad; }
void SetFFmpegFailedToLoad() { mFFmpegFailedToLoad = true; }
bool DidFFmpegFailToLoad() const { return mFFmpegFailedToLoad; }
+ const nsAString& KeySystem() const { return mKeySystem; }
+ bool IsKeySystemSupported() const { return mIsKeySystemSupported; }
+ enum KeySystemIssue {
+ eUnset,
+ eWidevineWithNoWMF
+ };
+ void SetKeySystemIssue(KeySystemIssue aKeySystemIssue)
+ {
+ mKeySystemIssue = aKeySystemIssue;
+ }
+ KeySystemIssue GetKeySystemIssue() const
+ {
+ return mKeySystemIssue;
+ }
+
private:
+ // Currently-known type of diagnostics. Set from one of the 'Store...' methods.
+ // This helps ensure diagnostics are only stored once,
+ // and makes it easy to know what information they contain.
+ DiagnosticsType mDiagnosticsType = eUnsaved;
+
nsString mFormat;
// True if there is at least one decoder that can play that format.
bool mCanPlay = false;
bool mWMFFailedToLoad = false;
bool mFFmpegFailedToLoad = false;
+
+ nsString mKeySystem;
+ bool mIsKeySystemSupported = false;
+ KeySystemIssue mKeySystemIssue = eUnset;
};
} // namespace mozilla
#endif
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -28,16 +28,17 @@
#include "mozilla/EMEUtils.h"
#include "GMPUtils.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsXULAppAPI.h"
#include "gmp-audio-decode.h"
#include "gmp-video-decode.h"
+#include "DecoderDoctorDiagnostics.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeySystemAccess,
mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeySystemAccess)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeySystemAccess)
@@ -316,129 +317,144 @@ MediaKeySystemAccess::GetKeySystemStatus
}
#endif
return MediaKeySystemStatus::Cdm_not_supported;
}
static bool
GMPDecryptsAndDecodesAAC(mozIGeckoMediaPluginService* aGMPS,
- const nsAString& aKeySystem)
+ const nsAString& aKeySystem,
+ DecoderDoctorDiagnostics* aDiagnostics)
{
MOZ_ASSERT(HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
return HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
NS_LITERAL_CSTRING("aac"));
}
static bool
GMPDecryptsAndDecodesH264(mozIGeckoMediaPluginService* aGMPS,
- const nsAString& aKeySystem)
+ const nsAString& aKeySystem,
+ DecoderDoctorDiagnostics* aDiagnostics)
{
MOZ_ASSERT(HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
return HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
NS_LITERAL_CSTRING("h264"));
}
// If this keysystem's CDM explicitly says it doesn't support decoding,
// that means it's OK with passing the decrypted samples back to Gecko
// for decoding.
static bool
GMPDecryptsAndGeckoDecodesH264(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
- const nsAString& aContentType)
+ const nsAString& aContentType,
+ DecoderDoctorDiagnostics* aDiagnostics)
{
MOZ_ASSERT(HaveGMPFor(aGMPService,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
MOZ_ASSERT(IsH264ContentType(aContentType));
return !HaveGMPFor(aGMPService,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
NS_LITERAL_CSTRING("h264")) &&
- MP4Decoder::CanHandleMediaType(aContentType,
- /* DecoderDoctorDiagnostics* */ nullptr);
+ MP4Decoder::CanHandleMediaType(aContentType, aDiagnostics);
}
static bool
GMPDecryptsAndGeckoDecodesAAC(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
- const nsAString& aContentType)
+ const nsAString& aContentType,
+ DecoderDoctorDiagnostics* aDiagnostics)
{
MOZ_ASSERT(HaveGMPFor(aGMPService,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
MOZ_ASSERT(IsAACContentType(aContentType));
- return !HaveGMPFor(aGMPService,
- NS_ConvertUTF16toUTF8(aKeySystem),
- NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
- NS_LITERAL_CSTRING("aac")) &&
+ if (HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
+ NS_LITERAL_CSTRING("aac"))) {
+ // We do have a GMP for AAC -> Gecko itself does *not* decode AAC.
+ return false;
+ }
#if defined(MOZ_WIDEVINE_EME) && defined(XP_WIN)
- // Widevine CDM doesn't include an AAC decoder. So if WMF can't
- // decode AAC, and a codec wasn't specified, be conservative
- // and reject the MediaKeys request, since our policy is to prevent
- // the Adobe GMP's unencrypted AAC decoding path being used to
- // decode content decrypted by the Widevine CDM.
- (!aKeySystem.EqualsLiteral("com.widevine.alpha") || WMFDecoderModule::HasAAC()) &&
+ // Widevine CDM doesn't include an AAC decoder. So if WMF can't
+ // decode AAC, and a codec wasn't specified, be conservative
+ // and reject the MediaKeys request, since our policy is to prevent
+ // the Adobe GMP's unencrypted AAC decoding path being used to
+ // decode content decrypted by the Widevine CDM.
+ if (aKeySystem.EqualsLiteral("com.widevine.alpha") &&
+ !WMFDecoderModule::HasAAC()) {
+ if (aDiagnostics) {
+ aDiagnostics->SetKeySystemIssue(
+ DecoderDoctorDiagnostics::eWidevineWithNoWMF);
+ }
+ return false;
+ }
#endif
- MP4Decoder::CanHandleMediaType(aContentType,
- /* DecoderDoctorDiagnostics* */ nullptr);
+ return MP4Decoder::CanHandleMediaType(aContentType, aDiagnostics);
}
static bool
IsSupportedAudio(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
- const nsAString& aAudioType)
+ const nsAString& aAudioType,
+ DecoderDoctorDiagnostics* aDiagnostics)
{
return IsAACContentType(aAudioType) &&
- (GMPDecryptsAndDecodesAAC(aGMPService, aKeySystem) ||
- GMPDecryptsAndGeckoDecodesAAC(aGMPService, aKeySystem, aAudioType));
+ (GMPDecryptsAndDecodesAAC(aGMPService, aKeySystem, aDiagnostics) ||
+ GMPDecryptsAndGeckoDecodesAAC(aGMPService, aKeySystem, aAudioType, aDiagnostics));
}
static bool
IsSupportedVideo(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
- const nsAString& aVideoType)
+ const nsAString& aVideoType,
+ DecoderDoctorDiagnostics* aDiagnostics)
{
return IsH264ContentType(aVideoType) &&
- (GMPDecryptsAndDecodesH264(aGMPService, aKeySystem) ||
- GMPDecryptsAndGeckoDecodesH264(aGMPService, aKeySystem, aVideoType));
+ (GMPDecryptsAndDecodesH264(aGMPService, aKeySystem, aDiagnostics) ||
+ GMPDecryptsAndGeckoDecodesH264(aGMPService, aKeySystem, aVideoType, aDiagnostics));
}
static bool
IsSupported(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
- const MediaKeySystemConfiguration& aConfig)
+ const MediaKeySystemConfiguration& aConfig,
+ DecoderDoctorDiagnostics* aDiagnostics)
{
if (aConfig.mInitDataType.IsEmpty() &&
aConfig.mAudioType.IsEmpty() &&
aConfig.mVideoType.IsEmpty()) {
// Not an old-style request.
return false;
}
// Backwards compatibility with legacy MediaKeySystemConfiguration method.
if (!aConfig.mInitDataType.IsEmpty() &&
!aConfig.mInitDataType.EqualsLiteral("cenc")) {
return false;
}
if (!aConfig.mAudioType.IsEmpty() &&
- !IsSupportedAudio(aGMPService, aKeySystem, aConfig.mAudioType)) {
+ !IsSupportedAudio(aGMPService, aKeySystem, aConfig.mAudioType, aDiagnostics)) {
return false;
}
if (!aConfig.mVideoType.IsEmpty() &&
- !IsSupportedVideo(aGMPService, aKeySystem, aConfig.mVideoType)) {
+ !IsSupportedVideo(aGMPService, aKeySystem, aConfig.mVideoType, aDiagnostics)) {
return false;
}
return true;
}
static bool
IsSupportedInitDataType(const nsString& aCandidate, const nsAString& aKeySystem)
@@ -453,17 +469,18 @@ IsSupportedInitDataType(const nsString&
) &&
(aCandidate.EqualsLiteral("keyids") || aCandidate.EqualsLiteral("webm)")));
}
static bool
GetSupportedConfig(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const MediaKeySystemConfiguration& aCandidate,
- MediaKeySystemConfiguration& aOutConfig)
+ MediaKeySystemConfiguration& aOutConfig,
+ DecoderDoctorDiagnostics* aDiagnostics)
{
MediaKeySystemConfiguration config;
config.mLabel = aCandidate.mLabel;
if (aCandidate.mInitDataTypes.WasPassed()) {
nsTArray<nsString> initDataTypes;
for (const nsString& candidate : aCandidate.mInitDataTypes.Value()) {
if (IsSupportedInitDataType(candidate, aKeySystem)) {
initDataTypes.AppendElement(candidate);
@@ -473,30 +490,30 @@ GetSupportedConfig(mozIGeckoMediaPluginS
return false;
}
config.mInitDataTypes.Construct();
config.mInitDataTypes.Value().Assign(initDataTypes);
}
if (aCandidate.mAudioCapabilities.WasPassed()) {
nsTArray<MediaKeySystemMediaCapability> caps;
for (const MediaKeySystemMediaCapability& cap : aCandidate.mAudioCapabilities.Value()) {
- if (IsSupportedAudio(aGMPService, aKeySystem, cap.mContentType)) {
+ if (IsSupportedAudio(aGMPService, aKeySystem, cap.mContentType, aDiagnostics)) {
caps.AppendElement(cap);
}
}
if (caps.IsEmpty()) {
return false;
}
config.mAudioCapabilities.Construct();
config.mAudioCapabilities.Value().Assign(caps);
}
if (aCandidate.mVideoCapabilities.WasPassed()) {
nsTArray<MediaKeySystemMediaCapability> caps;
for (const MediaKeySystemMediaCapability& cap : aCandidate.mVideoCapabilities.Value()) {
- if (IsSupportedVideo(aGMPService, aKeySystem, cap.mContentType)) {
+ if (IsSupportedVideo(aGMPService, aKeySystem, cap.mContentType, aDiagnostics)) {
caps.AppendElement(cap);
}
}
if (caps.IsEmpty()) {
return false;
}
config.mVideoCapabilities.Construct();
config.mVideoCapabilities.Value().Assign(caps);
@@ -504,72 +521,79 @@ GetSupportedConfig(mozIGeckoMediaPluginS
#if defined(MOZ_WIDEVINE_EME) && defined(XP_WIN)
// Widevine CDM doesn't include an AAC decoder. So if WMF can't decode AAC,
// and a codec wasn't specified, be conservative and reject the MediaKeys request.
if (aKeySystem.EqualsLiteral("com.widevine.alpha") &&
(!aCandidate.mAudioCapabilities.WasPassed() ||
!aCandidate.mVideoCapabilities.WasPassed()) &&
!WMFDecoderModule::HasAAC()) {
+ if (aDiagnostics) {
+ aDiagnostics->SetKeySystemIssue(
+ DecoderDoctorDiagnostics::eWidevineWithNoWMF);
+ }
return false;
}
#endif
aOutConfig = config;
return true;
}
// Backwards compatibility with legacy requestMediaKeySystemAccess with fields
// from old MediaKeySystemOptions dictionary.
/* static */
bool
MediaKeySystemAccess::IsSupported(const nsAString& aKeySystem,
- const Sequence<MediaKeySystemConfiguration>& aConfigs)
+ const Sequence<MediaKeySystemConfiguration>& aConfigs,
+ DecoderDoctorDiagnostics* aDiagnostics)
{
nsCOMPtr<mozIGeckoMediaPluginService> mps =
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
if (NS_WARN_IF(!mps)) {
return false;
}
if (!HaveGMPFor(mps,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))) {
return false;
}
for (const MediaKeySystemConfiguration& config : aConfigs) {
- if (mozilla::dom::IsSupported(mps, aKeySystem, config)) {
+ if (mozilla::dom::IsSupported(mps, aKeySystem, config, aDiagnostics)) {
return true;
}
}
return false;
}
/* static */
bool
MediaKeySystemAccess::GetSupportedConfig(const nsAString& aKeySystem,
const Sequence<MediaKeySystemConfiguration>& aConfigs,
- MediaKeySystemConfiguration& aOutConfig)
+ MediaKeySystemConfiguration& aOutConfig,
+ DecoderDoctorDiagnostics* aDiagnostics)
{
nsCOMPtr<mozIGeckoMediaPluginService> mps =
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
if (NS_WARN_IF(!mps)) {
return false;
}
if (!HaveGMPFor(mps,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))) {
return false;
}
for (const MediaKeySystemConfiguration& config : aConfigs) {
- if (mozilla::dom::GetSupportedConfig(mps, aKeySystem, config, aOutConfig)) {
+ if (mozilla::dom::GetSupportedConfig(
+ mps, aKeySystem, config, aOutConfig, aDiagnostics)) {
return true;
}
}
return false;
}
--- a/dom/media/eme/MediaKeySystemAccess.h
+++ b/dom/media/eme/MediaKeySystemAccess.h
@@ -14,16 +14,19 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/MediaKeySystemAccessBinding.h"
#include "mozilla/dom/MediaKeysRequestStatusBinding.h"
#include "js/TypeDecls.h"
namespace mozilla {
+
+class DecoderDoctorDiagnostics;
+
namespace dom {
class MediaKeySystemAccess final : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeySystemAccess)
@@ -51,29 +54,31 @@ public:
static MediaKeySystemStatus GetKeySystemStatus(const nsAString& aKeySystem,
int32_t aMinCdmVersion,
nsACString& aOutExceptionMessage,
nsACString& aOutCdmVersion);
static bool IsSupported(const nsAString& aKeySystem,
- const Sequence<MediaKeySystemConfiguration>& aConfigs);
+ const Sequence<MediaKeySystemConfiguration>& aConfigs,
+ DecoderDoctorDiagnostics* aDiagnostics);
static void NotifyObservers(nsPIDOMWindowInner* aWindow,
const nsAString& aKeySystem,
MediaKeySystemStatus aStatus);
static bool IsGMPPresentOnDisk(const nsAString& aKeySystem,
const nsACString& aVersion,
nsACString& aOutMessage);
static bool GetSupportedConfig(const nsAString& aKeySystem,
const Sequence<MediaKeySystemConfiguration>& aConfigs,
- MediaKeySystemConfiguration& aOutConfig);
+ MediaKeySystemConfiguration& aOutConfig,
+ DecoderDoctorDiagnostics* aDiagnostics);
private:
nsCOMPtr<nsPIDOMWindowInner> mParent;
const nsString mKeySystem;
const nsString mCDMVersion;
const MediaKeySystemConfiguration mConfig;
};
--- a/dom/media/eme/MediaKeySystemAccessManager.cpp
+++ b/dom/media/eme/MediaKeySystemAccessManager.cpp
@@ -1,13 +1,14 @@
/* 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 "MediaKeySystemAccessManager.h"
+#include "DecoderDoctorDiagnostics.h"
#include "mozilla/Preferences.h"
#include "mozilla/EMEUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsIObserverService.h"
#include "mozilla/Services.h"
#include "mozilla/DetailedPromise.h"
#ifdef XP_WIN
@@ -75,35 +76,41 @@ MediaKeySystemAccessManager::Request(Det
void
MediaKeySystemAccessManager::Request(DetailedPromise* aPromise,
const nsAString& aKeySystem,
const Sequence<MediaKeySystemConfiguration>& aConfigs,
RequestType aType)
{
EME_LOG("MediaKeySystemAccessManager::Request %s", NS_ConvertUTF16toUTF8(aKeySystem).get());
+ DecoderDoctorDiagnostics diagnostics;
+
// Parse keysystem, split it out into keySystem prefix, and version suffix.
nsAutoString keySystem;
int32_t minCdmVersion = NO_CDM_VERSION;
if (!ParseKeySystem(aKeySystem, keySystem, minCdmVersion)) {
// Not to inform user, because nothing to do if the keySystem is not
// supported.
aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
NS_LITERAL_CSTRING("Key system string is invalid,"
" or key system is unsupported"));
+ diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(),
+ aKeySystem, false, __func__);
return;
}
if (!Preferences::GetBool("media.eme.enabled", false)) {
// EME disabled by user, send notification to chrome so UI can inform user.
MediaKeySystemAccess::NotifyObservers(mWindow,
aKeySystem,
MediaKeySystemStatus::Api_disabled);
aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
NS_LITERAL_CSTRING("EME has been preffed off"));
+ diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(),
+ aKeySystem, false, __func__);
return;
}
nsAutoCString message;
nsAutoCString cdmVersion;
MediaKeySystemStatus status =
MediaKeySystemAccess::GetKeySystemStatus(keySystem, minCdmVersion, message, cdmVersion);
@@ -136,46 +143,54 @@ MediaKeySystemAccessManager::Request(Det
MediaKeySystemAccess::NotifyObservers(mWindow, keySystem, status);
} else {
// We waited or can't wait for an update and we still can't service
// the request. Give up. Chrome will still be showing a "I can't play,
// updating" notification.
aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
NS_LITERAL_CSTRING("Gave up while waiting for a CDM update"));
}
+ diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(),
+ aKeySystem, false, __func__);
return;
}
if (status != MediaKeySystemStatus::Available) {
if (status != MediaKeySystemStatus::Error) {
// Failed due to user disabling something, send a notification to
// chrome, so we can show some UI to explain how the user can rectify
// the situation.
MediaKeySystemAccess::NotifyObservers(mWindow, keySystem, status);
aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR, message);
return;
}
aPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("GetKeySystemAccess failed"));
+ diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(),
+ aKeySystem, false, __func__);
return;
}
MediaKeySystemConfiguration config;
// TODO: Remove IsSupported() check here once we remove backwards
// compatibility with initial implementation...
- if (MediaKeySystemAccess::GetSupportedConfig(keySystem, aConfigs, config) ||
- MediaKeySystemAccess::IsSupported(keySystem, aConfigs)) {
+ if (MediaKeySystemAccess::GetSupportedConfig(keySystem, aConfigs, config, &diagnostics) ||
+ MediaKeySystemAccess::IsSupported(keySystem, aConfigs, &diagnostics)) {
RefPtr<MediaKeySystemAccess> access(
new MediaKeySystemAccess(mWindow, keySystem, NS_ConvertUTF8toUTF16(cdmVersion), config));
aPromise->MaybeResolve(access);
+ diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(),
+ aKeySystem, true, __func__);
return;
}
// Not to inform user, because nothing to do if the corresponding keySystem
// configuration is not supported.
aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
NS_LITERAL_CSTRING("Key system configuration is not supported"));
+ diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(),
+ aKeySystem, false, __func__);
}
MediaKeySystemAccessManager::PendingRequest::PendingRequest(DetailedPromise* aPromise,
const nsAString& aKeySystem,
const Sequence<MediaKeySystemConfiguration>& aConfigs,
nsITimer* aTimer)
: mPromise(aPromise)
, mKeySystem(aKeySystem)