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

Side by Side Diff: content/renderer/media/crypto/ppapi_decryptor.cc

Issue 265993002: Add Promises for EME (Chromium side) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments + fewer error codes Created 6 years, 6 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 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/crypto/ppapi_decryptor.h" 5 #include "content/renderer/media/crypto/ppapi_decryptor.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback.h"
10 #include "base/callback_helpers.h" 11 #include "base/callback_helpers.h"
11 #include "base/location.h" 12 #include "base/location.h"
12 #include "base/logging.h" 13 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h" 14 #include "base/message_loop/message_loop.h"
14 #include "base/message_loop/message_loop_proxy.h" 15 #include "base/message_loop/message_loop_proxy.h"
15 #include "content/renderer/media/crypto/key_systems.h" 16 #include "content/renderer/media/crypto/key_systems.h"
16 #include "content/renderer/pepper/content_decryptor_delegate.h" 17 #include "content/renderer/pepper/content_decryptor_delegate.h"
17 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" 18 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
18 #include "media/base/audio_decoder_config.h" 19 #include "media/base/audio_decoder_config.h"
20 #include "media/base/cdm_promise.h"
19 #include "media/base/data_buffer.h" 21 #include "media/base/data_buffer.h"
20 #include "media/base/decoder_buffer.h" 22 #include "media/base/decoder_buffer.h"
21 #include "media/base/video_decoder_config.h" 23 #include "media/base/video_decoder_config.h"
22 #include "media/base/video_frame.h" 24 #include "media/base/video_frame.h"
23 25
24 namespace content { 26 namespace content {
25 27
28 // When overriding SimpleCdmPromise, need some callbacks that will never get
29 // used.
30 static void DoNothingOnResolve() {
31 NOTIMPLEMENTED();
32 }
33
34 static void DoNothingOnError(media::MediaKeys::Exception exception_code,
xhwang 2014/05/29 23:44:38 s/Error/Reject to be consistent?
jrummell 2014/05/30 18:04:25 Done.
35 uint32 system_code,
36 const std::string& error_message) {
37 NOTIMPLEMENTED();
38 }
39
40 // This class is needed so that resolving an Update() promise triggers playback
41 // of the stream. It intercepts the resolve() call to invoke an additional
42 // callback.
43 class SessionUpdatedPromise : public media::SimpleCdmPromise {
44 public:
45 SessionUpdatedPromise(scoped_ptr<media::SimpleCdmPromise> caller_promise,
46 base::Closure additional_resolve_cb)
47 : media::SimpleCdmPromise(base::Bind(&DoNothingOnResolve),
48 base::Bind(&DoNothingOnError)),
xhwang 2014/05/29 23:44:38 hmm, this is still hacky. How about drop DISALLO
jrummell 2014/05/30 18:04:25 Added default constructor on SimpleCdmPromise, so
xhwang 2014/06/02 21:59:21 I like this much better :)
49 caller_promise_(caller_promise.Pass()),
50 additional_resolve_cb_(additional_resolve_cb) {}
51
52 virtual void resolve() OVERRIDE {
53 additional_resolve_cb_.Run();
54 caller_promise_->resolve();
55 }
56
57 virtual void reject(media::MediaKeys::Exception exception_code,
58 uint32 system_code,
59 const std::string& error_message) OVERRIDE {
60 caller_promise_->reject(exception_code, system_code, error_message);
61 }
62
63 protected:
64 scoped_ptr<media::SimpleCdmPromise> caller_promise_;
65 base::Closure additional_resolve_cb_;
66 };
67
26 scoped_ptr<PpapiDecryptor> PpapiDecryptor::Create( 68 scoped_ptr<PpapiDecryptor> PpapiDecryptor::Create(
27 const std::string& key_system, 69 const std::string& key_system,
28 const GURL& security_origin, 70 const GURL& security_origin,
29 const CreatePepperCdmCB& create_pepper_cdm_cb, 71 const CreatePepperCdmCB& create_pepper_cdm_cb,
30 const media::SessionCreatedCB& session_created_cb,
31 const media::SessionMessageCB& session_message_cb, 72 const media::SessionMessageCB& session_message_cb,
32 const media::SessionReadyCB& session_ready_cb, 73 const media::SessionReadyCB& session_ready_cb,
33 const media::SessionClosedCB& session_closed_cb, 74 const media::SessionClosedCB& session_closed_cb,
34 const media::SessionErrorCB& session_error_cb) { 75 const media::SessionErrorCB& session_error_cb) {
35 std::string plugin_type = GetPepperType(key_system); 76 std::string plugin_type = GetPepperType(key_system);
36 DCHECK(!plugin_type.empty()); 77 DCHECK(!plugin_type.empty());
37 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper = 78 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper =
38 create_pepper_cdm_cb.Run(plugin_type, security_origin); 79 create_pepper_cdm_cb.Run(plugin_type, security_origin);
39 if (!pepper_cdm_wrapper) { 80 if (!pepper_cdm_wrapper) {
40 DLOG(ERROR) << "Plugin instance creation failed."; 81 DLOG(ERROR) << "Plugin instance creation failed.";
41 return scoped_ptr<PpapiDecryptor>(); 82 return scoped_ptr<PpapiDecryptor>();
42 } 83 }
43 84
44 return scoped_ptr<PpapiDecryptor>( 85 return scoped_ptr<PpapiDecryptor>(
45 new PpapiDecryptor(key_system, 86 new PpapiDecryptor(key_system,
46 pepper_cdm_wrapper.Pass(), 87 pepper_cdm_wrapper.Pass(),
47 session_created_cb,
48 session_message_cb, 88 session_message_cb,
49 session_ready_cb, 89 session_ready_cb,
50 session_closed_cb, 90 session_closed_cb,
51 session_error_cb)); 91 session_error_cb));
52 } 92 }
53 93
54 PpapiDecryptor::PpapiDecryptor( 94 PpapiDecryptor::PpapiDecryptor(
55 const std::string& key_system, 95 const std::string& key_system,
56 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper, 96 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper,
57 const media::SessionCreatedCB& session_created_cb,
58 const media::SessionMessageCB& session_message_cb, 97 const media::SessionMessageCB& session_message_cb,
59 const media::SessionReadyCB& session_ready_cb, 98 const media::SessionReadyCB& session_ready_cb,
60 const media::SessionClosedCB& session_closed_cb, 99 const media::SessionClosedCB& session_closed_cb,
61 const media::SessionErrorCB& session_error_cb) 100 const media::SessionErrorCB& session_error_cb)
62 : pepper_cdm_wrapper_(pepper_cdm_wrapper.Pass()), 101 : pepper_cdm_wrapper_(pepper_cdm_wrapper.Pass()),
63 session_created_cb_(session_created_cb),
64 session_message_cb_(session_message_cb), 102 session_message_cb_(session_message_cb),
65 session_ready_cb_(session_ready_cb), 103 session_ready_cb_(session_ready_cb),
66 session_closed_cb_(session_closed_cb), 104 session_closed_cb_(session_closed_cb),
67 session_error_cb_(session_error_cb), 105 session_error_cb_(session_error_cb),
68 render_loop_proxy_(base::MessageLoopProxy::current()), 106 render_loop_proxy_(base::MessageLoopProxy::current()),
69 weak_ptr_factory_(this) { 107 weak_ptr_factory_(this) {
70 DCHECK(pepper_cdm_wrapper_.get()); 108 DCHECK(pepper_cdm_wrapper_.get());
71 DCHECK(!session_created_cb_.is_null());
72 DCHECK(!session_message_cb_.is_null()); 109 DCHECK(!session_message_cb_.is_null());
73 DCHECK(!session_ready_cb_.is_null()); 110 DCHECK(!session_ready_cb_.is_null());
74 DCHECK(!session_closed_cb_.is_null()); 111 DCHECK(!session_closed_cb_.is_null());
75 DCHECK(!session_error_cb_.is_null()); 112 DCHECK(!session_error_cb_.is_null());
76 113
77 base::WeakPtr<PpapiDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr(); 114 base::WeakPtr<PpapiDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr();
78 CdmDelegate()->Initialize( 115 CdmDelegate()->Initialize(
79 key_system, 116 key_system,
80 base::Bind(&PpapiDecryptor::OnSessionCreated, weak_this),
81 base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this), 117 base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this),
82 base::Bind(&PpapiDecryptor::OnSessionReady, weak_this), 118 base::Bind(&PpapiDecryptor::OnSessionReady, weak_this),
83 base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this), 119 base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this),
84 base::Bind(&PpapiDecryptor::OnSessionError, weak_this), 120 base::Bind(&PpapiDecryptor::OnSessionError, weak_this),
85 base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this)); 121 base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this));
86 } 122 }
87 123
88 PpapiDecryptor::~PpapiDecryptor() { 124 PpapiDecryptor::~PpapiDecryptor() {
89 pepper_cdm_wrapper_.reset(); 125 pepper_cdm_wrapper_.reset();
90 } 126 }
91 127
92 bool PpapiDecryptor::CreateSession(uint32 session_id, 128 void PpapiDecryptor::CreateSession(
93 const std::string& content_type, 129 const std::string& init_data_type,
94 const uint8* init_data, 130 const uint8* init_data,
95 int init_data_length) { 131 int init_data_length,
96 DVLOG(2) << __FUNCTION__; 132 SessionType session_type,
97 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); 133 scoped_ptr<media::NewSessionCdmPromise> promise) {
98
99 if (!CdmDelegate() ||
100 !CdmDelegate()->CreateSession(
101 session_id, content_type, init_data, init_data_length)) {
102 ReportFailureToCallPlugin(session_id);
103 return false;
104 }
105
106 return true;
107 }
108
109 void PpapiDecryptor::LoadSession(uint32 session_id,
110 const std::string& web_session_id) {
111 DVLOG(2) << __FUNCTION__; 134 DVLOG(2) << __FUNCTION__;
112 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); 135 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
113 136
114 if (!CdmDelegate()) { 137 if (!CdmDelegate()) {
115 ReportFailureToCallPlugin(session_id); 138 promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
116 return; 139 return;
117 } 140 }
118 141
119 CdmDelegate()->LoadSession(session_id, web_session_id); 142 CdmDelegate()->CreateSession(init_data_type,
143 init_data,
144 init_data_length,
145 session_type,
146 promise.Pass());
120 } 147 }
121 148
122 void PpapiDecryptor::UpdateSession(uint32 session_id, 149 void PpapiDecryptor::LoadSession(
123 const uint8* response, 150 const std::string& web_session_id,
124 int response_length) { 151 scoped_ptr<media::NewSessionCdmPromise> promise) {
125 DVLOG(2) << __FUNCTION__; 152 DVLOG(2) << __FUNCTION__;
126 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); 153 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
127 154
128 if (!CdmDelegate() || 155 if (!CdmDelegate()) {
129 !CdmDelegate()->UpdateSession(session_id, response, response_length)) { 156 promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
130 ReportFailureToCallPlugin(session_id);
131 return; 157 return;
132 } 158 }
159
160 CdmDelegate()->LoadSession(web_session_id, promise.Pass());
133 } 161 }
134 162
135 void PpapiDecryptor::ReleaseSession(uint32 session_id) { 163 void PpapiDecryptor::UpdateSession(
136 DVLOG(2) << __FUNCTION__; 164 const std::string& web_session_id,
165 const uint8* response,
166 int response_length,
167 scoped_ptr<media::SimpleCdmPromise> promise) {
137 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); 168 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
138 169
139 if (!CdmDelegate() || !CdmDelegate()->ReleaseSession(session_id)) { 170 if (!CdmDelegate()) {
140 ReportFailureToCallPlugin(session_id); 171 promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
141 return; 172 return;
142 } 173 }
174
175 scoped_ptr<SessionUpdatedPromise> update_promise(
xhwang 2014/05/29 23:44:38 s/update_promise/session_updated_promise?
jrummell 2014/05/30 18:04:25 Done.
176 new SessionUpdatedPromise(promise.Pass(),
177 base::Bind(&PpapiDecryptor::ResumePlayback,
178 weak_ptr_factory_.GetWeakPtr())));
179 CdmDelegate()->UpdateSession(
180 web_session_id,
181 response,
182 response_length,
183 update_promise.PassAs<media::SimpleCdmPromise>());
184 }
185
186 void PpapiDecryptor::ReleaseSession(
187 const std::string& web_session_id,
188 scoped_ptr<media::SimpleCdmPromise> promise) {
189 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
190
191 if (!CdmDelegate()) {
192 promise->reject(INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist.");
193 return;
194 }
195
196 CdmDelegate()->ReleaseSession(web_session_id, promise.Pass());
143 } 197 }
144 198
145 media::Decryptor* PpapiDecryptor::GetDecryptor() { 199 media::Decryptor* PpapiDecryptor::GetDecryptor() {
146 return this; 200 return this;
147 } 201 }
148 202
149 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type, 203 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type,
150 const NewKeyCB& new_key_cb) { 204 const NewKeyCB& new_key_cb) {
151 if (!render_loop_proxy_->BelongsToCurrentThread()) { 205 if (!render_loop_proxy_->BelongsToCurrentThread()) {
152 render_loop_proxy_->PostTask(FROM_HERE, 206 render_loop_proxy_->PostTask(FROM_HERE,
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 weak_ptr_factory_.GetWeakPtr(), 377 weak_ptr_factory_.GetWeakPtr(),
324 stream_type)); 378 stream_type));
325 return; 379 return;
326 } 380 }
327 381
328 DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type; 382 DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type;
329 if (CdmDelegate()) 383 if (CdmDelegate())
330 CdmDelegate()->DeinitializeDecoder(stream_type); 384 CdmDelegate()->DeinitializeDecoder(stream_type);
331 } 385 }
332 386
333 void PpapiDecryptor::ReportFailureToCallPlugin(uint32 session_id) {
334 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
335 DVLOG(1) << "Failed to call plugin.";
336 session_error_cb_.Run(session_id, kUnknownError, 0);
337 }
338
339 void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type, 387 void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type,
340 bool success) { 388 bool success) {
341 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); 389 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
342 switch (stream_type) { 390 switch (stream_type) {
343 case kAudio: 391 case kAudio:
344 DCHECK(!audio_decoder_init_cb_.is_null()); 392 DCHECK(!audio_decoder_init_cb_.is_null());
345 base::ResetAndReturn(&audio_decoder_init_cb_).Run(success); 393 base::ResetAndReturn(&audio_decoder_init_cb_).Run(success);
346 break; 394 break;
347 case kVideo: 395 case kVideo:
348 DCHECK(!video_decoder_init_cb_.is_null()); 396 DCHECK(!video_decoder_init_cb_.is_null());
349 base::ResetAndReturn(&video_decoder_init_cb_).Run(success); 397 base::ResetAndReturn(&video_decoder_init_cb_).Run(success);
350 break; 398 break;
351 default: 399 default:
352 NOTREACHED(); 400 NOTREACHED();
353 } 401 }
354 } 402 }
355 403
356 void PpapiDecryptor::OnSessionCreated(uint32 session_id, 404 void PpapiDecryptor::OnSessionMessage(const std::string& web_session_id,
357 const std::string& web_session_id) {
358 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
359 session_created_cb_.Run(session_id, web_session_id);
360 }
361
362 void PpapiDecryptor::OnSessionMessage(uint32 session_id,
363 const std::vector<uint8>& message, 405 const std::vector<uint8>& message,
364 const GURL& destination_url) { 406 const GURL& destination_url) {
365 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); 407 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
366 session_message_cb_.Run(session_id, message, destination_url); 408 session_message_cb_.Run(web_session_id, message, destination_url);
367 } 409 }
368 410
369 void PpapiDecryptor::OnSessionReady(uint32 session_id) { 411 void PpapiDecryptor::OnSessionReady(const std::string& web_session_id) {
370 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); 412 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
371 413
414 ResumePlayback();
415 session_ready_cb_.Run(web_session_id);
416 }
417
418 void PpapiDecryptor::OnSessionClosed(const std::string& web_session_id) {
419 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
420 session_closed_cb_.Run(web_session_id);
421 }
422
423 void PpapiDecryptor::OnSessionError(const std::string& web_session_id,
424 MediaKeys::Exception exception_code,
425 uint32 system_code,
426 const std::string& error_description) {
427 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
428 session_error_cb_.Run(
429 web_session_id, exception_code, system_code, error_description);
430 }
431
432 void PpapiDecryptor::ResumePlayback() {
372 // Based on the spec, we need to resume playback when update() completes 433 // Based on the spec, we need to resume playback when update() completes
373 // successfully, or when a session is successfully loaded. In both cases, 434 // successfully, or when a session is successfully loaded (triggered by
374 // the CDM fires OnSessionReady() event. So we choose to call the NewKeyCBs 435 // OnSessionReady()). So we choose to call the NewKeyCBs here.
375 // here.
376 // TODO(xhwang): Rename OnSessionReady to indicate that the playback may
377 // resume successfully (e.g. a new key is available or available again).
378 if (!new_audio_key_cb_.is_null()) 436 if (!new_audio_key_cb_.is_null())
379 new_audio_key_cb_.Run(); 437 new_audio_key_cb_.Run();
380 438
381 if (!new_video_key_cb_.is_null()) 439 if (!new_video_key_cb_.is_null())
382 new_video_key_cb_.Run(); 440 new_video_key_cb_.Run();
383
384 session_ready_cb_.Run(session_id);
385 }
386
387 void PpapiDecryptor::OnSessionClosed(uint32 session_id) {
388 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
389 session_closed_cb_.Run(session_id);
390 }
391
392 void PpapiDecryptor::OnSessionError(uint32 session_id,
393 media::MediaKeys::KeyError error_code,
394 uint32 system_code) {
395 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
396 session_error_cb_.Run(session_id, error_code, system_code);
397 } 441 }
398 442
399 void PpapiDecryptor::OnFatalPluginError() { 443 void PpapiDecryptor::OnFatalPluginError() {
400 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); 444 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
401 pepper_cdm_wrapper_.reset(); 445 pepper_cdm_wrapper_.reset();
402 } 446 }
403 447
404 ContentDecryptorDelegate* PpapiDecryptor::CdmDelegate() { 448 ContentDecryptorDelegate* PpapiDecryptor::CdmDelegate() {
405 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); 449 DCHECK(render_loop_proxy_->BelongsToCurrentThread());
406 return (pepper_cdm_wrapper_) ? pepper_cdm_wrapper_->GetCdmDelegate() : NULL; 450 return (pepper_cdm_wrapper_) ? pepper_cdm_wrapper_->GetCdmDelegate() : NULL;
407 } 451 }
408 452
409 } // namespace content 453 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698