Index: Source/modules/encryptedmedia/HTMLMediaElementEncryptedMedia.cpp |
diff --git a/Source/modules/encryptedmedia/HTMLMediaElementEncryptedMedia.cpp b/Source/modules/encryptedmedia/HTMLMediaElementEncryptedMedia.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..88888db0b406654ca9b864b9f82cfb82dad5be71 |
--- /dev/null |
+++ b/Source/modules/encryptedmedia/HTMLMediaElementEncryptedMedia.cpp |
@@ -0,0 +1,353 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "config.h" |
+#include "modules/encryptedmedia/HTMLMediaElementEncryptedMedia.h" |
+ |
+#include "RuntimeEnabledFeatures.h" |
+#include "bindings/v8/ExceptionState.h" |
+#include "core/dom/ExceptionCode.h" |
+#include "core/html/HTMLMediaElement.h" |
+#include "core/html/MediaKeyError.h" |
+#include "core/html/MediaKeyEvent.h" |
+#include "modules/encryptedmedia/MediaKeyNeededEvent.h" |
+#include "modules/encryptedmedia/MediaKeys.h" |
+#include "platform/Logging.h" |
+ |
+namespace WebCore { |
+ |
+static void throwExceptionIfMediaKeyExceptionOccurred(const String& keySystem, const String& sessionId, blink::WebMediaPlayer::MediaKeyException exception, ExceptionState& exceptionState) |
+{ |
+ switch (exception) { |
+ case blink::WebMediaPlayer::MediaKeyExceptionNoError: |
+ return; |
+ case blink::WebMediaPlayer::MediaKeyExceptionInvalidPlayerState: |
+ exceptionState.throwDOMException(InvalidStateError, "The player is in an invalid state."); |
+ return; |
+ case blink::WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported: |
+ exceptionState.throwDOMException(NotSupportedError, "The key system provided ('" + keySystem +"') is not supported."); |
+ return; |
+ case blink::WebMediaPlayer::MediaKeyExceptionInvalidAccess: |
+ exceptionState.throwDOMException(InvalidAccessError, "The session ID provided ('" + sessionId + "') is invalid."); |
+ return; |
+ } |
+ |
+ ASSERT_NOT_REACHED(); |
+ return; |
+} |
+ |
+HTMLMediaElementEncryptedMedia::HTMLMediaElementEncryptedMedia() |
+ : m_emeMode(EmeModeNotSelected) |
+{ |
+} |
+ |
+HTMLMediaElementEncryptedMedia::~HTMLMediaElementEncryptedMedia() |
+{ |
+} |
+ |
+const char* HTMLMediaElementEncryptedMedia::supplementName() |
+{ |
+ return "HTMLMediaElementEncryptedMedia"; |
+} |
+ |
+HTMLMediaElementEncryptedMedia& HTMLMediaElementEncryptedMedia::from(HTMLMediaElement& element) |
+{ |
+ Supplement<HTMLMediaElement>* supplement = Supplement<HTMLMediaElement>::from(element, supplementName()); |
+ if (!supplement) { |
+ supplement = new HTMLMediaElementEncryptedMedia(); |
+ provideTo(element, supplementName(), adoptPtr(supplement)); |
+ } |
+ return *static_cast<HTMLMediaElementEncryptedMedia*>(supplement); |
+} |
+ |
+bool HTMLMediaElementEncryptedMedia::setEmeMode(EmeMode emeMode, ExceptionState& exceptionState) |
+{ |
+ if (m_emeMode != EmeModeNotSelected && m_emeMode != emeMode) { |
+ exceptionState.throwDOMException(InvalidStateError, "Mixed use of EME prefixed and unprefixed API not allowed."); |
+ return false; |
+ } |
+ m_emeMode = emeMode; |
+ return true; |
+} |
+ |
+blink::WebContentDecryptionModule* HTMLMediaElementEncryptedMedia::contentDecryptionModule() |
+{ |
+ return m_mediaKeys ? m_mediaKeys->contentDecryptionModule() : 0; |
+} |
+ |
+MediaKeys* HTMLMediaElementEncryptedMedia::mediaKeys(HTMLMediaElement& element) |
+{ |
+ HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(element); |
+ return thisElement.m_mediaKeys.get(); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::setMediaKeysInternal(HTMLMediaElement& element, MediaKeys* mediaKeys) |
+{ |
+ if (m_mediaKeys == mediaKeys) |
+ return; |
+ |
+ ASSERT(m_emeMode == EmeModeUnprefixed); |
+ |
+ if (m_mediaKeys) |
+ m_mediaKeys->setMediaElement(0); |
+ m_mediaKeys = mediaKeys; |
+ if (m_mediaKeys) |
+ m_mediaKeys->setMediaElement(&element); |
+ |
+ // If a player is connected, tell it that the CDM has changed. |
+ if (element.webMediaPlayer()) |
+ element.webMediaPlayer()->setContentDecryptionModule(contentDecryptionModule()); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::setMediaKeys(HTMLMediaElement& element, MediaKeys* mediaKeys, ExceptionState& exceptionState) |
+{ |
+ WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::setMediaKeys"); |
+ HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(element); |
+ |
+ if (!thisElement.setEmeMode(EmeModeUnprefixed, exceptionState)) |
+ return; |
+ |
+ thisElement.setMediaKeysInternal(element, mediaKeys); |
+} |
+ |
+// Create a MediaKeyNeededEvent for WD EME. |
+static PassRefPtr<Event> createNeedKeyEvent(const String& contentType, const unsigned char* initData, unsigned initDataLength) |
+{ |
+ MediaKeyNeededEventInit initializer; |
+ initializer.contentType = contentType; |
+ initializer.initData = Uint8Array::create(initData, initDataLength); |
+ initializer.bubbles = false; |
+ initializer.cancelable = false; |
+ |
+ return MediaKeyNeededEvent::create(EventTypeNames::needkey, initializer); |
+} |
+ |
+// Create a 'needkey' MediaKeyEvent for v0.1b EME. |
+static PassRefPtr<Event> createWebkitNeedKeyEvent(const String& contentType, const unsigned char* initData, unsigned initDataLength) |
+{ |
+ MediaKeyEventInit webkitInitializer; |
+ webkitInitializer.keySystem = String(); |
+ webkitInitializer.sessionId = String(); |
+ webkitInitializer.initData = Uint8Array::create(initData, initDataLength); |
+ webkitInitializer.bubbles = false; |
+ webkitInitializer.cancelable = false; |
+ |
+ return MediaKeyEvent::create(EventTypeNames::webkitneedkey, webkitInitializer); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::webkitGenerateKeyRequest(HTMLMediaElement& element, const String& keySystem, PassRefPtr<Uint8Array> initData, ExceptionState& exceptionState) |
+{ |
+ HTMLMediaElementEncryptedMedia::from(element).generateKeyRequest(element.webMediaPlayer(), keySystem, initData, exceptionState); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::generateKeyRequest(blink::WebMediaPlayer* webMediaPlayer, const String& keySystem, PassRefPtr<Uint8Array> initData, ExceptionState& exceptionState) |
+{ |
+ WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::webkitGenerateKeyRequest"); |
+ |
+ if (!setEmeMode(EmeModePrefixed, exceptionState)) |
+ return; |
+ |
+ if (keySystem.isEmpty()) { |
+ exceptionState.throwDOMException(SyntaxError, "The key system provided is empty."); |
+ return; |
+ } |
+ |
+ if (!webMediaPlayer) { |
+ exceptionState.throwDOMException(InvalidStateError, "No media has been loaded."); |
+ return; |
+ } |
+ |
+ const unsigned char* initDataPointer = 0; |
+ unsigned initDataLength = 0; |
+ if (initData) { |
+ initDataPointer = initData->data(); |
+ initDataLength = initData->length(); |
+ } |
+ |
+ blink::WebMediaPlayer::MediaKeyException result = webMediaPlayer->generateKeyRequest(keySystem, initDataPointer, initDataLength); |
+ throwExceptionIfMediaKeyExceptionOccurred(keySystem, String(), result, exceptionState); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::webkitGenerateKeyRequest(HTMLMediaElement& mediaElement, const String& keySystem, ExceptionState& exceptionState) |
+{ |
+ webkitGenerateKeyRequest(mediaElement, keySystem, Uint8Array::create(0), exceptionState); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::webkitAddKey(HTMLMediaElement& element, const String& keySystem, PassRefPtr<Uint8Array> key, PassRefPtr<Uint8Array> initData, const String& sessionId, ExceptionState& exceptionState) |
+{ |
+ HTMLMediaElementEncryptedMedia::from(element).addKey(element.webMediaPlayer(), keySystem, key, initData, sessionId, exceptionState); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::addKey(blink::WebMediaPlayer* webMediaPlayer, const String& keySystem, PassRefPtr<Uint8Array> key, PassRefPtr<Uint8Array> initData, const String& sessionId, ExceptionState& exceptionState) |
+{ |
+ WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::webkitAddKey"); |
+ |
+ if (!setEmeMode(EmeModePrefixed, exceptionState)) |
+ return; |
+ |
+ if (keySystem.isEmpty()) { |
+ exceptionState.throwDOMException(SyntaxError, "The key system provided is empty."); |
+ return; |
+ } |
+ |
+ if (!key) { |
+ exceptionState.throwDOMException(SyntaxError, "The key provided is invalid."); |
+ return; |
+ } |
+ |
+ if (!key->length()) { |
+ exceptionState.throwDOMException(TypeMismatchError, "The key provided is invalid."); |
+ return; |
+ } |
+ |
+ if (!webMediaPlayer) { |
+ exceptionState.throwDOMException(InvalidStateError, "No media has been loaded."); |
+ return; |
+ } |
+ |
+ const unsigned char* initDataPointer = 0; |
+ unsigned initDataLength = 0; |
+ if (initData) { |
+ initDataPointer = initData->data(); |
+ initDataLength = initData->length(); |
+ } |
+ |
+ blink::WebMediaPlayer::MediaKeyException result = webMediaPlayer->addKey(keySystem, key->data(), key->length(), initDataPointer, initDataLength, sessionId); |
+ throwExceptionIfMediaKeyExceptionOccurred(keySystem, sessionId, result, exceptionState); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::webkitAddKey(HTMLMediaElement& mediaElement, const String& keySystem, PassRefPtr<Uint8Array> key, ExceptionState& exceptionState) |
+{ |
+ webkitAddKey(mediaElement, keySystem, key, Uint8Array::create(0), String(), exceptionState); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::webkitCancelKeyRequest(HTMLMediaElement& element, const String& keySystem, const String& sessionId, ExceptionState& exceptionState) |
+{ |
+ HTMLMediaElementEncryptedMedia::from(element).cancelKeyRequest(element.webMediaPlayer(), keySystem, sessionId, exceptionState); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::cancelKeyRequest(blink::WebMediaPlayer* webMediaPlayer, const String& keySystem, const String& sessionId, ExceptionState& exceptionState) |
+{ |
+ WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::webkitCancelKeyRequest"); |
+ |
+ if (!setEmeMode(EmeModePrefixed, exceptionState)) |
+ return; |
+ |
+ if (keySystem.isEmpty()) { |
+ exceptionState.throwDOMException(SyntaxError, "The key system provided is empty."); |
+ return; |
+ } |
+ |
+ if (!webMediaPlayer) { |
+ exceptionState.throwDOMException(InvalidStateError, "No media has been loaded."); |
+ return; |
+ } |
+ |
+ blink::WebMediaPlayer::MediaKeyException result = webMediaPlayer->cancelKeyRequest(keySystem, sessionId); |
+ throwExceptionIfMediaKeyExceptionOccurred(keySystem, sessionId, result, exceptionState); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::keyAdded(HTMLMediaElement& element, const String& keySystem, const String& sessionId) |
+{ |
+ WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::mediaPlayerKeyAdded"); |
+ |
+ MediaKeyEventInit initializer; |
+ initializer.keySystem = keySystem; |
+ initializer.sessionId = sessionId; |
+ initializer.bubbles = false; |
+ initializer.cancelable = false; |
+ |
+ RefPtr<Event> event = MediaKeyEvent::create(EventTypeNames::webkitkeyadded, initializer); |
+ event->setTarget(&element); |
+ element.scheduleEvent(event.release()); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::keyError(HTMLMediaElement& element, const String& keySystem, const String& sessionId, blink::WebMediaPlayerClient::MediaKeyErrorCode errorCode, unsigned short systemCode) |
+{ |
+ WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::mediaPlayerKeyError: sessionID=%s, errorCode=%d, systemCode=%d", sessionId.utf8().data(), errorCode, systemCode); |
+ |
+ MediaKeyError::Code mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN; |
+ switch (errorCode) { |
+ case blink::WebMediaPlayerClient::MediaKeyErrorCodeUnknown: |
+ mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN; |
+ break; |
+ case blink::WebMediaPlayerClient::MediaKeyErrorCodeClient: |
+ mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_CLIENT; |
+ break; |
+ case blink::WebMediaPlayerClient::MediaKeyErrorCodeService: |
+ mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_SERVICE; |
+ break; |
+ case blink::WebMediaPlayerClient::MediaKeyErrorCodeOutput: |
+ mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_OUTPUT; |
+ break; |
+ case blink::WebMediaPlayerClient::MediaKeyErrorCodeHardwareChange: |
+ mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_HARDWARECHANGE; |
+ break; |
+ case blink::WebMediaPlayerClient::MediaKeyErrorCodeDomain: |
+ mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_DOMAIN; |
+ break; |
+ } |
+ |
+ MediaKeyEventInit initializer; |
+ initializer.keySystem = keySystem; |
+ initializer.sessionId = sessionId; |
+ initializer.errorCode = MediaKeyError::create(mediaKeyErrorCode); |
+ initializer.systemCode = systemCode; |
+ initializer.bubbles = false; |
+ initializer.cancelable = false; |
+ |
+ RefPtr<Event> event = MediaKeyEvent::create(EventTypeNames::webkitkeyerror, initializer); |
+ event->setTarget(&element); |
+ element.scheduleEvent(event.release()); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::keyMessage(HTMLMediaElement& element, const String& keySystem, const String& sessionId, const unsigned char* message, unsigned messageLength, const blink::WebURL& defaultURL) |
+{ |
+ WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::mediaPlayerKeyMessage: sessionID=%s", sessionId.utf8().data()); |
+ |
+ MediaKeyEventInit initializer; |
+ initializer.keySystem = keySystem; |
+ initializer.sessionId = sessionId; |
+ initializer.message = Uint8Array::create(message, messageLength); |
+ initializer.defaultURL = KURL(defaultURL); |
+ initializer.bubbles = false; |
+ initializer.cancelable = false; |
+ |
+ RefPtr<Event> event = MediaKeyEvent::create(EventTypeNames::webkitkeymessage, initializer); |
+ event->setTarget(&element); |
+ element.scheduleEvent(event.release()); |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::keyNeeded(HTMLMediaElement& element, const String& contentType, const unsigned char* initData, unsigned initDataLength) |
+{ |
+ WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::mediaPlayerKeyNeeded: contentType=%s", contentType.utf8().data()); |
+ |
+ if (RuntimeEnabledFeatures::encryptedMediaEnabled()) { |
+ // Send event for WD EME. |
+ RefPtr<Event> event = createNeedKeyEvent(contentType, initData, initDataLength); |
+ event->setTarget(&element); |
+ element.scheduleEvent(event.release()); |
+ } |
+ |
+ if (RuntimeEnabledFeatures::prefixedEncryptedMediaEnabled()) { |
+ // Send event for v0.1b EME. |
+ RefPtr<Event> event = createWebkitNeedKeyEvent(contentType, initData, initDataLength); |
+ event->setTarget(&element); |
+ element.scheduleEvent(event.release()); |
+ } |
+} |
+ |
+void HTMLMediaElementEncryptedMedia::playerDestroyed(HTMLMediaElement& element) |
+{ |
+ HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(element); |
+ thisElement.setMediaKeysInternal(element, 0); |
+} |
+ |
+blink::WebContentDecryptionModule* HTMLMediaElementEncryptedMedia::contentDecryptionModule(HTMLMediaElement& element) |
+{ |
+ HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia::from(element); |
+ return thisElement.contentDecryptionModule(); |
+} |
+ |
+} // namespace WebCore |