Line data Source code
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 : #include "WidevineDecryptor.h"
7 :
8 : #include "WidevineAdapter.h"
9 : #include "WidevineUtils.h"
10 : #include "WidevineFileIO.h"
11 : #include <stdarg.h>
12 : #include "base/time.h"
13 :
14 : using namespace cdm;
15 : using namespace std;
16 :
17 : namespace mozilla {
18 :
19 3 : static map<uint32_t, RefPtr<CDMWrapper>> sDecryptors;
20 :
21 : /* static */
22 : RefPtr<CDMWrapper>
23 0 : WidevineDecryptor::GetInstance(uint32_t aInstanceId)
24 : {
25 0 : auto itr = sDecryptors.find(aInstanceId);
26 0 : if (itr != sDecryptors.end()) {
27 0 : return itr->second;
28 : }
29 0 : return nullptr;
30 : }
31 :
32 :
33 0 : WidevineDecryptor::WidevineDecryptor()
34 0 : : mCallback(nullptr)
35 : {
36 0 : CDM_LOG("WidevineDecryptor created this=%p, instanceId=%u", this, mInstanceId);
37 0 : AddRef(); // Released in DecryptingComplete().
38 0 : }
39 :
40 0 : WidevineDecryptor::~WidevineDecryptor()
41 : {
42 0 : CDM_LOG("WidevineDecryptor destroyed this=%p, instanceId=%u", this, mInstanceId);
43 0 : }
44 :
45 : void
46 0 : WidevineDecryptor::SetCDM(RefPtr<CDMWrapper> aCDM, uint32_t aInstanceId)
47 : {
48 0 : mCDM = aCDM;
49 0 : mInstanceId = aInstanceId;
50 0 : sDecryptors[mInstanceId] = aCDM.forget();
51 0 : }
52 :
53 : void
54 0 : WidevineDecryptor::Init(GMPDecryptorCallback* aCallback,
55 : bool aDistinctiveIdentifierRequired,
56 : bool aPersistentStateRequired)
57 : {
58 0 : CDM_LOG("WidevineDecryptor::Init() this=%p distinctiveId=%d persistentState=%d",
59 : this, aDistinctiveIdentifierRequired, aPersistentStateRequired);
60 0 : MOZ_ASSERT(aCallback);
61 0 : mCallback = aCallback;
62 0 : MOZ_ASSERT(mCDM);
63 0 : mDistinctiveIdentifierRequired = aDistinctiveIdentifierRequired;
64 0 : mPersistentStateRequired = aPersistentStateRequired;
65 0 : if (CDM()) {
66 0 : CDM()->Initialize(aDistinctiveIdentifierRequired,
67 0 : aPersistentStateRequired);
68 : }
69 0 : }
70 :
71 : static SessionType
72 0 : ToCDMSessionType(GMPSessionType aSessionType)
73 : {
74 0 : switch (aSessionType) {
75 0 : case kGMPTemporySession: return kTemporary;
76 0 : case kGMPPersistentSession: return kPersistentLicense;
77 0 : case kGMPSessionInvalid: return kTemporary;
78 : // TODO: kPersistentKeyRelease
79 : }
80 0 : MOZ_ASSERT(false); // Not supposed to get here.
81 : return kTemporary;
82 : }
83 :
84 : void
85 0 : WidevineDecryptor::CreateSession(uint32_t aCreateSessionToken,
86 : uint32_t aPromiseId,
87 : const char* aInitDataType,
88 : uint32_t aInitDataTypeSize,
89 : const uint8_t* aInitData,
90 : uint32_t aInitDataSize,
91 : GMPSessionType aSessionType)
92 : {
93 0 : CDM_LOG("Decryptor::CreateSession(token=%d, pid=%d)", aCreateSessionToken, aPromiseId);
94 : InitDataType initDataType;
95 0 : if (!strcmp(aInitDataType, "cenc")) {
96 0 : initDataType = kCenc;
97 0 : } else if (!strcmp(aInitDataType, "webm")) {
98 0 : initDataType = kWebM;
99 0 : } else if (!strcmp(aInitDataType, "keyids")) {
100 0 : initDataType = kKeyIds;
101 : } else {
102 : // Invalid init data type
103 0 : const char* errorMsg = "Invalid init data type when creating session.";
104 0 : OnRejectPromise(aPromiseId, kNotSupportedError, 0, errorMsg, sizeof(errorMsg));
105 0 : return;
106 : }
107 0 : mPromiseIdToNewSessionTokens[aPromiseId] = aCreateSessionToken;
108 0 : CDM()->CreateSessionAndGenerateRequest(aPromiseId,
109 : ToCDMSessionType(aSessionType),
110 : initDataType,
111 0 : aInitData, aInitDataSize);
112 : }
113 :
114 : void
115 0 : WidevineDecryptor::LoadSession(uint32_t aPromiseId,
116 : const char* aSessionId,
117 : uint32_t aSessionIdLength)
118 : {
119 0 : CDM_LOG("Decryptor::LoadSession(pid=%d, %s)", aPromiseId, aSessionId);
120 : // TODO: session type??
121 0 : CDM()->LoadSession(aPromiseId, kPersistentLicense, aSessionId, aSessionIdLength);
122 0 : }
123 :
124 : void
125 0 : WidevineDecryptor::UpdateSession(uint32_t aPromiseId,
126 : const char* aSessionId,
127 : uint32_t aSessionIdLength,
128 : const uint8_t* aResponse,
129 : uint32_t aResponseSize)
130 : {
131 0 : CDM_LOG("Decryptor::UpdateSession(pid=%d, session=%s)", aPromiseId, aSessionId);
132 0 : CDM()->UpdateSession(aPromiseId, aSessionId, aSessionIdLength, aResponse, aResponseSize);
133 0 : }
134 :
135 : void
136 0 : WidevineDecryptor::CloseSession(uint32_t aPromiseId,
137 : const char* aSessionId,
138 : uint32_t aSessionIdLength)
139 : {
140 0 : CDM_LOG("Decryptor::CloseSession(pid=%d, session=%s)", aPromiseId, aSessionId);
141 0 : CDM()->CloseSession(aPromiseId, aSessionId, aSessionIdLength);
142 0 : }
143 :
144 : void
145 0 : WidevineDecryptor::RemoveSession(uint32_t aPromiseId,
146 : const char* aSessionId,
147 : uint32_t aSessionIdLength)
148 : {
149 0 : CDM_LOG("Decryptor::RemoveSession(%s)", aSessionId);
150 0 : CDM()->RemoveSession(aPromiseId, aSessionId, aSessionIdLength);
151 0 : }
152 :
153 : void
154 0 : WidevineDecryptor::SetServerCertificate(uint32_t aPromiseId,
155 : const uint8_t* aServerCert,
156 : uint32_t aServerCertSize)
157 : {
158 0 : CDM_LOG("Decryptor::SetServerCertificate()");
159 0 : CDM()->SetServerCertificate(aPromiseId, aServerCert, aServerCertSize);
160 0 : }
161 :
162 : void
163 0 : WidevineDecryptor::Decrypt(GMPBuffer* aBuffer,
164 : GMPEncryptedBufferMetadata* aMetadata)
165 : {
166 0 : if (!mCallback) {
167 0 : CDM_LOG("WidevineDecryptor::Decrypt() this=%p FAIL; !mCallback", this);
168 0 : return;
169 : }
170 0 : const GMPEncryptedBufferMetadata* crypto = aMetadata;
171 0 : InputBuffer sample;
172 0 : nsTArray<SubsampleEntry> subsamples;
173 0 : InitInputBuffer(crypto, aBuffer->Id(), aBuffer->Data(), aBuffer->Size(), sample, subsamples);
174 0 : WidevineDecryptedBlock decrypted;
175 0 : Status rv = CDM()->Decrypt(sample, &decrypted);
176 0 : CDM_LOG("Decryptor::Decrypt(timestamp=%" PRId64 ") rv=%d sz=%d",
177 : sample.timestamp, rv, decrypted.DecryptedBuffer()->Size());
178 0 : if (rv == kSuccess) {
179 0 : aBuffer->Resize(decrypted.DecryptedBuffer()->Size());
180 0 : memcpy(aBuffer->Data(),
181 0 : decrypted.DecryptedBuffer()->Data(),
182 0 : decrypted.DecryptedBuffer()->Size());
183 : }
184 0 : mCallback->Decrypted(aBuffer, ToGMPErr(rv));
185 : }
186 :
187 : void
188 0 : WidevineDecryptor::DecryptingComplete()
189 : {
190 0 : CDM_LOG("WidevineDecryptor::DecryptingComplete() this=%p, instanceId=%u",
191 : this, mInstanceId);
192 : // Drop our references to the CDMWrapper. When any other references
193 : // held elsewhere are dropped (for example references held by a
194 : // WidevineVideoDecoder, or a runnable), the CDMWrapper destroys
195 : // the CDM.
196 0 : mCDM = nullptr;
197 0 : sDecryptors.erase(mInstanceId);
198 0 : mCallback = nullptr;
199 0 : Release();
200 0 : }
201 :
202 : Buffer*
203 0 : WidevineDecryptor::Allocate(uint32_t aCapacity)
204 : {
205 0 : CDM_LOG("Decryptor::Allocate(capacity=%u)", aCapacity);
206 0 : return new WidevineBuffer(aCapacity);
207 : }
208 :
209 : class TimerTask : public GMPTask {
210 : public:
211 0 : TimerTask(WidevineDecryptor* aDecryptor,
212 : RefPtr<CDMWrapper> aCDM,
213 : void* aContext)
214 0 : : mDecryptor(aDecryptor)
215 : , mCDM(aCDM)
216 0 : , mContext(aContext)
217 : {
218 0 : }
219 0 : ~TimerTask() override = default;
220 0 : void Run() override {
221 0 : mCDM->GetCDM()->TimerExpired(mContext);
222 0 : }
223 0 : void Destroy() override { delete this; }
224 : private:
225 : RefPtr<WidevineDecryptor> mDecryptor;
226 : RefPtr<CDMWrapper> mCDM;
227 : void* mContext;
228 : };
229 :
230 : void
231 0 : WidevineDecryptor::SetTimer(int64_t aDelayMs, void* aContext)
232 : {
233 0 : CDM_LOG("Decryptor::SetTimer(delay_ms=%" PRId64 ", context=0x%p)", aDelayMs, aContext);
234 0 : if (mCDM) {
235 0 : GMPSetTimerOnMainThread(new TimerTask(this, mCDM, aContext), aDelayMs);
236 : }
237 0 : }
238 :
239 : Time
240 0 : WidevineDecryptor::GetCurrentWallTime()
241 : {
242 0 : return base::Time::Now().ToDoubleT();
243 : }
244 :
245 : void
246 0 : WidevineDecryptor::OnResolveNewSessionPromise(uint32_t aPromiseId,
247 : const char* aSessionId,
248 : uint32_t aSessionIdSize)
249 : {
250 0 : if (!mCallback) {
251 0 : CDM_LOG("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d) FAIL; !mCallback", aPromiseId);
252 0 : return;
253 : }
254 :
255 : // This is laid out in the API. If we fail to load a session we should
256 : // call OnResolveNewSessionPromise with nullptr as the sessionId.
257 : // We can safely assume this means that we have failed to load a session
258 : // as the other methods specify calling 'OnRejectPromise' when they fail.
259 0 : if (!aSessionId) {
260 0 : CDM_LOG("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d) Failed to load session", aPromiseId);
261 0 : mCallback->ResolveLoadSessionPromise(aPromiseId, false);
262 0 : return;
263 : }
264 :
265 0 : CDM_LOG("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d)", aPromiseId);
266 0 : auto iter = mPromiseIdToNewSessionTokens.find(aPromiseId);
267 0 : if (iter == mPromiseIdToNewSessionTokens.end()) {
268 0 : CDM_LOG("FAIL: Decryptor::OnResolveNewSessionPromise(aPromiseId=%d) unknown aPromiseId", aPromiseId);
269 0 : return;
270 : }
271 0 : mCallback->SetSessionId(iter->second, aSessionId, aSessionIdSize);
272 0 : mCallback->ResolvePromise(aPromiseId);
273 0 : mPromiseIdToNewSessionTokens.erase(iter);
274 : }
275 :
276 : void
277 0 : WidevineDecryptor::OnResolvePromise(uint32_t aPromiseId)
278 : {
279 0 : if (!mCallback) {
280 0 : CDM_LOG("Decryptor::OnResolvePromise(aPromiseId=0x%d) FAIL; !mCallback", aPromiseId);
281 0 : return;
282 : }
283 0 : CDM_LOG("Decryptor::OnResolvePromise(aPromiseId=%d)", aPromiseId);
284 0 : mCallback->ResolvePromise(aPromiseId);
285 : }
286 :
287 : static GMPDOMException
288 0 : ToGMPDOMException(cdm::Error aError)
289 : {
290 0 : switch (aError) {
291 0 : case kNotSupportedError: return kGMPNotSupportedError;
292 0 : case kInvalidStateError: return kGMPInvalidStateError;
293 : case kInvalidAccessError:
294 : // Note: Chrome converts kInvalidAccessError to TypeError, since the
295 : // Chromium CDM API doesn't have a type error enum value. The EME spec
296 : // requires TypeError in some places, so we do the same conversion.
297 : // See bug 1313202.
298 0 : return kGMPTypeError;
299 0 : case kQuotaExceededError: return kGMPQuotaExceededError;
300 0 : case kUnknownError: return kGMPInvalidModificationError; // Note: Unique placeholder.
301 0 : case kClientError: return kGMPAbortError; // Note: Unique placeholder.
302 0 : case kOutputError: return kGMPSecurityError; // Note: Unique placeholder.
303 : };
304 0 : return kGMPTimeoutError; // Note: Unique placeholder.
305 : }
306 :
307 : void
308 0 : WidevineDecryptor::OnRejectPromise(uint32_t aPromiseId,
309 : Error aError,
310 : uint32_t aSystemCode,
311 : const char* aErrorMessage,
312 : uint32_t aErrorMessageSize)
313 : {
314 0 : if (!mCallback) {
315 0 : CDM_LOG("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s) FAIL; !mCallback",
316 : aPromiseId, (int)aError, aSystemCode, aErrorMessage);
317 0 : return;
318 : }
319 0 : CDM_LOG("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s)",
320 : aPromiseId, (int)aError, aSystemCode, aErrorMessage);
321 0 : mCallback->RejectPromise(aPromiseId,
322 : ToGMPDOMException(aError),
323 : !aErrorMessageSize ? "" : aErrorMessage,
324 0 : aErrorMessageSize);
325 : }
326 :
327 : static GMPSessionMessageType
328 0 : ToGMPMessageType(MessageType message_type)
329 : {
330 0 : switch (message_type) {
331 0 : case kLicenseRequest: return kGMPLicenseRequest;
332 0 : case kLicenseRenewal: return kGMPLicenseRenewal;
333 0 : case kLicenseRelease: return kGMPLicenseRelease;
334 : }
335 0 : return kGMPMessageInvalid;
336 : }
337 :
338 : void
339 0 : WidevineDecryptor::OnSessionMessage(const char* aSessionId,
340 : uint32_t aSessionIdSize,
341 : MessageType aMessageType,
342 : const char* aMessage,
343 : uint32_t aMessageSize,
344 : const char* aLegacyDestinationUrl,
345 : uint32_t aLegacyDestinationUrlLength)
346 : {
347 0 : if (!mCallback) {
348 0 : CDM_LOG("Decryptor::OnSessionMessage() FAIL; !mCallback");
349 0 : return;
350 : }
351 0 : CDM_LOG("Decryptor::OnSessionMessage()");
352 0 : mCallback->SessionMessage(aSessionId,
353 : aSessionIdSize,
354 : ToGMPMessageType(aMessageType),
355 : reinterpret_cast<const uint8_t*>(aMessage),
356 0 : aMessageSize);
357 : }
358 :
359 : static GMPMediaKeyStatus
360 0 : ToGMPKeyStatus(KeyStatus aStatus)
361 : {
362 0 : switch (aStatus) {
363 0 : case kUsable: return kGMPUsable;
364 0 : case kInternalError: return kGMPInternalError;
365 0 : case kExpired: return kGMPExpired;
366 0 : case kOutputRestricted: return kGMPOutputRestricted;
367 0 : case kOutputDownscaled: return kGMPOutputDownscaled;
368 0 : case kStatusPending: return kGMPStatusPending;
369 0 : case kReleased: return kGMPReleased;
370 : }
371 0 : return kGMPUnknown;
372 : }
373 :
374 : void
375 0 : WidevineDecryptor::OnSessionKeysChange(const char* aSessionId,
376 : uint32_t aSessionIdSize,
377 : bool aHasAdditionalUsableKey,
378 : const KeyInformation* aKeysInfo,
379 : uint32_t aKeysInfoCount)
380 : {
381 0 : if (!mCallback) {
382 0 : CDM_LOG("Decryptor::OnSessionKeysChange() FAIL; !mCallback");
383 0 : return;
384 : }
385 0 : CDM_LOG("Decryptor::OnSessionKeysChange()");
386 :
387 0 : nsTArray<GMPMediaKeyInfo> key_infos;
388 0 : for (uint32_t i = 0; i < aKeysInfoCount; i++) {
389 0 : key_infos.AppendElement(GMPMediaKeyInfo(aKeysInfo[i].key_id,
390 0 : aKeysInfo[i].key_id_size,
391 0 : ToGMPKeyStatus(aKeysInfo[i].status)));
392 : }
393 0 : mCallback->BatchedKeyStatusChanged(aSessionId, aSessionIdSize,
394 0 : key_infos.Elements(), key_infos.Length());
395 : }
396 :
397 : static GMPTimestamp
398 0 : ToGMPTime(Time aCDMTime)
399 : {
400 0 : return static_cast<GMPTimestamp>(aCDMTime * 1000);
401 : }
402 :
403 : void
404 0 : WidevineDecryptor::OnExpirationChange(const char* aSessionId,
405 : uint32_t aSessionIdSize,
406 : Time aNewExpiryTime)
407 : {
408 0 : if (!mCallback) {
409 0 : CDM_LOG("Decryptor::OnExpirationChange(sid=%s) t=%lf FAIL; !mCallback",
410 : aSessionId, aNewExpiryTime);
411 0 : return;
412 : }
413 0 : CDM_LOG("Decryptor::OnExpirationChange(sid=%s) t=%lf", aSessionId, aNewExpiryTime);
414 0 : mCallback->ExpirationChange(aSessionId, aSessionIdSize, ToGMPTime(aNewExpiryTime));
415 : }
416 :
417 : void
418 0 : WidevineDecryptor::OnSessionClosed(const char* aSessionId,
419 : uint32_t aSessionIdSize)
420 : {
421 0 : if (!mCallback) {
422 0 : CDM_LOG("Decryptor::OnSessionClosed(sid=%s) FAIL; !mCallback", aSessionId);
423 0 : return;
424 : }
425 0 : CDM_LOG("Decryptor::OnSessionClosed(sid=%s)", aSessionId);
426 0 : mCallback->SessionClosed(aSessionId, aSessionIdSize);
427 : }
428 :
429 : void
430 0 : WidevineDecryptor::OnLegacySessionError(const char* aSessionId,
431 : uint32_t aSessionIdLength,
432 : Error aError,
433 : uint32_t aSystemCode,
434 : const char* aErrorMessage,
435 : uint32_t aErrorMessageLength)
436 : {
437 0 : if (!mCallback) {
438 0 : CDM_LOG("Decryptor::OnLegacySessionError(sid=%s, error=%d) FAIL; !mCallback",
439 : aSessionId, (int)aError);
440 0 : return;
441 : }
442 0 : CDM_LOG("Decryptor::OnLegacySessionError(sid=%s, error=%d)", aSessionId, (int)aError);
443 0 : mCallback->SessionError(aSessionId,
444 : aSessionIdLength,
445 : ToGMPDOMException(aError),
446 : aSystemCode,
447 : aErrorMessage,
448 0 : aErrorMessageLength);
449 : }
450 :
451 : void
452 0 : WidevineDecryptor::SendPlatformChallenge(const char* aServiceId,
453 : uint32_t aServiceIdSize,
454 : const char* aChallenge,
455 : uint32_t aChallengeSize)
456 : {
457 0 : CDM_LOG("Decryptor::SendPlatformChallenge(service_id=%s)", aServiceId);
458 0 : }
459 :
460 : void
461 0 : WidevineDecryptor::EnableOutputProtection(uint32_t aDesiredProtectionMask)
462 : {
463 0 : CDM_LOG("Decryptor::EnableOutputProtection(mask=0x%x)", aDesiredProtectionMask);
464 0 : }
465 :
466 : void
467 0 : WidevineDecryptor::QueryOutputProtectionStatus()
468 : {
469 0 : CDM_LOG("Decryptor::QueryOutputProtectionStatus()");
470 0 : }
471 :
472 : void
473 0 : WidevineDecryptor::OnDeferredInitializationDone(StreamType aStreamType,
474 : Status aDecoderStatus)
475 : {
476 0 : CDM_LOG("Decryptor::OnDeferredInitializationDone()");
477 0 : }
478 :
479 : FileIO*
480 0 : WidevineDecryptor::CreateFileIO(FileIOClient* aClient)
481 : {
482 0 : CDM_LOG("Decryptor::CreateFileIO()");
483 0 : if (!mPersistentStateRequired) {
484 0 : return nullptr;
485 : }
486 0 : return new WidevineFileIO(aClient);
487 : }
488 :
489 9 : } // namespace mozilla
|