1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/time/time.h"
11 #include "media/base/cdm_promise.h"
12 #include "media/base/decoder_buffer.h"
13 #include "media/base/eme_constants.h"
14 #include "media/base/subsample_entry.h"
15
16 namespace {
17
18 // Copy the cypher bytes as specified by |subsamples| from |src| to |dst|.
19 // Clear bytes contained in |src| that are specified by |subsamples| will be
20 // skipped. This is used when copying all the protected data out of a sample.
21 //
22 // NOTE: Before invoking this call the |subsamples| data must have been verified
23 // against the length of the |src| array to ensure we won't go out of bounds or
24 // have overflow. This can be done with media::VerifySubsamplesMatchSize.
ExtractSubsampleCypherBytes(const std::vector<media::SubsampleEntry> & subsamples,const uint8_t * src,uint8_t * dst)25 void ExtractSubsampleCypherBytes(
26 const std::vector<media::SubsampleEntry>& subsamples,
27 const uint8_t* src,
28 uint8_t* dst) {
29 for (const auto& subsample : subsamples) {
30 src += subsample.clear_bytes;
31 memcpy(dst, src, subsample.cypher_bytes);
32 src += subsample.cypher_bytes;
33 dst += subsample.cypher_bytes;
34 }
35 }
36
37 // Copy the cypher bytes as specified by |subsamples| from |src| to |dst|.
38 // Any clear bytes mentioned in |subsamples| will be skipped in |dst|. This is
39 // used when copying the decrypted bytes back into the buffer, replacing the
40 // encrypted portions.
41 //
42 // NOTE: Before invoking this call the |subsamples| data must have been verified
43 // against the length of the |src| array to ensure we won't go out of bounds or
44 // have overflow. This can be done with media::VerifySubsamplesMatchSize.
InsertSubsampleCypherBytes(const std::vector<media::SubsampleEntry> & subsamples,const uint8_t * src,uint8_t * dst)45 void InsertSubsampleCypherBytes(
46 const std::vector<media::SubsampleEntry>& subsamples,
47 const uint8_t* src,
48 uint8_t* dst) {
49 for (const auto& subsample : subsamples) {
50 dst += subsample.clear_bytes;
51 memcpy(dst, src, subsample.cypher_bytes);
52 src += subsample.cypher_bytes;
53 dst += subsample.cypher_bytes;
54 }
55 }
56
57 // Copy the decrypted data into the output buffer. The buffer will contain
58 // all of the data if there was no subsampling or if we were doing CBCS with
59 // multiple subsamples. Otherwise we need to copy based on the subsampling.
CopyDecryptedDataToDecoderBuffer(scoped_refptr<media::DecoderBuffer> encrypted,const std::vector<uint8_t> & decrypted_data)60 scoped_refptr<media::DecoderBuffer> CopyDecryptedDataToDecoderBuffer(
61 scoped_refptr<media::DecoderBuffer> encrypted,
62 const std::vector<uint8_t>& decrypted_data) {
63 scoped_refptr<media::DecoderBuffer> decrypted;
64 if (encrypted->decrypt_config()->subsamples().empty() ||
65 (encrypted->decrypt_config()->encryption_scheme() ==
66 media::EncryptionScheme::kCbcs &&
67 encrypted->decrypt_config()->subsamples().size() > 1)) {
68 decrypted = media::DecoderBuffer::CopyFrom(decrypted_data.data(),
69 decrypted_data.size());
70 } else {
71 decrypted = media::DecoderBuffer::CopyFrom(encrypted->data(),
72 encrypted->data_size());
73 InsertSubsampleCypherBytes(encrypted->decrypt_config()->subsamples(),
74 decrypted_data.data(),
75 decrypted->writable_data());
76 }
77
78 // Copy the auxiliary fields.
79 decrypted->set_timestamp(encrypted->timestamp());
80 decrypted->set_duration(encrypted->duration());
81 decrypted->set_is_key_frame(encrypted->is_key_frame());
82 decrypted->CopySideDataFrom(encrypted->side_data(),
83 encrypted->side_data_size());
84 return decrypted;
85 }
86
RejectPromiseConnectionLost(std::unique_ptr<media::CdmPromise> promise)87 void RejectPromiseConnectionLost(std::unique_ptr<media::CdmPromise> promise) {
88 promise->reject(media::CdmPromise::Exception::INVALID_STATE_ERROR, 0,
89 "Mojo connection lost");
90 }
91
92 } // namespace
93
94 namespace chromeos {
95
ContentDecryptionModuleAdapter(std::unique_ptr<CdmStorageAdapter> storage,mojo::AssociatedRemote<cdm::mojom::ContentDecryptionModule> cros_cdm_remote,const media::SessionMessageCB & session_message_cb,const media::SessionClosedCB & session_closed_cb,const media::SessionKeysChangeCB & session_keys_change_cb,const media::SessionExpirationUpdateCB & session_expiration_update_cb)96 ContentDecryptionModuleAdapter::ContentDecryptionModuleAdapter(
97 std::unique_ptr<CdmStorageAdapter> storage,
98 mojo::AssociatedRemote<cdm::mojom::ContentDecryptionModule> cros_cdm_remote,
99 const media::SessionMessageCB& session_message_cb,
100 const media::SessionClosedCB& session_closed_cb,
101 const media::SessionKeysChangeCB& session_keys_change_cb,
102 const media::SessionExpirationUpdateCB& session_expiration_update_cb)
103 : storage_(std::move(storage)),
104 cros_cdm_remote_(std::move(cros_cdm_remote)),
105 session_message_cb_(session_message_cb),
106 session_closed_cb_(session_closed_cb),
107 session_keys_change_cb_(session_keys_change_cb),
108 session_expiration_update_cb_(session_expiration_update_cb),
109 mojo_task_runner_(base::SequencedTaskRunnerHandle::Get()) {
110 DVLOG(1) << "Created ContentDecryptionModuleAdapter";
111 cros_cdm_remote_.set_disconnect_handler(
112 base::BindOnce(&ContentDecryptionModuleAdapter::OnConnectionError,
113 base::Unretained(this)));
114 }
115
116 mojo::PendingAssociatedRemote<cdm::mojom::ContentDecryptionModuleClient>
GetClientInterface()117 ContentDecryptionModuleAdapter::GetClientInterface() {
118 CHECK(!cros_client_receiver_.is_bound());
119 auto ret = cros_client_receiver_.BindNewEndpointAndPassRemote();
120 cros_client_receiver_.set_disconnect_handler(
121 base::BindOnce(&ContentDecryptionModuleAdapter::OnConnectionError,
122 base::Unretained(this)));
123 return ret;
124 }
125
SetServerCertificate(const std::vector<uint8_t> & certificate_data,std::unique_ptr<media::SimpleCdmPromise> promise)126 void ContentDecryptionModuleAdapter::SetServerCertificate(
127 const std::vector<uint8_t>& certificate_data,
128 std::unique_ptr<media::SimpleCdmPromise> promise) {
129 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
130 DVLOG(2) << __func__;
131 if (!cros_cdm_remote_) {
132 RejectPromiseConnectionLost(std::move(promise));
133 return;
134 }
135 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
136 cros_cdm_remote_->SetServerCertificate(
137 certificate_data,
138 base::BindOnce(&ContentDecryptionModuleAdapter::OnSimplePromiseResult,
139 base::Unretained(this), promise_id));
140 }
141
GetStatusForPolicy(media::HdcpVersion min_hdcp_version,std::unique_ptr<media::KeyStatusCdmPromise> promise)142 void ContentDecryptionModuleAdapter::GetStatusForPolicy(
143 media::HdcpVersion min_hdcp_version,
144 std::unique_ptr<media::KeyStatusCdmPromise> promise) {
145 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
146 DVLOG(2) << __func__;
147 if (!cros_cdm_remote_) {
148 RejectPromiseConnectionLost(std::move(promise));
149 return;
150 }
151 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
152 cros_cdm_remote_->GetStatusForPolicy(
153 min_hdcp_version,
154 base::BindOnce(&ContentDecryptionModuleAdapter::OnGetStatusForPolicy,
155 base::Unretained(this), promise_id));
156 }
157
CreateSessionAndGenerateRequest(media::CdmSessionType session_type,media::EmeInitDataType init_data_type,const std::vector<uint8_t> & init_data,std::unique_ptr<media::NewSessionCdmPromise> promise)158 void ContentDecryptionModuleAdapter::CreateSessionAndGenerateRequest(
159 media::CdmSessionType session_type,
160 media::EmeInitDataType init_data_type,
161 const std::vector<uint8_t>& init_data,
162 std::unique_ptr<media::NewSessionCdmPromise> promise) {
163 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
164 DVLOG(2) << __func__;
165 if (!cros_cdm_remote_) {
166 RejectPromiseConnectionLost(std::move(promise));
167 return;
168 }
169 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
170 cros_cdm_remote_->CreateSessionAndGenerateRequest(
171 session_type, init_data_type, init_data,
172 base::BindOnce(&ContentDecryptionModuleAdapter::OnSessionPromiseResult,
173 base::Unretained(this), promise_id));
174 }
175
LoadSession(media::CdmSessionType session_type,const std::string & session_id,std::unique_ptr<media::NewSessionCdmPromise> promise)176 void ContentDecryptionModuleAdapter::LoadSession(
177 media::CdmSessionType session_type,
178 const std::string& session_id,
179 std::unique_ptr<media::NewSessionCdmPromise> promise) {
180 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
181 DVLOG(2) << __func__;
182 if (!cros_cdm_remote_) {
183 RejectPromiseConnectionLost(std::move(promise));
184 return;
185 }
186 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
187 cros_cdm_remote_->LoadSession(
188 session_type, session_id,
189 base::BindOnce(&ContentDecryptionModuleAdapter::OnSessionPromiseResult,
190 base::Unretained(this), promise_id));
191 }
192
UpdateSession(const std::string & session_id,const std::vector<uint8_t> & response,std::unique_ptr<media::SimpleCdmPromise> promise)193 void ContentDecryptionModuleAdapter::UpdateSession(
194 const std::string& session_id,
195 const std::vector<uint8_t>& response,
196 std::unique_ptr<media::SimpleCdmPromise> promise) {
197 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
198 DVLOG(2) << __func__;
199 if (!cros_cdm_remote_) {
200 RejectPromiseConnectionLost(std::move(promise));
201 return;
202 }
203 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
204 cros_cdm_remote_->UpdateSession(
205 session_id, response,
206 base::BindOnce(&ContentDecryptionModuleAdapter::OnSimplePromiseResult,
207 base::Unretained(this), promise_id));
208 }
209
CloseSession(const std::string & session_id,std::unique_ptr<media::SimpleCdmPromise> promise)210 void ContentDecryptionModuleAdapter::CloseSession(
211 const std::string& session_id,
212 std::unique_ptr<media::SimpleCdmPromise> promise) {
213 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
214 DVLOG(2) << __func__;
215 if (!cros_cdm_remote_) {
216 RejectPromiseConnectionLost(std::move(promise));
217 return;
218 }
219 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
220 cros_cdm_remote_->CloseSession(
221 session_id,
222 base::BindOnce(&ContentDecryptionModuleAdapter::OnSimplePromiseResult,
223 base::Unretained(this), promise_id));
224 }
225
RemoveSession(const std::string & session_id,std::unique_ptr<media::SimpleCdmPromise> promise)226 void ContentDecryptionModuleAdapter::RemoveSession(
227 const std::string& session_id,
228 std::unique_ptr<media::SimpleCdmPromise> promise) {
229 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
230 DVLOG(2) << __func__;
231 if (!cros_cdm_remote_) {
232 RejectPromiseConnectionLost(std::move(promise));
233 return;
234 }
235 uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
236 cros_cdm_remote_->RemoveSession(
237 session_id,
238 base::BindOnce(&ContentDecryptionModuleAdapter::OnSimplePromiseResult,
239 base::Unretained(this), promise_id));
240 }
241
GetCdmContext()242 media::CdmContext* ContentDecryptionModuleAdapter::GetCdmContext() {
243 return this;
244 }
245
246 std::unique_ptr<media::CallbackRegistration>
RegisterEventCB(EventCB event_cb)247 ContentDecryptionModuleAdapter::RegisterEventCB(EventCB event_cb) {
248 return event_callbacks_.Register(std::move(event_cb));
249 }
250
GetDecryptor()251 media::Decryptor* ContentDecryptionModuleAdapter::GetDecryptor() {
252 return this;
253 }
254
GetChromeOsCdmContext()255 ChromeOsCdmContext* ContentDecryptionModuleAdapter::GetChromeOsCdmContext() {
256 return this;
257 }
258
GetHwKeyData(const media::DecryptConfig * decrypt_config,const std::vector<uint8_t> & hw_identifier,GetHwKeyDataCB callback)259 void ContentDecryptionModuleAdapter::GetHwKeyData(
260 const media::DecryptConfig* decrypt_config,
261 const std::vector<uint8_t>& hw_identifier,
262 GetHwKeyDataCB callback) {
263 // This can get called from decoder threads or mojo threads, so we may need
264 // to repost the task.
265 if (!mojo_task_runner_->RunsTasksInCurrentSequence()) {
266 mojo_task_runner_->PostTask(
267 FROM_HERE, base::BindOnce(&ContentDecryptionModuleAdapter::GetHwKeyData,
268 weak_factory_.GetWeakPtr(), decrypt_config,
269 hw_identifier, std::move(callback)));
270 return;
271 }
272 if (!cros_cdm_remote_) {
273 std::move(callback).Run(media::Decryptor::Status::kError,
274 std::vector<uint8_t>());
275 return;
276 }
277 auto cros_decrypt_config = cdm::mojom::DecryptConfig::New();
278 cros_decrypt_config->key_id = decrypt_config->key_id();
279 cros_decrypt_config->iv = decrypt_config->iv();
280 cros_decrypt_config->encryption_scheme = decrypt_config->encryption_scheme();
281
282 cros_cdm_remote_->GetHwKeyData(std::move(cros_decrypt_config), hw_identifier,
283 std::move(callback));
284 }
285
OnSessionMessage(const std::string & session_id,media::CdmMessageType message_type,const std::vector<uint8_t> & message)286 void ContentDecryptionModuleAdapter::OnSessionMessage(
287 const std::string& session_id,
288 media::CdmMessageType message_type,
289 const std::vector<uint8_t>& message) {
290 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
291 DVLOG(2) << __func__;
292 session_message_cb_.Run(session_id, message_type, message);
293 }
294
OnSessionClosed(const std::string & session_id)295 void ContentDecryptionModuleAdapter::OnSessionClosed(
296 const std::string& session_id) {
297 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
298 DVLOG(2) << __func__;
299 cdm_session_tracker_.RemoveSession(session_id);
300 session_closed_cb_.Run(session_id);
301 }
302
OnSessionKeysChange(const std::string & session_id,bool has_additional_usable_key,std::vector<std::unique_ptr<media::CdmKeyInformation>> keys_info)303 void ContentDecryptionModuleAdapter::OnSessionKeysChange(
304 const std::string& session_id,
305 bool has_additional_usable_key,
306 std::vector<std::unique_ptr<media::CdmKeyInformation>> keys_info) {
307 DVLOG(2) << __func__
308 << " has_additional_usable_key: " << has_additional_usable_key;
309 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
310
311 if (has_additional_usable_key)
312 event_callbacks_.Notify(Event::kHasAdditionalUsableKey);
313
314 session_keys_change_cb_.Run(session_id, has_additional_usable_key,
315 std::move(keys_info));
316 }
317
OnSessionExpirationUpdate(const std::string & session_id,double new_expiry_time_sec)318 void ContentDecryptionModuleAdapter::OnSessionExpirationUpdate(
319 const std::string& session_id,
320 double new_expiry_time_sec) {
321 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
322 session_expiration_update_cb_.Run(
323 session_id, base::Time::FromDoubleT(new_expiry_time_sec));
324 }
325
Decrypt(StreamType stream_type,scoped_refptr<media::DecoderBuffer> encrypted,DecryptCB decrypt_cb)326 void ContentDecryptionModuleAdapter::Decrypt(
327 StreamType stream_type,
328 scoped_refptr<media::DecoderBuffer> encrypted,
329 DecryptCB decrypt_cb) {
330 // This can get called from decoder threads or mojo threads, so we may need
331 // to repost the task.
332 if (!mojo_task_runner_->RunsTasksInCurrentSequence()) {
333 mojo_task_runner_->PostTask(
334 FROM_HERE, base::BindOnce(&ContentDecryptionModuleAdapter::Decrypt,
335 weak_factory_.GetWeakPtr(), stream_type,
336 encrypted, std::move(decrypt_cb)));
337 return;
338 }
339 DVLOG(2) << __func__ << ": " << encrypted->AsHumanReadableString(true);
340 if (!cros_cdm_remote_) {
341 std::move(decrypt_cb).Run(media::Decryptor::kError, nullptr);
342 return;
343 }
344
345 const media::DecryptConfig* decrypt_config = encrypted->decrypt_config();
346 if (!decrypt_config) {
347 // If there is no DecryptConfig, then the data is unencrypted so return it
348 // immediately.
349 std::move(decrypt_cb).Run(kSuccess, encrypted);
350 return;
351 }
352
353 cdm::mojom::DecryptConfigPtr cros_decrypt_config(
354 cdm::mojom::DecryptConfig::New());
355 cros_decrypt_config->key_id = decrypt_config->key_id();
356 cros_decrypt_config->iv = decrypt_config->iv();
357 if (decrypt_config->HasPattern()) {
358 cros_decrypt_config->encryption_pattern =
359 decrypt_config->encryption_pattern().value();
360 }
361 cros_decrypt_config->encryption_scheme = decrypt_config->encryption_scheme();
362
363 const std::vector<media::SubsampleEntry>& subsamples =
364 decrypt_config->subsamples();
365 if (subsamples.empty()) {
366 StoreDecryptCallback(stream_type, std::move(decrypt_cb));
367 // No subsamples specified, request decryption of entire block.
368 // TODO(jkardatzke): Evaluate the performance cost here of copying the data
369 // and see if want to use something like MojoDecoderBufferWriter instead.
370 cros_cdm_remote_->Decrypt(
371 std::vector<uint8_t>(encrypted->data(),
372 encrypted->data() + encrypted->data_size()),
373 std::move(cros_decrypt_config),
374 base::BindOnce(&ContentDecryptionModuleAdapter::OnDecrypt,
375 base::Unretained(this), stream_type, encrypted,
376 encrypted->data_size()));
377 return;
378 }
379
380 if (!VerifySubsamplesMatchSize(subsamples, encrypted->data_size())) {
381 LOG(ERROR) << "Subsample sizes do not match input size";
382 std::move(decrypt_cb).Run(kError, nullptr);
383 return;
384 }
385
386 // Compute the size of the encrypted portion. Overflow, etc. checked by
387 // the call to VerifySubsamplesMatchSize().
388 size_t total_encrypted_size = 0;
389 for (const auto& subsample : subsamples)
390 total_encrypted_size += subsample.cypher_bytes;
391
392 // No need to decrypt if there is no encrypted data.
393 if (total_encrypted_size == 0) {
394 encrypted->set_decrypt_config(nullptr);
395 std::move(decrypt_cb).Run(kSuccess, encrypted);
396 return;
397 }
398
399 StoreDecryptCallback(stream_type, std::move(decrypt_cb));
400
401 // For CENC, the encrypted portions of all subsamples must form a contiguous
402 // block, such that an encrypted subsample that ends away from a block
403 // boundary is immediately followed by the start of the next encrypted
404 // subsample. We copy all encrypted subsamples to a contiguous buffer, decrypt
405 // them, then copy the decrypted bytes over the encrypted bytes in the output.
406 // For CBCS, if there is more than one sample, then we need to pass the
407 // subsample information or otherwise we would need to call decrypt for each
408 // individual subsample since each subsample uses the same IV and it can't be
409 // decrypted as one large block like CENC.
410 if (decrypt_config->encryption_scheme() == media::EncryptionScheme::kCenc ||
411 subsamples.size() == 1) {
412 std::vector<uint8_t> encrypted_bytes(total_encrypted_size);
413 ExtractSubsampleCypherBytes(subsamples, encrypted->data(),
414 encrypted_bytes.data());
415 cros_cdm_remote_->Decrypt(
416 std::move(encrypted_bytes), std::move(cros_decrypt_config),
417 base::BindOnce(&ContentDecryptionModuleAdapter::OnDecrypt,
418 base::Unretained(this), stream_type, encrypted,
419 total_encrypted_size));
420 return;
421 }
422
423 // We need to specify the subsampling and put that in the decrypt config.
424 for (const auto& sample : subsamples) {
425 cros_decrypt_config->subsamples.push_back(cdm::mojom::SubsampleEntry::New(
426 sample.clear_bytes, sample.cypher_bytes));
427 }
428 // TODO(jkardatzke): Evaluate the performance cost here of copying the data
429 // and see if want to use something like MojoDecoderBufferWriter instead.
430 cros_cdm_remote_->Decrypt(
431 std::vector<uint8_t>(encrypted->data(),
432 encrypted->data() + encrypted->data_size()),
433 std::move(cros_decrypt_config),
434 base::BindOnce(&ContentDecryptionModuleAdapter::OnDecrypt,
435 base::Unretained(this), stream_type, encrypted,
436 encrypted->data_size()));
437 }
438
CancelDecrypt(StreamType stream_type)439 void ContentDecryptionModuleAdapter::CancelDecrypt(StreamType stream_type) {
440 // This can get called from decoder threads or mojo threads, so we may need
441 // to repost the task.
442 if (!mojo_task_runner_->RunsTasksInCurrentSequence()) {
443 mojo_task_runner_->PostTask(
444 FROM_HERE,
445 base::BindOnce(&ContentDecryptionModuleAdapter::CancelDecrypt,
446 weak_factory_.GetWeakPtr(), stream_type));
447 return;
448 }
449 media::Decryptor::DecryptCB callback =
450 std::move(stream_type == kVideo ? pending_video_decrypt_cb_
451 : pending_audio_decrypt_cb_);
452 if (callback)
453 std::move(callback).Run(media::Decryptor::kSuccess, nullptr);
454 }
455
InitializeAudioDecoder(const media::AudioDecoderConfig & config,DecoderInitCB init_cb)456 void ContentDecryptionModuleAdapter::InitializeAudioDecoder(
457 const media::AudioDecoderConfig& config,
458 DecoderInitCB init_cb) {
459 // ContentDecryptionModuleAdapter does not support audio decoding.
460 std::move(init_cb).Run(false);
461 }
462
InitializeVideoDecoder(const media::VideoDecoderConfig & config,DecoderInitCB init_cb)463 void ContentDecryptionModuleAdapter::InitializeVideoDecoder(
464 const media::VideoDecoderConfig& config,
465 DecoderInitCB init_cb) {
466 // ContentDecryptionModuleAdapter does not support video decoding.
467 std::move(init_cb).Run(false);
468 }
469
DecryptAndDecodeAudio(scoped_refptr<media::DecoderBuffer> encrypted,const AudioDecodeCB & audio_decode_cb)470 void ContentDecryptionModuleAdapter::DecryptAndDecodeAudio(
471 scoped_refptr<media::DecoderBuffer> encrypted,
472 const AudioDecodeCB& audio_decode_cb) {
473 NOTREACHED()
474 << "ContentDecryptionModuleAdapter does not support audio decoding";
475 }
476
DecryptAndDecodeVideo(scoped_refptr<media::DecoderBuffer> encrypted,const VideoDecodeCB & video_decode_cb)477 void ContentDecryptionModuleAdapter::DecryptAndDecodeVideo(
478 scoped_refptr<media::DecoderBuffer> encrypted,
479 const VideoDecodeCB& video_decode_cb) {
480 NOTREACHED()
481 << "ContentDecryptionModuleAdapter does not support video decoding";
482 }
483
ResetDecoder(StreamType stream_type)484 void ContentDecryptionModuleAdapter::ResetDecoder(StreamType stream_type) {
485 NOTREACHED() << "ContentDecryptionModuleAdapter does not support decoding";
486 }
487
DeinitializeDecoder(StreamType stream_type)488 void ContentDecryptionModuleAdapter::DeinitializeDecoder(
489 StreamType stream_type) {
490 // We do not support audio/video decoding, but since this can be called any
491 // time after InitializeAudioDecoder/InitializeVideoDecoder, nothing to be
492 // done here.
493 }
494
CanAlwaysDecrypt()495 bool ContentDecryptionModuleAdapter::CanAlwaysDecrypt() {
496 return false;
497 }
498
~ContentDecryptionModuleAdapter()499 ContentDecryptionModuleAdapter::~ContentDecryptionModuleAdapter() {
500 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
501 DVLOG(2) << __func__;
502 cdm_session_tracker_.CloseRemainingSessions(session_closed_cb_);
503 }
504
OnConnectionError()505 void ContentDecryptionModuleAdapter::OnConnectionError() {
506 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
507 DVLOG(1) << __func__;
508 // The mojo connection doesn't manage our lifecycle, that's handled by the
509 // owner of the media::ContentDecryptionModule implementation we provide; so
510 // only drop the bindings and notify the other end about all of the closed
511 // sessions; don't destruct here.
512 cros_client_receiver_.reset();
513 cros_cdm_remote_.reset();
514
515 // We've lost our communication, so reject all outstanding promises and close
516 // any open sessions.
517 cdm_promise_adapter_.Clear();
518 cdm_session_tracker_.CloseRemainingSessions(session_closed_cb_);
519 }
520
RejectTrackedPromise(uint32_t promise_id,cdm::mojom::CdmPromiseResultPtr promise_result)521 void ContentDecryptionModuleAdapter::RejectTrackedPromise(
522 uint32_t promise_id,
523 cdm::mojom::CdmPromiseResultPtr promise_result) {
524 cdm_promise_adapter_.RejectPromise(promise_id, promise_result->exception,
525 promise_result->system_code,
526 promise_result->error_message);
527 }
528
OnSimplePromiseResult(uint32_t promise_id,cdm::mojom::CdmPromiseResultPtr promise_result)529 void ContentDecryptionModuleAdapter::OnSimplePromiseResult(
530 uint32_t promise_id,
531 cdm::mojom::CdmPromiseResultPtr promise_result) {
532 DVLOG(1) << __func__ << " received result: " << promise_result->success;
533 if (!promise_result->success) {
534 RejectTrackedPromise(promise_id, std::move(promise_result));
535 return;
536 }
537 cdm_promise_adapter_.ResolvePromise(promise_id);
538 }
539
OnGetStatusForPolicy(uint32_t promise_id,cdm::mojom::CdmPromiseResultPtr promise_result,media::CdmKeyInformation::KeyStatus key_status)540 void ContentDecryptionModuleAdapter::OnGetStatusForPolicy(
541 uint32_t promise_id,
542 cdm::mojom::CdmPromiseResultPtr promise_result,
543 media::CdmKeyInformation::KeyStatus key_status) {
544 if (!promise_result->success) {
545 RejectTrackedPromise(promise_id, std::move(promise_result));
546 return;
547 }
548 cdm_promise_adapter_.ResolvePromise(promise_id, key_status);
549 }
550
OnSessionPromiseResult(uint32_t promise_id,cdm::mojom::CdmPromiseResultPtr promise_result,const std::string & session_id)551 void ContentDecryptionModuleAdapter::OnSessionPromiseResult(
552 uint32_t promise_id,
553 cdm::mojom::CdmPromiseResultPtr promise_result,
554 const std::string& session_id) {
555 DVLOG(1) << __func__ << " received result: " << promise_result->success
556 << " session: " << session_id;
557 if (!promise_result->success) {
558 RejectTrackedPromise(promise_id, std::move(promise_result));
559 return;
560 }
561 cdm_session_tracker_.AddSession(session_id);
562 cdm_promise_adapter_.ResolvePromise(promise_id, session_id);
563 }
564
StoreDecryptCallback(StreamType stream_type,DecryptCB decrypt_cb)565 void ContentDecryptionModuleAdapter::StoreDecryptCallback(
566 StreamType stream_type,
567 DecryptCB decrypt_cb) {
568 if (stream_type == kVideo) {
569 DCHECK(!pending_video_decrypt_cb_);
570 pending_video_decrypt_cb_ = std::move(decrypt_cb);
571 } else {
572 DCHECK(!pending_audio_decrypt_cb_);
573 pending_audio_decrypt_cb_ = std::move(decrypt_cb);
574 }
575 }
576
OnDecrypt(StreamType stream_type,scoped_refptr<media::DecoderBuffer> encrypted,size_t expected_decrypt_size,media::Decryptor::Status status,const std::vector<uint8_t> & decrypted_data)577 void ContentDecryptionModuleAdapter::OnDecrypt(
578 StreamType stream_type,
579 scoped_refptr<media::DecoderBuffer> encrypted,
580 size_t expected_decrypt_size,
581 media::Decryptor::Status status,
582 const std::vector<uint8_t>& decrypted_data) {
583 media::Decryptor::DecryptCB callback =
584 std::move(stream_type == kVideo ? pending_video_decrypt_cb_
585 : pending_audio_decrypt_cb_);
586 if (!callback) {
587 // This happens if CancelDecrypt was called.
588 DVLOG(1) << __func__ << " decrypt callback empty";
589 return;
590 }
591 if (status != media::Decryptor::kSuccess) {
592 if (status == media::Decryptor::kNoKey) {
593 DVLOG(1) << "Decryption failed due to no key";
594 } else {
595 LOG(ERROR) << "Failure decrypting data: " << status;
596 }
597 std::move(callback).Run(status, nullptr);
598 return;
599 }
600
601 if (decrypted_data.size() != expected_decrypt_size) {
602 LOG(ERROR) << "Decrypted data size mismatch got: " << decrypted_data.size()
603 << " expected: " << expected_decrypt_size;
604 std::move(callback).Run(media::Decryptor::kError, nullptr);
605 return;
606 }
607
608 std::move(callback).Run(
609 media::Decryptor::kSuccess,
610 CopyDecryptedDataToDecoderBuffer(std::move(encrypted), decrypted_data));
611 }
612
613 } // namespace chromeos
614