Home | History | Annotate | Download | only in encryptedmedia
      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 
     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:
     79     SetContentDecryptionModuleResult(SuccessCallback success, FailureCallback failure)
     80         : m_successCallback(success)
     81         , m_failureCallback(failure)
     82     {
     83     }
     84 
     85     // ContentDecryptionModuleResult implementation.
     86     virtual void complete() OVERRIDE
     87     {
     88         m_successCallback();
     89     }
     90 
     91     virtual void completeWithSession(blink::WebContentDecryptionModuleResult::SessionStatus status) OVERRIDE
     92     {
     93         ASSERT_NOT_REACHED();
     94         m_failureCallback(InvalidStateError, "Unexpected completion.");
     95     }
     96 
     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 
    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 
    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 
    127 SetMediaKeysHandler::~SetMediaKeysHandler()
    128 {
    129 }
    130 
    131 void SetMediaKeysHandler::timerFired(Timer<SetMediaKeysHandler>*)
    132 {
    133     clearExistingMediaKeys();
    134 }
    135 
    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 
    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 
    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 
    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 
    230 HTMLMediaElementEncryptedMedia::HTMLMediaElementEncryptedMedia()
    231     : m_emeMode(EmeModeNotSelected)
    232 {
    233 }
    234 
    235 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(HTMLMediaElementEncryptedMedia)
    236 
    237 const char* HTMLMediaElementEncryptedMedia::supplementName()
    238 {
    239     return "HTMLMediaElementEncryptedMedia";
    240 }
    241 
    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 
    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 
    261 WebContentDecryptionModule* HTMLMediaElementEncryptedMedia::contentDecryptionModule()
    262 {
    263     return m_mediaKeys ? m_mediaKeys->contentDecryptionModule() : 0;
    264 }
    265 
    266 MediaKeys* HTMLMediaElementEncryptedMedia::mediaKeys(HTMLMediaElement& element)
    267 {
    268     HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(element);
    269     return thisElement.m_mediaKeys.get();
    270 }
    271 
    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.
    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.
    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 
    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 
    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 
    349 void HTMLMediaElementEncryptedMedia::webkitGenerateKeyRequest(HTMLMediaElement& mediaElement, const String& keySystem, ExceptionState& exceptionState)
    350 {
    351     webkitGenerateKeyRequest(mediaElement, keySystem, Uint8Array::create(0), exceptionState);
    352 }
    353 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    538 WebContentDecryptionModule* HTMLMediaElementEncryptedMedia::contentDecryptionModule(HTMLMediaElement& element)
    539 {
    540     HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(element);
    541     return thisElement.contentDecryptionModule();
    542 }
    543 
    544 void HTMLMediaElementEncryptedMedia::trace(Visitor* visitor)
    545 {
    546     visitor->trace(m_mediaKeys);
    547     WillBeHeapSupplement<HTMLMediaElement>::trace(visitor);
    548 }
    549 
    550 } // namespace blink
    551