1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef DecoderDoctorDiagnostics_h_ 8 #define DecoderDoctorDiagnostics_h_ 9 10 #include "MediaResult.h" 11 #include "mozilla/DefineEnum.h" 12 #include "mozilla/EnumSet.h" 13 #include "mozilla/EnumTypeTraits.h" 14 #include "mozilla/dom/DecoderDoctorNotificationBinding.h" 15 #include "nsString.h" 16 17 namespace mozilla { 18 19 namespace dom { 20 class Document; 21 } 22 23 struct DecoderDoctorEvent { 24 enum Domain { 25 eAudioSinkStartup, 26 } mDomain; 27 nsresult mResult; 28 }; 29 30 // DecoderDoctorDiagnostics class, used to gather data from PDMs/DecoderTraits, 31 // and then notify the user about issues preventing (or worsening) playback. 32 // 33 // The expected usage is: 34 // 1. Instantiate a DecoderDoctorDiagnostics in a function (close to the point 35 // where a webpage is trying to know whether some MIME types can be played, 36 // or trying to play a media file). 37 // 2. Pass a pointer to the DecoderDoctorDiagnostics structure to one of the 38 // CanPlayStatus/IsTypeSupported/(others?). During that call, some PDMs may 39 // add relevant diagnostic information. 40 // 3. Analyze the collected diagnostics, and optionally dispatch an event to the 41 // UX, to notify the user about potential playback issues and how to resolve 42 // them. 43 // 44 // This class' methods must be called from the main thread. 45 46 class DecoderDoctorDiagnostics { 47 friend struct IPC::ParamTraits<mozilla::DecoderDoctorDiagnostics>; 48 49 public: 50 // Store the diagnostic information collected so far on a document for a 51 // given format. All diagnostics for a document will be analyzed together 52 // within a short timeframe. 53 // Should only be called once. 54 void StoreFormatDiagnostics(dom::Document* aDocument, 55 const nsAString& aFormat, bool aCanPlay, 56 const char* aCallSite); 57 58 void StoreMediaKeySystemAccess(dom::Document* aDocument, 59 const nsAString& aKeySystem, bool aIsSupported, 60 const char* aCallSite); 61 62 void StoreEvent(dom::Document* aDocument, const DecoderDoctorEvent& aEvent, 63 const char* aCallSite); 64 65 void StoreDecodeError(dom::Document* aDocument, const MediaResult& aError, 66 const nsString& aMediaSrc, const char* aCallSite); 67 68 void StoreDecodeWarning(dom::Document* aDocument, const MediaResult& aWarning, 69 const nsString& aMediaSrc, const char* aCallSite); 70 71 enum DiagnosticsType { 72 eUnsaved, 73 eFormatSupportCheck, 74 eMediaKeySystemAccessRequest, 75 eEvent, 76 eDecodeError, 77 eDecodeWarning 78 }; 79 DiagnosticsType Type() const { return mDiagnosticsType; } 80 81 // Description string, for logging purposes; only call on stored diags. 82 nsCString GetDescription() const; 83 84 // Methods to record diagnostic information: 85 86 MOZ_DEFINE_ENUM_CLASS_AT_CLASS_SCOPE( 87 Flags, (CanPlay, WMFFailedToLoad, FFmpegNotFound, LibAVCodecUnsupported, 88 GMPPDMFailedToStartup, VideoNotSupported, AudioNotSupported)); 89 using FlagsSet = mozilla::EnumSet<Flags>; 90 91 const nsAString& Format() const { return mFormat; } 92 bool CanPlay() const { return mFlags.contains(Flags::CanPlay); } 93 94 void SetFailureFlags(const FlagsSet& aFlags) { mFlags = aFlags; } 95 void SetWMFFailedToLoad() { mFlags += Flags::WMFFailedToLoad; } 96 bool DidWMFFailToLoad() const { 97 return mFlags.contains(Flags::WMFFailedToLoad); 98 } 99 100 void SetFFmpegNotFound() { mFlags += Flags::FFmpegNotFound; } 101 bool DidFFmpegNotFound() const { 102 return mFlags.contains(Flags::FFmpegNotFound); 103 } 104 105 void SetLibAVCodecUnsupported() { mFlags += Flags::LibAVCodecUnsupported; } 106 bool IsLibAVCodecUnsupported() const { 107 return mFlags.contains(Flags::LibAVCodecUnsupported); 108 } 109 110 void SetGMPPDMFailedToStartup() { mFlags += Flags::GMPPDMFailedToStartup; } 111 bool DidGMPPDMFailToStartup() const { 112 return mFlags.contains(Flags::GMPPDMFailedToStartup); 113 } 114 115 void SetVideoNotSupported() { mFlags += Flags::VideoNotSupported; } 116 void SetAudioNotSupported() { mFlags += Flags::AudioNotSupported; } 117 118 void SetGMP(const nsACString& aGMP) { mGMP = aGMP; } 119 const nsACString& GMP() const { return mGMP; } 120 121 const nsAString& KeySystem() const { return mKeySystem; } 122 bool IsKeySystemSupported() const { return mIsKeySystemSupported; } 123 enum KeySystemIssue { eUnset, eWidevineWithNoWMF }; 124 void SetKeySystemIssue(KeySystemIssue aKeySystemIssue) { 125 mKeySystemIssue = aKeySystemIssue; 126 } 127 KeySystemIssue GetKeySystemIssue() const { return mKeySystemIssue; } 128 129 DecoderDoctorEvent event() const { return mEvent; } 130 131 const MediaResult& DecodeIssue() const { return mDecodeIssue; } 132 const nsString& DecodeIssueMediaSrc() const { return mDecodeIssueMediaSrc; } 133 134 // This method is only used for testing. 135 void SetDecoderDoctorReportType(const dom::DecoderDoctorReportType& aType); 136 137 private: 138 // Currently-known type of diagnostics. Set from one of the 'Store...' 139 // methods. This helps ensure diagnostics are only stored once, and makes it 140 // easy to know what information they contain. 141 DiagnosticsType mDiagnosticsType = eUnsaved; 142 143 nsString mFormat; 144 FlagsSet mFlags; 145 nsCString mGMP; 146 147 nsString mKeySystem; 148 bool mIsKeySystemSupported = false; 149 KeySystemIssue mKeySystemIssue = eUnset; 150 151 DecoderDoctorEvent mEvent; 152 153 MediaResult mDecodeIssue = NS_OK; 154 nsString mDecodeIssueMediaSrc; 155 }; 156 157 // Used for IPDL serialization. 158 // The 'value' have to be the biggest enum from DecoderDoctorDiagnostics::Flags. 159 template <> 160 struct MaxEnumValue<::mozilla::DecoderDoctorDiagnostics::Flags> { 161 static constexpr unsigned int value = 162 static_cast<unsigned int>(DecoderDoctorDiagnostics::sFlagsCount); 163 }; 164 165 } // namespace mozilla 166 167 #endif 168