• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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