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