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