| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Apple Inc. All rights reserved. | 2 * Copyright (C) 2013 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 */ | 24 */ |
| 25 | 25 |
| 26 #include "config.h" | 26 #include "config.h" |
| 27 #include "modules/encryptedmedia/MediaKeySession.h" | 27 #include "modules/encryptedmedia/MediaKeySession.h" |
| 28 | 28 |
| 29 #if ENABLE(ENCRYPTED_MEDIA_V2) | 29 #if ENABLE(ENCRYPTED_MEDIA_V2) |
| 30 | 30 |
| 31 #include "core/dom/Event.h" | 31 #include "core/dom/Event.h" |
| 32 #include "core/dom/GenericEventQueue.h" | 32 #include "core/dom/GenericEventQueue.h" |
| 33 #include "core/html/MediaKeyError.h" | 33 #include "core/html/MediaKeyError.h" |
| 34 #include "modules/encryptedmedia/CDM.h" | 34 #include "core/platform/graphics/CDM.h" |
| 35 #include "modules/encryptedmedia/MediaKeyMessageEvent.h" | 35 #include "modules/encryptedmedia/MediaKeyMessageEvent.h" |
| 36 #include "modules/encryptedmedia/MediaKeys.h" | 36 #include "modules/encryptedmedia/MediaKeys.h" |
| 37 | 37 |
| 38 namespace WebCore { | 38 namespace WebCore { |
| 39 | 39 |
| 40 PassRefPtr<MediaKeySession> MediaKeySession::create(ScriptExecutionContext* cont
ext, MediaKeys* keys, const String& keySystem) | 40 PassRefPtr<MediaKeySession> MediaKeySession::create(ScriptExecutionContext* cont
ext, CDM& cdm, MediaKeys* keys) |
| 41 { | 41 { |
| 42 return adoptRef(new MediaKeySession(context, keys, keySystem)); | 42 return adoptRef(new MediaKeySession(context, cdm, keys)); |
| 43 } | 43 } |
| 44 | 44 |
| 45 MediaKeySession::MediaKeySession(ScriptExecutionContext* context, MediaKeys* key
s, const String& keySystem) | 45 MediaKeySession::MediaKeySession(ScriptExecutionContext* context, CDM& cdm, Medi
aKeys* keys) |
| 46 : ContextDestructionObserver(context) | 46 : ContextDestructionObserver(context) |
| 47 , m_asyncEventQueue(GenericEventQueue::create(this)) |
| 48 , m_keySystem(keys->keySystem()) |
| 49 , m_session(cdm.createSession(this)) |
| 47 , m_keys(keys) | 50 , m_keys(keys) |
| 48 , m_keySystem(keySystem) | |
| 49 , m_asyncEventQueue(GenericEventQueue::create(this)) | |
| 50 , m_session(keys->cdm()->createSession()) | |
| 51 , m_keyRequestTimer(this, &MediaKeySession::keyRequestTimerFired) | 51 , m_keyRequestTimer(this, &MediaKeySession::keyRequestTimerFired) |
| 52 , m_addKeyTimer(this, &MediaKeySession::addKeyTimerFired) | 52 , m_addKeyTimer(this, &MediaKeySession::addKeyTimerFired) |
| 53 { | 53 { |
| 54 ScriptWrappable::init(this); | 54 ScriptWrappable::init(this); |
| 55 } | 55 } |
| 56 | 56 |
| 57 MediaKeySession::~MediaKeySession() | 57 MediaKeySession::~MediaKeySession() |
| 58 { | 58 { |
| 59 close(); | 59 close(); |
| 60 } | 60 } |
| 61 | 61 |
| 62 void MediaKeySession::setError(MediaKeyError* error) | 62 void MediaKeySession::setError(MediaKeyError* error) |
| 63 { | 63 { |
| 64 m_error = error; | 64 m_error = error; |
| 65 } | 65 } |
| 66 | 66 |
| 67 PassRefPtr<MediaKeyError> MediaKeySession::error() const |
| 68 { |
| 69 return m_error; |
| 70 } |
| 71 |
| 67 void MediaKeySession::close() | 72 void MediaKeySession::close() |
| 68 { | 73 { |
| 74 ASSERT(!m_keys == !m_session); |
| 75 |
| 69 if (m_session) | 76 if (m_session) |
| 70 m_session->releaseKeys(); | 77 m_session->close(); |
| 71 m_session.clear(); | 78 m_session.clear(); |
| 72 m_asyncEventQueue->cancelAllEvents(); | 79 m_asyncEventQueue->cancelAllEvents(); |
| 80 |
| 81 // FIXME: Release ref that MediaKeys has by removing it from m_sessions. |
| 82 // if (m_keys) m_keys->sessionClosed(this); |
| 83 m_keys = 0; |
| 73 } | 84 } |
| 74 | 85 |
| 75 const String& MediaKeySession::sessionId() const | 86 String MediaKeySession::sessionId() const |
| 76 { | 87 { |
| 77 return m_session->sessionId(); | 88 return m_session->sessionId(); |
| 78 } | 89 } |
| 79 | 90 |
| 80 void MediaKeySession::generateKeyRequest(const String& mimeType, Uint8Array* ini
tData) | 91 void MediaKeySession::generateKeyRequest(const String& mimeType, Uint8Array* ini
tData) |
| 81 { | 92 { |
| 82 m_pendingKeyRequests.append(PendingKeyRequest(mimeType, initData)); | 93 m_pendingKeyRequests.append(PendingKeyRequest(mimeType, initData)); |
| 94 // FIXME: Eliminate timers. Asynchronicity will be handled in Chromium. |
| 83 m_keyRequestTimer.startOneShot(0); | 95 m_keyRequestTimer.startOneShot(0); |
| 84 } | 96 } |
| 85 | 97 |
| 86 void MediaKeySession::keyRequestTimerFired(Timer<MediaKeySession>*) | 98 void MediaKeySession::keyRequestTimerFired(Timer<MediaKeySession>*) |
| 87 { | 99 { |
| 88 ASSERT(m_pendingKeyRequests.size()); | 100 ASSERT(m_pendingKeyRequests.size()); |
| 89 if (!m_session) | 101 if (!m_session) |
| 90 return; | 102 return; |
| 91 | 103 |
| 92 while (!m_pendingKeyRequests.isEmpty()) { | 104 while (!m_pendingKeyRequests.isEmpty()) { |
| 93 PendingKeyRequest request = m_pendingKeyRequests.takeFirst(); | 105 PendingKeyRequest request = m_pendingKeyRequests.takeFirst(); |
| 94 | 106 |
| 95 // NOTE: Continued from step 5 in MediaKeys::createSession(). | 107 // NOTE: Continued from step 5 in MediaKeys::createSession(). |
| 96 // The user agent will asynchronously execute the following steps in the
task: | 108 // The user agent will asynchronously execute the following steps in the
task: |
| 97 | 109 |
| 98 // 1. Let cdm be the cdm loaded in the MediaKeys constructor. | 110 // 1. Let cdm be the cdm loaded in the MediaKeys constructor. |
| 99 // 2. Let destinationURL be null. | 111 // 2. Let destinationURL be null. |
| 100 String destinationURL; | |
| 101 MediaKeyError::Code errorCode = 0; | |
| 102 unsigned long systemCode = 0; | |
| 103 | 112 |
| 104 // 3. Use cdm to generate a key request and follow the steps for the fir
st matching condition from the following list: | 113 // 3. Use cdm to generate a key request and follow the steps for the fir
st matching condition from the following list: |
| 105 | 114 m_session->generateKeyRequest(request.mimeType, *request.initData); |
| 106 RefPtr<Uint8Array> keyRequest = m_session->generateKeyRequest(request.mi
meType, request.initData.get(), destinationURL, errorCode, systemCode); | |
| 107 | |
| 108 // Otherwise [if a request is not successfully generated]: | |
| 109 if (!keyRequest) { | |
| 110 // 3.1. Create a new MediaKeyError object with the following attribu
tes: | |
| 111 // code = the appropriate MediaKeyError code | |
| 112 // systemCode = a Key System-specific value, if provided, and 0
otherwise | |
| 113 RefPtr<MediaKeyError> error = MediaKeyError::create(errorCode, syste
mCode).get(); | |
| 114 | |
| 115 // 3.2. Set the MediaKeySession object's error attribute to the erro
r object created in the previous step. | |
| 116 setError(error.get()); | |
| 117 | |
| 118 // 3.3. queue a task to fire a simple event named keyerror at the Me
diaKeySession object. | |
| 119 RefPtr<Event> event = Event::create(eventNames().webkitkeyerrorEvent
, false, false); | |
| 120 event->setTarget(this); | |
| 121 m_asyncEventQueue->enqueueEvent(event.release()); | |
| 122 | |
| 123 // 3.4. Abort the task. | |
| 124 continue; | |
| 125 } | |
| 126 | |
| 127 // 4. queue a task to fire a simple event named keymessage at the new ob
ject | |
| 128 // The event is of type MediaKeyMessageEvent and has: | |
| 129 // message = key request | |
| 130 // destinationURL = destinationURL | |
| 131 MediaKeyMessageEventInit init; | |
| 132 init.bubbles = false; | |
| 133 init.cancelable = false; | |
| 134 init.message = keyRequest; | |
| 135 init.destinationURL = destinationURL; | |
| 136 RefPtr<MediaKeyMessageEvent> event = MediaKeyMessageEvent::create(eventN
ames().webkitkeymessageEvent, init); | |
| 137 event->setTarget(this); | |
| 138 m_asyncEventQueue->enqueueEvent(event); | |
| 139 } | 115 } |
| 140 } | 116 } |
| 141 | 117 |
| 142 void MediaKeySession::update(Uint8Array* key, ExceptionCode& ec) | 118 void MediaKeySession::update(Uint8Array* key, ExceptionCode& ec) |
| 143 { | 119 { |
| 144 // From <http://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/encry
pted-media.html#dom-addkey>: | 120 // From <http://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/e
ncrypted-media.html#dom-addkey>: |
| 145 // The addKey(key) method must run the following steps: | 121 // The addKey(key) method must run the following steps: |
| 146 // 1. If the first or second argument [sic] is null or an empty array, throw
an INVALID_ACCESS_ERR. | 122 // 1. If the first or second argument [sic] is null or an empty array, throw
an INVALID_ACCESS_ERR. |
| 147 // NOTE: the reference to a "second argument" is a spec bug. | 123 // NOTE: the reference to a "second argument" is a spec bug. |
| 148 if (!key || !key->length()) { | 124 if (!key || !key->length()) { |
| 149 ec = INVALID_ACCESS_ERR; | 125 ec = INVALID_ACCESS_ERR; |
| 150 return; | 126 return; |
| 151 } | 127 } |
| 152 | 128 |
| 153 // 2. Schedule a task to handle the call, providing key. | 129 // 2. Schedule a task to handle the call, providing key. |
| 154 m_pendingKeys.append(key); | 130 m_pendingKeys.append(key); |
| 155 m_addKeyTimer.startOneShot(0); | 131 m_addKeyTimer.startOneShot(0); |
| 156 } | 132 } |
| 157 | 133 |
| 158 void MediaKeySession::addKeyTimerFired(Timer<MediaKeySession>*) | 134 void MediaKeySession::addKeyTimerFired(Timer<MediaKeySession>*) |
| 159 { | 135 { |
| 160 ASSERT(m_pendingKeys.size()); | 136 ASSERT(m_pendingKeys.size()); |
| 161 if (!m_session) | 137 if (!m_session) |
| 162 return; | 138 return; |
| 163 | 139 |
| 164 while (!m_pendingKeys.isEmpty()) { | 140 while (!m_pendingKeys.isEmpty()) { |
| 165 RefPtr<Uint8Array> pendingKey = m_pendingKeys.takeFirst(); | 141 RefPtr<Uint8Array> pendingKey = m_pendingKeys.takeFirst(); |
| 166 unsigned short errorCode = 0; | 142 unsigned short errorCode = 0; |
| 167 unsigned long systemCode = 0; | 143 unsigned long systemCode = 0; |
| 168 | 144 |
| 169 // NOTE: Continued from step 2. of MediaKeySession::update() | 145 // NOTE: Continued from step 2. of MediaKeySession::update() |
| 170 // 2.1. Let cdm be the cdm loaded in the MediaKeys constructor. | 146 // 2.1. Let cdm be the cdm loaded in the MediaKeys constructor. |
| 171 // NOTE: This is m_session. | 147 // NOTE: This is m_session. |
| 172 // 2.2. Let 'did store key' be false. | 148 // 2.2. Let 'did store key' be false. |
| 173 bool didStoreKey = false; | |
| 174 // 2.3. Let 'next message' be null. | 149 // 2.3. Let 'next message' be null. |
| 175 RefPtr<Uint8Array> nextMessage; | |
| 176 // 2.4. Use cdm to handle key. | 150 // 2.4. Use cdm to handle key. |
| 177 didStoreKey = m_session->update(pendingKey.get(), nextMessage, errorCode
, systemCode); | 151 m_session->update(*pendingKey); |
| 178 // 2.5. If did store key is true and the media element is waiting for a
key, queue a task to attempt to resume playback. | 152 } |
| 179 // TODO: Find and restart the media element | 153 } |
| 180 | 154 |
| 181 // 2.6. If next message is not null, queue a task to fire a simple event
named keymessage at the MediaKeySession object. | 155 void MediaKeySession::keyAdded() |
| 182 // The event is of type MediaKeyMessageEvent and has: | 156 { |
| 183 // message = next message | 157 RefPtr<Event> event = Event::create(eventNames().webkitkeyaddedEvent, false,
false); |
| 184 // destinationURL = null | 158 event->setTarget(this); |
| 185 if (nextMessage) { | 159 m_asyncEventQueue->enqueueEvent(event); |
| 186 MediaKeyMessageEventInit init; | 160 } |
| 187 init.bubbles = false; | |
| 188 init.cancelable = false; | |
| 189 init.message = nextMessage; | |
| 190 RefPtr<MediaKeyMessageEvent> event = MediaKeyMessageEvent::create(ev
entNames().webkitkeymessageEvent, init); | |
| 191 event->setTarget(this); | |
| 192 m_asyncEventQueue->enqueueEvent(event); | |
| 193 } | |
| 194 | 161 |
| 195 // 2.7. If did store key is true, queue a task to fire a simple event na
med keyadded at the MediaKeySession object. | 162 // Queue a task to fire a simple event named keyadded at the MediaKeySession obj
ect. |
| 196 if (didStoreKey) { | 163 void MediaKeySession::keyError(MediaKeyError::Code errorCode, unsigned long syst
emCode) |
| 197 RefPtr<Event> keyaddedEvent = Event::create(eventNames().webkitkeyad
dedEvent, false, false); | 164 { |
| 198 keyaddedEvent->setTarget(this); | 165 // 1. Create a new MediaKeyError object with the following attributes: |
| 199 m_asyncEventQueue->enqueueEvent(keyaddedEvent); | 166 // code = the appropriate MediaKeyError code |
| 200 } | 167 // systemCode = a Key System-specific value, if provided, and 0 otherwise |
| 168 // 2. Set the MediaKeySession object's error attribute to the error object c
reated in the previous step. |
| 169 m_error = MediaKeyError::create(errorCode, systemCode); |
| 201 | 170 |
| 202 // 2.8. If any of the preceding steps in the task failed | 171 // 3. queue a task to fire a simple event named keyerror at the MediaKeySess
ion object. |
| 203 if (!didStoreKey) { | 172 RefPtr<Event> event = Event::create(eventNames().webkitkeyerrorEvent, false,
false); |
| 204 // 2.8.1. Create a new MediaKeyError object with the following attri
butes: | 173 event->setTarget(this); |
| 205 // code = the appropriate MediaKeyError code | 174 m_asyncEventQueue->enqueueEvent(event.release()); |
| 206 // systemCode = a Key System-specific value, if provided, and
0 otherwise | 175 } |
| 207 RefPtr<MediaKeyError> error = MediaKeyError::create(errorCode, syste
mCode).get(); | |
| 208 | 176 |
| 209 // 2.8.2. Set the MediaKeySession object's error attribute to the er
ror object created in the previous step. | 177 // Queue a task to fire a simple event named keymessage at the new object |
| 210 setError(error.get()); | 178 void MediaKeySession::keyMessage(const unsigned char* message, unsigned messageL
ength, const KURL& destinationURL) |
| 179 { |
| 180 MediaKeyMessageEventInit init; |
| 181 init.bubbles = false; |
| 182 init.cancelable = false; |
| 183 init.message = Uint8Array::create(message, messageLength); |
| 184 init.destinationURL = destinationURL; |
| 211 | 185 |
| 212 // 2.8.3. queue a task to fire a simple event named keyerror at the
MediaKeySession object. | 186 RefPtr<MediaKeyMessageEvent> event = MediaKeyMessageEvent::create(eventNames
().webkitkeymessageEvent, init); |
| 213 RefPtr<Event> keyerrorEvent = Event::create(eventNames().webkitkeyer
rorEvent, false, false); | 187 event->setTarget(this); |
| 214 keyerrorEvent->setTarget(this); | 188 m_asyncEventQueue->enqueueEvent(event); |
| 215 m_asyncEventQueue->enqueueEvent(keyerrorEvent.release()); | |
| 216 | |
| 217 // 2.8.4. Abort the task. | |
| 218 // NOTE: no-op | |
| 219 } | |
| 220 } | |
| 221 } | 189 } |
| 222 | 190 |
| 223 const AtomicString& MediaKeySession::interfaceName() const | 191 const AtomicString& MediaKeySession::interfaceName() const |
| 224 { | 192 { |
| 225 return eventNames().interfaceForMediaKeySession; | 193 return eventNames().interfaceForMediaKeySession; |
| 226 } | 194 } |
| 227 | 195 |
| 228 ScriptExecutionContext* MediaKeySession::scriptExecutionContext() const | 196 ScriptExecutionContext* MediaKeySession::scriptExecutionContext() const |
| 229 { | 197 { |
| 230 return ContextDestructionObserver::scriptExecutionContext(); | 198 return ContextDestructionObserver::scriptExecutionContext(); |
| 231 } | 199 } |
| 232 | 200 |
| 233 } | 201 } |
| 234 | 202 |
| 235 #endif | 203 #endif |
| OLD | NEW |