OLD | NEW |
---|---|
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_helpers.h" | 10 #include "base/callback_helpers.h" |
11 #include "base/location.h" | 11 #include "base/location.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
14 #include "base/message_loop/message_loop_proxy.h" | 14 #include "base/message_loop/message_loop_proxy.h" |
15 #include "content/renderer/media/crypto/key_systems.h" | 15 #include "content/renderer/media/crypto/key_systems.h" |
16 #include "content/renderer/pepper/content_decryptor_delegate.h" | 16 #include "content/renderer/pepper/content_decryptor_delegate.h" |
17 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" | 17 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" |
18 #include "media/base/audio_decoder_config.h" | 18 #include "media/base/audio_decoder_config.h" |
19 #include "media/base/cdm_promise.h" | |
19 #include "media/base/data_buffer.h" | 20 #include "media/base/data_buffer.h" |
20 #include "media/base/decoder_buffer.h" | 21 #include "media/base/decoder_buffer.h" |
21 #include "media/base/video_decoder_config.h" | 22 #include "media/base/video_decoder_config.h" |
22 #include "media/base/video_frame.h" | 23 #include "media/base/video_frame.h" |
23 | 24 |
24 namespace content { | 25 namespace content { |
25 | 26 |
27 // This class is need so that resolving an Update() promise triggers playback | |
xhwang
2014/05/23 06:01:23
s/need/needed
jrummell
2014/05/29 00:54:40
Done.
| |
28 // of the stream. | |
29 class SessionUpdatedPromise : public media::SimpleCdmPromise { | |
30 public: | |
31 SessionUpdatedPromise(scoped_ptr<media::SimpleCdmPromise> caller_promise, | |
32 base::Callback<void()> resolve_cb) | |
xhwang
2014/05/23 06:01:23
s/resolve/additional_resolve/ ? It's not super cle
jrummell
2014/05/29 00:54:40
Done.
| |
33 : CdmPromise(resolve_cb, | |
34 base::Bind(&media::SimpleCdmPromise::reject, | |
35 base::Unretained(caller_promise.get()))), | |
36 caller_promise_(caller_promise.Pass()) {} | |
37 | |
38 virtual void resolve() OVERRIDE { | |
39 media::SimpleCdmPromise::resolve(); | |
40 caller_promise_->resolve(); | |
41 } | |
42 | |
43 protected: | |
44 scoped_ptr<media::SimpleCdmPromise> caller_promise_; | |
xhwang
2014/05/23 06:01:23
We use both composition and inheritance? This seem
jrummell
2014/05/29 00:54:40
Done.
| |
45 }; | |
46 | |
26 scoped_ptr<PpapiDecryptor> PpapiDecryptor::Create( | 47 scoped_ptr<PpapiDecryptor> PpapiDecryptor::Create( |
27 const std::string& key_system, | 48 const std::string& key_system, |
28 const GURL& security_origin, | 49 const GURL& security_origin, |
29 const CreatePepperCdmCB& create_pepper_cdm_cb, | 50 const CreatePepperCdmCB& create_pepper_cdm_cb, |
30 const media::SessionCreatedCB& session_created_cb, | |
31 const media::SessionMessageCB& session_message_cb, | 51 const media::SessionMessageCB& session_message_cb, |
32 const media::SessionReadyCB& session_ready_cb, | 52 const media::SessionReadyCB& session_ready_cb, |
33 const media::SessionClosedCB& session_closed_cb, | 53 const media::SessionClosedCB& session_closed_cb, |
34 const media::SessionErrorCB& session_error_cb) { | 54 const media::SessionErrorCB& session_error_cb) { |
35 std::string plugin_type = GetPepperType(key_system); | 55 std::string plugin_type = GetPepperType(key_system); |
36 DCHECK(!plugin_type.empty()); | 56 DCHECK(!plugin_type.empty()); |
37 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper = | 57 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper = |
38 create_pepper_cdm_cb.Run(plugin_type, security_origin); | 58 create_pepper_cdm_cb.Run(plugin_type, security_origin); |
39 if (!pepper_cdm_wrapper) { | 59 if (!pepper_cdm_wrapper) { |
40 DLOG(ERROR) << "Plugin instance creation failed."; | 60 DLOG(ERROR) << "Plugin instance creation failed."; |
41 return scoped_ptr<PpapiDecryptor>(); | 61 return scoped_ptr<PpapiDecryptor>(); |
42 } | 62 } |
43 | 63 |
44 return scoped_ptr<PpapiDecryptor>( | 64 return scoped_ptr<PpapiDecryptor>( |
45 new PpapiDecryptor(key_system, | 65 new PpapiDecryptor(key_system, |
46 pepper_cdm_wrapper.Pass(), | 66 pepper_cdm_wrapper.Pass(), |
47 session_created_cb, | |
48 session_message_cb, | 67 session_message_cb, |
49 session_ready_cb, | 68 session_ready_cb, |
50 session_closed_cb, | 69 session_closed_cb, |
51 session_error_cb)); | 70 session_error_cb)); |
52 } | 71 } |
53 | 72 |
54 PpapiDecryptor::PpapiDecryptor( | 73 PpapiDecryptor::PpapiDecryptor( |
55 const std::string& key_system, | 74 const std::string& key_system, |
56 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper, | 75 scoped_ptr<PepperCdmWrapper> pepper_cdm_wrapper, |
57 const media::SessionCreatedCB& session_created_cb, | |
58 const media::SessionMessageCB& session_message_cb, | 76 const media::SessionMessageCB& session_message_cb, |
59 const media::SessionReadyCB& session_ready_cb, | 77 const media::SessionReadyCB& session_ready_cb, |
60 const media::SessionClosedCB& session_closed_cb, | 78 const media::SessionClosedCB& session_closed_cb, |
61 const media::SessionErrorCB& session_error_cb) | 79 const media::SessionErrorCB& session_error_cb) |
62 : pepper_cdm_wrapper_(pepper_cdm_wrapper.Pass()), | 80 : pepper_cdm_wrapper_(pepper_cdm_wrapper.Pass()), |
63 session_created_cb_(session_created_cb), | |
64 session_message_cb_(session_message_cb), | 81 session_message_cb_(session_message_cb), |
65 session_ready_cb_(session_ready_cb), | 82 session_ready_cb_(session_ready_cb), |
66 session_closed_cb_(session_closed_cb), | 83 session_closed_cb_(session_closed_cb), |
67 session_error_cb_(session_error_cb), | 84 session_error_cb_(session_error_cb), |
68 render_loop_proxy_(base::MessageLoopProxy::current()), | 85 render_loop_proxy_(base::MessageLoopProxy::current()), |
69 weak_ptr_factory_(this) { | 86 weak_ptr_factory_(this) { |
70 DCHECK(pepper_cdm_wrapper_.get()); | 87 DCHECK(pepper_cdm_wrapper_.get()); |
71 DCHECK(!session_created_cb_.is_null()); | |
72 DCHECK(!session_message_cb_.is_null()); | 88 DCHECK(!session_message_cb_.is_null()); |
73 DCHECK(!session_ready_cb_.is_null()); | 89 DCHECK(!session_ready_cb_.is_null()); |
74 DCHECK(!session_closed_cb_.is_null()); | 90 DCHECK(!session_closed_cb_.is_null()); |
75 DCHECK(!session_error_cb_.is_null()); | 91 DCHECK(!session_error_cb_.is_null()); |
76 | 92 |
77 base::WeakPtr<PpapiDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr(); | 93 base::WeakPtr<PpapiDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr(); |
78 CdmDelegate()->Initialize( | 94 CdmDelegate()->Initialize( |
79 key_system, | 95 key_system, |
80 base::Bind(&PpapiDecryptor::OnSessionCreated, weak_this), | |
81 base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this), | 96 base::Bind(&PpapiDecryptor::OnSessionMessage, weak_this), |
82 base::Bind(&PpapiDecryptor::OnSessionReady, weak_this), | 97 base::Bind(&PpapiDecryptor::OnSessionReady, weak_this), |
83 base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this), | 98 base::Bind(&PpapiDecryptor::OnSessionClosed, weak_this), |
84 base::Bind(&PpapiDecryptor::OnSessionError, weak_this), | 99 base::Bind(&PpapiDecryptor::OnSessionError, weak_this), |
85 base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this)); | 100 base::Bind(&PpapiDecryptor::OnFatalPluginError, weak_this)); |
86 } | 101 } |
87 | 102 |
88 PpapiDecryptor::~PpapiDecryptor() { | 103 PpapiDecryptor::~PpapiDecryptor() { |
89 pepper_cdm_wrapper_.reset(); | 104 pepper_cdm_wrapper_.reset(); |
90 } | 105 } |
91 | 106 |
92 bool PpapiDecryptor::CreateSession(uint32 session_id, | 107 void PpapiDecryptor::CreateSession( |
93 const std::string& content_type, | 108 const std::string& init_data_type, |
94 const uint8* init_data, | 109 const uint8* init_data, |
95 int init_data_length) { | 110 int init_data_length, |
96 DVLOG(2) << __FUNCTION__; | 111 SessionType session_type, |
97 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); | 112 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__; | 113 DVLOG(2) << __FUNCTION__; |
112 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); | 114 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); |
113 | 115 |
114 if (!CdmDelegate()) { | 116 if (!CdmDelegate()) { |
115 ReportFailureToCallPlugin(session_id); | 117 promise->reject( |
118 EXCEPTION_INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist."); | |
119 promise.reset(); | |
xhwang
2014/05/23 06:01:23
Here and elsewhere: promise is a scoped_ptr; you d
jrummell
2014/05/29 00:54:40
Done to make it obvious. Removed since the promise
| |
116 return; | 120 return; |
117 } | 121 } |
118 | 122 |
119 CdmDelegate()->LoadSession(session_id, web_session_id); | 123 CdmDelegate()->CreateSession(init_data_type, |
124 init_data, | |
125 init_data_length, | |
126 session_type, | |
127 promise.Pass()); | |
120 } | 128 } |
121 | 129 |
122 void PpapiDecryptor::UpdateSession(uint32 session_id, | 130 void PpapiDecryptor::LoadSession( |
123 const uint8* response, | 131 const std::string& web_session_id, |
124 int response_length) { | 132 scoped_ptr<media::NewSessionCdmPromise> promise) { |
125 DVLOG(2) << __FUNCTION__; | 133 DVLOG(2) << __FUNCTION__; |
126 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); | 134 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); |
127 | 135 |
128 if (!CdmDelegate() || | 136 if (!CdmDelegate()) { |
129 !CdmDelegate()->UpdateSession(session_id, response, response_length)) { | 137 promise->reject( |
130 ReportFailureToCallPlugin(session_id); | 138 EXCEPTION_INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist."); |
139 promise.reset(); | |
131 return; | 140 return; |
132 } | 141 } |
142 | |
143 CdmDelegate()->LoadSession(web_session_id, promise.Pass()); | |
133 } | 144 } |
134 | 145 |
135 void PpapiDecryptor::ReleaseSession(uint32 session_id) { | 146 void PpapiDecryptor::UpdateSession( |
136 DVLOG(2) << __FUNCTION__; | 147 const std::string& web_session_id, |
148 const uint8* response, | |
149 int response_length, | |
150 scoped_ptr<media::SimpleCdmPromise> promise) { | |
137 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); | 151 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); |
138 | 152 |
139 if (!CdmDelegate() || !CdmDelegate()->ReleaseSession(session_id)) { | 153 if (!CdmDelegate()) { |
140 ReportFailureToCallPlugin(session_id); | 154 promise->reject( |
155 EXCEPTION_INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist."); | |
156 promise.reset(); | |
141 return; | 157 return; |
142 } | 158 } |
159 | |
160 scoped_ptr<SessionUpdatedPromise> update_promise( | |
161 new SessionUpdatedPromise(promise.Pass(), | |
162 base::Bind(&PpapiDecryptor::ResumePlayback, | |
163 weak_ptr_factory_.GetWeakPtr()))); | |
164 CdmDelegate()->UpdateSession( | |
165 web_session_id, | |
166 response, | |
167 response_length, | |
168 update_promise.PassAs<media::SimpleCdmPromise>()); | |
169 } | |
170 | |
171 void PpapiDecryptor::ReleaseSession( | |
172 const std::string& web_session_id, | |
173 scoped_ptr<media::SimpleCdmPromise> promise) { | |
174 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); | |
175 | |
176 if (!CdmDelegate()) { | |
177 promise->reject( | |
178 EXCEPTION_INVALID_STATE_ERROR, 0, "CdmDelegate() does not exist."); | |
179 promise.reset(); | |
180 return; | |
181 } | |
182 | |
183 CdmDelegate()->ReleaseSession(web_session_id, promise.Pass()); | |
143 } | 184 } |
144 | 185 |
145 media::Decryptor* PpapiDecryptor::GetDecryptor() { | 186 media::Decryptor* PpapiDecryptor::GetDecryptor() { |
146 return this; | 187 return this; |
147 } | 188 } |
148 | 189 |
149 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type, | 190 void PpapiDecryptor::RegisterNewKeyCB(StreamType stream_type, |
150 const NewKeyCB& new_key_cb) { | 191 const NewKeyCB& new_key_cb) { |
151 if (!render_loop_proxy_->BelongsToCurrentThread()) { | 192 if (!render_loop_proxy_->BelongsToCurrentThread()) { |
152 render_loop_proxy_->PostTask(FROM_HERE, | 193 render_loop_proxy_->PostTask(FROM_HERE, |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
323 weak_ptr_factory_.GetWeakPtr(), | 364 weak_ptr_factory_.GetWeakPtr(), |
324 stream_type)); | 365 stream_type)); |
325 return; | 366 return; |
326 } | 367 } |
327 | 368 |
328 DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type; | 369 DVLOG(2) << __FUNCTION__ << " - stream_type: " << stream_type; |
329 if (CdmDelegate()) | 370 if (CdmDelegate()) |
330 CdmDelegate()->DeinitializeDecoder(stream_type); | 371 CdmDelegate()->DeinitializeDecoder(stream_type); |
331 } | 372 } |
332 | 373 |
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, | 374 void PpapiDecryptor::OnDecoderInitialized(StreamType stream_type, |
340 bool success) { | 375 bool success) { |
341 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); | 376 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); |
342 switch (stream_type) { | 377 switch (stream_type) { |
343 case kAudio: | 378 case kAudio: |
344 DCHECK(!audio_decoder_init_cb_.is_null()); | 379 DCHECK(!audio_decoder_init_cb_.is_null()); |
345 base::ResetAndReturn(&audio_decoder_init_cb_).Run(success); | 380 base::ResetAndReturn(&audio_decoder_init_cb_).Run(success); |
346 break; | 381 break; |
347 case kVideo: | 382 case kVideo: |
348 DCHECK(!video_decoder_init_cb_.is_null()); | 383 DCHECK(!video_decoder_init_cb_.is_null()); |
349 base::ResetAndReturn(&video_decoder_init_cb_).Run(success); | 384 base::ResetAndReturn(&video_decoder_init_cb_).Run(success); |
350 break; | 385 break; |
351 default: | 386 default: |
352 NOTREACHED(); | 387 NOTREACHED(); |
353 } | 388 } |
354 } | 389 } |
355 | 390 |
356 void PpapiDecryptor::OnSessionCreated(uint32 session_id, | 391 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, | 392 const std::vector<uint8>& message, |
364 const std::string& destination_url) { | 393 const std::string& destination_url) { |
365 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); | 394 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); |
366 session_message_cb_.Run(session_id, message, destination_url); | 395 session_message_cb_.Run(web_session_id, message, destination_url); |
367 } | 396 } |
368 | 397 |
369 void PpapiDecryptor::OnSessionReady(uint32 session_id) { | 398 void PpapiDecryptor::OnSessionReady(const std::string& web_session_id) { |
370 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); | 399 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); |
371 | 400 |
401 ResumePlayback(); | |
402 session_ready_cb_.Run(web_session_id); | |
403 } | |
404 | |
405 void PpapiDecryptor::OnSessionClosed(const std::string& web_session_id) { | |
406 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); | |
407 session_closed_cb_.Run(web_session_id); | |
408 } | |
409 | |
410 void PpapiDecryptor::OnSessionError(const std::string& web_session_id, | |
411 MediaKeys::Exception exception_code, | |
412 uint32 system_code, | |
413 const std::string& error_description) { | |
414 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); | |
415 session_error_cb_.Run( | |
416 web_session_id, exception_code, system_code, error_description); | |
417 } | |
418 | |
419 void PpapiDecryptor::ResumePlayback() { | |
372 // Based on the spec, we need to resume playback when update() completes | 420 // Based on the spec, we need to resume playback when update() completes |
373 // successfully, or when a session is successfully loaded. In both cases, | 421 // successfully, or when a session is successfully loaded (triggered by |
374 // the CDM fires OnSessionReady() event. So we choose to call the NewKeyCBs | 422 // 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()) | 423 if (!new_audio_key_cb_.is_null()) |
379 new_audio_key_cb_.Run(); | 424 new_audio_key_cb_.Run(); |
380 | 425 |
381 if (!new_video_key_cb_.is_null()) | 426 if (!new_video_key_cb_.is_null()) |
382 new_video_key_cb_.Run(); | 427 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 } | 428 } |
398 | 429 |
399 void PpapiDecryptor::OnFatalPluginError() { | 430 void PpapiDecryptor::OnFatalPluginError() { |
400 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); | 431 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); |
401 pepper_cdm_wrapper_.reset(); | 432 pepper_cdm_wrapper_.reset(); |
402 } | 433 } |
403 | 434 |
404 ContentDecryptorDelegate* PpapiDecryptor::CdmDelegate() { | 435 ContentDecryptorDelegate* PpapiDecryptor::CdmDelegate() { |
405 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); | 436 DCHECK(render_loop_proxy_->BelongsToCurrentThread()); |
406 return (pepper_cdm_wrapper_) ? pepper_cdm_wrapper_->GetCdmDelegate() : NULL; | 437 return (pepper_cdm_wrapper_) ? pepper_cdm_wrapper_->GetCdmDelegate() : NULL; |
407 } | 438 } |
408 | 439 |
409 } // namespace content | 440 } // namespace content |
OLD | NEW |