Bug 848994 - p6. Analyze Windows issues - r=cpearce
authorGerald Squelart <gsquelart@mozilla.com>
Fri, 22 Apr 2016 13:42:11 +1000
changeset 332311 4f09b3b6b8e9181652c1a005898ee019ddc11456
parent 332310 0843709b5d55e352fc464a43619bb982a4af6487
child 332312 e07d236d6566e9637a155a9de08c08bb8cef9eb9
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs848994
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 848994 - p6. Analyze Windows issues - r=cpearce Analyze the diagnostics information gathered so far, and dispatch notifications as appropriate. The most important case in this bug is when Widevine is requested but WMF and Silverlight are missing. The generic case of WMF missing (when needed to play) is there too. Note: Currently no notifications are actually sent to the front-end by default, the following patch will add filtering to allow/prevent targeted notifications. MozReview-Commit-ID: EB9PKrMgKSr
dom/locales/en-US/chrome/dom/dom.properties
dom/media/DecoderDoctorDiagnostics.cpp
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -102,21 +102,24 @@ MediaLoadInvalidURI=Invalid URI. Load of
 # LOCALIZATION NOTE: %1$S is the media resource's format/codec type (basically equivalent to the file type, e.g. MP4,AVI,WMV,MOV etc), %2$S is the URL of the media resource which failed to load.
 MediaLoadUnsupportedTypeAttribute=Specified "type" attribute of "%1$S" is not supported. Load of media resource %2$S failed.
 # LOCALIZATION NOTE: %1$S is the "media" attribute value of the <source> element. It is a media query. %2$S is the URL of the media resource which failed to load.
 MediaLoadSourceMediaNotMatched=Specified "media" attribute of "%1$S" does not match the environment. Load of media resource %2$S failed.
 # LOCALIZATION NOTE: %1$S is the MIME type HTTP header being sent by the web server, %2$S is the URL of the media resource which failed to load.
 MediaLoadUnsupportedMimeType=HTTP "Content-Type" of "%1$S" is not supported. Load of media resource %2$S failed.
 # LOCALIZATION NOTE: %S is the URL of the media resource which failed to load because of error in decoding.
 MediaLoadDecodeError=Media resource %S could not be decoded.
+MediaWidevineNoWMFNoSilverlight=Trying to play Widevine with no Windows Media Foundation (nor Silverlight fallback), see https://support.mozilla.org/kb/fix-video-audio-problems-firefox-windows
+# LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
+MediaWMFNeeded=To play video formats %S, you need to install extra Microsoft software, see https://support.mozilla.org/kb/fix-video-audio-problems-firefox-windows
+# LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
+MediaPlatformDecoderNotFound=The video on this page can't be played. Your system may not have the required video codecs for: %S
 # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
 MediaCannotPlayNoDecoders=Cannot play media. No decoders for requested formats: %S
 # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
-MediaPlatformDecoderNotFound=The video on this page can't be played. Your system may not have the required video codecs for: %S
-# LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
 MediaNoDecoders=No decoders for some of the requested formats: %S
 # LOCALIZATION NOTE: Do not translate "MediaRecorder".
 MediaRecorderMultiTracksNotSupported=MediaRecorder does not support recording multiple tracks of the same type at this time.
 # LOCALIZATION NOTE: %S is the ID of the MediaStreamTrack passed to MediaStream.addTrack(). Do not translate "MediaStreamTrack" and "AudioChannel".
 MediaStreamAddTrackDifferentAudioChannel=MediaStreamTrack %S could not be added since it belongs to a different AudioChannel.
 # LOCALIZATION NOTE: Do not translate "MediaStream", "stop()" and "MediaStreamTrack"
 MediaStreamStopDeprecatedWarning=MediaStream.stop() is deprecated and will soon be removed. Use MediaStreamTrack.stop() instead.
 # LOCALIZATION NOTE: Do not translate "DOMException", "code" and "name"
--- a/dom/media/DecoderDoctorDiagnostics.cpp
+++ b/dom/media/DecoderDoctorDiagnostics.cpp
@@ -261,41 +261,42 @@ DispatchNotification(nsISupports* aSubje
     obs->NotifyObservers(aSubject, "decoder-doctor-notification", json.get());
   }
 }
 
 void
 DecoderDoctorDocumentWatcher::ReportAnalysis(
   dom::DecoderDoctorNotificationType aNotificationType,
   const char* aReportStringId,
-  const nsAString& aFormats)
+  const nsAString& aParams)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!mDocument) {
     return;
   }
 
-  const char16_t* params[] = { aFormats.Data() };
+  // 'params' will only be forwarded for non-empty strings.
+  const char16_t* params[1] = { aParams.Data() };
   DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::ReportAnalysis() ReportToConsole - aMsg='%s' params[0]='%s'",
            this, mDocument, aReportStringId,
-           NS_ConvertUTF16toUTF8(params[0]).get());
+           aParams.IsEmpty() ? "<no params>" : NS_ConvertUTF16toUTF8(params[0]).get());
   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                   NS_LITERAL_CSTRING("Media"),
                                   mDocument,
                                   nsContentUtils::eDOM_PROPERTIES,
                                   aReportStringId,
-                                  params,
-                                  ArrayLength(params));
+                                  aParams.IsEmpty() ? nullptr : params,
+                                  aParams.IsEmpty() ? 0 : 1);
 
   // For now, disable all front-end notifications by default.
   // TODO: Future bugs will use finer-grained filtering instead.
   if (Preferences::GetBool("media.decoderdoctor.enable-notification-bar", false)) {
     DispatchNotification(
-      mDocument->GetInnerWindow(), aNotificationType, aFormats);
+      mDocument->GetInnerWindow(), aNotificationType, aParams);
   }
 }
 
 enum SilverlightPresence {
   eNoSilverlight,
   eSilverlightDisabled,
   eSilverlightEnabled
 };
@@ -316,89 +317,143 @@ CheckSilverlight()
         return plugin->IsEnabled() ? eSilverlightEnabled : eSilverlightDisabled;
       }
     }
   }
 
   return eNoSilverlight;
 }
 
+static void AppendToStringList(nsAString& list, const nsAString& item)
+{
+  if (!list.IsEmpty()) {
+    list += NS_LITERAL_STRING(", ");
+  }
+  list += item;
+}
+
 void
 DecoderDoctorDocumentWatcher::SynthesizeAnalysis()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   bool canPlay = false;
+#if defined(XP_WIN)
+  bool WMFNeeded = false;
+#endif
 #if defined(MOZ_FFMPEG)
   bool FFMpegNeeded = false;
 #endif
+  nsAutoString playableFormats;
   nsAutoString unplayableFormats;
+  nsAutoString supportedKeySystems;
   nsAutoString unsupportedKeySystems;
+  DecoderDoctorDiagnostics::KeySystemIssue lastKeySystemIssue =
+    DecoderDoctorDiagnostics::eUnset;
 
   for (auto& diag : mDiagnosticsSequence) {
     switch (diag.mDecoderDoctorDiagnostics.Type()) {
     case DecoderDoctorDiagnostics::eFormatSupportCheck:
       if (diag.mDecoderDoctorDiagnostics.CanPlay()) {
         canPlay = true;
+        AppendToStringList(playableFormats,
+                           diag.mDecoderDoctorDiagnostics.Format());
       } else {
+#if defined(XP_WIN)
+        if (diag.mDecoderDoctorDiagnostics.DidWMFFailToLoad()) {
+          WMFNeeded = true;
+        }
+#endif
 #if defined(MOZ_FFMPEG)
         if (diag.mDecoderDoctorDiagnostics.DidFFmpegFailToLoad()) {
           FFMpegNeeded = true;
         }
 #endif
-        if (!unplayableFormats.IsEmpty()) {
-          unplayableFormats += NS_LITERAL_STRING(", ");
-        }
-        unplayableFormats += diag.mDecoderDoctorDiagnostics.Format();
+        AppendToStringList(unplayableFormats,
+                           diag.mDecoderDoctorDiagnostics.Format());
       }
       break;
     case DecoderDoctorDiagnostics::eMediaKeySystemAccessRequest:
-      if (!diag.mDecoderDoctorDiagnostics.IsKeySystemSupported()) {
-        if (!unsupportedKeySystems.IsEmpty()) {
-          unsupportedKeySystems += NS_LITERAL_STRING(", ");
+      if (diag.mDecoderDoctorDiagnostics.IsKeySystemSupported()) {
+        AppendToStringList(supportedKeySystems,
+                           diag.mDecoderDoctorDiagnostics.KeySystem());
+      } else {
+        AppendToStringList(unsupportedKeySystems,
+                           diag.mDecoderDoctorDiagnostics.KeySystem());
+        DecoderDoctorDiagnostics::KeySystemIssue issue =
+          diag.mDecoderDoctorDiagnostics.GetKeySystemIssue();
+        if (issue != DecoderDoctorDiagnostics::eUnset) {
+          lastKeySystemIssue = issue;
         }
-        unsupportedKeySystems += diag.mDecoderDoctorDiagnostics.KeySystem();
       }
       break;
     default:
       MOZ_ASSERT(diag.mDecoderDoctorDiagnostics.Type()
                    == DecoderDoctorDiagnostics::eFormatSupportCheck
                  || diag.mDecoderDoctorDiagnostics.Type()
                       == DecoderDoctorDiagnostics::eMediaKeySystemAccessRequest);
       break;
     }
   }
 
-  if (!canPlay) {
+  // Look at Key System issues first, as they may influence format checks.
+  if (!unsupportedKeySystems.IsEmpty() && supportedKeySystems.IsEmpty()) {
+    // No supported key systems!
+    switch (lastKeySystemIssue) {
+    case DecoderDoctorDiagnostics::eWidevineWithNoWMF:
+      if (CheckSilverlight() != eSilverlightEnabled) {
+        DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - unsupported key systems: %s, widevine without WMF nor Silverlight",
+                 this, mDocument, NS_ConvertUTF16toUTF8(unplayableFormats).get());
+        ReportAnalysis(dom::DecoderDoctorNotificationType::Platform_decoder_not_found,
+                       "MediaWidevineNoWMFNoSilverlight", NS_LITERAL_STRING(""));
+        return;
+      }
+      break;
+    default:
+      break;
+    }
+  }
+
+  if (!canPlay && !unplayableFormats.IsEmpty()) {
+#if defined(XP_WIN)
+    if (WMFNeeded) {
+      DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - formats: %s -> Cannot play media because WMF was not found",
+               this, mDocument, NS_ConvertUTF16toUTF8(unplayableFormats).get());
+      ReportAnalysis(dom::DecoderDoctorNotificationType::Platform_decoder_not_found,
+                     "MediaWMFNeeded", unplayableFormats);
+      return;
+    }
+#endif
 #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());
       ReportAnalysis(dom::DecoderDoctorNotificationType::Platform_decoder_not_found,
                      "MediaPlatformDecoderNotFound", unplayableFormats);
-    } else
+      return;
+    }
 #endif
-    {
-      DD_WARN("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - Cannot play media, unplayable formats: %s",
-              this, mDocument, NS_ConvertUTF16toUTF8(unplayableFormats).get());
-      ReportAnalysis(dom::DecoderDoctorNotificationType::Cannot_play,
-                     "MediaCannotPlayNoDecoders", unplayableFormats);
-    }
-  } else if (!unplayableFormats.IsEmpty()) {
+    DD_WARN("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - Cannot play media, unplayable formats: %s",
+            this, mDocument, NS_ConvertUTF16toUTF8(unplayableFormats).get());
+    ReportAnalysis(dom::DecoderDoctorNotificationType::Cannot_play,
+                   "MediaCannotPlayNoDecoders", unplayableFormats);
+    return;
+  }
+  if (!unplayableFormats.IsEmpty()) {
     DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - Can play media, but no decoders for some requested formats: %s",
             this, mDocument, NS_ConvertUTF16toUTF8(unplayableFormats).get());
     if (Preferences::GetBool("media.decoderdoctor.verbose", false)) {
       ReportAnalysis(
         dom::DecoderDoctorNotificationType::Can_play_but_some_missing_decoders,
         "MediaNoDecoders", unplayableFormats);
     }
-  } else {
-    DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - Can play media, decoders available for all requested formats",
-             this, mDocument);
+    return;
   }
+  DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - Can play media, decoders available for all requested formats",
+           this, mDocument);
 }
 
 void
 DecoderDoctorDocumentWatcher::AddDiagnostics(DecoderDoctorDiagnostics&& aDiagnostics,
                                              const char* aCallSite)
 {
   MOZ_ASSERT(NS_IsMainThread());