1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef ChromiumCDMParent_h_
7 #define ChromiumCDMParent_h_
8 
9 #include "DecryptJob.h"
10 #include "GMPCrashHelper.h"
11 #include "GMPCrashHelperHolder.h"
12 #include "GMPMessageUtils.h"
13 #include "mozilla/gmp/PChromiumCDMParent.h"
14 #include "mozilla/RefPtr.h"
15 #include "nsDataHashtable.h"
16 #include "PlatformDecoderModule.h"
17 #include "ImageContainer.h"
18 #include "mozilla/ErrorResult.h"
19 #include "mozilla/Span.h"
20 #include "ReorderQueue.h"
21 
22 class ChromiumCDMCallback;
23 
24 namespace mozilla {
25 
26 class MediaRawData;
27 class ChromiumCDMProxy;
28 
29 namespace gmp {
30 
31 class GMPContentParent;
32 
33 class ChromiumCDMParent final : public PChromiumCDMParent,
34                                 public GMPCrashHelperHolder {
35   friend class PChromiumCDMParent;
36 
37  public:
38   typedef MozPromise<bool, MediaResult, /* IsExclusive = */ true> InitPromise;
39 
40   // Mark AddRef and Release as `final`, as they overload pure virtual
41   // implementations in PChromiumCDMParent.
42   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChromiumCDMParent, final)
43 
44   ChromiumCDMParent(GMPContentParent* aContentParent, uint32_t aPluginId);
45 
PluginId()46   uint32_t PluginId() const { return mPluginId; }
47 
48   RefPtr<InitPromise> Init(ChromiumCDMCallback* aCDMCallback,
49                            bool aAllowDistinctiveIdentifier,
50                            bool aAllowPersistentState,
51                            nsIEventTarget* aMainThread);
52 
53   void CreateSession(uint32_t aCreateSessionToken, uint32_t aSessionType,
54                      uint32_t aInitDataType, uint32_t aPromiseId,
55                      const nsTArray<uint8_t>& aInitData);
56 
57   void LoadSession(uint32_t aPromiseId, uint32_t aSessionType,
58                    nsString aSessionId);
59 
60   void SetServerCertificate(uint32_t aPromiseId,
61                             const nsTArray<uint8_t>& aCert);
62 
63   void UpdateSession(const nsCString& aSessionId, uint32_t aPromiseId,
64                      const nsTArray<uint8_t>& aResponse);
65 
66   void CloseSession(const nsCString& aSessionId, uint32_t aPromiseId);
67 
68   void RemoveSession(const nsCString& aSessionId, uint32_t aPromiseId);
69 
70   void GetStatusForPolicy(uint32_t aPromiseId,
71                           const nsCString& aMinHdcpVersion);
72 
73   RefPtr<DecryptPromise> Decrypt(MediaRawData* aSample);
74 
75   // TODO: Add functions for clients to send data to CDM, and
76   // a Close() function.
77   RefPtr<MediaDataDecoder::InitPromise> InitializeVideoDecoder(
78       const gmp::CDMVideoDecoderConfig& aConfig, const VideoInfo& aInfo,
79       RefPtr<layers::ImageContainer> aImageContainer);
80 
81   RefPtr<MediaDataDecoder::DecodePromise> DecryptAndDecodeFrame(
82       MediaRawData* aSample);
83 
84   RefPtr<MediaDataDecoder::FlushPromise> FlushVideoDecoder();
85 
86   RefPtr<MediaDataDecoder::DecodePromise> Drain();
87 
88   RefPtr<ShutdownPromise> ShutdownVideoDecoder();
89 
90   void Shutdown();
91 
92  protected:
93   ~ChromiumCDMParent() = default;
94 
95   ipc::IPCResult Recv__delete__() override;
96   ipc::IPCResult RecvOnResolvePromiseWithKeyStatus(const uint32_t& aPromiseId,
97                                                    const uint32_t& aKeyStatus);
98   ipc::IPCResult RecvOnResolveNewSessionPromise(const uint32_t& aPromiseId,
99                                                 const nsCString& aSessionId);
100   ipc::IPCResult RecvResolveLoadSessionPromise(const uint32_t& aPromiseId,
101                                                const bool& aSuccessful);
102   ipc::IPCResult RecvOnResolvePromise(const uint32_t& aPromiseId);
103   ipc::IPCResult RecvOnRejectPromise(const uint32_t& aPromiseId,
104                                      const uint32_t& aError,
105                                      const uint32_t& aSystemCode,
106                                      const nsCString& aErrorMessage);
107   ipc::IPCResult RecvOnSessionMessage(const nsCString& aSessionId,
108                                       const uint32_t& aMessageType,
109                                       nsTArray<uint8_t>&& aMessage);
110   ipc::IPCResult RecvOnSessionKeysChange(
111       const nsCString& aSessionId, nsTArray<CDMKeyInformation>&& aKeysInfo);
112   ipc::IPCResult RecvOnExpirationChange(const nsCString& aSessionId,
113                                         const double& aSecondsSinceEpoch);
114   ipc::IPCResult RecvOnSessionClosed(const nsCString& aSessionId);
115   ipc::IPCResult RecvDecrypted(const uint32_t& aId, const uint32_t& aStatus,
116                                ipc::Shmem&& aData);
117   ipc::IPCResult RecvDecryptFailed(const uint32_t& aId,
118                                    const uint32_t& aStatus);
119   ipc::IPCResult RecvOnDecoderInitDone(const uint32_t& aStatus);
120   ipc::IPCResult RecvDecodedShmem(const CDMVideoFrame& aFrame,
121                                   ipc::Shmem&& aShmem);
122   ipc::IPCResult RecvDecodedData(const CDMVideoFrame& aFrame,
123                                  nsTArray<uint8_t>&& aData);
124   ipc::IPCResult RecvDecodeFailed(const uint32_t& aStatus);
125   ipc::IPCResult RecvShutdown();
126   ipc::IPCResult RecvResetVideoDecoderComplete();
127   ipc::IPCResult RecvDrainComplete();
128   ipc::IPCResult RecvIncreaseShmemPoolSize();
129   void ActorDestroy(ActorDestroyReason aWhy) override;
130   bool SendBufferToCDM(uint32_t aSizeInBytes);
131 
132   void ReorderAndReturnOutput(RefPtr<VideoData>&& aFrame);
133 
134   void RejectPromise(uint32_t aPromiseId, ErrorResult&& aException,
135                      const nsCString& aErrorMessage);
136 
137   void ResolvePromise(uint32_t aPromiseId);
138   // Helpers to reject our promise if we are shut down.
139   void RejectPromiseShutdown(uint32_t aPromiseId);
140   // Helper to reject our promise with an InvalidStateError and the given
141   // message.
142   void RejectPromiseWithStateError(uint32_t aPromiseId,
143                                    const nsCString& aErrorMessage);
144 
145   bool InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer, MediaRawData* aSample);
146 
147   bool PurgeShmems();
148   bool EnsureSufficientShmems(size_t aVideoFrameSize);
149   already_AddRefed<VideoData> CreateVideoFrame(const CDMVideoFrame& aFrame,
150                                                Span<uint8_t> aData);
151 
152   const uint32_t mPluginId;
153   GMPContentParent* mContentParent;
154   // Note: this pointer is a weak reference as ChromiumCDMProxy has a strong
155   // reference to the ChromiumCDMCallback.
156   ChromiumCDMCallback* mCDMCallback = nullptr;
157   nsDataHashtable<nsUint32HashKey, uint32_t> mPromiseToCreateSessionToken;
158   nsTArray<RefPtr<DecryptJob>> mDecrypts;
159 
160   MozPromiseHolder<InitPromise> mInitPromise;
161 
162   MozPromiseHolder<MediaDataDecoder::InitPromise> mInitVideoDecoderPromise;
163   MozPromiseHolder<MediaDataDecoder::DecodePromise> mDecodePromise;
164 
165   RefPtr<layers::ImageContainer> mImageContainer;
166   VideoInfo mVideoInfo;
167   uint64_t mLastStreamOffset = 0;
168 
169   MozPromiseHolder<MediaDataDecoder::FlushPromise> mFlushDecoderPromise;
170 
171   size_t mVideoFrameBufferSize = 0;
172 
173   // Count of the number of shmems in the set used to return decoded video
174   // frames from the CDM to Gecko.
175   uint32_t mVideoShmemsActive = 0;
176   // Maximum number of shmems to use to return decoded video frames.
177   uint32_t mVideoShmemLimit;
178 
179   bool mIsShutdown = false;
180   bool mVideoDecoderInitialized = false;
181   bool mActorDestroyed = false;
182   bool mAbnormalShutdown = false;
183 
184   // The H.264 decoder in Widevine CDM versions 970 and later output in decode
185   // order rather than presentation order, so we reorder in presentation order
186   // before presenting. mMaxRefFrames is non-zero if we have an initialized
187   // decoder and we are decoding H.264. If so, it stores the maximum length of
188   // the reorder queue that we need. Note we may have multiple decoders for the
189   // life time of this object, but never more than one active at once.
190   uint32_t mMaxRefFrames = 0;
191   ReorderQueue mReorderQueue;
192 };
193 
194 }  // namespace gmp
195 }  // namespace mozilla
196 
197 #endif  // ChromiumCDMParent_h_
198