OLD | NEW |
(Empty) | |
| 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 "RuntimeEnabledFeatures.h" |
| 9 #include "bindings/v8/ExceptionState.h" |
| 10 #include "core/dom/ExceptionCode.h" |
| 11 #include "core/html/HTMLMediaElement.h" |
| 12 #include "core/html/MediaKeyError.h" |
| 13 #include "core/html/MediaKeyEvent.h" |
| 14 #include "modules/encryptedmedia/MediaKeyNeededEvent.h" |
| 15 #include "modules/encryptedmedia/MediaKeys.h" |
| 16 #include "platform/Logging.h" |
| 17 |
| 18 namespace WebCore { |
| 19 |
| 20 static void throwExceptionIfMediaKeyExceptionOccurred(const String& keySystem, c
onst String& sessionId, blink::WebMediaPlayer::MediaKeyException exception, Exce
ptionState& exceptionState) |
| 21 { |
| 22 switch (exception) { |
| 23 case blink::WebMediaPlayer::MediaKeyExceptionNoError: |
| 24 return; |
| 25 case blink::WebMediaPlayer::MediaKeyExceptionInvalidPlayerState: |
| 26 exceptionState.throwDOMException(InvalidStateError, "The player is in an
invalid state."); |
| 27 return; |
| 28 case blink::WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported: |
| 29 exceptionState.throwDOMException(NotSupportedError, "The key system prov
ided ('" + keySystem +"') is not supported."); |
| 30 return; |
| 31 case blink::WebMediaPlayer::MediaKeyExceptionInvalidAccess: |
| 32 exceptionState.throwDOMException(InvalidAccessError, "The session ID pro
vided ('" + sessionId + "') is invalid."); |
| 33 return; |
| 34 } |
| 35 |
| 36 ASSERT_NOT_REACHED(); |
| 37 return; |
| 38 } |
| 39 |
| 40 HTMLMediaElementEncryptedMedia::HTMLMediaElementEncryptedMedia() |
| 41 : m_emeMode(EmeModeNotSelected) |
| 42 { |
| 43 } |
| 44 |
| 45 HTMLMediaElementEncryptedMedia::~HTMLMediaElementEncryptedMedia() |
| 46 { |
| 47 } |
| 48 |
| 49 const char* HTMLMediaElementEncryptedMedia::supplementName() |
| 50 { |
| 51 return "HTMLMediaElementEncryptedMedia"; |
| 52 } |
| 53 |
| 54 HTMLMediaElementEncryptedMedia& HTMLMediaElementEncryptedMedia::from(HTMLMediaEl
ement& element) |
| 55 { |
| 56 Supplement<HTMLMediaElement>* supplement = Supplement<HTMLMediaElement>::fro
m(element, supplementName()); |
| 57 if (!supplement) { |
| 58 supplement = new HTMLMediaElementEncryptedMedia(); |
| 59 provideTo(element, supplementName(), adoptPtr(supplement)); |
| 60 } |
| 61 return *static_cast<HTMLMediaElementEncryptedMedia*>(supplement); |
| 62 } |
| 63 |
| 64 bool HTMLMediaElementEncryptedMedia::setEmeMode(EmeMode emeMode, ExceptionState&
exceptionState) |
| 65 { |
| 66 if (m_emeMode != EmeModeNotSelected && m_emeMode != emeMode) { |
| 67 exceptionState.throwDOMException(InvalidStateError, "Mixed use of EME pr
efixed and unprefixed API not allowed."); |
| 68 return false; |
| 69 } |
| 70 m_emeMode = emeMode; |
| 71 return true; |
| 72 } |
| 73 |
| 74 blink::WebContentDecryptionModule* HTMLMediaElementEncryptedMedia::contentDecryp
tionModule() |
| 75 { |
| 76 return m_mediaKeys ? m_mediaKeys->contentDecryptionModule() : 0; |
| 77 } |
| 78 |
| 79 MediaKeys* HTMLMediaElementEncryptedMedia::mediaKeys(HTMLMediaElement& element) |
| 80 { |
| 81 HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia
::from(element); |
| 82 return thisElement.m_mediaKeys.get(); |
| 83 } |
| 84 |
| 85 void HTMLMediaElementEncryptedMedia::setMediaKeysInternal(HTMLMediaElement& elem
ent, MediaKeys* mediaKeys) |
| 86 { |
| 87 if (m_mediaKeys == mediaKeys) |
| 88 return; |
| 89 |
| 90 ASSERT(m_emeMode == EmeModeUnprefixed); |
| 91 |
| 92 if (m_mediaKeys) |
| 93 m_mediaKeys->setMediaElement(0); |
| 94 m_mediaKeys = mediaKeys; |
| 95 if (m_mediaKeys) |
| 96 m_mediaKeys->setMediaElement(&element); |
| 97 |
| 98 // If a player is connected, tell it that the CDM has changed. |
| 99 if (element.webMediaPlayer()) |
| 100 element.webMediaPlayer()->setContentDecryptionModule(contentDecryptionMo
dule()); |
| 101 } |
| 102 |
| 103 void HTMLMediaElementEncryptedMedia::setMediaKeys(HTMLMediaElement& element, Med
iaKeys* mediaKeys, ExceptionState& exceptionState) |
| 104 { |
| 105 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::setMediaKeys"); |
| 106 HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia
::from(element); |
| 107 |
| 108 if (!thisElement.setEmeMode(EmeModeUnprefixed, exceptionState)) |
| 109 return; |
| 110 |
| 111 thisElement.setMediaKeysInternal(element, mediaKeys); |
| 112 } |
| 113 |
| 114 // Create a MediaKeyNeededEvent for WD EME. |
| 115 static PassRefPtr<Event> createNeedKeyEvent(const String& contentType, const uns
igned char* initData, unsigned initDataLength) |
| 116 { |
| 117 MediaKeyNeededEventInit initializer; |
| 118 initializer.contentType = contentType; |
| 119 initializer.initData = Uint8Array::create(initData, initDataLength); |
| 120 initializer.bubbles = false; |
| 121 initializer.cancelable = false; |
| 122 |
| 123 return MediaKeyNeededEvent::create(EventTypeNames::needkey, initializer); |
| 124 } |
| 125 |
| 126 // Create a 'needkey' MediaKeyEvent for v0.1b EME. |
| 127 static PassRefPtr<Event> createWebkitNeedKeyEvent(const String& contentType, con
st unsigned char* initData, unsigned initDataLength) |
| 128 { |
| 129 MediaKeyEventInit webkitInitializer; |
| 130 webkitInitializer.keySystem = String(); |
| 131 webkitInitializer.sessionId = String(); |
| 132 webkitInitializer.initData = Uint8Array::create(initData, initDataLength); |
| 133 webkitInitializer.bubbles = false; |
| 134 webkitInitializer.cancelable = false; |
| 135 |
| 136 return MediaKeyEvent::create(EventTypeNames::webkitneedkey, webkitInitialize
r); |
| 137 } |
| 138 |
| 139 void HTMLMediaElementEncryptedMedia::webkitGenerateKeyRequest(HTMLMediaElement&
element, const String& keySystem, PassRefPtr<Uint8Array> initData, ExceptionStat
e& exceptionState) |
| 140 { |
| 141 HTMLMediaElementEncryptedMedia::from(element).generateKeyRequest(element.web
MediaPlayer(), keySystem, initData, exceptionState); |
| 142 } |
| 143 |
| 144 void HTMLMediaElementEncryptedMedia::generateKeyRequest(blink::WebMediaPlayer* w
ebMediaPlayer, const String& keySystem, PassRefPtr<Uint8Array> initData, Excepti
onState& exceptionState) |
| 145 { |
| 146 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::webkitGenerateKeyRequest"); |
| 147 |
| 148 if (!setEmeMode(EmeModePrefixed, exceptionState)) |
| 149 return; |
| 150 |
| 151 if (keySystem.isEmpty()) { |
| 152 exceptionState.throwDOMException(SyntaxError, "The key system provided i
s empty."); |
| 153 return; |
| 154 } |
| 155 |
| 156 if (!webMediaPlayer) { |
| 157 exceptionState.throwDOMException(InvalidStateError, "No media has been l
oaded."); |
| 158 return; |
| 159 } |
| 160 |
| 161 const unsigned char* initDataPointer = 0; |
| 162 unsigned initDataLength = 0; |
| 163 if (initData) { |
| 164 initDataPointer = initData->data(); |
| 165 initDataLength = initData->length(); |
| 166 } |
| 167 |
| 168 blink::WebMediaPlayer::MediaKeyException result = webMediaPlayer->generateKe
yRequest(keySystem, initDataPointer, initDataLength); |
| 169 throwExceptionIfMediaKeyExceptionOccurred(keySystem, String(), result, excep
tionState); |
| 170 } |
| 171 |
| 172 void HTMLMediaElementEncryptedMedia::webkitGenerateKeyRequest(HTMLMediaElement&
mediaElement, const String& keySystem, ExceptionState& exceptionState) |
| 173 { |
| 174 webkitGenerateKeyRequest(mediaElement, keySystem, Uint8Array::create(0), exc
eptionState); |
| 175 } |
| 176 |
| 177 void HTMLMediaElementEncryptedMedia::webkitAddKey(HTMLMediaElement& element, con
st String& keySystem, PassRefPtr<Uint8Array> key, PassRefPtr<Uint8Array> initDat
a, const String& sessionId, ExceptionState& exceptionState) |
| 178 { |
| 179 HTMLMediaElementEncryptedMedia::from(element).addKey(element.webMediaPlayer(
), keySystem, key, initData, sessionId, exceptionState); |
| 180 } |
| 181 |
| 182 void HTMLMediaElementEncryptedMedia::addKey(blink::WebMediaPlayer* webMediaPlaye
r, const String& keySystem, PassRefPtr<Uint8Array> key, PassRefPtr<Uint8Array> i
nitData, const String& sessionId, ExceptionState& exceptionState) |
| 183 { |
| 184 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::webkitAddKey"); |
| 185 |
| 186 if (!setEmeMode(EmeModePrefixed, exceptionState)) |
| 187 return; |
| 188 |
| 189 if (keySystem.isEmpty()) { |
| 190 exceptionState.throwDOMException(SyntaxError, "The key system provided i
s empty."); |
| 191 return; |
| 192 } |
| 193 |
| 194 if (!key) { |
| 195 exceptionState.throwDOMException(SyntaxError, "The key provided is inval
id."); |
| 196 return; |
| 197 } |
| 198 |
| 199 if (!key->length()) { |
| 200 exceptionState.throwDOMException(TypeMismatchError, "The key provided is
invalid."); |
| 201 return; |
| 202 } |
| 203 |
| 204 if (!webMediaPlayer) { |
| 205 exceptionState.throwDOMException(InvalidStateError, "No media has been l
oaded."); |
| 206 return; |
| 207 } |
| 208 |
| 209 const unsigned char* initDataPointer = 0; |
| 210 unsigned initDataLength = 0; |
| 211 if (initData) { |
| 212 initDataPointer = initData->data(); |
| 213 initDataLength = initData->length(); |
| 214 } |
| 215 |
| 216 blink::WebMediaPlayer::MediaKeyException result = webMediaPlayer->addKey(key
System, key->data(), key->length(), initDataPointer, initDataLength, sessionId); |
| 217 throwExceptionIfMediaKeyExceptionOccurred(keySystem, sessionId, result, exce
ptionState); |
| 218 } |
| 219 |
| 220 void HTMLMediaElementEncryptedMedia::webkitAddKey(HTMLMediaElement& mediaElement
, const String& keySystem, PassRefPtr<Uint8Array> key, ExceptionState& exception
State) |
| 221 { |
| 222 webkitAddKey(mediaElement, keySystem, key, Uint8Array::create(0), String(),
exceptionState); |
| 223 } |
| 224 |
| 225 void HTMLMediaElementEncryptedMedia::webkitCancelKeyRequest(HTMLMediaElement& el
ement, const String& keySystem, const String& sessionId, ExceptionState& excepti
onState) |
| 226 { |
| 227 HTMLMediaElementEncryptedMedia::from(element).cancelKeyRequest(element.webMe
diaPlayer(), keySystem, sessionId, exceptionState); |
| 228 } |
| 229 |
| 230 void HTMLMediaElementEncryptedMedia::cancelKeyRequest(blink::WebMediaPlayer* web
MediaPlayer, const String& keySystem, const String& sessionId, ExceptionState& e
xceptionState) |
| 231 { |
| 232 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::webkitCancelKeyRequest"); |
| 233 |
| 234 if (!setEmeMode(EmeModePrefixed, exceptionState)) |
| 235 return; |
| 236 |
| 237 if (keySystem.isEmpty()) { |
| 238 exceptionState.throwDOMException(SyntaxError, "The key system provided i
s empty."); |
| 239 return; |
| 240 } |
| 241 |
| 242 if (!webMediaPlayer) { |
| 243 exceptionState.throwDOMException(InvalidStateError, "No media has been l
oaded."); |
| 244 return; |
| 245 } |
| 246 |
| 247 blink::WebMediaPlayer::MediaKeyException result = webMediaPlayer->cancelKeyR
equest(keySystem, sessionId); |
| 248 throwExceptionIfMediaKeyExceptionOccurred(keySystem, sessionId, result, exce
ptionState); |
| 249 } |
| 250 |
| 251 void HTMLMediaElementEncryptedMedia::keyAdded(HTMLMediaElement& element, const S
tring& keySystem, const String& sessionId) |
| 252 { |
| 253 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::mediaPlayerKeyAdded"); |
| 254 |
| 255 MediaKeyEventInit initializer; |
| 256 initializer.keySystem = keySystem; |
| 257 initializer.sessionId = sessionId; |
| 258 initializer.bubbles = false; |
| 259 initializer.cancelable = false; |
| 260 |
| 261 RefPtr<Event> event = MediaKeyEvent::create(EventTypeNames::webkitkeyadded,
initializer); |
| 262 event->setTarget(&element); |
| 263 element.scheduleEvent(event.release()); |
| 264 } |
| 265 |
| 266 void HTMLMediaElementEncryptedMedia::keyError(HTMLMediaElement& element, const S
tring& keySystem, const String& sessionId, blink::WebMediaPlayerClient::MediaKey
ErrorCode errorCode, unsigned short systemCode) |
| 267 { |
| 268 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::mediaPlayerKeyError: session
ID=%s, errorCode=%d, systemCode=%d", sessionId.utf8().data(), errorCode, systemC
ode); |
| 269 |
| 270 MediaKeyError::Code mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN; |
| 271 switch (errorCode) { |
| 272 case blink::WebMediaPlayerClient::MediaKeyErrorCodeUnknown: |
| 273 mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN; |
| 274 break; |
| 275 case blink::WebMediaPlayerClient::MediaKeyErrorCodeClient: |
| 276 mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_CLIENT; |
| 277 break; |
| 278 case blink::WebMediaPlayerClient::MediaKeyErrorCodeService: |
| 279 mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_SERVICE; |
| 280 break; |
| 281 case blink::WebMediaPlayerClient::MediaKeyErrorCodeOutput: |
| 282 mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_OUTPUT; |
| 283 break; |
| 284 case blink::WebMediaPlayerClient::MediaKeyErrorCodeHardwareChange: |
| 285 mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_HARDWARECHANGE; |
| 286 break; |
| 287 case blink::WebMediaPlayerClient::MediaKeyErrorCodeDomain: |
| 288 mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_DOMAIN; |
| 289 break; |
| 290 } |
| 291 |
| 292 MediaKeyEventInit initializer; |
| 293 initializer.keySystem = keySystem; |
| 294 initializer.sessionId = sessionId; |
| 295 initializer.errorCode = MediaKeyError::create(mediaKeyErrorCode); |
| 296 initializer.systemCode = systemCode; |
| 297 initializer.bubbles = false; |
| 298 initializer.cancelable = false; |
| 299 |
| 300 RefPtr<Event> event = MediaKeyEvent::create(EventTypeNames::webkitkeyerror,
initializer); |
| 301 event->setTarget(&element); |
| 302 element.scheduleEvent(event.release()); |
| 303 } |
| 304 |
| 305 void HTMLMediaElementEncryptedMedia::keyMessage(HTMLMediaElement& element, const
String& keySystem, const String& sessionId, const unsigned char* message, unsig
ned messageLength, const blink::WebURL& defaultURL) |
| 306 { |
| 307 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::mediaPlayerKeyMessage: sessi
onID=%s", sessionId.utf8().data()); |
| 308 |
| 309 MediaKeyEventInit initializer; |
| 310 initializer.keySystem = keySystem; |
| 311 initializer.sessionId = sessionId; |
| 312 initializer.message = Uint8Array::create(message, messageLength); |
| 313 initializer.defaultURL = KURL(defaultURL); |
| 314 initializer.bubbles = false; |
| 315 initializer.cancelable = false; |
| 316 |
| 317 RefPtr<Event> event = MediaKeyEvent::create(EventTypeNames::webkitkeymessage
, initializer); |
| 318 event->setTarget(&element); |
| 319 element.scheduleEvent(event.release()); |
| 320 } |
| 321 |
| 322 void HTMLMediaElementEncryptedMedia::keyNeeded(HTMLMediaElement& element, const
String& contentType, const unsigned char* initData, unsigned initDataLength) |
| 323 { |
| 324 WTF_LOG(Media, "HTMLMediaElementEncryptedMedia::mediaPlayerKeyNeeded: conten
tType=%s", contentType.utf8().data()); |
| 325 |
| 326 if (RuntimeEnabledFeatures::encryptedMediaEnabled()) { |
| 327 // Send event for WD EME. |
| 328 RefPtr<Event> event = createNeedKeyEvent(contentType, initData, initData
Length); |
| 329 event->setTarget(&element); |
| 330 element.scheduleEvent(event.release()); |
| 331 } |
| 332 |
| 333 if (RuntimeEnabledFeatures::prefixedEncryptedMediaEnabled()) { |
| 334 // Send event for v0.1b EME. |
| 335 RefPtr<Event> event = createWebkitNeedKeyEvent(contentType, initData, in
itDataLength); |
| 336 event->setTarget(&element); |
| 337 element.scheduleEvent(event.release()); |
| 338 } |
| 339 } |
| 340 |
| 341 void HTMLMediaElementEncryptedMedia::playerDestroyed(HTMLMediaElement& element) |
| 342 { |
| 343 HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia
::from(element); |
| 344 thisElement.setMediaKeysInternal(element, 0); |
| 345 } |
| 346 |
| 347 blink::WebContentDecryptionModule* HTMLMediaElementEncryptedMedia::contentDecryp
tionModule(HTMLMediaElement& element) |
| 348 { |
| 349 HTMLMediaElementEncryptedMedia& thisElement = HTMLMediaElementEncryptedMedia
::from(element); |
| 350 return thisElement.contentDecryptionModule(); |
| 351 } |
| 352 |
| 353 } // namespace WebCore |
OLD | NEW |