1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "modules/encryptedmedia/HTMLMediaElementEncryptedMedia.h"
7
8 #include "bindings/core/v8/ExceptionState.h"
9 #include "bindings/core/v8/ScriptPromise.h"
10 #include "bindings/core/v8/ScriptPromiseResolver.h"
11 #include "bindings/core/v8/ScriptState.h"
12 #include "core/dom/DOMException.h"
13 #include "core/dom/ExceptionCode.h"
14 #include "core/html/HTMLMediaElement.h"
15 #include "core/html/MediaKeyError.h"
16 #include "core/html/MediaKeyEvent.h"
17 #include "modules/encryptedmedia/MediaKeyNeededEvent.h"
18 #include "modules/encryptedmedia/MediaKeys.h"
19 #include "modules/encryptedmedia/SimpleContentDecryptionModuleResult.h"
20 #include "platform/ContentDecryptionModuleResult.h"
21 #include "platform/Logging.h"
22 #include "platform/RuntimeEnabledFeatures.h"
23 #include "wtf/Functional.h"
24 #include "wtf/Uint8Array.h"
25
26 namespace blink {
27
throwExceptionIfMediaKeyExceptionOccurred(const String & keySystem,const String & sessionId,WebMediaPlayer::MediaKeyException exception,ExceptionState & exceptionState)28 static void throwExceptionIfMediaKeyExceptionOccurred(const String& keySystem, const String& sessionId, WebMediaPlayer::MediaKeyException exception, ExceptionState& exceptionState)
29 {
30 switch (exception) {
31 case WebMediaPlayer::MediaKeyExceptionNoError:
32 return;
33 case WebMediaPlayer::MediaKeyExceptionInvalidPlayerState:
34 exceptionState.throwDOMException(InvalidStateError, "The player is in an invalid state.");
35 return;
36 case WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported:
37 exceptionState.throwDOMException(NotSupportedError, "The key system provided ('" + keySystem +"') is not supported.");
38 return;
39 case WebMediaPlayer::MediaKeyExceptionInvalidAccess:
40 exceptionState.throwDOMException(InvalidAccessError, "The session ID provided ('" + sessionId + "') is invalid.");
41 return;
42 }
43
44 ASSERT_NOT_REACHED();
45 return;
46 }
47
48 // This class allows MediaKeys to be set asynchronously.
49 class SetMediaKeysHandler : public ScriptPromiseResolver {
50 WTF_MAKE_NONCOPYABLE(SetMediaKeysHandler);
51
52 public:
53 static ScriptPromise create(ScriptState*, HTMLMediaElement&, MediaKeys*);
54 virtual ~SetMediaKeysHandler();
55
56 private:
57 SetMediaKeysHandler(ScriptState*, HTMLMediaElement&, MediaKeys*);
58 void timerFired(Timer<SetMediaKeysHandler>*);
59
60 void clearExistingMediaKeys();
61 void setNewMediaKeys();
62 void finish();
63
64 void reportSetFailed(ExceptionCode, const String& errorMessage);
65
66 // Keep media element alive until promise is fulfilled
67 RefPtrWillBePersistent<HTMLMediaElement> m_element;
68 Persistent<MediaKeys> m_newMediaKeys;
69 Timer<SetMediaKeysHandler> m_timer;
70 };
71
72 typedef Function<void()> SuccessCallback;
73 typedef Function<void(ExceptionCode, const String&)> FailureCallback;
74
75 // Represents the result used when setContentDecryptionModule() is called.
76 // Calls |success| if result is resolved, |failure| is result is rejected.
77 class SetContentDecryptionModuleResult FINAL : public ContentDecryptionModuleResult {
78 public:
SetContentDecryptionModuleResult(SuccessCallback success,FailureCallback failure)79 SetContentDecryptionModuleResult(SuccessCallback success, FailureCallback failure)
80 : m_successCallback(success)
81 , m_failureCallback(failure)
82 {
83 }
84
85 // ContentDecryptionModuleResult implementation.
complete()86 virtual void complete() OVERRIDE
87 {
88 m_successCallback();
89 }
90
completeWithSession(blink::WebContentDecryptionModuleResult::SessionStatus status)91 virtual void completeWithSession(blink::WebContentDecryptionModuleResult::SessionStatus status) OVERRIDE
92 {
93 ASSERT_NOT_REACHED();
94 m_failureCallback(InvalidStateError, "Unexpected completion.");
95 }
96
completeWithError(blink::WebContentDecryptionModuleException code,unsigned long systemCode,const blink::WebString & message)97 virtual void completeWithError(blink::WebContentDecryptionModuleException code, unsigned long systemCode, const blink::WebString& message) OVERRIDE
98 {
99 m_failureCallback(WebCdmExceptionToExceptionCode(code), message);
100 }
101
102 private:
103 SuccessCallback m_successCallback;
104 FailureCallback m_failureCallback;
105 };
106
create(ScriptState * scriptState,HTMLMediaElement & element,MediaKeys * mediaKeys)107 ScriptPromise SetMediaKeysHandler::create(ScriptState* scriptState, HTMLMediaElement& element, MediaKeys* mediaKeys)
108 {
109 RefPtr<SetMediaKeysHandler> handler = adoptRef(new SetMediaKeysHandler(scriptState, element, mediaKeys));
110 handler->suspendIfNeeded();
111 handler->keepAliveWhilePending();
112 return handler->promise();
113 }
114
SetMediaKeysHandler(ScriptState * scriptState,HTMLMediaElement & element,MediaKeys * mediaKeys)115 SetMediaKeysHandler::SetMediaKeysHandler(ScriptState* scriptState, HTMLMediaElement& element, MediaKeys* mediaKeys)
116 : ScriptPromiseResolver(scriptState)
117 , m_element(element)
118 , m_newMediaKeys(mediaKeys)
119 , m_timer(this, &SetMediaKeysHandler::timerFired)
120 {
121 WTF_LOG(Media, "SetMediaKeysHandler::SetMediaKeysHandler");
122
123 // 3. Run the remaining steps asynchronously.
124 m_timer.startOneShot(0, FROM_HERE);
125 }
126
~SetMediaKeysHandler()127 SetMediaKeysHandler::~SetMediaKeysHandler()
128 {
129 }
130
timerFired(Timer<SetMediaKeysHandler> *)131 void SetMediaKeysHandler::timerFired(Timer<SetMediaKeysHandler>*)
132 {
133 clearExistingMediaKeys();
134 }
135
clearExistingMediaKeys()136 void SetMediaKeysHandler::clearExistingMediaKeys()
137 {
138 WTF_LOG(Media, "SetMediaKeysHandler::clearExistingMediaKeys");
139 HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(*m_element);
140
141 // 3.1 If mediaKeys is not null, it is already in use by another media
142 // element, and the user agent is unable to use it with this element,
143 // reject promise with a new DOMException whose name is
144 // "QuotaExceededError".
145 // FIXME: Need to check whether mediaKeys is already in use by another
146 // media element.
147 // 3.2 If the mediaKeys attribute is not null, run the following steps:
148 if (thisElement.m_mediaKeys) {
149 // 3.2.1 If the user agent or CDM do not support removing the
150 // association, return a promise rejected with a new DOMException
151 // whose name is "NotSupportedError".
152 // (supported by blink).
153 // 3.2.2 If the association cannot currently be removed (i.e. during
154 // playback), return a promise rejected with a new DOMException
155 // whose name is "InvalidStateError".
156 if (m_element->webMediaPlayer()) {
157 reject(DOMException::create(InvalidStateError, "The existing MediaKeys object cannot be removed while a media resource is loaded."));
158 return;
159 }
160
161 // (next 2 steps not required as there is no player connected).
162 // 3.2.3 Stop using the CDM instance represented by the mediaKeys
163 // attribute to decrypt media data and remove the association
164 // with the media element.
165 // 3.2.4 If the preceding step failed, reject promise with a new
166 // DOMException whose name is the appropriate error name and
167 // that has an appropriate message.
168 }
169
170 // MediaKeys not currently set or no player connected, so continue on.
171 setNewMediaKeys();
172 }
173
setNewMediaKeys()174 void SetMediaKeysHandler::setNewMediaKeys()
175 {
176 WTF_LOG(Media, "SetMediaKeysHandler::setNewMediaKeys");
177
178 // 3.3 If mediaKeys is not null, run the following steps:
179 if (m_newMediaKeys) {
180 // 3.3.1 Associate the CDM instance represented by mediaKeys with the
181 // media element for decrypting media data.
182 // 3.3.2 If the preceding step failed, run the following steps:
183 // (done in reportSetFailed()).
184 // 3.3.3 Run the Attempt to Resume Playback If Necessary algorithm on
185 // the media element. The user agent may choose to skip this
186 // step if it knows resuming will fail (i.e. mediaKeys has no
187 // sessions).
188 // (Handled in Chromium).
189 if (m_element->webMediaPlayer()) {
190 SuccessCallback successCallback = bind(&SetMediaKeysHandler::finish, this);
191 FailureCallback failureCallback = bind<ExceptionCode, const String&>(&SetMediaKeysHandler::reportSetFailed, this);
192 ContentDecryptionModuleResult* result = new SetContentDecryptionModuleResult(successCallback, failureCallback);
193 m_element->webMediaPlayer()->setContentDecryptionModule(m_newMediaKeys->contentDecryptionModule(), result->result());
194
195 // Don't do anything more until |result| is resolved (or rejected).
196 return;
197 }
198 }
199
200 // MediaKeys doesn't need to be set on the player, so continue on.
201 finish();
202 }
203
finish()204 void SetMediaKeysHandler::finish()
205 {
206 WTF_LOG(Media, "SetMediaKeysHandler::finish");
207 HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(*m_element);
208
209 // 3.4 Set the mediaKeys attribute to mediaKeys.
210 thisElement.m_mediaKeys = m_newMediaKeys;
211
212 // 3.5 Resolve promise with undefined.
213 resolve();
214 }
215
reportSetFailed(ExceptionCode code,const String & errorMessage)216 void SetMediaKeysHandler::reportSetFailed(ExceptionCode code, const String& errorMessage)
217 {
218 WTF_LOG(Media, "SetMediaKeysHandler::reportSetFailed");
219 HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(*m_element);
220
221 // 3.3.2 If the preceding step failed, run the following steps:
222 // 3.3.2.1 Set the mediaKeys attribute to null.
223 thisElement.m_mediaKeys.clear();
224
225 // 3.3.2.2 Reject promise with a new DOMException whose name is the
226 // appropriate error name and that has an appropriate message.
227 reject(DOMException::create(code, errorMessage));
228 }
229
HTMLMediaElementEncryptedMedia()230 HTMLMediaElementEncryptedMedia::HTMLMediaElementEncryptedMedia()
231 : m_emeMode(EmeModeNotSelected)
232 {
233 }
234
DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(HTMLMediaElementEncryptedMedia) const235 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(HTMLMediaElementEncryptedMedia)
236
237 const char* HTMLMediaElementEncryptedMedia::supplementName()
238 {
239 return "HTMLMediaElementEncryptedMedia";
240 }
241
from(HTMLMediaElement & element)242 HTMLMediaElementEncryptedMedia& HTMLMediaElementEncryptedMedia::from(HTMLMediaElement& element)
243 {
244 HTMLMediaElementEncryptedMedia* supplement = static_cast<HTMLMediaElementEncryptedMedia*>(WillBeHeapSupplement<HTMLMediaElement>::from(element, supplementName()));
245 if (!supplement) {
246 supplement = new HTMLMediaElementEncryptedMedia();
247 provideTo(element, supplementName(), adoptPtrWillBeNoop(supplement));
248 }
249 return *supplement;
250 }
251
setEmeMode(EmeMode emeMode)252 bool HTMLMediaElementEncryptedMedia::setEmeMode(EmeMode emeMode)
253 {
254 if (m_emeMode != EmeModeNotSelected && m_emeMode != emeMode)
255 return false;
256
257 m_emeMode = emeMode;
258 return true;
259 }
260
contentDecryptionModule()261 WebContentDecryptionModule* HTMLMediaElementEncryptedMedia::contentDecryptionModule()
262 {
263 return m_mediaKeys ? m_mediaKeys->contentDecryptionModule() : 0;
264 }
265
mediaKeys(HTMLMediaElement & element)266 MediaKeys* HTMLMediaElementEncryptedMedia::mediaKeys(HTMLMediaElement& element)
267 {
268 HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(element);
269 return thisElement.m_mediaKeys.get();
270 }
271
setMediaKeys(ScriptState * scriptState,HTMLMediaElement & element,MediaKeys * mediaKeys)272 ScriptPromise HTMLMediaElementEncryptedMedia::setMediaKeys(ScriptState* scriptState, HTMLMediaElement& element, MediaKeys* mediaKeys)
273 {
274 HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(element);
275 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::setMediaKeys current(%p), new(%p)", thisElement.m_mediaKeys.get(), mediaKeys);
276
277 if (!thisElement.setEmeMode(EmeModeUnprefixed))
278 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(InvalidStateError, "Mixed use of EME prefixed and unprefixed API not allowed."));
279
280 // 1. If mediaKeys and the mediaKeys attribute are the same object, return
281 // a promise resolved with undefined.
282 if (thisElement.m_mediaKeys == mediaKeys)
283 return ScriptPromise::cast(scriptState, V8ValueTraits<V8UndefinedType>::toV8Value(V8UndefinedType(), scriptState->context()->Global(), scriptState->isolate()));
284
285 // 2. Let promise be a new promise. Remaining steps done in handler.
286 return SetMediaKeysHandler::create(scriptState, element, mediaKeys);
287 }
288
289 // Create a MediaKeyNeededEvent for WD EME.
createNeedKeyEvent(const String & contentType,const unsigned char * initData,unsigned initDataLength)290 static PassRefPtrWillBeRawPtr<Event> createNeedKeyEvent(const String& contentType, const unsigned char* initData, unsigned initDataLength)
291 {
292 MediaKeyNeededEventInit initializer;
293 initializer.contentType = contentType;
294 initializer.initData = Uint8Array::create(initData, initDataLength);
295 initializer.bubbles = false;
296 initializer.cancelable = false;
297
298 return MediaKeyNeededEvent::create(EventTypeNames::needkey, initializer);
299 }
300
301 // Create a 'needkey' MediaKeyEvent for v0.1b EME.
createWebkitNeedKeyEvent(const String & contentType,const unsigned char * initData,unsigned initDataLength)302 static PassRefPtrWillBeRawPtr<Event> createWebkitNeedKeyEvent(const String& contentType, const unsigned char* initData, unsigned initDataLength)
303 {
304 MediaKeyEventInit webkitInitializer;
305 webkitInitializer.keySystem = String();
306 webkitInitializer.sessionId = String();
307 webkitInitializer.initData = Uint8Array::create(initData, initDataLength);
308 webkitInitializer.bubbles = false;
309 webkitInitializer.cancelable = false;
310
311 return MediaKeyEvent::create(EventTypeNames::webkitneedkey, webkitInitializer);
312 }
313
webkitGenerateKeyRequest(HTMLMediaElement & element,const String & keySystem,PassRefPtr<Uint8Array> initData,ExceptionState & exceptionState)314 void HTMLMediaElementEncryptedMedia::webkitGenerateKeyRequest(HTMLMediaElement& element, const String& keySystem, PassRefPtr<Uint8Array> initData, ExceptionState& exceptionState)
315 {
316 HTMLMediaElementEncryptedMedia::from(element).generateKeyRequest(element.webMediaPlayer(), keySystem, initData, exceptionState);
317 }
318
generateKeyRequest(WebMediaPlayer * webMediaPlayer,const String & keySystem,PassRefPtr<Uint8Array> initData,ExceptionState & exceptionState)319 void HTMLMediaElementEncryptedMedia::generateKeyRequest(WebMediaPlayer* webMediaPlayer, const String& keySystem, PassRefPtr<Uint8Array> initData, ExceptionState& exceptionState)
320 {
321 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::webkitGenerateKeyRequest");
322
323 if (!setEmeMode(EmeModePrefixed)) {
324 exceptionState.throwDOMException(InvalidStateError, "Mixed use of EME prefixed and unprefixed API not allowed.");
325 return;
326 }
327
328 if (keySystem.isEmpty()) {
329 exceptionState.throwDOMException(SyntaxError, "The key system provided is empty.");
330 return;
331 }
332
333 if (!webMediaPlayer) {
334 exceptionState.throwDOMException(InvalidStateError, "No media has been loaded.");
335 return;
336 }
337
338 const unsigned char* initDataPointer = 0;
339 unsigned initDataLength = 0;
340 if (initData) {
341 initDataPointer = initData->data();
342 initDataLength = initData->length();
343 }
344
345 WebMediaPlayer::MediaKeyException result = webMediaPlayer->generateKeyRequest(keySystem, initDataPointer, initDataLength);
346 throwExceptionIfMediaKeyExceptionOccurred(keySystem, String(), result, exceptionState);
347 }
348
webkitGenerateKeyRequest(HTMLMediaElement & mediaElement,const String & keySystem,ExceptionState & exceptionState)349 void HTMLMediaElementEncryptedMedia::webkitGenerateKeyRequest(HTMLMediaElement& mediaElement, const String& keySystem, ExceptionState& exceptionState)
350 {
351 webkitGenerateKeyRequest(mediaElement, keySystem, Uint8Array::create(0), exceptionState);
352 }
353
webkitAddKey(HTMLMediaElement & element,const String & keySystem,PassRefPtr<Uint8Array> key,PassRefPtr<Uint8Array> initData,const String & sessionId,ExceptionState & exceptionState)354 void HTMLMediaElementEncryptedMedia::webkitAddKey(HTMLMediaElement& element, const String& keySystem, PassRefPtr<Uint8Array> key, PassRefPtr<Uint8Array> initData, const String& sessionId, ExceptionState& exceptionState)
355 {
356 HTMLMediaElementEncryptedMedia::from(element).addKey(element.webMediaPlayer(), keySystem, key, initData, sessionId, exceptionState);
357 }
358
addKey(WebMediaPlayer * webMediaPlayer,const String & keySystem,PassRefPtr<Uint8Array> key,PassRefPtr<Uint8Array> initData,const String & sessionId,ExceptionState & exceptionState)359 void HTMLMediaElementEncryptedMedia::addKey(WebMediaPlayer* webMediaPlayer, const String& keySystem, PassRefPtr<Uint8Array> key, PassRefPtr<Uint8Array> initData, const String& sessionId, ExceptionState& exceptionState)
360 {
361 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::webkitAddKey");
362
363 if (!setEmeMode(EmeModePrefixed)) {
364 exceptionState.throwDOMException(InvalidStateError, "Mixed use of EME prefixed and unprefixed API not allowed.");
365 return;
366 }
367
368 if (keySystem.isEmpty()) {
369 exceptionState.throwDOMException(SyntaxError, "The key system provided is empty.");
370 return;
371 }
372
373 if (!key) {
374 exceptionState.throwDOMException(SyntaxError, "The key provided is invalid.");
375 return;
376 }
377
378 if (!key->length()) {
379 exceptionState.throwDOMException(TypeMismatchError, "The key provided is invalid.");
380 return;
381 }
382
383 if (!webMediaPlayer) {
384 exceptionState.throwDOMException(InvalidStateError, "No media has been loaded.");
385 return;
386 }
387
388 const unsigned char* initDataPointer = 0;
389 unsigned initDataLength = 0;
390 if (initData) {
391 initDataPointer = initData->data();
392 initDataLength = initData->length();
393 }
394
395 WebMediaPlayer::MediaKeyException result = webMediaPlayer->addKey(keySystem, key->data(), key->length(), initDataPointer, initDataLength, sessionId);
396 throwExceptionIfMediaKeyExceptionOccurred(keySystem, sessionId, result, exceptionState);
397 }
398
webkitAddKey(HTMLMediaElement & mediaElement,const String & keySystem,PassRefPtr<Uint8Array> key,ExceptionState & exceptionState)399 void HTMLMediaElementEncryptedMedia::webkitAddKey(HTMLMediaElement& mediaElement, const String& keySystem, PassRefPtr<Uint8Array> key, ExceptionState& exceptionState)
400 {
401 webkitAddKey(mediaElement, keySystem, key, Uint8Array::create(0), String(), exceptionState);
402 }
403
webkitCancelKeyRequest(HTMLMediaElement & element,const String & keySystem,const String & sessionId,ExceptionState & exceptionState)404 void HTMLMediaElementEncryptedMedia::webkitCancelKeyRequest(HTMLMediaElement& element, const String& keySystem, const String& sessionId, ExceptionState& exceptionState)
405 {
406 HTMLMediaElementEncryptedMedia::from(element).cancelKeyRequest(element.webMediaPlayer(), keySystem, sessionId, exceptionState);
407 }
408
cancelKeyRequest(WebMediaPlayer * webMediaPlayer,const String & keySystem,const String & sessionId,ExceptionState & exceptionState)409 void HTMLMediaElementEncryptedMedia::cancelKeyRequest(WebMediaPlayer* webMediaPlayer, const String& keySystem, const String& sessionId, ExceptionState& exceptionState)
410 {
411 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::webkitCancelKeyRequest");
412
413 if (!setEmeMode(EmeModePrefixed)) {
414 exceptionState.throwDOMException(InvalidStateError, "Mixed use of EME prefixed and unprefixed API not allowed.");
415 return;
416 }
417
418 if (keySystem.isEmpty()) {
419 exceptionState.throwDOMException(SyntaxError, "The key system provided is empty.");
420 return;
421 }
422
423 if (!webMediaPlayer) {
424 exceptionState.throwDOMException(InvalidStateError, "No media has been loaded.");
425 return;
426 }
427
428 WebMediaPlayer::MediaKeyException result = webMediaPlayer->cancelKeyRequest(keySystem, sessionId);
429 throwExceptionIfMediaKeyExceptionOccurred(keySystem, sessionId, result, exceptionState);
430 }
431
keyAdded(HTMLMediaElement & element,const String & keySystem,const String & sessionId)432 void HTMLMediaElementEncryptedMedia::keyAdded(HTMLMediaElement& element, const String& keySystem, const String& sessionId)
433 {
434 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::mediaPlayerKeyAdded");
435
436 MediaKeyEventInit initializer;
437 initializer.keySystem = keySystem;
438 initializer.sessionId = sessionId;
439 initializer.bubbles = false;
440 initializer.cancelable = false;
441
442 RefPtrWillBeRawPtr<Event> event = MediaKeyEvent::create(EventTypeNames::webkitkeyadded, initializer);
443 event->setTarget(&element);
444 element.scheduleEvent(event.release());
445 }
446
keyError(HTMLMediaElement & element,const String & keySystem,const String & sessionId,WebMediaPlayerClient::MediaKeyErrorCode errorCode,unsigned short systemCode)447 void HTMLMediaElementEncryptedMedia::keyError(HTMLMediaElement& element, const String& keySystem, const String& sessionId, WebMediaPlayerClient::MediaKeyErrorCode errorCode, unsigned short systemCode)
448 {
449 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::mediaPlayerKeyError: sessionID=%s, errorCode=%d, systemCode=%d", sessionId.utf8().data(), errorCode, systemCode);
450
451 MediaKeyError::Code mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN;
452 switch (errorCode) {
453 case WebMediaPlayerClient::MediaKeyErrorCodeUnknown:
454 mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN;
455 break;
456 case WebMediaPlayerClient::MediaKeyErrorCodeClient:
457 mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_CLIENT;
458 break;
459 case WebMediaPlayerClient::MediaKeyErrorCodeService:
460 mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_SERVICE;
461 break;
462 case WebMediaPlayerClient::MediaKeyErrorCodeOutput:
463 mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_OUTPUT;
464 break;
465 case WebMediaPlayerClient::MediaKeyErrorCodeHardwareChange:
466 mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_HARDWARECHANGE;
467 break;
468 case WebMediaPlayerClient::MediaKeyErrorCodeDomain:
469 mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_DOMAIN;
470 break;
471 }
472
473 MediaKeyEventInit initializer;
474 initializer.keySystem = keySystem;
475 initializer.sessionId = sessionId;
476 initializer.errorCode = MediaKeyError::create(mediaKeyErrorCode);
477 initializer.systemCode = systemCode;
478 initializer.bubbles = false;
479 initializer.cancelable = false;
480
481 RefPtrWillBeRawPtr<Event> event = MediaKeyEvent::create(EventTypeNames::webkitkeyerror, initializer);
482 event->setTarget(&element);
483 element.scheduleEvent(event.release());
484 }
485
keyMessage(HTMLMediaElement & element,const String & keySystem,const String & sessionId,const unsigned char * message,unsigned messageLength,const WebURL & defaultURL)486 void HTMLMediaElementEncryptedMedia::keyMessage(HTMLMediaElement& element, const String& keySystem, const String& sessionId, const unsigned char* message, unsigned messageLength, const WebURL& defaultURL)
487 {
488 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::mediaPlayerKeyMessage: sessionID=%s", sessionId.utf8().data());
489
490 MediaKeyEventInit initializer;
491 initializer.keySystem = keySystem;
492 initializer.sessionId = sessionId;
493 initializer.message = Uint8Array::create(message, messageLength);
494 initializer.defaultURL = KURL(defaultURL);
495 initializer.bubbles = false;
496 initializer.cancelable = false;
497
498 RefPtrWillBeRawPtr<Event> event = MediaKeyEvent::create(EventTypeNames::webkitkeymessage, initializer);
499 event->setTarget(&element);
500 element.scheduleEvent(event.release());
501 }
502
keyNeeded(HTMLMediaElement & element,const String & contentType,const unsigned char * initData,unsigned initDataLength)503 void HTMLMediaElementEncryptedMedia::keyNeeded(HTMLMediaElement& element, const String& contentType, const unsigned char* initData, unsigned initDataLength)
504 {
505 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::mediaPlayerKeyNeeded: contentType=%s", contentType.utf8().data());
506
507 if (RuntimeEnabledFeatures::encryptedMediaEnabled()) {
508 // Send event for WD EME.
509 RefPtrWillBeRawPtr<Event> event = createNeedKeyEvent(contentType, initData, initDataLength);
510 event->setTarget(&element);
511 element.scheduleEvent(event.release());
512 }
513
514 if (RuntimeEnabledFeatures::prefixedEncryptedMediaEnabled()) {
515 // Send event for v0.1b EME.
516 RefPtrWillBeRawPtr<Event> event = createWebkitNeedKeyEvent(contentType, initData, initDataLength);
517 event->setTarget(&element);
518 element.scheduleEvent(event.release());
519 }
520 }
521
playerDestroyed(HTMLMediaElement & element)522 void HTMLMediaElementEncryptedMedia::playerDestroyed(HTMLMediaElement& element)
523 {
524 #if ENABLE(OILPAN)
525 // FIXME: Oilpan: remove this once the media player is on the heap. crbug.com/378229
526 if (element.isFinalizing())
527 return;
528 #endif
529
530 HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(element);
531 if (!thisElement.m_mediaKeys)
532 return;
533
534 ASSERT(thisElement.m_emeMode == EmeModeUnprefixed);
535 thisElement.m_mediaKeys.clear();
536 }
537
contentDecryptionModule(HTMLMediaElement & element)538 WebContentDecryptionModule* HTMLMediaElementEncryptedMedia::contentDecryptionModule(HTMLMediaElement& element)
539 {
540 HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(element);
541 return thisElement.contentDecryptionModule();
542 }
543
trace(Visitor * visitor)544 void HTMLMediaElementEncryptedMedia::trace(Visitor* visitor)
545 {
546 visitor->trace(m_mediaKeys);
547 WillBeHeapSupplement<HTMLMediaElement>::trace(visitor);
548 }
549
550 } // namespace blink
551