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
3 // found in the LICENSE file.
5 #include "media/cdm/ppapi/cdm_adapter.h"
7 #include "media/base/limits.h"
8 #include "media/cdm/ppapi/cdm_file_io_impl.h"
9 #include "media/cdm/ppapi/cdm_helpers.h"
10 #include "media/cdm/ppapi/cdm_logging.h"
11 #include "media/cdm/ppapi/supported_cdm_versions.h"
12 #include "ppapi/c/ppb_console.h"
13 #include "ppapi/cpp/private/uma_private.h"
15 #if defined(CHECK_DOCUMENT_URL)
16 #include "ppapi/cpp/dev/url_util_dev.h"
17 #include "ppapi/cpp/instance_handle.h"
18 #endif // defined(CHECK_DOCUMENT_URL)
22 // Constants for UMA reporting of file size (in KB) via HistogramCustomCounts().
23 // Note that the histogram is log-scaled (rather than linear).
24 const uint32_t kSizeKBMin
= 1;
25 const uint32_t kSizeKBMax
= 512 * 1024; // 512MB
26 const uint32_t kSizeKBBuckets
= 100;
29 #define DLOG_TO_CONSOLE(message) LogToConsole(message);
31 #define DLOG_TO_CONSOLE(message) (void)(message);
35 return pp::Module::Get()->core()->IsMainThread();
38 // Posts a task to run |cb| on the main thread. The task is posted even if the
39 // current thread is the main thread.
40 void PostOnMain(pp::CompletionCallback cb
) {
41 pp::Module::Get()->core()->CallOnMainThread(0, cb
, PP_OK
);
44 // Ensures |cb| is called on the main thread, either because the current thread
45 // is the main thread or by posting it to the main thread.
46 void CallOnMain(pp::CompletionCallback cb
) {
47 // TODO(tomfinegan): This is only necessary because PPAPI doesn't allow calls
48 // off the main thread yet. Remove this once the change lands.
55 // Configures a cdm::InputBuffer. |subsamples| must exist as long as
56 // |input_buffer| is in use.
57 void ConfigureInputBuffer(
58 const pp::Buffer_Dev
& encrypted_buffer
,
59 const PP_EncryptedBlockInfo
& encrypted_block_info
,
60 std::vector
<cdm::SubsampleEntry
>* subsamples
,
61 cdm::InputBuffer
* input_buffer
) {
62 PP_DCHECK(subsamples
);
63 PP_DCHECK(!encrypted_buffer
.is_null());
65 input_buffer
->data
= static_cast<uint8_t*>(encrypted_buffer
.data());
66 input_buffer
->data_size
= encrypted_block_info
.data_size
;
67 PP_DCHECK(encrypted_buffer
.size() >= input_buffer
->data_size
);
69 PP_DCHECK(encrypted_block_info
.key_id_size
<=
70 arraysize(encrypted_block_info
.key_id
));
71 input_buffer
->key_id_size
= encrypted_block_info
.key_id_size
;
72 input_buffer
->key_id
= input_buffer
->key_id_size
> 0 ?
73 encrypted_block_info
.key_id
: NULL
;
75 PP_DCHECK(encrypted_block_info
.iv_size
<= arraysize(encrypted_block_info
.iv
));
76 input_buffer
->iv_size
= encrypted_block_info
.iv_size
;
77 input_buffer
->iv
= encrypted_block_info
.iv_size
> 0 ?
78 encrypted_block_info
.iv
: NULL
;
80 input_buffer
->num_subsamples
= encrypted_block_info
.num_subsamples
;
81 if (encrypted_block_info
.num_subsamples
> 0) {
82 subsamples
->reserve(encrypted_block_info
.num_subsamples
);
84 for (uint32_t i
= 0; i
< encrypted_block_info
.num_subsamples
; ++i
) {
85 subsamples
->push_back(cdm::SubsampleEntry(
86 encrypted_block_info
.subsamples
[i
].clear_bytes
,
87 encrypted_block_info
.subsamples
[i
].cipher_bytes
));
90 input_buffer
->subsamples
= &(*subsamples
)[0];
93 input_buffer
->timestamp
= encrypted_block_info
.tracking_info
.timestamp
;
96 PP_DecryptResult
CdmStatusToPpDecryptResult(cdm::Status status
) {
99 return PP_DECRYPTRESULT_SUCCESS
;
101 return PP_DECRYPTRESULT_DECRYPT_NOKEY
;
102 case cdm::kNeedMoreData
:
103 return PP_DECRYPTRESULT_NEEDMOREDATA
;
104 case cdm::kDecryptError
:
105 return PP_DECRYPTRESULT_DECRYPT_ERROR
;
106 case cdm::kDecodeError
:
107 return PP_DECRYPTRESULT_DECODE_ERROR
;
110 return PP_DECRYPTRESULT_DECODE_ERROR
;
114 PP_DecryptedFrameFormat
CdmVideoFormatToPpDecryptedFrameFormat(
115 cdm::VideoFormat format
) {
118 return PP_DECRYPTEDFRAMEFORMAT_YV12
;
120 return PP_DECRYPTEDFRAMEFORMAT_I420
;
122 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN
;
126 PP_DecryptedSampleFormat
CdmAudioFormatToPpDecryptedSampleFormat(
127 cdm::AudioFormat format
) {
129 case cdm::kAudioFormatU8
:
130 return PP_DECRYPTEDSAMPLEFORMAT_U8
;
131 case cdm::kAudioFormatS16
:
132 return PP_DECRYPTEDSAMPLEFORMAT_S16
;
133 case cdm::kAudioFormatS32
:
134 return PP_DECRYPTEDSAMPLEFORMAT_S32
;
135 case cdm::kAudioFormatF32
:
136 return PP_DECRYPTEDSAMPLEFORMAT_F32
;
137 case cdm::kAudioFormatPlanarS16
:
138 return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16
;
139 case cdm::kAudioFormatPlanarF32
:
140 return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32
;
142 return PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN
;
146 cdm::AudioDecoderConfig::AudioCodec
PpAudioCodecToCdmAudioCodec(
147 PP_AudioCodec codec
) {
149 case PP_AUDIOCODEC_VORBIS
:
150 return cdm::AudioDecoderConfig::kCodecVorbis
;
151 case PP_AUDIOCODEC_AAC
:
152 return cdm::AudioDecoderConfig::kCodecAac
;
154 return cdm::AudioDecoderConfig::kUnknownAudioCodec
;
158 cdm::VideoDecoderConfig::VideoCodec
PpVideoCodecToCdmVideoCodec(
159 PP_VideoCodec codec
) {
161 case PP_VIDEOCODEC_VP8
:
162 return cdm::VideoDecoderConfig::kCodecVp8
;
163 case PP_VIDEOCODEC_H264
:
164 return cdm::VideoDecoderConfig::kCodecH264
;
165 case PP_VIDEOCODEC_VP9
:
166 return cdm::VideoDecoderConfig::kCodecVp9
;
168 return cdm::VideoDecoderConfig::kUnknownVideoCodec
;
172 cdm::VideoDecoderConfig::VideoCodecProfile
PpVCProfileToCdmVCProfile(
173 PP_VideoCodecProfile profile
) {
175 case PP_VIDEOCODECPROFILE_NOT_NEEDED
:
176 return cdm::VideoDecoderConfig::kProfileNotNeeded
;
177 case PP_VIDEOCODECPROFILE_H264_BASELINE
:
178 return cdm::VideoDecoderConfig::kH264ProfileBaseline
;
179 case PP_VIDEOCODECPROFILE_H264_MAIN
:
180 return cdm::VideoDecoderConfig::kH264ProfileMain
;
181 case PP_VIDEOCODECPROFILE_H264_EXTENDED
:
182 return cdm::VideoDecoderConfig::kH264ProfileExtended
;
183 case PP_VIDEOCODECPROFILE_H264_HIGH
:
184 return cdm::VideoDecoderConfig::kH264ProfileHigh
;
185 case PP_VIDEOCODECPROFILE_H264_HIGH_10
:
186 return cdm::VideoDecoderConfig::kH264ProfileHigh10
;
187 case PP_VIDEOCODECPROFILE_H264_HIGH_422
:
188 return cdm::VideoDecoderConfig::kH264ProfileHigh422
;
189 case PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE
:
190 return cdm::VideoDecoderConfig::kH264ProfileHigh444Predictive
;
192 return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile
;
196 cdm::VideoFormat
PpDecryptedFrameFormatToCdmVideoFormat(
197 PP_DecryptedFrameFormat format
) {
199 case PP_DECRYPTEDFRAMEFORMAT_YV12
:
201 case PP_DECRYPTEDFRAMEFORMAT_I420
:
204 return cdm::kUnknownVideoFormat
;
208 cdm::StreamType
PpDecryptorStreamTypeToCdmStreamType(
209 PP_DecryptorStreamType stream_type
) {
210 switch (stream_type
) {
211 case PP_DECRYPTORSTREAMTYPE_AUDIO
:
212 return cdm::kStreamTypeAudio
;
213 case PP_DECRYPTORSTREAMTYPE_VIDEO
:
214 return cdm::kStreamTypeVideo
;
218 return cdm::kStreamTypeVideo
;
221 cdm::SessionType
PpSessionTypeToCdmSessionType(PP_SessionType session_type
) {
222 switch (session_type
) {
223 case PP_SESSIONTYPE_TEMPORARY
:
224 return cdm::kTemporary
;
225 case PP_SESSIONTYPE_PERSISTENT_LICENSE
:
226 return cdm::kPersistentLicense
;
227 case PP_SESSIONTYPE_PERSISTENT_RELEASE
:
228 return cdm::kPersistentKeyRelease
;
232 return cdm::kTemporary
;
235 cdm::InitDataType
PpInitDataTypeToCdmInitDataType(
236 PP_InitDataType init_data_type
) {
237 switch (init_data_type
) {
238 case PP_INITDATATYPE_CENC
:
240 case PP_INITDATATYPE_KEYIDS
:
242 case PP_INITDATATYPE_WEBM
:
250 PP_CdmExceptionCode
CdmExceptionTypeToPpCdmExceptionType(cdm::Error error
) {
252 case cdm::kNotSupportedError
:
253 return PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR
;
254 case cdm::kInvalidStateError
:
255 return PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR
;
256 case cdm::kInvalidAccessError
:
257 return PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR
;
258 case cdm::kQuotaExceededError
:
259 return PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR
;
260 case cdm::kUnknownError
:
261 return PP_CDMEXCEPTIONCODE_UNKNOWNERROR
;
262 case cdm::kClientError
:
263 return PP_CDMEXCEPTIONCODE_CLIENTERROR
;
264 case cdm::kOutputError
:
265 return PP_CDMEXCEPTIONCODE_OUTPUTERROR
;
269 return PP_CDMEXCEPTIONCODE_UNKNOWNERROR
;
272 PP_CdmMessageType
CdmMessageTypeToPpMessageType(cdm::MessageType message
) {
274 case cdm::kLicenseRequest
:
275 return PP_CDMMESSAGETYPE_LICENSE_REQUEST
;
276 case cdm::kLicenseRenewal
:
277 return PP_CDMMESSAGETYPE_LICENSE_RENEWAL
;
278 case cdm::kLicenseRelease
:
279 return PP_CDMMESSAGETYPE_LICENSE_RELEASE
;
283 return PP_CDMMESSAGETYPE_LICENSE_REQUEST
;
286 PP_CdmKeyStatus
CdmKeyStatusToPpKeyStatus(cdm::KeyStatus status
) {
289 return PP_CDMKEYSTATUS_USABLE
;
290 case cdm::kInternalError
:
291 return PP_CDMKEYSTATUS_INVALID
;
293 return PP_CDMKEYSTATUS_EXPIRED
;
294 case cdm::kOutputNotAllowed
:
295 return PP_CDMKEYSTATUS_OUTPUTNOTALLOWED
;
296 case cdm::kOutputDownscaled
:
297 return PP_CDMKEYSTATUS_OUTPUTDOWNSCALED
;
298 case cdm::kStatusPending
:
299 return PP_CDMKEYSTATUS_STATUSPENDING
;
303 return PP_CDMKEYSTATUS_INVALID
;
310 CdmAdapter::CdmAdapter(PP_Instance instance
, pp::Module
* module
)
311 : pp::Instance(instance
),
312 pp::ContentDecryptor_Private(this),
313 #if defined(OS_CHROMEOS)
314 output_protection_(this),
315 platform_verification_(this),
316 output_link_mask_(0),
317 output_protection_mask_(0),
318 query_output_protection_in_progress_(false),
319 uma_for_output_protection_query_reported_(false),
320 uma_for_output_protection_positive_result_reported_(false),
324 allow_distinctive_identifier_(false),
325 allow_persistent_state_(false),
326 deferred_initialize_audio_decoder_(false),
327 deferred_audio_decoder_config_id_(0),
328 deferred_initialize_video_decoder_(false),
329 deferred_video_decoder_config_id_(0),
330 last_read_file_size_kb_(0),
331 file_size_uma_reported_(false) {
332 callback_factory_
.Initialize(this);
335 CdmAdapter::~CdmAdapter() {}
337 bool CdmAdapter::CreateCdmInstance(const std::string
& key_system
) {
339 cdm_
= make_linked_ptr(CdmWrapper::Create(
340 key_system
.data(), key_system
.size(), GetCdmHost
, this));
341 bool success
= cdm_
!= NULL
;
343 const std::string message
= "CDM instance for " + key_system
+
344 (success
? "" : " could not be") + " created.";
345 DLOG_TO_CONSOLE(message
);
346 CDM_DLOG() << message
;
351 // No errors should be reported in this function because the spec says:
352 // "Store this new error object internally with the MediaKeys instance being
353 // created. This will be used to fire an error against any session created for
354 // this instance." These errors will be reported during session creation
355 // (CreateSession()) or session loading (LoadSession()).
356 // TODO(xhwang): If necessary, we need to store the error here if we want to
357 // support more specific error reporting (other than "Unknown").
358 void CdmAdapter::Initialize(const std::string
& key_system
,
359 bool allow_distinctive_identifier
,
360 bool allow_persistent_state
) {
361 PP_DCHECK(!key_system
.empty());
362 // TODO(jrummell): Remove this check when CDM creation is asynchronous.
363 // http://crbug.com/469003
364 PP_DCHECK(key_system_
.empty() || (key_system_
== key_system
&& cdm_
));
366 #if defined(CHECK_DOCUMENT_URL)
367 PP_URLComponents_Dev url_components
= {};
368 const pp::URLUtil_Dev
* url_util
= pp::URLUtil_Dev::Get();
371 pp::Var href
= url_util
->GetDocumentURL(pp::InstanceHandle(pp_instance()),
373 PP_DCHECK(href
.is_string());
374 std::string url
= href
.AsString();
375 PP_DCHECK(!url
.empty());
376 std::string url_scheme
=
377 url
.substr(url_components
.scheme
.begin
, url_components
.scheme
.len
);
378 if (url_scheme
!= "file") {
379 // Skip this check for file:// URLs as they don't have a host component.
380 PP_DCHECK(url_components
.host
.begin
);
381 PP_DCHECK(0 < url_components
.host
.len
);
383 #endif // defined(CHECK_DOCUMENT_URL)
385 if (!cdm_
&& !CreateCdmInstance(key_system
))
389 key_system_
= key_system
;
390 allow_distinctive_identifier_
= allow_distinctive_identifier
;
391 allow_persistent_state_
= allow_persistent_state
;
392 cdm_
->Initialize(allow_distinctive_identifier
, allow_persistent_state
);
395 void CdmAdapter::SetServerCertificate(uint32_t promise_id
,
396 pp::VarArrayBuffer server_certificate
) {
397 const uint8_t* server_certificate_ptr
=
398 static_cast<const uint8_t*>(server_certificate
.Map());
399 const uint32_t server_certificate_size
= server_certificate
.ByteLength();
401 if (!server_certificate_ptr
||
402 server_certificate_size
< media::limits::kMinCertificateLength
||
403 server_certificate_size
> media::limits::kMaxCertificateLength
) {
405 promise_id
, cdm::kInvalidAccessError
, 0, "Incorrect certificate.");
409 // Initialize() doesn't report an error, so SetServerCertificate() can be
410 // called even if Initialize() failed.
411 // TODO(jrummell): Remove this code when prefixed EME gets removed.
413 RejectPromise(promise_id
,
414 cdm::kInvalidStateError
,
416 "CDM has not been initialized.");
420 cdm_
->SetServerCertificate(
421 promise_id
, server_certificate_ptr
, server_certificate_size
);
424 void CdmAdapter::CreateSessionAndGenerateRequest(uint32_t promise_id
,
425 PP_SessionType session_type
,
426 PP_InitDataType init_data_type
,
427 pp::VarArrayBuffer init_data
) {
428 // Initialize() doesn't report an error, so CreateSession() can be called
429 // even if Initialize() failed.
430 // TODO(jrummell): Remove this code when prefixed EME gets removed.
431 // TODO(jrummell): Verify that Initialize() failing does not resolve the
432 // MediaKeys.create() promise.
434 RejectPromise(promise_id
,
435 cdm::kInvalidStateError
,
437 "CDM has not been initialized.");
441 cdm_
->CreateSessionAndGenerateRequest(
442 promise_id
, PpSessionTypeToCdmSessionType(session_type
),
443 PpInitDataTypeToCdmInitDataType(init_data_type
),
444 static_cast<const uint8_t*>(init_data
.Map()), init_data
.ByteLength());
447 void CdmAdapter::LoadSession(uint32_t promise_id
,
448 PP_SessionType session_type
,
449 const std::string
& session_id
) {
450 // Initialize() doesn't report an error, so LoadSession() can be called
451 // even if Initialize() failed.
452 // TODO(jrummell): Remove this code when prefixed EME gets removed.
453 // TODO(jrummell): Verify that Initialize() failing does not resolve the
454 // MediaKeys.create() promise.
456 RejectPromise(promise_id
,
457 cdm::kInvalidStateError
,
459 "CDM has not been initialized.");
463 cdm_
->LoadSession(promise_id
, PpSessionTypeToCdmSessionType(session_type
),
464 session_id
.data(), session_id
.size());
467 void CdmAdapter::UpdateSession(uint32_t promise_id
,
468 const std::string
& session_id
,
469 pp::VarArrayBuffer response
) {
470 const uint8_t* response_ptr
= static_cast<const uint8_t*>(response
.Map());
471 const uint32_t response_size
= response
.ByteLength();
473 PP_DCHECK(!session_id
.empty());
474 PP_DCHECK(response_ptr
);
475 PP_DCHECK(response_size
> 0);
477 cdm_
->UpdateSession(promise_id
, session_id
.data(), session_id
.length(),
478 response_ptr
, response_size
);
481 void CdmAdapter::CloseSession(uint32_t promise_id
,
482 const std::string
& session_id
) {
483 cdm_
->CloseSession(promise_id
, session_id
.data(), session_id
.length());
486 void CdmAdapter::RemoveSession(uint32_t promise_id
,
487 const std::string
& session_id
) {
488 cdm_
->RemoveSession(promise_id
, session_id
.data(), session_id
.length());
491 // Note: In the following decryption/decoding related functions, errors are NOT
492 // reported via KeyError, but are reported via corresponding PPB calls.
494 void CdmAdapter::Decrypt(pp::Buffer_Dev encrypted_buffer
,
495 const PP_EncryptedBlockInfo
& encrypted_block_info
) {
496 PP_DCHECK(!encrypted_buffer
.is_null());
498 // Release a buffer that the caller indicated it is finished with.
499 allocator_
.Release(encrypted_block_info
.tracking_info
.buffer_id
);
501 cdm::Status status
= cdm::kDecryptError
;
502 LinkedDecryptedBlock
decrypted_block(new DecryptedBlockImpl());
505 cdm::InputBuffer input_buffer
;
506 std::vector
<cdm::SubsampleEntry
> subsamples
;
507 ConfigureInputBuffer(encrypted_buffer
, encrypted_block_info
, &subsamples
,
509 status
= cdm_
->Decrypt(input_buffer
, decrypted_block
.get());
510 PP_DCHECK(status
!= cdm::kSuccess
||
511 (decrypted_block
->DecryptedBuffer() &&
512 decrypted_block
->DecryptedBuffer()->Size()));
515 CallOnMain(callback_factory_
.NewCallback(
516 &CdmAdapter::DeliverBlock
,
519 encrypted_block_info
.tracking_info
));
522 void CdmAdapter::InitializeAudioDecoder(
523 const PP_AudioDecoderConfig
& decoder_config
,
524 pp::Buffer_Dev extra_data_buffer
) {
525 PP_DCHECK(!deferred_initialize_audio_decoder_
);
526 PP_DCHECK(deferred_audio_decoder_config_id_
== 0);
527 cdm::Status status
= cdm::kSessionError
;
529 cdm::AudioDecoderConfig cdm_decoder_config
;
530 cdm_decoder_config
.codec
=
531 PpAudioCodecToCdmAudioCodec(decoder_config
.codec
);
532 cdm_decoder_config
.channel_count
= decoder_config
.channel_count
;
533 cdm_decoder_config
.bits_per_channel
= decoder_config
.bits_per_channel
;
534 cdm_decoder_config
.samples_per_second
= decoder_config
.samples_per_second
;
535 cdm_decoder_config
.extra_data
=
536 static_cast<uint8_t*>(extra_data_buffer
.data());
537 cdm_decoder_config
.extra_data_size
= extra_data_buffer
.size();
538 status
= cdm_
->InitializeAudioDecoder(cdm_decoder_config
);
541 if (status
== cdm::kDeferredInitialization
) {
542 deferred_initialize_audio_decoder_
= true;
543 deferred_audio_decoder_config_id_
= decoder_config
.request_id
;
547 CallOnMain(callback_factory_
.NewCallback(
548 &CdmAdapter::DecoderInitializeDone
,
549 PP_DECRYPTORSTREAMTYPE_AUDIO
,
550 decoder_config
.request_id
,
551 status
== cdm::kSuccess
));
554 void CdmAdapter::InitializeVideoDecoder(
555 const PP_VideoDecoderConfig
& decoder_config
,
556 pp::Buffer_Dev extra_data_buffer
) {
557 PP_DCHECK(!deferred_initialize_video_decoder_
);
558 PP_DCHECK(deferred_video_decoder_config_id_
== 0);
559 cdm::Status status
= cdm::kSessionError
;
561 cdm::VideoDecoderConfig cdm_decoder_config
;
562 cdm_decoder_config
.codec
=
563 PpVideoCodecToCdmVideoCodec(decoder_config
.codec
);
564 cdm_decoder_config
.profile
=
565 PpVCProfileToCdmVCProfile(decoder_config
.profile
);
566 cdm_decoder_config
.format
=
567 PpDecryptedFrameFormatToCdmVideoFormat(decoder_config
.format
);
568 cdm_decoder_config
.coded_size
.width
= decoder_config
.width
;
569 cdm_decoder_config
.coded_size
.height
= decoder_config
.height
;
570 cdm_decoder_config
.extra_data
=
571 static_cast<uint8_t*>(extra_data_buffer
.data());
572 cdm_decoder_config
.extra_data_size
= extra_data_buffer
.size();
573 status
= cdm_
->InitializeVideoDecoder(cdm_decoder_config
);
576 if (status
== cdm::kDeferredInitialization
) {
577 deferred_initialize_video_decoder_
= true;
578 deferred_video_decoder_config_id_
= decoder_config
.request_id
;
582 CallOnMain(callback_factory_
.NewCallback(
583 &CdmAdapter::DecoderInitializeDone
,
584 PP_DECRYPTORSTREAMTYPE_VIDEO
,
585 decoder_config
.request_id
,
586 status
== cdm::kSuccess
));
589 void CdmAdapter::DeinitializeDecoder(PP_DecryptorStreamType decoder_type
,
590 uint32_t request_id
) {
591 PP_DCHECK(cdm_
); // InitializeXxxxxDecoder should have succeeded.
593 cdm_
->DeinitializeDecoder(
594 PpDecryptorStreamTypeToCdmStreamType(decoder_type
));
597 CallOnMain(callback_factory_
.NewCallback(
598 &CdmAdapter::DecoderDeinitializeDone
,
603 void CdmAdapter::ResetDecoder(PP_DecryptorStreamType decoder_type
,
604 uint32_t request_id
) {
605 PP_DCHECK(cdm_
); // InitializeXxxxxDecoder should have succeeded.
607 cdm_
->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type
));
609 CallOnMain(callback_factory_
.NewCallback(&CdmAdapter::DecoderResetDone
,
614 void CdmAdapter::DecryptAndDecode(
615 PP_DecryptorStreamType decoder_type
,
616 pp::Buffer_Dev encrypted_buffer
,
617 const PP_EncryptedBlockInfo
& encrypted_block_info
) {
618 PP_DCHECK(cdm_
); // InitializeXxxxxDecoder should have succeeded.
619 // Release a buffer that the caller indicated it is finished with.
620 allocator_
.Release(encrypted_block_info
.tracking_info
.buffer_id
);
622 cdm::InputBuffer input_buffer
;
623 std::vector
<cdm::SubsampleEntry
> subsamples
;
624 if (cdm_
&& !encrypted_buffer
.is_null()) {
625 ConfigureInputBuffer(encrypted_buffer
,
626 encrypted_block_info
,
631 cdm::Status status
= cdm::kDecodeError
;
633 switch (decoder_type
) {
634 case PP_DECRYPTORSTREAMTYPE_VIDEO
: {
635 LinkedVideoFrame
video_frame(new VideoFrameImpl());
637 status
= cdm_
->DecryptAndDecodeFrame(input_buffer
, video_frame
.get());
638 CallOnMain(callback_factory_
.NewCallback(
639 &CdmAdapter::DeliverFrame
,
642 encrypted_block_info
.tracking_info
));
646 case PP_DECRYPTORSTREAMTYPE_AUDIO
: {
647 LinkedAudioFrames
audio_frames(new AudioFramesImpl());
649 status
= cdm_
->DecryptAndDecodeSamples(input_buffer
,
652 CallOnMain(callback_factory_
.NewCallback(
653 &CdmAdapter::DeliverSamples
,
656 encrypted_block_info
.tracking_info
));
666 cdm::Buffer
* CdmAdapter::Allocate(uint32_t capacity
) {
667 return allocator_
.Allocate(capacity
);
670 void CdmAdapter::SetTimer(int64_t delay_ms
, void* context
) {
671 // NOTE: doesn't really need to run on the main thread; could just as well run
672 // on a helper thread if |cdm_| were thread-friendly and care was taken. We
673 // only use CallOnMainThread() here to get delayed-execution behavior.
674 pp::Module::Get()->core()->CallOnMainThread(
676 callback_factory_
.NewCallback(&CdmAdapter::TimerExpired
, context
),
680 void CdmAdapter::TimerExpired(int32_t result
, void* context
) {
681 PP_DCHECK(result
== PP_OK
);
682 cdm_
->TimerExpired(context
);
685 cdm::Time
CdmAdapter::GetCurrentWallTime() {
686 return pp::Module::Get()->core()->GetTime();
689 void CdmAdapter::OnResolveNewSessionPromise(uint32_t promise_id
,
690 const char* session_id
,
691 uint32_t session_id_size
) {
692 PostOnMain(callback_factory_
.NewCallback(
693 &CdmAdapter::SendPromiseResolvedWithSessionInternal
, promise_id
,
694 std::string(session_id
, session_id_size
)));
697 void CdmAdapter::OnResolvePromise(uint32_t promise_id
) {
698 PostOnMain(callback_factory_
.NewCallback(
699 &CdmAdapter::SendPromiseResolvedInternal
, promise_id
));
702 void CdmAdapter::OnRejectPromise(uint32_t promise_id
,
704 uint32_t system_code
,
705 const char* error_message
,
706 uint32_t error_message_size
) {
707 // UMA to investigate http://crbug.com/410630
708 // TODO(xhwang): Remove after bug is fixed.
709 if (system_code
== 0x27) {
710 pp::UMAPrivate
uma_interface(this);
711 uma_interface
.HistogramCustomCounts("Media.EME.CdmFileIO.FileSizeKBOnError",
712 last_read_file_size_kb_
,
718 RejectPromise(promise_id
, error
, system_code
,
719 std::string(error_message
, error_message_size
));
722 void CdmAdapter::RejectPromise(uint32_t promise_id
,
724 uint32_t system_code
,
725 const std::string
& error_message
) {
726 PostOnMain(callback_factory_
.NewCallback(
727 &CdmAdapter::SendPromiseRejectedInternal
,
729 SessionError(error
, system_code
, error_message
)));
732 void CdmAdapter::OnSessionMessage(const char* session_id
,
733 uint32_t session_id_size
,
734 cdm::MessageType message_type
,
736 uint32_t message_size
,
737 const char* legacy_destination_url
,
738 uint32_t legacy_destination_url_size
) {
739 // License requests should not specify |legacy_destination_url|.
740 // |legacy_destination_url| is not passed to unprefixed EME applications,
741 // so it can be removed when the prefixed API is removed.
742 PP_DCHECK(legacy_destination_url_size
== 0 ||
743 message_type
!= cdm::MessageType::kLicenseRequest
);
745 PostOnMain(callback_factory_
.NewCallback(
746 &CdmAdapter::SendSessionMessageInternal
,
748 std::string(session_id
, session_id_size
), message_type
, message
,
750 std::string(legacy_destination_url
, legacy_destination_url_size
))));
753 void CdmAdapter::OnSessionKeysChange(const char* session_id
,
754 uint32_t session_id_size
,
755 bool has_additional_usable_key
,
756 const cdm::KeyInformation
* keys_info
,
757 uint32_t keys_info_count
) {
758 std::vector
<PP_KeyInformation
> key_information
;
759 for (uint32_t i
= 0; i
< keys_info_count
; ++i
) {
760 const auto& key_info
= keys_info
[i
];
761 PP_KeyInformation next_key
= {};
763 if (key_info
.key_id_size
> sizeof(next_key
.key_id
)) {
768 // Copy key_id into |next_key|.
769 memcpy(next_key
.key_id
, key_info
.key_id
, key_info
.key_id_size
);
771 // Set remaining fields on |next_key|.
772 next_key
.key_id_size
= key_info
.key_id_size
;
773 next_key
.key_status
= CdmKeyStatusToPpKeyStatus(key_info
.status
);
774 next_key
.system_code
= key_info
.system_code
;
775 key_information
.push_back(next_key
);
778 PostOnMain(callback_factory_
.NewCallback(
779 &CdmAdapter::SendSessionKeysChangeInternal
,
780 std::string(session_id
, session_id_size
), has_additional_usable_key
,
784 void CdmAdapter::OnExpirationChange(const char* session_id
,
785 uint32_t session_id_size
,
786 cdm::Time new_expiry_time
) {
787 PostOnMain(callback_factory_
.NewCallback(
788 &CdmAdapter::SendExpirationChangeInternal
,
789 std::string(session_id
, session_id_size
), new_expiry_time
));
792 void CdmAdapter::OnSessionClosed(const char* session_id
,
793 uint32_t session_id_size
) {
795 callback_factory_
.NewCallback(&CdmAdapter::SendSessionClosedInternal
,
796 std::string(session_id
, session_id_size
)));
799 void CdmAdapter::OnLegacySessionError(const char* session_id
,
800 uint32_t session_id_size
,
802 uint32_t system_code
,
803 const char* error_message
,
804 uint32_t error_message_size
) {
805 PostOnMain(callback_factory_
.NewCallback(
806 &CdmAdapter::SendSessionErrorInternal
,
807 std::string(session_id
, session_id_size
),
808 SessionError(error
, system_code
,
809 std::string(error_message
, error_message_size
))));
812 // Helpers to pass the event to Pepper.
814 void CdmAdapter::SendPromiseResolvedInternal(int32_t result
,
815 uint32_t promise_id
) {
816 PP_DCHECK(result
== PP_OK
);
817 pp::ContentDecryptor_Private::PromiseResolved(promise_id
);
820 void CdmAdapter::SendPromiseResolvedWithSessionInternal(
823 const std::string
& session_id
) {
824 PP_DCHECK(result
== PP_OK
);
825 pp::ContentDecryptor_Private::PromiseResolvedWithSession(promise_id
,
829 void CdmAdapter::SendPromiseRejectedInternal(int32_t result
,
831 const SessionError
& error
) {
832 PP_DCHECK(result
== PP_OK
);
833 pp::ContentDecryptor_Private::PromiseRejected(
835 CdmExceptionTypeToPpCdmExceptionType(error
.error
),
837 error
.error_description
);
840 void CdmAdapter::SendSessionMessageInternal(int32_t result
,
841 const SessionMessage
& message
) {
842 PP_DCHECK(result
== PP_OK
);
844 pp::VarArrayBuffer
message_array_buffer(message
.message
.size());
845 if (message
.message
.size() > 0) {
846 memcpy(message_array_buffer
.Map(), message
.message
.data(),
847 message
.message
.size());
850 pp::ContentDecryptor_Private::SessionMessage(
851 message
.session_id
, CdmMessageTypeToPpMessageType(message
.message_type
),
852 message_array_buffer
, message
.legacy_destination_url
);
855 void CdmAdapter::SendSessionClosedInternal(int32_t result
,
856 const std::string
& session_id
) {
857 PP_DCHECK(result
== PP_OK
);
858 pp::ContentDecryptor_Private::SessionClosed(session_id
);
861 void CdmAdapter::SendSessionErrorInternal(int32_t result
,
862 const std::string
& session_id
,
863 const SessionError
& error
) {
864 PP_DCHECK(result
== PP_OK
);
865 pp::ContentDecryptor_Private::LegacySessionError(
866 session_id
, CdmExceptionTypeToPpCdmExceptionType(error
.error
),
867 error
.system_code
, error
.error_description
);
870 void CdmAdapter::SendSessionKeysChangeInternal(
872 const std::string
& session_id
,
873 bool has_additional_usable_key
,
874 const std::vector
<PP_KeyInformation
>& key_info
) {
875 PP_DCHECK(result
== PP_OK
);
876 pp::ContentDecryptor_Private::SessionKeysChange(
877 session_id
, has_additional_usable_key
, key_info
);
880 void CdmAdapter::SendExpirationChangeInternal(int32_t result
,
881 const std::string
& session_id
,
882 cdm::Time new_expiry_time
) {
883 PP_DCHECK(result
== PP_OK
);
884 pp::ContentDecryptor_Private::SessionExpirationChange(session_id
,
888 void CdmAdapter::DeliverBlock(int32_t result
,
889 const cdm::Status
& status
,
890 const LinkedDecryptedBlock
& decrypted_block
,
891 const PP_DecryptTrackingInfo
& tracking_info
) {
892 PP_DCHECK(result
== PP_OK
);
893 PP_DecryptedBlockInfo decrypted_block_info
= {};
894 decrypted_block_info
.tracking_info
= tracking_info
;
895 decrypted_block_info
.tracking_info
.timestamp
= decrypted_block
->Timestamp();
896 decrypted_block_info
.tracking_info
.buffer_id
= 0;
897 decrypted_block_info
.data_size
= 0;
898 decrypted_block_info
.result
= CdmStatusToPpDecryptResult(status
);
900 pp::Buffer_Dev buffer
;
902 if (decrypted_block_info
.result
== PP_DECRYPTRESULT_SUCCESS
) {
903 PP_DCHECK(decrypted_block
.get() && decrypted_block
->DecryptedBuffer());
904 if (!decrypted_block
.get() || !decrypted_block
->DecryptedBuffer()) {
906 decrypted_block_info
.result
= PP_DECRYPTRESULT_DECRYPT_ERROR
;
908 PpbBuffer
* ppb_buffer
=
909 static_cast<PpbBuffer
*>(decrypted_block
->DecryptedBuffer());
910 decrypted_block_info
.tracking_info
.buffer_id
= ppb_buffer
->buffer_id();
911 decrypted_block_info
.data_size
= ppb_buffer
->Size();
913 buffer
= ppb_buffer
->TakeBuffer();
917 pp::ContentDecryptor_Private::DeliverBlock(buffer
, decrypted_block_info
);
920 void CdmAdapter::DecoderInitializeDone(int32_t result
,
921 PP_DecryptorStreamType decoder_type
,
924 PP_DCHECK(result
== PP_OK
);
925 pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type
,
930 void CdmAdapter::DecoderDeinitializeDone(int32_t result
,
931 PP_DecryptorStreamType decoder_type
,
932 uint32_t request_id
) {
933 pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type
,
937 void CdmAdapter::DecoderResetDone(int32_t result
,
938 PP_DecryptorStreamType decoder_type
,
939 uint32_t request_id
) {
940 pp::ContentDecryptor_Private::DecoderResetDone(decoder_type
, request_id
);
943 void CdmAdapter::DeliverFrame(
945 const cdm::Status
& status
,
946 const LinkedVideoFrame
& video_frame
,
947 const PP_DecryptTrackingInfo
& tracking_info
) {
948 PP_DCHECK(result
== PP_OK
);
949 PP_DecryptedFrameInfo decrypted_frame_info
= {};
950 decrypted_frame_info
.tracking_info
.request_id
= tracking_info
.request_id
;
951 decrypted_frame_info
.tracking_info
.buffer_id
= 0;
952 decrypted_frame_info
.result
= CdmStatusToPpDecryptResult(status
);
954 pp::Buffer_Dev buffer
;
956 if (decrypted_frame_info
.result
== PP_DECRYPTRESULT_SUCCESS
) {
957 if (!IsValidVideoFrame(video_frame
)) {
959 decrypted_frame_info
.result
= PP_DECRYPTRESULT_DECODE_ERROR
;
961 PpbBuffer
* ppb_buffer
=
962 static_cast<PpbBuffer
*>(video_frame
->FrameBuffer());
964 decrypted_frame_info
.tracking_info
.timestamp
= video_frame
->Timestamp();
965 decrypted_frame_info
.tracking_info
.buffer_id
= ppb_buffer
->buffer_id();
966 decrypted_frame_info
.format
=
967 CdmVideoFormatToPpDecryptedFrameFormat(video_frame
->Format());
968 decrypted_frame_info
.width
= video_frame
->Size().width
;
969 decrypted_frame_info
.height
= video_frame
->Size().height
;
970 decrypted_frame_info
.plane_offsets
[PP_DECRYPTEDFRAMEPLANES_Y
] =
971 video_frame
->PlaneOffset(cdm::VideoFrame::kYPlane
);
972 decrypted_frame_info
.plane_offsets
[PP_DECRYPTEDFRAMEPLANES_U
] =
973 video_frame
->PlaneOffset(cdm::VideoFrame::kUPlane
);
974 decrypted_frame_info
.plane_offsets
[PP_DECRYPTEDFRAMEPLANES_V
] =
975 video_frame
->PlaneOffset(cdm::VideoFrame::kVPlane
);
976 decrypted_frame_info
.strides
[PP_DECRYPTEDFRAMEPLANES_Y
] =
977 video_frame
->Stride(cdm::VideoFrame::kYPlane
);
978 decrypted_frame_info
.strides
[PP_DECRYPTEDFRAMEPLANES_U
] =
979 video_frame
->Stride(cdm::VideoFrame::kUPlane
);
980 decrypted_frame_info
.strides
[PP_DECRYPTEDFRAMEPLANES_V
] =
981 video_frame
->Stride(cdm::VideoFrame::kVPlane
);
983 buffer
= ppb_buffer
->TakeBuffer();
987 pp::ContentDecryptor_Private::DeliverFrame(buffer
, decrypted_frame_info
);
990 void CdmAdapter::DeliverSamples(int32_t result
,
991 const cdm::Status
& status
,
992 const LinkedAudioFrames
& audio_frames
,
993 const PP_DecryptTrackingInfo
& tracking_info
) {
994 PP_DCHECK(result
== PP_OK
);
996 PP_DecryptedSampleInfo decrypted_sample_info
= {};
997 decrypted_sample_info
.tracking_info
= tracking_info
;
998 decrypted_sample_info
.tracking_info
.timestamp
= 0;
999 decrypted_sample_info
.tracking_info
.buffer_id
= 0;
1000 decrypted_sample_info
.data_size
= 0;
1001 decrypted_sample_info
.result
= CdmStatusToPpDecryptResult(status
);
1003 pp::Buffer_Dev buffer
;
1005 if (decrypted_sample_info
.result
== PP_DECRYPTRESULT_SUCCESS
) {
1006 PP_DCHECK(audio_frames
.get() && audio_frames
->FrameBuffer());
1007 if (!audio_frames
.get() || !audio_frames
->FrameBuffer()) {
1009 decrypted_sample_info
.result
= PP_DECRYPTRESULT_DECRYPT_ERROR
;
1011 PpbBuffer
* ppb_buffer
=
1012 static_cast<PpbBuffer
*>(audio_frames
->FrameBuffer());
1014 decrypted_sample_info
.tracking_info
.buffer_id
= ppb_buffer
->buffer_id();
1015 decrypted_sample_info
.data_size
= ppb_buffer
->Size();
1016 decrypted_sample_info
.format
=
1017 CdmAudioFormatToPpDecryptedSampleFormat(audio_frames
->Format());
1019 buffer
= ppb_buffer
->TakeBuffer();
1023 pp::ContentDecryptor_Private::DeliverSamples(buffer
, decrypted_sample_info
);
1026 bool CdmAdapter::IsValidVideoFrame(const LinkedVideoFrame
& video_frame
) {
1027 if (!video_frame
.get() ||
1028 !video_frame
->FrameBuffer() ||
1029 (video_frame
->Format() != cdm::kI420
&&
1030 video_frame
->Format() != cdm::kYv12
)) {
1031 CDM_DLOG() << "Invalid video frame!";
1035 PpbBuffer
* ppb_buffer
= static_cast<PpbBuffer
*>(video_frame
->FrameBuffer());
1037 for (uint32_t i
= 0; i
< cdm::VideoFrame::kMaxPlanes
; ++i
) {
1038 int plane_height
= (i
== cdm::VideoFrame::kYPlane
) ?
1039 video_frame
->Size().height
: (video_frame
->Size().height
+ 1) / 2;
1040 cdm::VideoFrame::VideoPlane plane
=
1041 static_cast<cdm::VideoFrame::VideoPlane
>(i
);
1042 if (ppb_buffer
->Size() < video_frame
->PlaneOffset(plane
) +
1043 plane_height
* video_frame
->Stride(plane
)) {
1051 void CdmAdapter::OnFirstFileRead(int32_t file_size_bytes
) {
1052 PP_DCHECK(IsMainThread());
1053 PP_DCHECK(file_size_bytes
>= 0);
1055 last_read_file_size_kb_
= file_size_bytes
/ 1024;
1057 if (file_size_uma_reported_
)
1060 pp::UMAPrivate
uma_interface(this);
1061 uma_interface
.HistogramCustomCounts(
1062 "Media.EME.CdmFileIO.FileSizeKBOnFirstRead",
1063 last_read_file_size_kb_
,
1067 file_size_uma_reported_
= true;
1070 #if !defined(NDEBUG)
1071 void CdmAdapter::LogToConsole(const pp::Var
& value
) {
1072 PP_DCHECK(IsMainThread());
1073 const PPB_Console
* console
= reinterpret_cast<const PPB_Console
*>(
1074 pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE
));
1075 console
->Log(pp_instance(), PP_LOGLEVEL_LOG
, value
.pp_var());
1077 #endif // !defined(NDEBUG)
1079 void CdmAdapter::SendPlatformChallenge(const char* service_id
,
1080 uint32_t service_id_size
,
1081 const char* challenge
,
1082 uint32_t challenge_size
) {
1083 #if defined(OS_CHROMEOS)
1084 // If access to a distinctive identifier is not allowed, block platform
1085 // verification to prevent access to such an identifier.
1086 if (allow_distinctive_identifier_
) {
1087 pp::VarArrayBuffer
challenge_var(challenge_size
);
1088 uint8_t* var_data
= static_cast<uint8_t*>(challenge_var
.Map());
1089 memcpy(var_data
, challenge
, challenge_size
);
1091 std::string
service_id_str(service_id
, service_id_size
);
1093 linked_ptr
<PepperPlatformChallengeResponse
> response(
1094 new PepperPlatformChallengeResponse());
1096 int32_t result
= platform_verification_
.ChallengePlatform(
1097 pp::Var(service_id_str
),
1099 &response
->signed_data
,
1100 &response
->signed_data_signature
,
1101 &response
->platform_key_certificate
,
1102 callback_factory_
.NewCallback(&CdmAdapter::SendPlatformChallengeDone
,
1104 challenge_var
.Unmap();
1105 if (result
== PP_OK_COMPLETIONPENDING
)
1108 // Fall through on error and issue an empty OnPlatformChallengeResponse().
1109 PP_DCHECK(result
!= PP_OK
);
1113 cdm::PlatformChallengeResponse platform_challenge_response
= {};
1114 cdm_
->OnPlatformChallengeResponse(platform_challenge_response
);
1117 void CdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask
) {
1118 #if defined(OS_CHROMEOS)
1119 int32_t result
= output_protection_
.EnableProtection(
1120 desired_protection_mask
, callback_factory_
.NewCallback(
1121 &CdmAdapter::EnableProtectionDone
));
1123 // Errors are ignored since clients must call QueryOutputProtectionStatus() to
1124 // inspect the protection status on a regular basis.
1126 if (result
!= PP_OK
&& result
!= PP_OK_COMPLETIONPENDING
)
1127 CDM_DLOG() << __FUNCTION__
<< " failed!";
1131 void CdmAdapter::QueryOutputProtectionStatus() {
1132 #if defined(OS_CHROMEOS)
1133 PP_DCHECK(!query_output_protection_in_progress_
);
1135 output_link_mask_
= output_protection_mask_
= 0;
1136 const int32_t result
= output_protection_
.QueryStatus(
1138 &output_protection_mask_
,
1139 callback_factory_
.NewCallback(
1140 &CdmAdapter::QueryOutputProtectionStatusDone
));
1141 if (result
== PP_OK_COMPLETIONPENDING
) {
1142 query_output_protection_in_progress_
= true;
1143 ReportOutputProtectionQuery();
1147 // Fall through on error and issue an empty OnQueryOutputProtectionStatus().
1148 PP_DCHECK(result
!= PP_OK
);
1149 CDM_DLOG() << __FUNCTION__
<< " failed, result = " << result
;
1151 cdm_
->OnQueryOutputProtectionStatus(cdm::kQueryFailed
, 0, 0);
1154 void CdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type
,
1155 cdm::Status decoder_status
) {
1156 switch (stream_type
) {
1157 case cdm::kStreamTypeAudio
:
1158 PP_DCHECK(deferred_initialize_audio_decoder_
);
1160 callback_factory_
.NewCallback(&CdmAdapter::DecoderInitializeDone
,
1161 PP_DECRYPTORSTREAMTYPE_AUDIO
,
1162 deferred_audio_decoder_config_id_
,
1163 decoder_status
== cdm::kSuccess
));
1164 deferred_initialize_audio_decoder_
= false;
1165 deferred_audio_decoder_config_id_
= 0;
1167 case cdm::kStreamTypeVideo
:
1168 PP_DCHECK(deferred_initialize_video_decoder_
);
1170 callback_factory_
.NewCallback(&CdmAdapter::DecoderInitializeDone
,
1171 PP_DECRYPTORSTREAMTYPE_VIDEO
,
1172 deferred_video_decoder_config_id_
,
1173 decoder_status
== cdm::kSuccess
));
1174 deferred_initialize_video_decoder_
= false;
1175 deferred_video_decoder_config_id_
= 0;
1180 // The CDM owns the returned object and must call FileIO::Close() to release it.
1181 cdm::FileIO
* CdmAdapter::CreateFileIO(cdm::FileIOClient
* client
) {
1182 if (!allow_persistent_state_
) {
1184 << "Cannot create FileIO because persistent state is not allowed.";
1188 return new CdmFileIOImpl(
1189 client
, pp_instance(),
1190 callback_factory_
.NewCallback(&CdmAdapter::OnFirstFileRead
));
1193 #if defined(OS_CHROMEOS)
1194 void CdmAdapter::ReportOutputProtectionUMA(OutputProtectionStatus status
) {
1195 pp::UMAPrivate
uma_interface(this);
1196 uma_interface
.HistogramEnumeration(
1197 "Media.EME.OutputProtection", status
, OUTPUT_PROTECTION_MAX
);
1200 void CdmAdapter::ReportOutputProtectionQuery() {
1201 if (uma_for_output_protection_query_reported_
)
1204 ReportOutputProtectionUMA(OUTPUT_PROTECTION_QUERIED
);
1205 uma_for_output_protection_query_reported_
= true;
1208 void CdmAdapter::ReportOutputProtectionQueryResult() {
1209 if (uma_for_output_protection_positive_result_reported_
)
1212 // Report UMAs for output protection query result.
1213 uint32_t external_links
= (output_link_mask_
& ~cdm::kLinkTypeInternal
);
1215 if (!external_links
) {
1216 ReportOutputProtectionUMA(OUTPUT_PROTECTION_NO_EXTERNAL_LINK
);
1217 uma_for_output_protection_positive_result_reported_
= true;
1221 const uint32_t kProtectableLinks
=
1222 cdm::kLinkTypeHDMI
| cdm::kLinkTypeDVI
| cdm::kLinkTypeDisplayPort
;
1223 bool is_unprotectable_link_connected
= external_links
& ~kProtectableLinks
;
1224 bool is_hdcp_enabled_on_all_protectable_links
=
1225 output_protection_mask_
& cdm::kProtectionHDCP
;
1227 if (!is_unprotectable_link_connected
&&
1228 is_hdcp_enabled_on_all_protectable_links
) {
1229 ReportOutputProtectionUMA(
1230 OUTPUT_PROTECTION_ALL_EXTERNAL_LINKS_PROTECTED
);
1231 uma_for_output_protection_positive_result_reported_
= true;
1235 // Do not report a negative result because it could be a false negative.
1236 // Instead, we will calculate number of negatives using the total number of
1237 // queries and success results.
1240 void CdmAdapter::SendPlatformChallengeDone(
1242 const linked_ptr
<PepperPlatformChallengeResponse
>& response
) {
1243 if (result
!= PP_OK
) {
1244 CDM_DLOG() << __FUNCTION__
<< ": Platform challenge failed!";
1245 cdm::PlatformChallengeResponse platform_challenge_response
= {};
1246 cdm_
->OnPlatformChallengeResponse(platform_challenge_response
);
1250 pp::VarArrayBuffer
signed_data_var(response
->signed_data
);
1251 pp::VarArrayBuffer
signed_data_signature_var(response
->signed_data_signature
);
1252 std::string platform_key_certificate_string
=
1253 response
->platform_key_certificate
.AsString();
1255 cdm::PlatformChallengeResponse platform_challenge_response
= {
1256 static_cast<uint8_t*>(signed_data_var
.Map()),
1257 signed_data_var
.ByteLength(),
1258 static_cast<uint8_t*>(signed_data_signature_var
.Map()),
1259 signed_data_signature_var
.ByteLength(),
1260 reinterpret_cast<const uint8_t*>(platform_key_certificate_string
.data()),
1261 static_cast<uint32_t>(platform_key_certificate_string
.length())};
1262 cdm_
->OnPlatformChallengeResponse(platform_challenge_response
);
1264 signed_data_var
.Unmap();
1265 signed_data_signature_var
.Unmap();
1268 void CdmAdapter::EnableProtectionDone(int32_t result
) {
1269 // Does nothing since clients must call QueryOutputProtectionStatus() to
1270 // inspect the protection status on a regular basis.
1271 CDM_DLOG() << __FUNCTION__
<< " : " << result
;
1274 void CdmAdapter::QueryOutputProtectionStatusDone(int32_t result
) {
1275 PP_DCHECK(query_output_protection_in_progress_
);
1276 query_output_protection_in_progress_
= false;
1278 // Return a query status of failed on error.
1279 cdm::QueryResult query_result
;
1280 if (result
!= PP_OK
) {
1281 CDM_DLOG() << __FUNCTION__
<< " failed, result = " << result
;
1282 output_link_mask_
= output_protection_mask_
= 0;
1283 query_result
= cdm::kQueryFailed
;
1285 query_result
= cdm::kQuerySucceeded
;
1286 ReportOutputProtectionQueryResult();
1289 cdm_
->OnQueryOutputProtectionStatus(query_result
, output_link_mask_
,
1290 output_protection_mask_
);
1294 CdmAdapter::SessionError::SessionError(cdm::Error error
,
1295 uint32_t system_code
,
1296 const std::string
& error_description
)
1298 system_code(system_code
),
1299 error_description(error_description
) {
1302 CdmAdapter::SessionMessage::SessionMessage(
1303 const std::string
& session_id
,
1304 cdm::MessageType message_type
,
1305 const char* message
,
1306 uint32_t message_size
,
1307 const std::string
& legacy_destination_url
)
1308 : session_id(session_id
),
1309 message_type(message_type
),
1310 message(message
, message
+ message_size
),
1311 legacy_destination_url(legacy_destination_url
) {
1314 void* GetCdmHost(int host_interface_version
, void* user_data
) {
1315 if (!host_interface_version
|| !user_data
)
1319 cdm::ContentDecryptionModule::Host::kVersion
== cdm::Host_8::kVersion
,
1320 "update the code below");
1322 // Ensure IsSupportedCdmHostVersion matches implementation of this function.
1323 // Always update this DCHECK when updating this function.
1324 // If this check fails, update this function and DCHECK or update
1325 // IsSupportedCdmHostVersion.
1328 // Future version is not supported.
1329 !IsSupportedCdmHostVersion(cdm::Host_8::kVersion
+ 1) &&
1330 // Current version is supported.
1331 IsSupportedCdmHostVersion(cdm::Host_8::kVersion
) &&
1332 // Include all previous supported versions (if any) here.
1333 IsSupportedCdmHostVersion(cdm::Host_7::kVersion
) &&
1334 // One older than the oldest supported version is not supported.
1335 !IsSupportedCdmHostVersion(cdm::Host_7::kVersion
- 1));
1336 PP_DCHECK(IsSupportedCdmHostVersion(host_interface_version
));
1338 CdmAdapter
* cdm_adapter
= static_cast<CdmAdapter
*>(user_data
);
1339 CDM_DLOG() << "Create CDM Host with version " << host_interface_version
;
1340 switch (host_interface_version
) {
1341 case cdm::Host_8::kVersion
:
1342 return static_cast<cdm::Host_8
*>(cdm_adapter
);
1343 case cdm::Host_7::kVersion
:
1344 return static_cast<cdm::Host_7
*>(cdm_adapter
);
1351 // This object is the global object representing this plugin library as long
1353 class CdmAdapterModule
: public pp::Module
{
1355 CdmAdapterModule() : pp::Module() {
1356 // This function blocks the renderer thread (PluginInstance::Initialize()).
1357 // Move this call to other places if this may be a concern in the future.
1358 INITIALIZE_CDM_MODULE();
1360 virtual ~CdmAdapterModule() {
1361 DeinitializeCdmModule();
1364 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
1365 return new CdmAdapter(instance
, this);
1369 CdmFileIOImpl::ResourceTracker cdm_file_io_impl_resource_tracker
;
1372 } // namespace media
1376 // Factory function for your specialization of the Module object.
1377 Module
* CreateModule() {
1378 return new media::CdmAdapterModule();