Bug 848994 - p6. Analyze Windows issues - r?cpearce draft
authorGerald Squelart <gsquelart@mozilla.com>
Fri, 22 Apr 2016 11:48:28 +1000
changeset 355187 a0204911f2a644bfa0036f145b26fab4a5220d81
parent 355186 d266ffa3207f92f8b436978b1a3aa13b16b920e1
child 355188 75915add0bc9cbac0e3ba535c4f3d68bc57e74ef
push id16221
push usergsquelart@mozilla.com
push dateFri, 22 Apr 2016 01:56:41 +0000
reviewerscpearce
bugs848994
milestone48.0a1
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());