Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "GMPCDMProxy.h"
8 : #include "mozilla/EMEUtils.h"
9 : #include "mozilla/PodOperations.h"
10 :
11 : #include "mozilla/dom/MediaKeys.h"
12 : #include "mozilla/dom/MediaKeySession.h"
13 : #include "mozIGeckoMediaPluginService.h"
14 : #include "nsPrintfCString.h"
15 : #include "nsString.h"
16 : #include "prenv.h"
17 : #include "GMPCDMCallbackProxy.h"
18 : #include "GMPService.h"
19 : #include "MainThreadUtils.h"
20 : #include "MediaData.h"
21 : #include "DecryptJob.h"
22 : #include "GMPUtils.h"
23 :
24 : namespace mozilla {
25 :
26 0 : GMPCDMProxy::GMPCDMProxy(dom::MediaKeys* aKeys,
27 : const nsAString& aKeySystem,
28 : GMPCrashHelper* aCrashHelper,
29 : bool aDistinctiveIdentifierRequired,
30 : bool aPersistentStateRequired,
31 0 : nsIEventTarget* aMainThread)
32 : : CDMProxy(aKeys,
33 : aKeySystem,
34 : aDistinctiveIdentifierRequired,
35 : aPersistentStateRequired,
36 : aMainThread)
37 : , mCrashHelper(aCrashHelper)
38 : , mCDM(nullptr)
39 : , mShutdownCalled(false)
40 : , mDecryptorId(0)
41 0 : , mCreatePromiseId(0)
42 : {
43 0 : MOZ_ASSERT(NS_IsMainThread());
44 0 : MOZ_COUNT_CTOR(GMPCDMProxy);
45 0 : }
46 :
47 0 : GMPCDMProxy::~GMPCDMProxy()
48 : {
49 0 : MOZ_COUNT_DTOR(GMPCDMProxy);
50 0 : }
51 :
52 : void
53 0 : GMPCDMProxy::Init(PromiseId aPromiseId,
54 : const nsAString& aOrigin,
55 : const nsAString& aTopLevelOrigin,
56 : const nsAString& aGMPName)
57 : {
58 0 : MOZ_ASSERT(NS_IsMainThread());
59 0 : NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
60 :
61 0 : EME_LOG("GMPCDMProxy::Init (%s, %s)",
62 : NS_ConvertUTF16toUTF8(aOrigin).get(),
63 : NS_ConvertUTF16toUTF8(aTopLevelOrigin).get());
64 :
65 0 : nsCString pluginVersion;
66 0 : if (!mOwnerThread) {
67 : nsCOMPtr<mozIGeckoMediaPluginService> mps =
68 0 : do_GetService("@mozilla.org/gecko-media-plugin-service;1");
69 0 : if (!mps) {
70 0 : RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
71 0 : NS_LITERAL_CSTRING("Couldn't get MediaPluginService in GMPCDMProxy::Init"));
72 0 : return;
73 : }
74 0 : mps->GetThread(getter_AddRefs(mOwnerThread));
75 0 : if (!mOwnerThread) {
76 0 : RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
77 0 : NS_LITERAL_CSTRING("Couldn't get GMP thread GMPCDMProxy::Init"));
78 0 : return;
79 : }
80 : }
81 :
82 0 : if (aGMPName.IsEmpty()) {
83 : RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
84 0 : nsPrintfCString("Unknown GMP for keysystem '%s'", NS_ConvertUTF16toUTF8(mKeySystem).get()));
85 0 : return;
86 : }
87 :
88 0 : UniquePtr<InitData> data(new InitData());
89 0 : data->mPromiseId = aPromiseId;
90 0 : data->mOrigin = aOrigin;
91 0 : data->mTopLevelOrigin = aTopLevelOrigin;
92 0 : data->mGMPName = aGMPName;
93 0 : data->mCrashHelper = mCrashHelper;
94 : nsCOMPtr<nsIRunnable> task(
95 0 : NewRunnableMethod<UniquePtr<InitData>&&>("GMPCDMProxy::gmp_Init",
96 : this,
97 : &GMPCDMProxy::gmp_Init,
98 0 : Move(data)));
99 0 : mOwnerThread->EventTarget()->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
100 : }
101 :
102 : #ifdef DEBUG
103 : bool
104 0 : GMPCDMProxy::IsOnOwnerThread()
105 : {
106 0 : return mOwnerThread->IsOnCurrentThread();
107 : }
108 : #endif
109 :
110 : void
111 0 : GMPCDMProxy::gmp_InitDone(GMPDecryptorProxy* aCDM, UniquePtr<InitData>&& aData)
112 : {
113 0 : EME_LOG("GMPCDMProxy::gmp_InitDone");
114 0 : if (mShutdownCalled) {
115 0 : if (aCDM) {
116 0 : aCDM->Close();
117 : }
118 0 : RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
119 0 : NS_LITERAL_CSTRING("GMPCDMProxy was shut down before init could complete"));
120 0 : return;
121 : }
122 0 : if (!aCDM) {
123 0 : RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
124 0 : NS_LITERAL_CSTRING("GetGMPDecryptor failed to return a CDM"));
125 0 : return;
126 : }
127 :
128 0 : mCDM = aCDM;
129 0 : mCallback.reset(new GMPCDMCallbackProxy(this, mMainThread));
130 0 : mCDM->Init(mCallback.get(),
131 0 : mDistinctiveIdentifierRequired,
132 0 : mPersistentStateRequired);
133 :
134 : // Await the OnSetDecryptorId callback.
135 0 : mCreatePromiseId = aData->mPromiseId;
136 : }
137 :
138 0 : void GMPCDMProxy::OnSetDecryptorId(uint32_t aId)
139 : {
140 0 : MOZ_ASSERT(mCreatePromiseId);
141 0 : mDecryptorId = aId;
142 : nsCOMPtr<nsIRunnable> task(
143 0 : NewRunnableMethod<uint32_t>("GMPCDMProxy::OnCDMCreated",
144 : this,
145 : &GMPCDMProxy::OnCDMCreated,
146 0 : mCreatePromiseId));
147 0 : mMainThread->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
148 0 : }
149 :
150 0 : class gmp_InitDoneCallback : public GetGMPDecryptorCallback
151 : {
152 : public:
153 0 : gmp_InitDoneCallback(GMPCDMProxy* aGMPCDMProxy,
154 : UniquePtr<GMPCDMProxy::InitData>&& aData)
155 0 : : mGMPCDMProxy(aGMPCDMProxy),
156 0 : mData(Move(aData))
157 : {
158 0 : }
159 :
160 0 : void Done(GMPDecryptorProxy* aCDM)
161 : {
162 0 : mGMPCDMProxy->gmp_InitDone(aCDM, Move(mData));
163 0 : }
164 :
165 : private:
166 : RefPtr<GMPCDMProxy> mGMPCDMProxy;
167 : UniquePtr<GMPCDMProxy::InitData> mData;
168 : };
169 :
170 0 : class gmp_InitGetGMPDecryptorCallback : public GetNodeIdCallback
171 : {
172 : public:
173 0 : gmp_InitGetGMPDecryptorCallback(GMPCDMProxy* aGMPCDMProxy,
174 : UniquePtr<GMPCDMProxy::InitData>&& aData)
175 0 : : mGMPCDMProxy(aGMPCDMProxy),
176 0 : mData(Move(aData))
177 : {
178 0 : }
179 :
180 0 : void Done(nsresult aResult, const nsACString& aNodeId)
181 : {
182 0 : mGMPCDMProxy->gmp_InitGetGMPDecryptor(aResult, aNodeId, Move(mData));
183 0 : }
184 :
185 : private:
186 : RefPtr<GMPCDMProxy> mGMPCDMProxy;
187 : UniquePtr<GMPCDMProxy::InitData> mData;
188 : };
189 :
190 : void
191 0 : GMPCDMProxy::gmp_Init(UniquePtr<InitData>&& aData)
192 : {
193 0 : MOZ_ASSERT(IsOnOwnerThread());
194 :
195 : nsCOMPtr<mozIGeckoMediaPluginService> mps =
196 0 : do_GetService("@mozilla.org/gecko-media-plugin-service;1");
197 0 : if (!mps) {
198 0 : RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
199 0 : NS_LITERAL_CSTRING("Couldn't get MediaPluginService in GMPCDMProxy::gmp_Init"));
200 0 : return;
201 : }
202 :
203 : // Make a copy before we transfer ownership of aData to the
204 : // gmp_InitGetGMPDecryptorCallback.
205 0 : InitData data(*aData);
206 : UniquePtr<GetNodeIdCallback> callback(
207 0 : new gmp_InitGetGMPDecryptorCallback(this, Move(aData)));
208 0 : nsresult rv = mps->GetNodeId(data.mOrigin,
209 : data.mTopLevelOrigin,
210 : data.mGMPName,
211 0 : Move(callback));
212 0 : if (NS_FAILED(rv)) {
213 0 : RejectPromise(data.mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
214 0 : NS_LITERAL_CSTRING("Call to GetNodeId() failed early"));
215 : }
216 : }
217 :
218 : void
219 0 : GMPCDMProxy::gmp_InitGetGMPDecryptor(nsresult aResult,
220 : const nsACString& aNodeId,
221 : UniquePtr<InitData>&& aData)
222 : {
223 0 : uint32_t promiseID = aData->mPromiseId;
224 0 : if (NS_FAILED(aResult)) {
225 0 : RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR,
226 0 : NS_LITERAL_CSTRING("GetNodeId() called back, but with a failure result"));
227 0 : return;
228 : }
229 :
230 0 : mNodeId = aNodeId;
231 0 : MOZ_ASSERT(!GetNodeId().IsEmpty());
232 :
233 : nsCOMPtr<mozIGeckoMediaPluginService> mps =
234 0 : do_GetService("@mozilla.org/gecko-media-plugin-service;1");
235 0 : if (!mps) {
236 0 : RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR,
237 0 : NS_LITERAL_CSTRING("Couldn't get MediaPluginService in GMPCDMProxy::gmp_InitGetGMPDecryptor"));
238 0 : return;
239 : }
240 :
241 0 : EME_LOG("GMPCDMProxy::gmp_Init (%s, %s) NodeId=%s",
242 : NS_ConvertUTF16toUTF8(aData->mOrigin).get(),
243 : NS_ConvertUTF16toUTF8(aData->mTopLevelOrigin).get(),
244 : GetNodeId().get());
245 :
246 0 : nsTArray<nsCString> tags;
247 0 : tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem));
248 :
249 : // Note: must capture helper refptr here, before the Move()
250 : // when we create the GetGMPDecryptorCallback below.
251 0 : RefPtr<GMPCrashHelper> crashHelper = Move(aData->mCrashHelper);
252 : UniquePtr<GetGMPDecryptorCallback> callback(new gmp_InitDoneCallback(this,
253 0 : Move(aData)));
254 0 : nsresult rv = mps->GetGMPDecryptor(crashHelper,
255 : &tags,
256 0 : GetNodeId(),
257 0 : Move(callback));
258 0 : if (NS_FAILED(rv)) {
259 0 : RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR,
260 0 : NS_LITERAL_CSTRING("Call to GetGMPDecryptor() failed early"));
261 : }
262 : }
263 :
264 : void
265 0 : GMPCDMProxy::OnCDMCreated(uint32_t aPromiseId)
266 : {
267 0 : MOZ_ASSERT(NS_IsMainThread());
268 0 : if (mKeys.IsNull()) {
269 0 : return;
270 : }
271 0 : MOZ_ASSERT(!GetNodeId().IsEmpty());
272 0 : if (mCDM) {
273 0 : mKeys->OnCDMCreated(aPromiseId, mCDM->GetPluginId());
274 : } else {
275 : // No CDM? Just reject the promise.
276 0 : mKeys->RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
277 0 : NS_LITERAL_CSTRING("Null CDM in OnCDMCreated()"));
278 : }
279 : }
280 :
281 : void
282 0 : GMPCDMProxy::CreateSession(uint32_t aCreateSessionToken,
283 : dom::MediaKeySessionType aSessionType,
284 : PromiseId aPromiseId,
285 : const nsAString& aInitDataType,
286 : nsTArray<uint8_t>& aInitData)
287 : {
288 0 : MOZ_ASSERT(NS_IsMainThread());
289 0 : MOZ_ASSERT(mOwnerThread);
290 :
291 0 : UniquePtr<CreateSessionData> data(new CreateSessionData());
292 0 : data->mSessionType = aSessionType;
293 0 : data->mCreateSessionToken = aCreateSessionToken;
294 0 : data->mPromiseId = aPromiseId;
295 0 : data->mInitDataType = NS_ConvertUTF16toUTF8(aInitDataType);
296 0 : data->mInitData = Move(aInitData);
297 :
298 : nsCOMPtr<nsIRunnable> task(
299 0 : NewRunnableMethod<UniquePtr<CreateSessionData>&&>("GMPCDMProxy::gmp_CreateSession",
300 : this,
301 : &GMPCDMProxy::gmp_CreateSession,
302 0 : Move(data)));
303 0 : mOwnerThread->EventTarget()->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
304 0 : }
305 :
306 : GMPSessionType
307 0 : ToGMPSessionType(dom::MediaKeySessionType aSessionType) {
308 0 : switch (aSessionType) {
309 0 : case dom::MediaKeySessionType::Temporary: return kGMPTemporySession;
310 0 : case dom::MediaKeySessionType::Persistent_license: return kGMPPersistentSession;
311 0 : default: return kGMPTemporySession;
312 : };
313 : };
314 :
315 : void
316 0 : GMPCDMProxy::gmp_CreateSession(UniquePtr<CreateSessionData>&& aData)
317 : {
318 0 : MOZ_ASSERT(IsOnOwnerThread());
319 0 : if (!mCDM) {
320 0 : RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
321 0 : NS_LITERAL_CSTRING("Null CDM in gmp_CreateSession"));
322 0 : return;
323 : }
324 0 : mCDM->CreateSession(aData->mCreateSessionToken,
325 0 : aData->mPromiseId,
326 0 : aData->mInitDataType,
327 0 : aData->mInitData,
328 0 : ToGMPSessionType(aData->mSessionType));
329 : }
330 :
331 : void
332 0 : GMPCDMProxy::LoadSession(PromiseId aPromiseId,
333 : dom::MediaKeySessionType aSessionType,
334 : const nsAString& aSessionId)
335 : {
336 0 : MOZ_ASSERT(NS_IsMainThread());
337 0 : MOZ_ASSERT(mOwnerThread);
338 :
339 0 : UniquePtr<SessionOpData> data(new SessionOpData());
340 0 : data->mPromiseId = aPromiseId;
341 0 : data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
342 : nsCOMPtr<nsIRunnable> task(
343 0 : NewRunnableMethod<UniquePtr<SessionOpData>&&>("GMPCDMProxy::gmp_LoadSession",
344 : this,
345 : &GMPCDMProxy::gmp_LoadSession,
346 0 : Move(data)));
347 0 : mOwnerThread->EventTarget()->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
348 0 : }
349 :
350 : void
351 0 : GMPCDMProxy::gmp_LoadSession(UniquePtr<SessionOpData>&& aData)
352 : {
353 0 : MOZ_ASSERT(IsOnOwnerThread());
354 :
355 0 : if (!mCDM) {
356 0 : RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
357 0 : NS_LITERAL_CSTRING("Null CDM in gmp_LoadSession"));
358 0 : return;
359 : }
360 0 : mCDM->LoadSession(aData->mPromiseId, aData->mSessionId);
361 : }
362 :
363 : void
364 0 : GMPCDMProxy::SetServerCertificate(PromiseId aPromiseId,
365 : nsTArray<uint8_t>& aCert)
366 : {
367 0 : MOZ_ASSERT(NS_IsMainThread());
368 0 : MOZ_ASSERT(mOwnerThread);
369 :
370 0 : UniquePtr<SetServerCertificateData> data(new SetServerCertificateData());
371 0 : data->mPromiseId = aPromiseId;
372 0 : data->mCert = Move(aCert);
373 : nsCOMPtr<nsIRunnable> task(
374 0 : NewRunnableMethod<UniquePtr<SetServerCertificateData>&&>("GMPCDMProxy::gmp_SetServerCertificate",
375 : this,
376 : &GMPCDMProxy::gmp_SetServerCertificate,
377 0 : Move(data)));
378 0 : mOwnerThread->EventTarget()->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
379 0 : }
380 :
381 : void
382 0 : GMPCDMProxy::gmp_SetServerCertificate(UniquePtr<SetServerCertificateData>&& aData)
383 : {
384 0 : MOZ_ASSERT(IsOnOwnerThread());
385 0 : if (!mCDM) {
386 0 : RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
387 0 : NS_LITERAL_CSTRING("Null CDM in gmp_SetServerCertificate"));
388 0 : return;
389 : }
390 0 : mCDM->SetServerCertificate(aData->mPromiseId, aData->mCert);
391 : }
392 :
393 : void
394 0 : GMPCDMProxy::UpdateSession(const nsAString& aSessionId,
395 : PromiseId aPromiseId,
396 : nsTArray<uint8_t>& aResponse)
397 : {
398 0 : MOZ_ASSERT(NS_IsMainThread());
399 0 : MOZ_ASSERT(mOwnerThread);
400 0 : NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
401 :
402 0 : UniquePtr<UpdateSessionData> data(new UpdateSessionData());
403 0 : data->mPromiseId = aPromiseId;
404 0 : data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
405 0 : data->mResponse = Move(aResponse);
406 : nsCOMPtr<nsIRunnable> task(
407 0 : NewRunnableMethod<UniquePtr<UpdateSessionData>&&>("GMPCDMProxy::gmp_UpdateSession",
408 : this,
409 : &GMPCDMProxy::gmp_UpdateSession,
410 0 : Move(data)));
411 0 : mOwnerThread->EventTarget()->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
412 : }
413 :
414 : void
415 0 : GMPCDMProxy::gmp_UpdateSession(UniquePtr<UpdateSessionData>&& aData)
416 : {
417 0 : MOZ_ASSERT(IsOnOwnerThread());
418 0 : if (!mCDM) {
419 0 : RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
420 0 : NS_LITERAL_CSTRING("Null CDM in gmp_UpdateSession"));
421 0 : return;
422 : }
423 0 : mCDM->UpdateSession(aData->mPromiseId,
424 0 : aData->mSessionId,
425 0 : aData->mResponse);
426 : }
427 :
428 : void
429 0 : GMPCDMProxy::CloseSession(const nsAString& aSessionId,
430 : PromiseId aPromiseId)
431 : {
432 0 : MOZ_ASSERT(NS_IsMainThread());
433 0 : NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
434 :
435 0 : UniquePtr<SessionOpData> data(new SessionOpData());
436 0 : data->mPromiseId = aPromiseId;
437 0 : data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
438 : nsCOMPtr<nsIRunnable> task(
439 0 : NewRunnableMethod<UniquePtr<SessionOpData>&&>("GMPCDMProxy::gmp_CloseSession",
440 : this,
441 : &GMPCDMProxy::gmp_CloseSession,
442 0 : Move(data)));
443 0 : mOwnerThread->EventTarget()->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
444 : }
445 :
446 : void
447 0 : GMPCDMProxy::gmp_CloseSession(UniquePtr<SessionOpData>&& aData)
448 : {
449 0 : MOZ_ASSERT(IsOnOwnerThread());
450 0 : if (!mCDM) {
451 0 : RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
452 0 : NS_LITERAL_CSTRING("Null CDM in gmp_CloseSession"));
453 0 : return;
454 : }
455 0 : mCDM->CloseSession(aData->mPromiseId, aData->mSessionId);
456 : }
457 :
458 : void
459 0 : GMPCDMProxy::RemoveSession(const nsAString& aSessionId,
460 : PromiseId aPromiseId)
461 : {
462 0 : MOZ_ASSERT(NS_IsMainThread());
463 0 : NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
464 :
465 0 : UniquePtr<SessionOpData> data(new SessionOpData());
466 0 : data->mPromiseId = aPromiseId;
467 0 : data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
468 : nsCOMPtr<nsIRunnable> task(
469 0 : NewRunnableMethod<UniquePtr<SessionOpData>&&>("GMPCDMProxy::gmp_RemoveSession",
470 : this,
471 : &GMPCDMProxy::gmp_RemoveSession,
472 0 : Move(data)));
473 0 : mOwnerThread->EventTarget()->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
474 : }
475 :
476 : void
477 0 : GMPCDMProxy::gmp_RemoveSession(UniquePtr<SessionOpData>&& aData)
478 : {
479 0 : MOZ_ASSERT(IsOnOwnerThread());
480 0 : if (!mCDM) {
481 0 : RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
482 0 : NS_LITERAL_CSTRING("Null CDM in gmp_RemoveSession"));
483 0 : return;
484 : }
485 0 : mCDM->RemoveSession(aData->mPromiseId, aData->mSessionId);
486 : }
487 :
488 : void
489 0 : GMPCDMProxy::Shutdown()
490 : {
491 0 : MOZ_ASSERT(NS_IsMainThread());
492 0 : mKeys.Clear();
493 : // Note: This may end up being the last owning reference to the GMPCDMProxy.
494 0 : nsCOMPtr<nsIRunnable> task(NewRunnableMethod(
495 0 : "GMPCDMProxy::gmp_Shutdown", this, &GMPCDMProxy::gmp_Shutdown));
496 0 : if (mOwnerThread) {
497 0 : mOwnerThread->EventTarget()->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
498 : }
499 0 : }
500 :
501 : void
502 0 : GMPCDMProxy::gmp_Shutdown()
503 : {
504 0 : MOZ_ASSERT(IsOnOwnerThread());
505 :
506 0 : mShutdownCalled = true;
507 :
508 : // Abort any pending decrypt jobs, to awaken any clients waiting on a job.
509 0 : for (size_t i = 0; i < mDecryptionJobs.Length(); i++) {
510 0 : DecryptJob* job = mDecryptionJobs[i];
511 0 : job->PostResult(eme::AbortedErr);
512 : }
513 0 : mDecryptionJobs.Clear();
514 :
515 0 : if (mCDM) {
516 0 : mCDM->Close();
517 0 : mCDM = nullptr;
518 : }
519 0 : }
520 :
521 : void
522 0 : GMPCDMProxy::RejectPromise(PromiseId aId, nsresult aCode,
523 : const nsCString& aReason)
524 : {
525 0 : if (NS_IsMainThread()) {
526 0 : if (!mKeys.IsNull()) {
527 0 : mKeys->RejectPromise(aId, aCode, aReason);
528 : }
529 : } else {
530 : nsCOMPtr<nsIRunnable> task(new RejectPromiseTask(this, aId, aCode,
531 0 : aReason));
532 0 : mMainThread->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
533 : }
534 0 : }
535 :
536 : void
537 0 : GMPCDMProxy::ResolvePromise(PromiseId aId)
538 : {
539 0 : if (NS_IsMainThread()) {
540 0 : if (!mKeys.IsNull()) {
541 0 : mKeys->ResolvePromise(aId);
542 : } else {
543 0 : NS_WARNING("GMPCDMProxy unable to resolve promise!");
544 : }
545 : } else {
546 0 : nsCOMPtr<nsIRunnable> task;
547 0 : task = NewRunnableMethod<PromiseId>(
548 0 : "GMPCDMProxy::ResolvePromise", this, &GMPCDMProxy::ResolvePromise, aId);
549 0 : mMainThread->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
550 : }
551 0 : }
552 :
553 : const nsCString&
554 0 : GMPCDMProxy::GetNodeId() const
555 : {
556 0 : return mNodeId;
557 : }
558 :
559 : void
560 0 : GMPCDMProxy::OnSetSessionId(uint32_t aCreateSessionToken,
561 : const nsAString& aSessionId)
562 : {
563 0 : MOZ_ASSERT(NS_IsMainThread());
564 0 : if (mKeys.IsNull()) {
565 0 : return;
566 : }
567 :
568 0 : RefPtr<dom::MediaKeySession> session(mKeys->GetPendingSession(aCreateSessionToken));
569 0 : if (session) {
570 0 : session->SetSessionId(aSessionId);
571 : }
572 : }
573 :
574 : void
575 0 : GMPCDMProxy::OnResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccess)
576 : {
577 0 : MOZ_ASSERT(NS_IsMainThread());
578 0 : if (mKeys.IsNull()) {
579 0 : return;
580 : }
581 0 : mKeys->OnSessionLoaded(aPromiseId, aSuccess);
582 : }
583 :
584 : void
585 0 : GMPCDMProxy::OnSessionMessage(const nsAString& aSessionId,
586 : dom::MediaKeyMessageType aMessageType,
587 : nsTArray<uint8_t>& aMessage)
588 : {
589 0 : MOZ_ASSERT(NS_IsMainThread());
590 0 : if (mKeys.IsNull()) {
591 0 : return;
592 : }
593 0 : RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
594 0 : if (session) {
595 0 : session->DispatchKeyMessage(aMessageType, aMessage);
596 : }
597 : }
598 :
599 : void
600 0 : GMPCDMProxy::OnKeyStatusesChange(const nsAString& aSessionId)
601 : {
602 0 : MOZ_ASSERT(NS_IsMainThread());
603 0 : if (mKeys.IsNull()) {
604 0 : return;
605 : }
606 0 : RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
607 0 : if (session) {
608 0 : session->DispatchKeyStatusesChange();
609 : }
610 : }
611 :
612 : void
613 0 : GMPCDMProxy::OnExpirationChange(const nsAString& aSessionId,
614 : GMPTimestamp aExpiryTime)
615 : {
616 0 : MOZ_ASSERT(NS_IsMainThread());
617 0 : if (mKeys.IsNull()) {
618 0 : return;
619 : }
620 0 : RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
621 0 : if (session) {
622 : // Expiry of 0 is interpreted as "never expire". See bug 1345341.
623 0 : double t = (aExpiryTime == 0) ? std::numeric_limits<double>::quiet_NaN()
624 0 : : static_cast<double>(aExpiryTime);
625 0 : session->SetExpiration(t);
626 : }
627 : }
628 :
629 : void
630 0 : GMPCDMProxy::OnSessionClosed(const nsAString& aSessionId)
631 : {
632 0 : MOZ_ASSERT(NS_IsMainThread());
633 0 : if (mKeys.IsNull()) {
634 0 : return;
635 : }
636 0 : RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
637 0 : if (session) {
638 0 : session->OnClosed();
639 : }
640 : }
641 :
642 : void
643 0 : GMPCDMProxy::OnDecrypted(uint32_t aId,
644 : DecryptStatus aResult,
645 : const nsTArray<uint8_t>& aDecryptedData)
646 : {
647 0 : MOZ_ASSERT(IsOnOwnerThread());
648 0 : gmp_Decrypted(aId, aResult, aDecryptedData);
649 0 : }
650 :
651 : void
652 0 : GMPCDMProxy::OnSessionError(const nsAString& aSessionId,
653 : nsresult aException,
654 : uint32_t aSystemCode,
655 : const nsAString& aMsg)
656 : {
657 0 : MOZ_ASSERT(NS_IsMainThread());
658 0 : if (mKeys.IsNull()) {
659 0 : return;
660 : }
661 0 : RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
662 0 : if (session) {
663 0 : session->DispatchKeyError(aSystemCode);
664 : }
665 0 : LogToConsole(aMsg);
666 : }
667 :
668 : void
669 0 : GMPCDMProxy::OnRejectPromise(uint32_t aPromiseId,
670 : nsresult aDOMException,
671 : const nsCString& aMsg)
672 : {
673 0 : MOZ_ASSERT(NS_IsMainThread());
674 0 : RejectPromise(aPromiseId, aDOMException, aMsg);
675 0 : }
676 :
677 : const nsString&
678 0 : GMPCDMProxy::KeySystem() const
679 : {
680 0 : return mKeySystem;
681 : }
682 :
683 : CDMCaps&
684 0 : GMPCDMProxy::Capabilites() {
685 0 : return mCapabilites;
686 : }
687 :
688 : RefPtr<DecryptPromise>
689 0 : GMPCDMProxy::Decrypt(MediaRawData* aSample)
690 : {
691 0 : RefPtr<DecryptJob> job(new DecryptJob(aSample));
692 0 : RefPtr<DecryptPromise> promise(job->Ensure());
693 :
694 : nsCOMPtr<nsIRunnable> task(
695 0 : NewRunnableMethod<RefPtr<DecryptJob>>("GMPCDMProxy::gmp_Decrypt",
696 0 : this, &GMPCDMProxy::gmp_Decrypt, job));
697 0 : mOwnerThread->EventTarget()->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
698 0 : return promise;
699 : }
700 :
701 : void
702 0 : GMPCDMProxy::gmp_Decrypt(RefPtr<DecryptJob> aJob)
703 : {
704 0 : MOZ_ASSERT(IsOnOwnerThread());
705 :
706 0 : if (!mCDM) {
707 0 : aJob->PostResult(eme::AbortedErr);
708 0 : return;
709 : }
710 :
711 0 : nsTArray<uint8_t> data;
712 0 : data.AppendElements(aJob->mSample->Data(), aJob->mSample->Size());
713 0 : mCDM->Decrypt(aJob->mId, aJob->mSample->mCrypto, data);
714 0 : mDecryptionJobs.AppendElement(aJob.forget());
715 : }
716 :
717 : void
718 0 : GMPCDMProxy::gmp_Decrypted(uint32_t aId,
719 : DecryptStatus aResult,
720 : const nsTArray<uint8_t>& aDecryptedData)
721 : {
722 0 : MOZ_ASSERT(IsOnOwnerThread());
723 : #ifdef DEBUG
724 0 : bool jobIdFound = false;
725 : #endif
726 0 : for (size_t i = 0; i < mDecryptionJobs.Length(); i++) {
727 0 : DecryptJob* job = mDecryptionJobs[i];
728 0 : if (job->mId == aId) {
729 : #ifdef DEBUG
730 0 : jobIdFound = true;
731 : #endif
732 0 : job->PostResult(aResult, aDecryptedData);
733 0 : mDecryptionJobs.RemoveElementAt(i);
734 : }
735 : }
736 : #ifdef DEBUG
737 0 : if (!jobIdFound) {
738 0 : NS_WARNING("GMPDecryptorChild returned incorrect job ID");
739 : }
740 : #endif
741 0 : }
742 :
743 : void
744 0 : GMPCDMProxy::GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
745 : nsTArray<nsCString>& aSessionIds)
746 : {
747 0 : CDMCaps::AutoLock caps(Capabilites());
748 0 : caps.GetSessionIdsForKeyId(aKeyId, aSessionIds);
749 0 : }
750 :
751 : void
752 0 : GMPCDMProxy::Terminated()
753 : {
754 0 : MOZ_ASSERT(NS_IsMainThread());
755 0 : NS_WARNING("CDM terminated");
756 0 : if (mCreatePromiseId) {
757 0 : RejectPromise(mCreatePromiseId,
758 : NS_ERROR_DOM_MEDIA_FATAL_ERR,
759 0 : NS_LITERAL_CSTRING("Crashed waiting for CDM to initialize"));
760 0 : mCreatePromiseId = 0;
761 : }
762 0 : if (!mKeys.IsNull()) {
763 0 : mKeys->Terminated();
764 : }
765 0 : }
766 :
767 : uint32_t
768 0 : GMPCDMProxy::GetDecryptorId()
769 : {
770 0 : return mDecryptorId;
771 : }
772 :
773 : } // namespace mozilla
|