Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: Source/modules/encryptedmedia/MediaKeySession.cpp

Issue 543173002: Implement MediaKeySession.generateRequest() (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 20 matching lines...) Expand all
31 #include "bindings/core/v8/ScriptPromiseResolver.h" 31 #include "bindings/core/v8/ScriptPromiseResolver.h"
32 #include "bindings/core/v8/ScriptState.h" 32 #include "bindings/core/v8/ScriptState.h"
33 #include "core/dom/ExceptionCode.h" 33 #include "core/dom/ExceptionCode.h"
34 #include "core/events/Event.h" 34 #include "core/events/Event.h"
35 #include "core/events/GenericEventQueue.h" 35 #include "core/events/GenericEventQueue.h"
36 #include "core/html/MediaKeyError.h" 36 #include "core/html/MediaKeyError.h"
37 #include "modules/encryptedmedia/MediaKeyMessageEvent.h" 37 #include "modules/encryptedmedia/MediaKeyMessageEvent.h"
38 #include "modules/encryptedmedia/MediaKeys.h" 38 #include "modules/encryptedmedia/MediaKeys.h"
39 #include "modules/encryptedmedia/SimpleContentDecryptionModuleResult.h" 39 #include "modules/encryptedmedia/SimpleContentDecryptionModuleResult.h"
40 #include "platform/ContentDecryptionModuleResult.h" 40 #include "platform/ContentDecryptionModuleResult.h"
41 #include "platform/ContentType.h"
41 #include "platform/Logging.h" 42 #include "platform/Logging.h"
43 #include "platform/MIMETypeRegistry.h"
42 #include "platform/Timer.h" 44 #include "platform/Timer.h"
43 #include "public/platform/WebContentDecryptionModule.h" 45 #include "public/platform/WebContentDecryptionModule.h"
44 #include "public/platform/WebContentDecryptionModuleException.h" 46 #include "public/platform/WebContentDecryptionModuleException.h"
45 #include "public/platform/WebContentDecryptionModuleSession.h" 47 #include "public/platform/WebContentDecryptionModuleSession.h"
46 #include "public/platform/WebString.h" 48 #include "public/platform/WebString.h"
47 #include "public/platform/WebURL.h" 49 #include "public/platform/WebURL.h"
48 #include "wtf/ArrayBuffer.h" 50 #include "wtf/ArrayBuffer.h"
49 #include "wtf/ArrayBufferView.h" 51 #include "wtf/ArrayBufferView.h"
52 #include <cmath>
50 53
51 namespace blink { 54 namespace blink {
52 55
56 static bool isKeySystemSupportedWithInitDataType(const String& keySystem, const String& initDataType)
57 {
58 ASSERT(!keySystem.isEmpty());
59
60 // FIXME: initDataType != contentType. Implement this properly.
61 // http://crbug.com/385874.
62 String contentType = initDataType;
63 if (initDataType == "webm") {
64 contentType = "video/webm";
65 } else if (initDataType == "cenc") {
66 contentType = "video/mp4";
67 }
68
69 ContentType type(contentType);
70 String codecs = type.parameter("codecs");
ddorwin 2014/09/09 00:44:35 nit: Do we need the local variable?
jrummell 2014/09/09 19:55:59 Done.
71 return MIMETypeRegistry::isSupportedEncryptedMediaMIMEType(keySystem, type.t ype(), codecs);
72 }
73
53 // A class holding a pending action. 74 // A class holding a pending action.
54 class MediaKeySession::PendingAction : public GarbageCollectedFinalized<MediaKey Session::PendingAction> { 75 class MediaKeySession::PendingAction : public GarbageCollectedFinalized<MediaKey Session::PendingAction> {
55 public: 76 public:
56 enum Type { 77 enum Type {
78 GenerateRequest,
57 Update, 79 Update,
58 Release, 80 Release
59 Message
60 }; 81 };
61 82
62 Type type() const { return m_type; } 83 Type type() const { return m_type; }
63 84
64 const Persistent<ContentDecryptionModuleResult> result() const 85 const Persistent<ContentDecryptionModuleResult> result() const
65 { 86 {
66 ASSERT(m_type == Update || m_type == Release);
67 return m_result; 87 return m_result;
68 } 88 }
69 89
70 const RefPtr<ArrayBuffer> data() const 90 const RefPtr<ArrayBuffer> data() const
71 { 91 {
72 ASSERT(m_type == Update); 92 ASSERT(m_type == GenerateRequest || m_type == Update);
73 return m_data; 93 return m_data;
74 } 94 }
75 95
76 RefPtrWillBeRawPtr<Event> event() 96 const String& initDataType() const
77 { 97 {
78 ASSERT(m_type == Message); 98 ASSERT(m_type == GenerateRequest);
79 return m_event; 99 return m_initDataType;
100 }
101
102 static PendingAction* CreatePendingGenerateRequest(ContentDecryptionModuleRe sult* result, const String& initDataType, PassRefPtr<ArrayBuffer> initData)
103 {
104 ASSERT(result);
105 ASSERT(initData);
106 return new PendingAction(GenerateRequest, result, initDataType, initData );
80 } 107 }
81 108
82 static PendingAction* CreatePendingUpdate(ContentDecryptionModuleResult* res ult, PassRefPtr<ArrayBuffer> data) 109 static PendingAction* CreatePendingUpdate(ContentDecryptionModuleResult* res ult, PassRefPtr<ArrayBuffer> data)
83 { 110 {
84 ASSERT(result); 111 ASSERT(result);
85 ASSERT(data); 112 ASSERT(data);
86 return new PendingAction(Update, result, data); 113 return new PendingAction(Update, result, String(), data);
87 } 114 }
88 115
89 static PendingAction* CreatePendingRelease(ContentDecryptionModuleResult* re sult) 116 static PendingAction* CreatePendingRelease(ContentDecryptionModuleResult* re sult)
90 { 117 {
91 ASSERT(result); 118 ASSERT(result);
92 return new PendingAction(Release, result, PassRefPtr<ArrayBuffer>()); 119 return new PendingAction(Release, result, String(), PassRefPtr<ArrayBuff er>());
93 }
94
95 static PendingAction* CreatePendingMessage(PassRefPtrWillBeRawPtr<Event> eve nt)
96 {
97 ASSERT(event);
98 return new PendingAction(Message, event);
99 } 120 }
100 121
101 ~PendingAction() 122 ~PendingAction()
102 { 123 {
103 } 124 }
104 125
105 void trace(Visitor* visitor) 126 void trace(Visitor* visitor)
106 { 127 {
107 visitor->trace(m_result); 128 visitor->trace(m_result);
108 visitor->trace(m_event);
109 } 129 }
110 130
111 private: 131 private:
112 PendingAction(Type type, ContentDecryptionModuleResult* result, PassRefPtr<A rrayBuffer> data) 132 PendingAction(Type type, ContentDecryptionModuleResult* result, const String & initDataType, PassRefPtr<ArrayBuffer> data)
113 : m_type(type) 133 : m_type(type)
114 , m_result(result) 134 , m_result(result)
135 , m_initDataType(initDataType)
115 , m_data(data) 136 , m_data(data)
116 { 137 {
117 } 138 }
118 139
119 PendingAction(Type type, PassRefPtrWillBeRawPtr<Event> event)
120 : m_type(type)
121 , m_event(event)
122 {
123 }
124
125 const Type m_type; 140 const Type m_type;
126 const Member<ContentDecryptionModuleResult> m_result; 141 const Member<ContentDecryptionModuleResult> m_result;
142 const String m_initDataType;
127 const RefPtr<ArrayBuffer> m_data; 143 const RefPtr<ArrayBuffer> m_data;
128 const RefPtrWillBeMember<Event> m_event;
129 }; 144 };
130 145
131 // This class allows a MediaKeySession object to be created asynchronously. 146 // This class wraps the promise resolver used when initializing a new session
132 class MediaKeySessionInitializer : public ScriptPromiseResolver { 147 // and is passed to Chromium to fullfill the promise. This implementation of
133 WTF_MAKE_NONCOPYABLE(MediaKeySessionInitializer); 148 // completeWithSession() will resolve the promise with undefined, while
ddorwin 2014/09/09 00:44:35 "undefined" is not specified by the spec. Please a
jrummell 2014/09/09 19:55:59 I asked yhirano@ a while back, and he responded "c
149 // completeWithError() will reject the promise with an exception. complete()
150 // is not expected to be called, and will reject the promise.
151 class NewSessionResult : public ContentDecryptionModuleResult {
152 public:
153 NewSessionResult(ScriptState* scriptState, MediaKeySession* session)
154 : m_resolver(ScriptPromiseResolver::create(scriptState))
155 , m_session(session)
156 {
157 WTF_LOG(Media, "NewSessionResult(%p)", this);
158 }
134 159
135 public: 160 ~NewSessionResult()
ddorwin 2014/09/09 00:44:36 If any superclass's destructor is virtual, make th
jrummell 2014/09/09 19:55:59 Done.
136 static ScriptPromise create(ScriptState*, MediaKeys*, const String& initData Type, PassRefPtr<ArrayBuffer> initData, const String& sessionType);
137 virtual ~MediaKeySessionInitializer();
138
139 void completeWithSession(WebContentDecryptionModuleResult::SessionStatus);
140 void completeWithDOMException(ExceptionCode, const String& errorMessage);
141
142 private:
143 MediaKeySessionInitializer(ScriptState*, MediaKeys*, const String& initDataT ype, PassRefPtr<ArrayBuffer> initData, const String& sessionType);
144 void timerFired(Timer<MediaKeySessionInitializer>*);
145
146 Persistent<MediaKeys> m_mediaKeys;
147 OwnPtr<WebContentDecryptionModuleSession> m_cdmSession;
148
149 // The next 3 values are simply the initialization data saved so that the
150 // asynchronous creation has the data needed.
151 String m_initDataType;
152 RefPtr<ArrayBuffer> m_initData;
153 String m_sessionType;
154
155 Timer<MediaKeySessionInitializer> m_timer;
156 };
157
158 // Represents the result used when a new WebContentDecryptionModuleSession
159 // object has been created. Needed as MediaKeySessionInitializer can't be both
160 // a ScriptPromiseResolver and ContentDecryptionModuleResult at the same time.
161 class NewMediaKeySessionResult FINAL : public ContentDecryptionModuleResult {
162 public:
163 NewMediaKeySessionResult(MediaKeySessionInitializer* initializer)
164 : m_initializer(initializer)
165 { 161 {
162 WTF_LOG(Media, "~NewSessionResult(%p)", this);
166 } 163 }
167 164
168 // ContentDecryptionModuleResult implementation. 165 // ContentDecryptionModuleResult implementation.
169 virtual void complete() OVERRIDE 166 virtual void complete() OVERRIDE
170 { 167 {
171 ASSERT_NOT_REACHED(); 168 ASSERT_NOT_REACHED();
172 m_initializer->completeWithDOMException(InvalidStateError, "Unexpected c ompletion."); 169 completeWithDOMException(InvalidStateError, "Unexpected completion.");
173 } 170 }
174 171
175 virtual void completeWithSession(WebContentDecryptionModuleResult::SessionSt atus status) OVERRIDE 172 virtual void completeWithSession(WebContentDecryptionModuleResult::SessionSt atus status) OVERRIDE
176 { 173 {
177 m_initializer->completeWithSession(status); 174 if (status != WebContentDecryptionModuleResult::NewSession) {
175 ASSERT_NOT_REACHED();
176 completeWithDOMException(InvalidStateError, "Unexpected completion." );
177 }
178
179 m_session->finishGenerateRequest();
180 m_resolver->resolve(V8UndefinedType());
ddorwin 2014/09/09 00:44:35 See the comment on 148.
jrummell 2014/09/09 19:55:59 Added comment.
181 m_resolver.clear();
178 } 182 }
179 183
180 virtual void completeWithError(WebContentDecryptionModuleException code, uns igned long systemCode, const WebString& message) OVERRIDE 184 virtual void completeWithError(WebContentDecryptionModuleException exception Code, unsigned long systemCode, const WebString& errorMessage) OVERRIDE
181 { 185 {
182 m_initializer->completeWithDOMException(WebCdmExceptionToExceptionCode(c ode), message); 186 completeWithDOMException(WebCdmExceptionToExceptionCode(exceptionCode), errorMessage);
187 }
188
189 // It is only valid to call this before completion.
190 ScriptPromise promise() { return m_resolver->promise(); }
191
192 void trace(Visitor* visitor)
193 {
194 visitor->trace(m_session);
195 ContentDecryptionModuleResult::trace(visitor);
183 } 196 }
184 197
185 private: 198 private:
186 MediaKeySessionInitializer* m_initializer; 199 // Reject the promise with a DOMException.
200 void completeWithDOMException(ExceptionCode code, const String& errorMessage )
201 {
202 m_resolver->reject(DOMException::create(code, errorMessage));
203 m_resolver.clear();
204 }
205
206 RefPtr<ScriptPromiseResolver> m_resolver;
ddorwin 2014/09/09 00:44:36 OOC, why is this still a RefPtr?
jrummell 2014/09/09 19:55:58 ScriptPromiseResolver::create() returns PassRefPtr
207 Member<MediaKeySession> m_session;
187 }; 208 };
188 209
189 ScriptPromise MediaKeySessionInitializer::create(ScriptState* scriptState, Media Keys* mediaKeys, const String& initDataType, PassRefPtr<ArrayBuffer> initData, c onst String& sessionType) 210 MediaKeySession* MediaKeySession::create(ScriptState* scriptState, MediaKeys* me diaKeys, const String& sessionType)
190 { 211 {
191 RefPtr<MediaKeySessionInitializer> initializer = adoptRef(new MediaKeySessio nInitializer(scriptState, mediaKeys, initDataType, initData, sessionType)); 212 RefPtrWillBeRawPtr<MediaKeySession> session = adoptRefCountedGarbageCollecte dWillBeNoop(new MediaKeySession(scriptState, mediaKeys, sessionType));
192 initializer->suspendIfNeeded(); 213 session->suspendIfNeeded();
193 initializer->keepAliveWhilePending(); 214 return session.get();
194 return initializer->promise();
195 } 215 }
196 216
197 MediaKeySessionInitializer::MediaKeySessionInitializer(ScriptState* scriptState, MediaKeys* mediaKeys, const String& initDataType, PassRefPtr<ArrayBuffer> initD ata, const String& sessionType) 217 MediaKeySession::MediaKeySession(ScriptState* scriptState, MediaKeys* keys, cons t String& sessionType)
ddorwin 2014/09/09 00:44:36 nit: media_keys. keys seems a bit ambiguous.
jrummell 2014/09/09 19:55:58 Done.
198 : ScriptPromiseResolver(scriptState) 218 : ActiveDOMObject(scriptState->executionContext())
199 , m_mediaKeys(mediaKeys)
200 , m_initDataType(initDataType)
201 , m_initData(initData)
202 , m_sessionType(sessionType)
203 , m_timer(this, &MediaKeySessionInitializer::timerFired)
204 {
205 WTF_LOG(Media, "MediaKeySessionInitializer::MediaKeySessionInitializer");
206
207 // Start the timer so that MediaKeySession can be created asynchronously.
208 m_timer.startOneShot(0, FROM_HERE);
209 }
210
211 MediaKeySessionInitializer::~MediaKeySessionInitializer()
212 {
213 WTF_LOG(Media, "MediaKeySessionInitializer::~MediaKeySessionInitializer");
214 }
215
216 void MediaKeySessionInitializer::timerFired(Timer<MediaKeySessionInitializer>*)
217 {
218 WTF_LOG(Media, "MediaKeySessionInitializer::timerFired");
219
220 // Continue MediaKeys::createSession() at step 7.
221 // 7.1 Let request be null. (Request provided by cdm in message event).
222 // 7.2 Let default URL be null. (Also provided by cdm in message event).
223
224 // 7.3 Let cdm be the cdm loaded in create().
225 WebContentDecryptionModule* cdm = m_mediaKeys->contentDecryptionModule();
226
227 // 7.4 Use the cdm to execute the following steps:
228 // 7.4.1 If the init data is not valid for initDataType, reject promise
229 // with a new DOMException whose name is "InvalidAccessError".
230 // 7.4.2 If the init data is not supported by the cdm, reject promise with
231 // a new DOMException whose name is "NotSupportedError".
232 // 7.4.3 Let request be a request (e.g. a license request) generated based
233 // on the init data, which is interpreteted per initDataType, and
234 // sessionType. If sessionType is "temporary", the request is for a
235 // temporary non-persisted license. If sessionType is "persistent",
236 // the request is for a persistable license.
237 // 7.4.4 If the init data indicates a default URL, let default URL be
238 // that URL. The URL may be validated and/or normalized.
239 m_cdmSession = adoptPtr(cdm->createSession());
240 NewMediaKeySessionResult* result = new NewMediaKeySessionResult(this);
241 m_cdmSession->initializeNewSession(m_initDataType, static_cast<unsigned char *>(m_initData->data()), m_initData->byteLength(), m_sessionType, result->result( ));
242
243 WTF_LOG(Media, "MediaKeySessionInitializer::timerFired done");
244 // Note: As soon as the promise is resolved (or rejected), the
245 // ScriptPromiseResolver object (|this|) is freed. So if
246 // initializeNewSession() is synchronous, access to any members will crash.
247 }
248
249 void MediaKeySessionInitializer::completeWithSession(WebContentDecryptionModuleR esult::SessionStatus status)
250 {
251 WTF_LOG(Media, "MediaKeySessionInitializer::completeWithSession");
252
253 switch (status) {
254 case WebContentDecryptionModuleResult::NewSession: {
255 // Resume MediaKeys::createSession().
256 // 7.5 Let the session ID be a unique Session ID string. It may be
257 // obtained from cdm (it is).
258 // 7.6 Let session be a new MediaKeySession object, and initialize it.
259 // (Object was created previously, complete the steps for 7.6).
260 RefPtrWillBeRawPtr<MediaKeySession> session = adoptRefCountedGarbageColl ectedWillBeNoop(new MediaKeySession(executionContext(), m_mediaKeys, m_cdmSessio n.release()));
261 session->suspendIfNeeded();
262
263 // 7.7 If any of the preceding steps failed, reject promise with a
264 // new DOMException whose name is the appropriate error name
265 // and that has an appropriate message.
266 // (Implemented by CDM/Chromium calling completeWithError()).
267
268 // 7.8 Add an entry for the value of the sessionId attribute to the
269 // list of active session IDs for this object.
270 // (Implemented in SessionIdAdapter).
271
272 // 7.9 Run the Queue a "message" Event algorithm on the session,
273 // providing request and default URL.
274 // (Done by the CDM).
275
276 // 7.10 Resolve promise with session.
277 resolve(session.release());
278 WTF_LOG(Media, "MediaKeySessionInitializer::completeWithSession done w/s ession");
279 return;
280 }
281
282 case WebContentDecryptionModuleResult::SessionNotFound:
283 // Step 4.7.1 of MediaKeys::loadSession(): If there is no data
284 // stored for the sessionId in the origin, resolve promise with
285 // undefined.
286 resolve(V8UndefinedType());
287 WTF_LOG(Media, "MediaKeySessionInitializer::completeWithSession done w/u ndefined");
288 return;
289
290 case WebContentDecryptionModuleResult::SessionAlreadyExists:
291 // If a session already exists, resolve the promise with null.
292 resolve(V8NullType());
293 WTF_LOG(Media, "MediaKeySessionInitializer::completeWithSession done w/n ull");
294 return;
295 }
296 ASSERT_NOT_REACHED();
297 }
298
299 void MediaKeySessionInitializer::completeWithDOMException(ExceptionCode code, co nst String& errorMessage)
300 {
301 WTF_LOG(Media, "MediaKeySessionInitializer::completeWithDOMException");
302 reject(DOMException::create(code, errorMessage));
303 }
304
305 ScriptPromise MediaKeySession::create(ScriptState* scriptState, MediaKeys* media Keys, const String& initDataType, PassRefPtr<ArrayBuffer> initData, const String & sessionType)
306 {
307 // Since creation is done asynchronously, use MediaKeySessionInitializer
308 // to do it.
309 return MediaKeySessionInitializer::create(scriptState, mediaKeys, initDataTy pe, initData, sessionType);
310 }
311
312 MediaKeySession::MediaKeySession(ExecutionContext* context, MediaKeys* keys, Pas sOwnPtr<WebContentDecryptionModuleSession> cdmSession)
313 : ActiveDOMObject(context)
314 , m_keySystem(keys->keySystem()) 219 , m_keySystem(keys->keySystem())
ddorwin 2014/09/09 00:44:36 We should not be saving this - it's no longer a me
jrummell 2014/09/09 19:55:58 Will be done in a CL that cleans up this class.
315 , m_asyncEventQueue(GenericEventQueue::create(this)) 220 , m_asyncEventQueue(GenericEventQueue::create(this))
316 , m_session(cdmSession) 221 , m_mediaKeys(keys)
317 , m_keys(keys) 222 , m_expiration(nan(""))
ddorwin 2014/09/09 00:44:35 Why does this take a string? FYI, I also see NaN()
jrummell 2014/09/09 19:55:59 I just did a search for C++ nan, and it pointed to
ddorwin 2014/09/09 21:35:24 double.h is in Blink's WTF IIRC.
jrummell 2014/09/10 01:18:24 But that is for "class Double", which is different
223 , m_sessionType(sessionType)
224 , m_uninitialized(true)
225 , m_callable(false)
318 , m_isClosed(false) 226 , m_isClosed(false)
319 , m_closedPromise(new ClosedPromise(context, this, ClosedPromise::Closed)) 227 , m_closedPromise(new ClosedPromise(scriptState->executionContext(), this, C losedPromise::Closed))
320 , m_actionTimer(this, &MediaKeySession::actionTimerFired) 228 , m_actionTimer(this, &MediaKeySession::actionTimerFired)
321 { 229 {
322 WTF_LOG(Media, "MediaKeySession(%p)::MediaKeySession", this); 230 WTF_LOG(Media, "MediaKeySession(%p)::MediaKeySession", this);
323 ScriptWrappable::init(this); 231 ScriptWrappable::init(this);
324 m_session->setClientInterface(this);
325 232
326 // Resume MediaKeys::createSession() at step 7.6. 233 // MediaKeys::createSession(), step 2.
327 // 7.6.1 Set the error attribute to null. 234 // 2.1 Let the sessionId attribute be the empty string.
328 ASSERT(!m_error); 235 ASSERT(sessionId().isEmpty());
ddorwin 2014/09/09 00:44:36 nit: If we are going to keep these as members, we
jrummell 2014/09/09 19:55:59 Now that m_session is created above, member is gon
329 236
330 // 7.6.2 Set the sessionId attribute to session ID. 237 // 2.2 Let the expiration attribute be NaN.
331 ASSERT(!sessionId().isEmpty()); 238 ASSERT(isnan(expiration()));
332 239
333 // 7.6.3 Let expiration be NaN. 240 // 2.3 Let the closed attribute be a new promise.
334 // 7.6.4 Let closed be a new promise. 241 ASSERT(!closed(scriptState).isUndefinedOrNull());
335 // 7.6.5 Let the session type be sessionType. 242
336 // FIXME: Implement the previous 3 values. 243 // 2.4 Let the session type be sessionType.
244 ASSERT(sessionType == m_sessionType);
245
246 // 2.5 Let uninitialized be true.
247 ASSERT(m_uninitialized);
248
249 // 2.6 Let callable be false.
250 ASSERT(!m_callable);
337 } 251 }
338 252
339 MediaKeySession::~MediaKeySession() 253 MediaKeySession::~MediaKeySession()
340 { 254 {
341 WTF_LOG(Media, "MediaKeySession(%p)::~MediaKeySession", this); 255 WTF_LOG(Media, "MediaKeySession(%p)::~MediaKeySession", this);
342 m_session.clear(); 256 m_session.clear();
343 #if !ENABLE(OILPAN) 257 #if !ENABLE(OILPAN)
344 // MediaKeySession and m_asyncEventQueue always become unreachable 258 // MediaKeySession and m_asyncEventQueue always become unreachable
345 // together. So MediaKeySession and m_asyncEventQueue are destructed in the 259 // together. So MediaKeySession and m_asyncEventQueue are destructed in the
346 // same GC. We don't need to call cancelAllEvents explicitly in Oilpan. 260 // same GC. We don't need to call cancelAllEvents explicitly in Oilpan.
347 m_asyncEventQueue->cancelAllEvents(); 261 m_asyncEventQueue->cancelAllEvents();
348 #endif 262 #endif
349 } 263 }
350 264
351 void MediaKeySession::setError(MediaKeyError* error) 265 void MediaKeySession::setError(MediaKeyError* error)
352 { 266 {
353 m_error = error; 267 m_error = error;
354 } 268 }
355 269
356 String MediaKeySession::sessionId() const
357 {
358 return m_session->sessionId();
359 }
360
361 ScriptPromise MediaKeySession::closed(ScriptState* scriptState) 270 ScriptPromise MediaKeySession::closed(ScriptState* scriptState)
362 { 271 {
363 return m_closedPromise->promise(scriptState->world()); 272 return m_closedPromise->promise(scriptState->world());
364 } 273 }
365 274
275 ScriptPromise MediaKeySession::generateRequest(ScriptState* scriptState, const S tring& initDataType, ArrayBuffer* initData)
276 {
277 RefPtr<ArrayBuffer> initDataCopy = ArrayBuffer::create(initData->data(), ini tData->byteLength());
278 return generateRequestInternal(scriptState, initDataType, initDataCopy.relea se());
279 }
280
281 ScriptPromise MediaKeySession::generateRequest(ScriptState* scriptState, const S tring& initDataType, ArrayBufferView* initData)
282 {
283 RefPtr<ArrayBuffer> initDataCopy = ArrayBuffer::create(initData->baseAddress (), initData->byteLength());
284 return generateRequestInternal(scriptState, initDataType, initDataCopy.relea se());
285 }
286
287 ScriptPromise MediaKeySession::generateRequestInternal(ScriptState* scriptState, const String& initDataType, PassRefPtr<ArrayBuffer> initData)
288 {
289 WTF_LOG(Media, "MediaKeySession(%p)::generateRequest %s", this, initDataType .ascii().data());
290
291 // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/e ncrypted-media.html#dom-generaterequest:
ddorwin 2014/09/09 00:44:35 nit: Why the URL here? I don't think we have these
jrummell 2014/09/09 19:55:59 Just followed the existing pattern in update() and
292 // The generateRequest(initDataType, initData) method creates a new session
293 // for the specified initData. It must run the following steps:
294
295 // 1. If this object's uninitialized value is false, return a promise reject ed
296 // with a new DOMException whose name is "InvalidStateError".
297 if (!m_uninitialized) {
298 return ScriptPromise::rejectWithDOMException(
299 scriptState, DOMException::create(InvalidStateError, "The session al ready exists."));
ddorwin 2014/09/09 00:44:36 s/exists/initialized/ OR s/already exists/has alre
jrummell 2014/09/09 19:55:58 Done.
300 }
301
302 // 2. Let this object's uninitialized be false.
303 m_uninitialized = false;
304
305 // 3. If initDataType is an empty string, return a promise rejected with a
306 // new DOMException whose name is "InvalidAccessError".
307 if (initDataType.isEmpty()) {
308 return ScriptPromise::rejectWithDOMException(
309 scriptState, DOMException::create(InvalidAccessError, "The initDataT ype parameter is empty."));
310 }
311
312 // 4. If initData is an empty array, return a promise rejected with a new
313 // DOMException whose name is"InvalidAccessError".
314 if (!initData->byteLength()) {
315 return ScriptPromise::rejectWithDOMException(
316 scriptState, DOMException::create(InvalidAccessError, "The initData parameter is empty."));
317 }
318
319 // 5. Let media keys be the MediaKeys object that created this object.
320 // (Done in constructor.)
ddorwin 2014/09/09 00:44:36 nit: This isn't actually about saving it as a memb
jrummell 2014/09/09 19:55:58 Done.
321
322 // 6. If the content decryption module corresponding to media keys's keySyst em
323 // attribute does not support initDataType as an initialization data type ,
324 // return a promise rejected with a new DOMException whose name is
325 // "NotSupportedError". String comparison is case-sensitive.
326 if (!isKeySystemSupportedWithInitDataType(m_keySystem, initDataType)) {
ddorwin 2014/09/09 00:44:35 Per earlier comments and the algorithm, this shoul
jrummell 2014/09/09 19:55:59 But then we would have the issue that it is possib
ddorwin 2014/09/09 21:35:24 Good point! I probably need to update the spec too
327 return ScriptPromise::rejectWithDOMException(
328 scriptState, DOMException::create(NotSupportedError, "The initializa tion data type '" + initDataType + "' is not supported by the key system."));
329 }
330
331 // 7. Let init data be a copy of the contents of the initData parameter.
332 // (Done before calling this method.)
333
334 // 8. Let session type be this object's session type.
335 // (Done in constructor.)
336
337 // 9. Let promise be a new promise.
338 NewSessionResult* result = new NewSessionResult(scriptState, this);
339 ScriptPromise promise = result->promise();
340
341 // 10. Run the following steps asynchronously (documented in
342 // actionTimerFired())
343 m_pendingActions.append(PendingAction::CreatePendingGenerateRequest(result, initDataType, initData));
344 if (!m_actionTimer.isActive())
ddorwin 2014/09/09 00:44:36 I think this is an ASSERT - nothing else should ha
jrummell 2014/09/09 19:55:59 Done.
345 m_actionTimer.startOneShot(0, FROM_HERE);
346
347 // 11. Return promise.
348 return promise;
349 }
350
366 ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBuffer* res ponse) 351 ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBuffer* res ponse)
367 { 352 {
368 RefPtr<ArrayBuffer> responseCopy = ArrayBuffer::create(response->data(), res ponse->byteLength()); 353 RefPtr<ArrayBuffer> responseCopy = ArrayBuffer::create(response->data(), res ponse->byteLength());
369 return updateInternal(scriptState, responseCopy.release()); 354 return updateInternal(scriptState, responseCopy.release());
370 } 355 }
371 356
372 ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBufferView* response) 357 ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBufferView* response)
373 { 358 {
374 RefPtr<ArrayBuffer> responseCopy = ArrayBuffer::create(response->baseAddress (), response->byteLength()); 359 RefPtr<ArrayBuffer> responseCopy = ArrayBuffer::create(response->baseAddress (), response->byteLength());
375 return updateInternal(scriptState, responseCopy.release()); 360 return updateInternal(scriptState, responseCopy.release());
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 // Resolving promises now run synchronously and may result in additional 434 // Resolving promises now run synchronously and may result in additional
450 // actions getting added to the queue. As a result, swap the queue to 435 // actions getting added to the queue. As a result, swap the queue to
451 // a local copy to avoid problems if this happens. 436 // a local copy to avoid problems if this happens.
452 HeapDeque<Member<PendingAction> > pendingActions; 437 HeapDeque<Member<PendingAction> > pendingActions;
453 pendingActions.swap(m_pendingActions); 438 pendingActions.swap(m_pendingActions);
454 439
455 while (!pendingActions.isEmpty()) { 440 while (!pendingActions.isEmpty()) {
456 PendingAction* action = pendingActions.takeFirst(); 441 PendingAction* action = pendingActions.takeFirst();
457 442
458 switch (action->type()) { 443 switch (action->type()) {
444 case PendingAction::GenerateRequest:
445 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: GenerateReque st", this);
446
447 {
448 // 10.1 Let request be null.
449 // 10.2 Let cdm be the CDM loaded during the initialization of
450 // media keys.
451 WebContentDecryptionModule* cdm = m_mediaKeys->contentDecryption Module();
452
453 // 10.3 Use the cdm to execute the following steps:
454 // 10.3.1 If the init data is not valid for initDataType, reject
455 // promise with a new DOMException whose name is
456 // "InvalidAccessError".
457 // 10.3.2 If the init data is not supported by the cdm, reject
458 // promise with a new DOMException whose name is
459 // "NotSupportedError".
460 // 10.3.3 Let request be a request (e.g. a license request)
461 // generated based on the init data, which is interpreted
462 // per initDataType, and session type.
463 m_session = adoptPtr(cdm->createSession());
ddorwin 2014/09/09 00:44:36 We should do this during creation.
jrummell 2014/09/09 19:55:58 Done.
464 m_session->setClientInterface(this);
465 m_session->initializeNewSession(action->initDataType(), static_c ast<unsigned char*>(action->data()->data()), action->data()->byteLength(), m_ses sionType, action->result()->result());
466 }
467
468 // Remainder of steps executed in finishGenerateRequest(), called
469 // when |result| is resolved.
470 break;
471
459 case PendingAction::Update: 472 case PendingAction::Update:
460 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Update", this ); 473 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Update", this );
461 // NOTE: Continued from step 4 of MediaKeySession::update(). 474 // NOTE: Continued from step 4 of MediaKeySession::update().
462 // Continue the update call by passing message to the cdm. Once 475 // Continue the update call by passing message to the cdm. Once
463 // completed, it will resolve/reject the promise. 476 // completed, it will resolve/reject the promise.
464 m_session->update(static_cast<unsigned char*>(action->data()->data() ), action->data()->byteLength(), action->result()->result()); 477 m_session->update(static_cast<unsigned char*>(action->data()->data() ), action->data()->byteLength(), action->result()->result());
465 break; 478 break;
479
466 case PendingAction::Release: 480 case PendingAction::Release:
467 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Release", thi s); 481 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Release", thi s);
468 // NOTE: Continued from step 3 of MediaKeySession::release(). 482 // NOTE: Continued from step 3 of MediaKeySession::release().
469 // 3.1 Let cdm be the cdm loaded in create(). 483 // 3.1 Let cdm be the cdm loaded in create().
470 // 3.2 Use the cdm to execute the following steps: 484 // 3.2 Use the cdm to execute the following steps:
471 // 3.2.1 Process the close request. Do not remove stored session dat a. 485 // 3.2.1 Process the close request. Do not remove stored session dat a.
472 // 3.2.2 If the previous step caused the session to be closed, run t he 486 // 3.2.2 If the previous step caused the session to be closed, run t he
473 // Session Close algorithm on this object. 487 // Session Close algorithm on this object.
474 // 3.3 Resolve promise with undefined. 488 // 3.3 Resolve promise with undefined.
475 m_session->release(action->result()->result()); 489 m_session->release(action->result()->result());
476 break; 490 break;
477 case PendingAction::Message:
478 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Message", thi s);
479 m_asyncEventQueue->enqueueEvent(action->event().release());
480 break;
481 } 491 }
482 } 492 }
483 } 493 }
484 494
495 void MediaKeySession::finishGenerateRequest()
496 {
497 // 10.4 Set the sessionId attribute to a unique Session ID string.
498 // It may be obtained from cdm.
499 m_sessionId = m_session->sessionId();
ddorwin 2014/09/09 00:44:35 ASSERT(!empty()) Also, I'm not sure we should save
jrummell 2014/09/09 19:55:59 sessionId() now calls this function as needed.
500
501 // 10.5 If any of the preceding steps failed, reject promise with a new
502 // DOMException whose name is the appropriate error name.
503 // (Done by call to completeWithError()).
504
505 // 10.6 Add an entry for the value of the sessionId attribute to
506 // media keys's list of active session IDs.
507 // FIXME: Is this required?
ddorwin 2014/09/09 00:44:35 Probably not: https://www.w3.org/Bugs/Public/show_
jrummell 2014/09/09 19:55:59 Acknowledged.
508
509 // 10.7 Run the Queue a "message" Event algorithm on the session,
510 // providing request and null.
511 // (Done by the CDM).
ddorwin 2014/09/09 00:44:35 Hmm. We need to somehow guarantee that this messag
jrummell 2014/09/09 19:55:59 Added ASSERT in message() to verify this.
512
513 // 10.8 Let this object's callable be true.
514 m_callable = true;
515
516 // Additionally, we no longer need to keep MediaKeys around. Switch to
517 // WeakMember.
518 m_keys = m_mediaKeys;
519 m_mediaKeys.clear();
520 }
521
485 // Queue a task to fire a simple event named keymessage at the new object 522 // Queue a task to fire a simple event named keymessage at the new object
486 void MediaKeySession::message(const unsigned char* message, size_t messageLength , const WebURL& destinationURL) 523 void MediaKeySession::message(const unsigned char* message, size_t messageLength , const WebURL& destinationURL)
487 { 524 {
488 WTF_LOG(Media, "MediaKeySession(%p)::message", this); 525 WTF_LOG(Media, "MediaKeySession(%p)::message", this);
489 526
490 MediaKeyMessageEventInit init; 527 MediaKeyMessageEventInit init;
491 init.bubbles = false; 528 init.bubbles = false;
492 init.cancelable = false; 529 init.cancelable = false;
493 init.message = ArrayBuffer::create(static_cast<const void*>(message), messag eLength); 530 init.message = ArrayBuffer::create(static_cast<const void*>(message), messag eLength);
494 init.destinationURL = destinationURL.string(); 531 init.destinationURL = destinationURL.string();
495 532
496 RefPtrWillBeRawPtr<MediaKeyMessageEvent> event = MediaKeyMessageEvent::creat e(EventTypeNames::message, init); 533 RefPtrWillBeRawPtr<MediaKeyMessageEvent> event = MediaKeyMessageEvent::creat e(EventTypeNames::message, init);
497 event->setTarget(this); 534 event->setTarget(this);
498
499 if (!hasEventListeners()) {
500 // Since this event may be generated immediately after resolving the
501 // CreateSession() promise, it is possible that the JavaScript hasn't
502 // had time to run the .then() action and bind any necessary event
503 // handlers. If there are no event handlers connected, delay enqueuing
504 // this message to provide time for the JavaScript to run. This will
505 // also affect the (rare) case where there is no message handler
506 // attched during normal operation.
507 m_pendingActions.append(PendingAction::CreatePendingMessage(event.releas e()));
508 if (!m_actionTimer.isActive())
509 m_actionTimer.startOneShot(0, FROM_HERE);
510 return;
511 }
512
513 m_asyncEventQueue->enqueueEvent(event.release()); 535 m_asyncEventQueue->enqueueEvent(event.release());
514 } 536 }
515 537
516 void MediaKeySession::ready() 538 void MediaKeySession::ready()
517 { 539 {
518 WTF_LOG(Media, "MediaKeySession(%p)::ready", this); 540 WTF_LOG(Media, "MediaKeySession(%p)::ready", this);
519 541
520 RefPtrWillBeRawPtr<Event> event = Event::create(EventTypeNames::ready); 542 RefPtrWillBeRawPtr<Event> event = Event::create(EventTypeNames::ready);
521 event->setTarget(this); 543 event->setTarget(this);
522 m_asyncEventQueue->enqueueEvent(event.release()); 544 m_asyncEventQueue->enqueueEvent(event.release());
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
618 m_actionTimer.stop(); 640 m_actionTimer.stop();
619 m_pendingActions.clear(); 641 m_pendingActions.clear();
620 m_asyncEventQueue->close(); 642 m_asyncEventQueue->close();
621 } 643 }
622 644
623 void MediaKeySession::trace(Visitor* visitor) 645 void MediaKeySession::trace(Visitor* visitor)
624 { 646 {
625 visitor->trace(m_error); 647 visitor->trace(m_error);
626 visitor->trace(m_asyncEventQueue); 648 visitor->trace(m_asyncEventQueue);
627 visitor->trace(m_pendingActions); 649 visitor->trace(m_pendingActions);
650 visitor->trace(m_mediaKeys);
628 visitor->trace(m_keys); 651 visitor->trace(m_keys);
629 visitor->trace(m_closedPromise); 652 visitor->trace(m_closedPromise);
630 EventTargetWithInlineData::trace(visitor); 653 EventTargetWithInlineData::trace(visitor);
631 } 654 }
632 655
633 } // namespace blink 656 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698