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 |