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/cdm/ppapi/cdm_file_io_impl.h"
8 #include "media/cdm/ppapi/cdm_helpers.h"
9 #include "media/cdm/ppapi/cdm_logging.h"
10 #include "media/cdm/ppapi/supported_cdm_versions.h"
11 #include "ppapi/c/ppb_console.h"
12 #include "ppapi/cpp/private/uma_private.h"
14 #if defined(CHECK_DOCUMENT_URL)
15 #include "ppapi/cpp/dev/url_util_dev.h"
16 #include "ppapi/cpp/instance_handle.h"
17 #endif // defined(CHECK_DOCUMENT_URL)
22 #define DLOG_TO_CONSOLE(message) LogToConsole(message);
24 #define DLOG_TO_CONSOLE(message) (void)(message);
28 return pp::Module::Get()->core()->IsMainThread();
31 // Posts a task to run |cb| on the main thread. The task is posted even if the
32 // current thread is the main thread.
33 void PostOnMain(pp::CompletionCallback cb) {
34 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK);
37 // Ensures |cb| is called on the main thread, either because the current thread
38 // is the main thread or by posting it to the main thread.
39 void CallOnMain(pp::CompletionCallback cb) {
40 // TODO(tomfinegan): This is only necessary because PPAPI doesn't allow calls
41 // off the main thread yet. Remove this once the change lands.
48 // Configures a cdm::InputBuffer. |subsamples| must exist as long as
49 // |input_buffer| is in use.
50 void ConfigureInputBuffer(
51 const pp::Buffer_Dev& encrypted_buffer,
52 const PP_EncryptedBlockInfo& encrypted_block_info,
53 std::vector<cdm::SubsampleEntry>* subsamples,
54 cdm::InputBuffer* input_buffer) {
55 PP_DCHECK(subsamples);
56 PP_DCHECK(!encrypted_buffer.is_null());
58 input_buffer->data = static_cast<uint8_t*>(encrypted_buffer.data());
59 input_buffer->data_size = encrypted_block_info.data_size;
60 PP_DCHECK(encrypted_buffer.size() >= input_buffer->data_size);
62 PP_DCHECK(encrypted_block_info.key_id_size <=
63 arraysize(encrypted_block_info.key_id));
64 input_buffer->key_id_size = encrypted_block_info.key_id_size;
65 input_buffer->key_id = input_buffer->key_id_size > 0 ?
66 encrypted_block_info.key_id : NULL;
68 PP_DCHECK(encrypted_block_info.iv_size <= arraysize(encrypted_block_info.iv));
69 input_buffer->iv_size = encrypted_block_info.iv_size;
70 input_buffer->iv = encrypted_block_info.iv_size > 0 ?
71 encrypted_block_info.iv : NULL;
73 input_buffer->num_subsamples = encrypted_block_info.num_subsamples;
74 if (encrypted_block_info.num_subsamples > 0) {
75 subsamples->reserve(encrypted_block_info.num_subsamples);
77 for (uint32_t i = 0; i < encrypted_block_info.num_subsamples; ++i) {
78 subsamples->push_back(cdm::SubsampleEntry(
79 encrypted_block_info.subsamples[i].clear_bytes,
80 encrypted_block_info.subsamples[i].cipher_bytes));
83 input_buffer->subsamples = &(*subsamples)[0];
86 input_buffer->timestamp = encrypted_block_info.tracking_info.timestamp;
89 PP_DecryptResult CdmStatusToPpDecryptResult(cdm::Status status) {
92 return PP_DECRYPTRESULT_SUCCESS;
94 return PP_DECRYPTRESULT_DECRYPT_NOKEY;
95 case cdm::kNeedMoreData:
96 return PP_DECRYPTRESULT_NEEDMOREDATA;
97 case cdm::kDecryptError:
98 return PP_DECRYPTRESULT_DECRYPT_ERROR;
99 case cdm::kDecodeError:
100 return PP_DECRYPTRESULT_DECODE_ERROR;
103 return PP_DECRYPTRESULT_DECODE_ERROR;
107 PP_DecryptedFrameFormat CdmVideoFormatToPpDecryptedFrameFormat(
108 cdm::VideoFormat format) {
111 return PP_DECRYPTEDFRAMEFORMAT_YV12;
113 return PP_DECRYPTEDFRAMEFORMAT_I420;
115 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
119 PP_DecryptedSampleFormat CdmAudioFormatToPpDecryptedSampleFormat(
120 cdm::AudioFormat format) {
122 case cdm::kAudioFormatU8:
123 return PP_DECRYPTEDSAMPLEFORMAT_U8;
124 case cdm::kAudioFormatS16:
125 return PP_DECRYPTEDSAMPLEFORMAT_S16;
126 case cdm::kAudioFormatS32:
127 return PP_DECRYPTEDSAMPLEFORMAT_S32;
128 case cdm::kAudioFormatF32:
129 return PP_DECRYPTEDSAMPLEFORMAT_F32;
130 case cdm::kAudioFormatPlanarS16:
131 return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16;
132 case cdm::kAudioFormatPlanarF32:
133 return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32;
135 return PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN;
139 cdm::AudioDecoderConfig::AudioCodec PpAudioCodecToCdmAudioCodec(
140 PP_AudioCodec codec) {
142 case PP_AUDIOCODEC_VORBIS:
143 return cdm::AudioDecoderConfig::kCodecVorbis;
144 case PP_AUDIOCODEC_AAC:
145 return cdm::AudioDecoderConfig::kCodecAac;
147 return cdm::AudioDecoderConfig::kUnknownAudioCodec;
151 cdm::VideoDecoderConfig::VideoCodec PpVideoCodecToCdmVideoCodec(
152 PP_VideoCodec codec) {
154 case PP_VIDEOCODEC_VP8:
155 return cdm::VideoDecoderConfig::kCodecVp8;
156 case PP_VIDEOCODEC_H264:
157 return cdm::VideoDecoderConfig::kCodecH264;
158 case PP_VIDEOCODEC_VP9:
159 return cdm::VideoDecoderConfig::kCodecVp9;
161 return cdm::VideoDecoderConfig::kUnknownVideoCodec;
165 cdm::VideoDecoderConfig::VideoCodecProfile PpVCProfileToCdmVCProfile(
166 PP_VideoCodecProfile profile) {
168 case PP_VIDEOCODECPROFILE_NOT_NEEDED:
169 return cdm::VideoDecoderConfig::kProfileNotNeeded;
170 case PP_VIDEOCODECPROFILE_H264_BASELINE:
171 return cdm::VideoDecoderConfig::kH264ProfileBaseline;
172 case PP_VIDEOCODECPROFILE_H264_MAIN:
173 return cdm::VideoDecoderConfig::kH264ProfileMain;
174 case PP_VIDEOCODECPROFILE_H264_EXTENDED:
175 return cdm::VideoDecoderConfig::kH264ProfileExtended;
176 case PP_VIDEOCODECPROFILE_H264_HIGH:
177 return cdm::VideoDecoderConfig::kH264ProfileHigh;
178 case PP_VIDEOCODECPROFILE_H264_HIGH_10:
179 return cdm::VideoDecoderConfig::kH264ProfileHigh10;
180 case PP_VIDEOCODECPROFILE_H264_HIGH_422:
181 return cdm::VideoDecoderConfig::kH264ProfileHigh422;
182 case PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE:
183 return cdm::VideoDecoderConfig::kH264ProfileHigh444Predictive;
185 return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile;
189 cdm::VideoFormat PpDecryptedFrameFormatToCdmVideoFormat(
190 PP_DecryptedFrameFormat format) {
192 case PP_DECRYPTEDFRAMEFORMAT_YV12:
194 case PP_DECRYPTEDFRAMEFORMAT_I420:
197 return cdm::kUnknownVideoFormat;
201 cdm::StreamType PpDecryptorStreamTypeToCdmStreamType(
202 PP_DecryptorStreamType stream_type) {
203 switch (stream_type) {
204 case PP_DECRYPTORSTREAMTYPE_AUDIO:
205 return cdm::kStreamTypeAudio;
206 case PP_DECRYPTORSTREAMTYPE_VIDEO:
207 return cdm::kStreamTypeVideo;
211 return cdm::kStreamTypeVideo;
214 cdm::SessionType PpSessionTypeToCdmSessionType(PP_SessionType session_type) {
215 switch (session_type) {
216 case PP_SESSIONTYPE_TEMPORARY:
217 return cdm::kTemporary;
218 case PP_SESSIONTYPE_PERSISTENT:
219 return cdm::kPersistent;
222 return cdm::kTemporary;
226 PP_CdmExceptionCode CdmExceptionTypeToPpCdmExceptionType(cdm::Error error) {
228 case cdm::kNotSupportedError:
229 return PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR;
230 case cdm::kInvalidStateError:
231 return PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR;
232 case cdm::kInvalidAccessError:
233 return PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR;
234 case cdm::kQuotaExceededError:
235 return PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR;
236 case cdm::kUnknownError:
237 return PP_CDMEXCEPTIONCODE_UNKNOWNERROR;
238 case cdm::kClientError:
239 return PP_CDMEXCEPTIONCODE_CLIENTERROR;
240 case cdm::kOutputError:
241 return PP_CDMEXCEPTIONCODE_OUTPUTERROR;
244 return PP_CDMEXCEPTIONCODE_UNKNOWNERROR;
252 CdmAdapter::CdmAdapter(PP_Instance instance, pp::Module* module)
253 : pp::Instance(instance),
254 pp::ContentDecryptor_Private(this),
255 #if defined(OS_CHROMEOS)
256 output_protection_(this),
257 platform_verification_(this),
258 output_link_mask_(0),
259 output_protection_mask_(0),
260 query_output_protection_in_progress_(false),
261 uma_for_output_protection_query_reported_(false),
262 uma_for_output_protection_positive_result_reported_(false),
266 deferred_initialize_audio_decoder_(false),
267 deferred_audio_decoder_config_id_(0),
268 deferred_initialize_video_decoder_(false),
269 deferred_video_decoder_config_id_(0) {
270 callback_factory_.Initialize(this);
273 CdmAdapter::~CdmAdapter() {}
275 bool CdmAdapter::CreateCdmInstance(const std::string& key_system) {
277 cdm_ = make_linked_ptr(CdmWrapper::Create(
278 key_system.data(), key_system.size(), GetCdmHost, this));
279 bool success = cdm_ != NULL;
281 const std::string message = "CDM instance for " + key_system +
282 (success ? "" : " could not be") + " created.";
283 DLOG_TO_CONSOLE(message);
284 CDM_DLOG() << message;
289 // No errors should be reported in this function because the spec says:
290 // "Store this new error object internally with the MediaKeys instance being
291 // created. This will be used to fire an error against any session created for
292 // this instance." These errors will be reported during session creation
293 // (CreateSession()) or session loading (LoadSession()).
294 // TODO(xhwang): If necessary, we need to store the error here if we want to
295 // support more specific error reporting (other than "Unknown").
296 void CdmAdapter::Initialize(const std::string& key_system) {
297 PP_DCHECK(!key_system.empty());
298 PP_DCHECK(key_system_.empty() || (key_system_ == key_system && cdm_));
300 #if defined(CHECK_DOCUMENT_URL)
301 PP_URLComponents_Dev url_components = {};
302 const pp::URLUtil_Dev* url_util = pp::URLUtil_Dev::Get();
305 pp::Var href = url_util->GetDocumentURL(pp::InstanceHandle(pp_instance()),
307 PP_DCHECK(href.is_string());
308 std::string url = href.AsString();
309 PP_DCHECK(!url.empty());
310 std::string url_scheme =
311 url.substr(url_components.scheme.begin, url_components.scheme.len);
312 if (url_scheme != "file") {
313 // Skip this check for file:// URLs as they don't have a host component.
314 PP_DCHECK(url_components.host.begin);
315 PP_DCHECK(0 < url_components.host.len);
317 #endif // defined(CHECK_DOCUMENT_URL)
319 if (!cdm_ && !CreateCdmInstance(key_system))
323 key_system_ = key_system;
326 void CdmAdapter::CreateSession(uint32_t promise_id,
327 const std::string& init_data_type,
328 pp::VarArrayBuffer init_data,
329 PP_SessionType session_type) {
330 // Initialize() doesn't report an error, so CreateSession() can be called
331 // even if Initialize() failed.
332 // TODO(jrummell): Remove this code when prefixed EME gets removed.
333 // TODO(jrummell): Verify that Initialize() failing does not resolve the
334 // MediaKeys.create() promise.
336 RejectPromise(promise_id,
337 cdm::kInvalidStateError,
339 "CDM has not been initialized.");
343 cdm_->CreateSession(promise_id,
344 init_data_type.data(),
345 init_data_type.size(),
346 static_cast<const uint8_t*>(init_data.Map()),
347 init_data.ByteLength(),
348 PpSessionTypeToCdmSessionType(session_type));
351 void CdmAdapter::LoadSession(uint32_t promise_id,
352 const std::string& web_session_id) {
353 // Initialize() doesn't report an error, so LoadSession() can be called
354 // even if Initialize() failed.
355 // TODO(jrummell): Remove this code when prefixed EME gets removed.
356 // TODO(jrummell): Verify that Initialize() failing does not resolve the
357 // MediaKeys.create() promise.
359 RejectPromise(promise_id,
360 cdm::kInvalidStateError,
362 "CDM has not been initialized.");
366 cdm_->LoadSession(promise_id, web_session_id.data(), web_session_id.size());
369 void CdmAdapter::UpdateSession(uint32_t promise_id,
370 const std::string& web_session_id,
371 pp::VarArrayBuffer response) {
372 const uint8_t* response_ptr = static_cast<const uint8_t*>(response.Map());
373 const uint32_t response_size = response.ByteLength();
375 PP_DCHECK(!web_session_id.empty());
376 PP_DCHECK(response_ptr);
377 PP_DCHECK(response_size > 0);
379 cdm_->UpdateSession(promise_id,
380 web_session_id.data(),
381 web_session_id.length(),
386 void CdmAdapter::CloseSession(uint32_t promise_id,
387 const std::string& web_session_id) {
388 if (!cdm_->CloseSession(
389 promise_id, web_session_id.data(), web_session_id.length())) {
390 // CDM_4 and CDM_5 don't support this method, so reject the promise.
391 RejectPromise(promise_id, cdm::kNotSupportedError, 0, "Not implemented.");
395 void CdmAdapter::ReleaseSession(uint32_t promise_id,
396 const std::string& web_session_id) {
398 promise_id, web_session_id.data(), web_session_id.length());
401 void CdmAdapter::GetUsableKeyIds(uint32_t promise_id,
402 const std::string& web_session_id) {
403 if (!cdm_->GetUsableKeyIds(
404 promise_id, web_session_id.data(), web_session_id.length())) {
405 // CDM_4 and CDM_5 don't support this method, so reject the promise.
406 RejectPromise(promise_id, cdm::kNotSupportedError, 0, "Not implemented.");
410 // Note: In the following decryption/decoding related functions, errors are NOT
411 // reported via KeyError, but are reported via corresponding PPB calls.
413 void CdmAdapter::Decrypt(pp::Buffer_Dev encrypted_buffer,
414 const PP_EncryptedBlockInfo& encrypted_block_info) {
415 PP_DCHECK(!encrypted_buffer.is_null());
417 // Release a buffer that the caller indicated it is finished with.
418 allocator_.Release(encrypted_block_info.tracking_info.buffer_id);
420 cdm::Status status = cdm::kDecryptError;
421 LinkedDecryptedBlock decrypted_block(new DecryptedBlockImpl());
424 cdm::InputBuffer input_buffer;
425 std::vector<cdm::SubsampleEntry> subsamples;
426 ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples,
428 status = cdm_->Decrypt(input_buffer, decrypted_block.get());
429 PP_DCHECK(status != cdm::kSuccess ||
430 (decrypted_block->DecryptedBuffer() &&
431 decrypted_block->DecryptedBuffer()->Size()));
434 CallOnMain(callback_factory_.NewCallback(
435 &CdmAdapter::DeliverBlock,
438 encrypted_block_info.tracking_info));
441 void CdmAdapter::InitializeAudioDecoder(
442 const PP_AudioDecoderConfig& decoder_config,
443 pp::Buffer_Dev extra_data_buffer) {
444 PP_DCHECK(!deferred_initialize_audio_decoder_);
445 PP_DCHECK(deferred_audio_decoder_config_id_ == 0);
446 cdm::Status status = cdm::kSessionError;
448 cdm::AudioDecoderConfig cdm_decoder_config;
449 cdm_decoder_config.codec =
450 PpAudioCodecToCdmAudioCodec(decoder_config.codec);
451 cdm_decoder_config.channel_count = decoder_config.channel_count;
452 cdm_decoder_config.bits_per_channel = decoder_config.bits_per_channel;
453 cdm_decoder_config.samples_per_second = decoder_config.samples_per_second;
454 cdm_decoder_config.extra_data =
455 static_cast<uint8_t*>(extra_data_buffer.data());
456 cdm_decoder_config.extra_data_size = extra_data_buffer.size();
457 status = cdm_->InitializeAudioDecoder(cdm_decoder_config);
460 if (status == cdm::kDeferredInitialization) {
461 deferred_initialize_audio_decoder_ = true;
462 deferred_audio_decoder_config_id_ = decoder_config.request_id;
466 CallOnMain(callback_factory_.NewCallback(
467 &CdmAdapter::DecoderInitializeDone,
468 PP_DECRYPTORSTREAMTYPE_AUDIO,
469 decoder_config.request_id,
470 status == cdm::kSuccess));
473 void CdmAdapter::InitializeVideoDecoder(
474 const PP_VideoDecoderConfig& decoder_config,
475 pp::Buffer_Dev extra_data_buffer) {
476 PP_DCHECK(!deferred_initialize_video_decoder_);
477 PP_DCHECK(deferred_video_decoder_config_id_ == 0);
478 cdm::Status status = cdm::kSessionError;
480 cdm::VideoDecoderConfig cdm_decoder_config;
481 cdm_decoder_config.codec =
482 PpVideoCodecToCdmVideoCodec(decoder_config.codec);
483 cdm_decoder_config.profile =
484 PpVCProfileToCdmVCProfile(decoder_config.profile);
485 cdm_decoder_config.format =
486 PpDecryptedFrameFormatToCdmVideoFormat(decoder_config.format);
487 cdm_decoder_config.coded_size.width = decoder_config.width;
488 cdm_decoder_config.coded_size.height = decoder_config.height;
489 cdm_decoder_config.extra_data =
490 static_cast<uint8_t*>(extra_data_buffer.data());
491 cdm_decoder_config.extra_data_size = extra_data_buffer.size();
492 status = cdm_->InitializeVideoDecoder(cdm_decoder_config);
495 if (status == cdm::kDeferredInitialization) {
496 deferred_initialize_video_decoder_ = true;
497 deferred_video_decoder_config_id_ = decoder_config.request_id;
501 CallOnMain(callback_factory_.NewCallback(
502 &CdmAdapter::DecoderInitializeDone,
503 PP_DECRYPTORSTREAMTYPE_VIDEO,
504 decoder_config.request_id,
505 status == cdm::kSuccess));
508 void CdmAdapter::DeinitializeDecoder(PP_DecryptorStreamType decoder_type,
509 uint32_t request_id) {
510 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded.
512 cdm_->DeinitializeDecoder(
513 PpDecryptorStreamTypeToCdmStreamType(decoder_type));
516 CallOnMain(callback_factory_.NewCallback(
517 &CdmAdapter::DecoderDeinitializeDone,
522 void CdmAdapter::ResetDecoder(PP_DecryptorStreamType decoder_type,
523 uint32_t request_id) {
524 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded.
526 cdm_->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type));
528 CallOnMain(callback_factory_.NewCallback(&CdmAdapter::DecoderResetDone,
533 void CdmAdapter::DecryptAndDecode(
534 PP_DecryptorStreamType decoder_type,
535 pp::Buffer_Dev encrypted_buffer,
536 const PP_EncryptedBlockInfo& encrypted_block_info) {
537 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded.
538 // Release a buffer that the caller indicated it is finished with.
539 allocator_.Release(encrypted_block_info.tracking_info.buffer_id);
541 cdm::InputBuffer input_buffer;
542 std::vector<cdm::SubsampleEntry> subsamples;
543 if (cdm_ && !encrypted_buffer.is_null()) {
544 ConfigureInputBuffer(encrypted_buffer,
545 encrypted_block_info,
550 cdm::Status status = cdm::kDecodeError;
552 switch (decoder_type) {
553 case PP_DECRYPTORSTREAMTYPE_VIDEO: {
554 LinkedVideoFrame video_frame(new VideoFrameImpl());
556 status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get());
557 CallOnMain(callback_factory_.NewCallback(
558 &CdmAdapter::DeliverFrame,
561 encrypted_block_info.tracking_info));
565 case PP_DECRYPTORSTREAMTYPE_AUDIO: {
566 LinkedAudioFrames audio_frames(new AudioFramesImpl());
568 status = cdm_->DecryptAndDecodeSamples(input_buffer,
571 CallOnMain(callback_factory_.NewCallback(
572 &CdmAdapter::DeliverSamples,
575 encrypted_block_info.tracking_info));
585 cdm::Buffer* CdmAdapter::Allocate(uint32_t capacity) {
586 return allocator_.Allocate(capacity);
589 void CdmAdapter::SetTimer(int64_t delay_ms, void* context) {
590 // NOTE: doesn't really need to run on the main thread; could just as well run
591 // on a helper thread if |cdm_| were thread-friendly and care was taken. We
592 // only use CallOnMainThread() here to get delayed-execution behavior.
593 pp::Module::Get()->core()->CallOnMainThread(
595 callback_factory_.NewCallback(&CdmAdapter::TimerExpired, context),
599 void CdmAdapter::TimerExpired(int32_t result, void* context) {
600 PP_DCHECK(result == PP_OK);
601 cdm_->TimerExpired(context);
604 // cdm::Host_4 methods
606 double CdmAdapter::GetCurrentWallTimeInSeconds() {
607 return GetCurrentTime();
610 void CdmAdapter::OnSessionCreated(uint32_t session_id,
611 const char* web_session_id,
612 uint32_t web_session_id_length) {
613 uint32_t promise_id = cdm_->LookupPromiseId(session_id);
614 cdm_->AssignWebSessionId(session_id, web_session_id, web_session_id_length);
615 OnResolveNewSessionPromise(promise_id, web_session_id, web_session_id_length);
618 void CdmAdapter::OnSessionMessage(uint32_t session_id,
620 uint32_t message_length,
621 const char* destination_url,
622 uint32_t destination_url_length) {
623 std::string web_session_id = cdm_->LookupWebSessionId(session_id);
624 OnSessionMessage(web_session_id.data(),
625 web_session_id.length(),
629 destination_url_length);
632 void CdmAdapter::OnSessionReady(uint32_t session_id) {
633 uint32_t promise_id = cdm_->LookupPromiseId(session_id);
635 OnResolvePromise(promise_id);
637 std::string web_session_id = cdm_->LookupWebSessionId(session_id);
638 OnSessionReady(web_session_id.data(), web_session_id.length());
642 void CdmAdapter::OnSessionClosed(uint32_t session_id) {
643 uint32_t promise_id = cdm_->LookupPromiseId(session_id);
644 std::string web_session_id = cdm_->LookupWebSessionId(session_id);
645 cdm_->DropWebSessionId(web_session_id);
647 OnResolvePromise(promise_id);
649 OnSessionClosed(web_session_id.data(), web_session_id.length());
653 void CdmAdapter::OnSessionError(uint32_t session_id,
654 cdm::MediaKeyError error_code,
655 uint32_t system_code) {
656 uint32_t promise_id = cdm_->LookupPromiseId(session_id);
658 // Existing cdm::MediaKeyError don't map to DOM error names. Convert them
659 // into non-standard names so that the prefixed API can extract them.
660 // TODO(jrummell): Remove this conversion and the inverse when CDM4 is gone.
662 switch (error_code) {
663 case cdm::kPrefixedClientError:
664 error = cdm::kClientError;
666 case cdm::kPrefixedOutputError:
667 error = cdm::kOutputError;
669 case cdm::kPrefixedUnknownError:
671 error = cdm::kUnknownError;
676 RejectPromise(promise_id, error, system_code, std::string());
678 std::string web_session_id = cdm_->LookupWebSessionId(session_id);
679 OnSessionError(web_session_id.data(),
680 web_session_id.length(),
688 // cdm::Host_5 and cdm::Host_6 methods
690 cdm::Time CdmAdapter::GetCurrentTime() {
691 return GetCurrentWallTime();
694 cdm::Time CdmAdapter::GetCurrentWallTime() {
695 return pp::Module::Get()->core()->GetTime();
698 void CdmAdapter::OnResolvePromise(uint32_t promise_id) {
699 PostOnMain(callback_factory_.NewCallback(
700 &CdmAdapter::SendPromiseResolvedInternal, promise_id));
702 // CDM_5 doesn't support OnSessionKeysChange(), so simulate one if requested.
703 // Passing "true" which may result in false positives for retrying.
704 std::string session_id;
705 if (cdm_->SessionUsableKeysEventNeeded(promise_id, &session_id))
706 OnSessionKeysChange(session_id.data(), session_id.length(), true);
709 void CdmAdapter::OnResolveNewSessionPromise(uint32_t promise_id,
710 const char* web_session_id,
711 uint32_t web_session_id_length) {
712 PostOnMain(callback_factory_.NewCallback(
713 &CdmAdapter::SendPromiseResolvedWithSessionInternal,
715 std::string(web_session_id, web_session_id_length)));
717 // CDM_5 doesn't support OnSessionKeysChange(), so simulate one if requested.
718 // Passing "true" which may result in false positives for retrying.
719 std::string session_id;
720 if (cdm_->SessionUsableKeysEventNeeded(promise_id, &session_id))
721 OnSessionKeysChange(web_session_id, web_session_id_length, true);
724 void CdmAdapter::OnResolveKeyIdsPromise(uint32_t promise_id,
725 const cdm::BinaryData* usable_key_ids,
726 uint32_t usable_key_ids_length) {
727 std::vector<std::vector<uint8> > key_ids;
728 for (uint32_t i = 0; i < usable_key_ids_length; ++i) {
730 std::vector<uint8>(usable_key_ids[i].data,
731 usable_key_ids[i].data + usable_key_ids[i].length));
733 PostOnMain(callback_factory_.NewCallback(
734 &CdmAdapter::SendPromiseResolvedWithUsableKeyIdsInternal,
739 void CdmAdapter::OnRejectPromise(uint32_t promise_id,
741 uint32_t system_code,
742 const char* error_message,
743 uint32_t error_message_length) {
744 RejectPromise(promise_id,
747 std::string(error_message, error_message_length));
750 void CdmAdapter::RejectPromise(uint32_t promise_id,
752 uint32_t system_code,
753 const std::string& error_message) {
754 PostOnMain(callback_factory_.NewCallback(
755 &CdmAdapter::SendPromiseRejectedInternal,
757 SessionError(error, system_code, error_message)));
760 void CdmAdapter::OnSessionMessage(const char* web_session_id,
761 uint32_t web_session_id_length,
763 uint32_t message_length,
764 const char* destination_url,
765 uint32_t destination_url_length) {
766 PostOnMain(callback_factory_.NewCallback(
767 &CdmAdapter::SendSessionMessageInternal,
768 std::string(web_session_id, web_session_id_length),
769 std::vector<uint8>(message, message + message_length),
770 std::string(destination_url, destination_url_length)));
773 void CdmAdapter::OnSessionKeysChange(const char* web_session_id,
774 uint32_t web_session_id_length,
775 bool has_additional_usable_key) {
776 OnSessionUsableKeysChange(
777 web_session_id, web_session_id_length, has_additional_usable_key);
780 void CdmAdapter::OnSessionUsableKeysChange(const char* web_session_id,
781 uint32_t web_session_id_length,
782 bool has_additional_usable_key) {
783 PostOnMain(callback_factory_.NewCallback(
784 &CdmAdapter::SendSessionUsableKeysChangeInternal,
785 std::string(web_session_id, web_session_id_length),
786 has_additional_usable_key));
789 void CdmAdapter::OnExpirationChange(const char* web_session_id,
790 uint32_t web_session_id_length,
791 cdm::Time new_expiry_time) {
792 PostOnMain(callback_factory_.NewCallback(
793 &CdmAdapter::SendExpirationChangeInternal,
794 std::string(web_session_id, web_session_id_length),
798 void CdmAdapter::OnSessionReady(const char* web_session_id,
799 uint32_t web_session_id_length) {
800 PostOnMain(callback_factory_.NewCallback(
801 &CdmAdapter::SendSessionReadyInternal,
802 std::string(web_session_id, web_session_id_length)));
805 void CdmAdapter::OnSessionClosed(const char* web_session_id,
806 uint32_t web_session_id_length) {
807 PostOnMain(callback_factory_.NewCallback(
808 &CdmAdapter::SendSessionClosedInternal,
809 std::string(web_session_id, web_session_id_length)));
812 void CdmAdapter::OnSessionError(const char* web_session_id,
813 uint32_t web_session_id_length,
815 uint32_t system_code,
816 const char* error_message,
817 uint32_t error_message_length) {
818 PostOnMain(callback_factory_.NewCallback(
819 &CdmAdapter::SendSessionErrorInternal,
820 std::string(web_session_id, web_session_id_length),
823 std::string(error_message, error_message_length))));
826 // Helpers to pass the event to Pepper.
828 void CdmAdapter::SendPromiseResolvedInternal(int32_t result,
829 uint32_t promise_id) {
830 PP_DCHECK(result == PP_OK);
831 pp::ContentDecryptor_Private::PromiseResolved(promise_id);
834 void CdmAdapter::SendPromiseResolvedWithSessionInternal(
837 const std::string& web_session_id) {
838 PP_DCHECK(result == PP_OK);
839 pp::ContentDecryptor_Private::PromiseResolvedWithSession(promise_id,
843 void CdmAdapter::SendPromiseResolvedWithUsableKeyIdsInternal(
846 std::vector<std::vector<uint8> > key_ids) {
847 PP_DCHECK(result == PP_OK);
848 // TODO(jrummell): Implement this event in subsequent CL.
849 // (http://crbug.com/358271).
852 void CdmAdapter::SendPromiseRejectedInternal(int32_t result,
854 const SessionError& error) {
855 PP_DCHECK(result == PP_OK);
856 pp::ContentDecryptor_Private::PromiseRejected(
858 CdmExceptionTypeToPpCdmExceptionType(error.error),
860 error.error_description);
863 void CdmAdapter::SendSessionMessageInternal(
865 const std::string& web_session_id,
866 const std::vector<uint8>& message,
867 const std::string& destination_url) {
868 PP_DCHECK(result == PP_OK);
870 pp::VarArrayBuffer message_array_buffer(message.size());
871 if (message.size() > 0) {
872 memcpy(message_array_buffer.Map(), message.data(), message.size());
875 pp::ContentDecryptor_Private::SessionMessage(
876 web_session_id, message_array_buffer, destination_url);
879 void CdmAdapter::SendSessionReadyInternal(int32_t result,
880 const std::string& web_session_id) {
881 PP_DCHECK(result == PP_OK);
882 pp::ContentDecryptor_Private::SessionReady(web_session_id);
885 void CdmAdapter::SendSessionClosedInternal(int32_t result,
886 const std::string& web_session_id) {
887 PP_DCHECK(result == PP_OK);
888 pp::ContentDecryptor_Private::SessionClosed(web_session_id);
891 void CdmAdapter::SendSessionErrorInternal(int32_t result,
892 const std::string& web_session_id,
893 const SessionError& error) {
894 PP_DCHECK(result == PP_OK);
895 pp::ContentDecryptor_Private::SessionError(
897 CdmExceptionTypeToPpCdmExceptionType(error.error),
899 error.error_description);
902 void CdmAdapter::SendSessionUsableKeysChangeInternal(
904 const std::string& web_session_id,
905 bool has_additional_usable_key) {
906 PP_DCHECK(result == PP_OK);
907 // TODO(jrummell): Implement this event in subsequent CL.
908 // (http://crbug.com/358271).
911 void CdmAdapter::SendExpirationChangeInternal(int32_t result,
912 const std::string& web_session_id,
913 cdm::Time new_expiry_time) {
914 PP_DCHECK(result == PP_OK);
915 // TODO(jrummell): Implement this event in subsequent CL.
916 // (http://crbug.com/358271).
919 void CdmAdapter::DeliverBlock(int32_t result,
920 const cdm::Status& status,
921 const LinkedDecryptedBlock& decrypted_block,
922 const PP_DecryptTrackingInfo& tracking_info) {
923 PP_DCHECK(result == PP_OK);
924 PP_DecryptedBlockInfo decrypted_block_info = {};
925 decrypted_block_info.tracking_info = tracking_info;
926 decrypted_block_info.tracking_info.timestamp = decrypted_block->Timestamp();
927 decrypted_block_info.tracking_info.buffer_id = 0;
928 decrypted_block_info.data_size = 0;
929 decrypted_block_info.result = CdmStatusToPpDecryptResult(status);
931 pp::Buffer_Dev buffer;
933 if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) {
934 PP_DCHECK(decrypted_block.get() && decrypted_block->DecryptedBuffer());
935 if (!decrypted_block.get() || !decrypted_block->DecryptedBuffer()) {
937 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
939 PpbBuffer* ppb_buffer =
940 static_cast<PpbBuffer*>(decrypted_block->DecryptedBuffer());
941 decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
942 decrypted_block_info.data_size = ppb_buffer->Size();
944 buffer = ppb_buffer->TakeBuffer();
948 pp::ContentDecryptor_Private::DeliverBlock(buffer, decrypted_block_info);
951 void CdmAdapter::DecoderInitializeDone(int32_t result,
952 PP_DecryptorStreamType decoder_type,
955 PP_DCHECK(result == PP_OK);
956 pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type,
961 void CdmAdapter::DecoderDeinitializeDone(int32_t result,
962 PP_DecryptorStreamType decoder_type,
963 uint32_t request_id) {
964 pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type,
968 void CdmAdapter::DecoderResetDone(int32_t result,
969 PP_DecryptorStreamType decoder_type,
970 uint32_t request_id) {
971 pp::ContentDecryptor_Private::DecoderResetDone(decoder_type, request_id);
974 void CdmAdapter::DeliverFrame(
976 const cdm::Status& status,
977 const LinkedVideoFrame& video_frame,
978 const PP_DecryptTrackingInfo& tracking_info) {
979 PP_DCHECK(result == PP_OK);
980 PP_DecryptedFrameInfo decrypted_frame_info = {};
981 decrypted_frame_info.tracking_info.request_id = tracking_info.request_id;
982 decrypted_frame_info.tracking_info.buffer_id = 0;
983 decrypted_frame_info.result = CdmStatusToPpDecryptResult(status);
985 pp::Buffer_Dev buffer;
987 if (decrypted_frame_info.result == PP_DECRYPTRESULT_SUCCESS) {
988 if (!IsValidVideoFrame(video_frame)) {
990 decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR;
992 PpbBuffer* ppb_buffer =
993 static_cast<PpbBuffer*>(video_frame->FrameBuffer());
995 decrypted_frame_info.tracking_info.timestamp = video_frame->Timestamp();
996 decrypted_frame_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
997 decrypted_frame_info.format =
998 CdmVideoFormatToPpDecryptedFrameFormat(video_frame->Format());
999 decrypted_frame_info.width = video_frame->Size().width;
1000 decrypted_frame_info.height = video_frame->Size().height;
1001 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y] =
1002 video_frame->PlaneOffset(cdm::VideoFrame::kYPlane);
1003 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_U] =
1004 video_frame->PlaneOffset(cdm::VideoFrame::kUPlane);
1005 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_V] =
1006 video_frame->PlaneOffset(cdm::VideoFrame::kVPlane);
1007 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_Y] =
1008 video_frame->Stride(cdm::VideoFrame::kYPlane);
1009 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_U] =
1010 video_frame->Stride(cdm::VideoFrame::kUPlane);
1011 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_V] =
1012 video_frame->Stride(cdm::VideoFrame::kVPlane);
1014 buffer = ppb_buffer->TakeBuffer();
1018 pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info);
1021 void CdmAdapter::DeliverSamples(int32_t result,
1022 const cdm::Status& status,
1023 const LinkedAudioFrames& audio_frames,
1024 const PP_DecryptTrackingInfo& tracking_info) {
1025 PP_DCHECK(result == PP_OK);
1027 PP_DecryptedSampleInfo decrypted_sample_info = {};
1028 decrypted_sample_info.tracking_info = tracking_info;
1029 decrypted_sample_info.tracking_info.timestamp = 0;
1030 decrypted_sample_info.tracking_info.buffer_id = 0;
1031 decrypted_sample_info.data_size = 0;
1032 decrypted_sample_info.result = CdmStatusToPpDecryptResult(status);
1034 pp::Buffer_Dev buffer;
1036 if (decrypted_sample_info.result == PP_DECRYPTRESULT_SUCCESS) {
1037 PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer());
1038 if (!audio_frames.get() || !audio_frames->FrameBuffer()) {
1040 decrypted_sample_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
1042 PpbBuffer* ppb_buffer =
1043 static_cast<PpbBuffer*>(audio_frames->FrameBuffer());
1045 decrypted_sample_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
1046 decrypted_sample_info.data_size = ppb_buffer->Size();
1047 decrypted_sample_info.format =
1048 CdmAudioFormatToPpDecryptedSampleFormat(audio_frames->Format());
1050 buffer = ppb_buffer->TakeBuffer();
1054 pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_sample_info);
1057 bool CdmAdapter::IsValidVideoFrame(const LinkedVideoFrame& video_frame) {
1058 if (!video_frame.get() ||
1059 !video_frame->FrameBuffer() ||
1060 (video_frame->Format() != cdm::kI420 &&
1061 video_frame->Format() != cdm::kYv12)) {
1062 CDM_DLOG() << "Invalid video frame!";
1066 PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer());
1068 for (uint32_t i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) {
1069 int plane_height = (i == cdm::VideoFrame::kYPlane) ?
1070 video_frame->Size().height : (video_frame->Size().height + 1) / 2;
1071 cdm::VideoFrame::VideoPlane plane =
1072 static_cast<cdm::VideoFrame::VideoPlane>(i);
1073 if (ppb_buffer->Size() < video_frame->PlaneOffset(plane) +
1074 plane_height * video_frame->Stride(plane)) {
1082 #if !defined(NDEBUG)
1083 void CdmAdapter::LogToConsole(const pp::Var& value) {
1084 PP_DCHECK(IsMainThread());
1085 const PPB_Console* console = reinterpret_cast<const PPB_Console*>(
1086 pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE));
1087 console->Log(pp_instance(), PP_LOGLEVEL_LOG, value.pp_var());
1089 #endif // !defined(NDEBUG)
1091 void CdmAdapter::SendPlatformChallenge(
1092 const char* service_id, uint32_t service_id_length,
1093 const char* challenge, uint32_t challenge_length) {
1094 #if defined(OS_CHROMEOS)
1095 pp::VarArrayBuffer challenge_var(challenge_length);
1096 uint8_t* var_data = static_cast<uint8_t*>(challenge_var.Map());
1097 memcpy(var_data, challenge, challenge_length);
1099 std::string service_id_str(service_id, service_id_length);
1101 linked_ptr<PepperPlatformChallengeResponse> response(
1102 new PepperPlatformChallengeResponse());
1104 int32_t result = platform_verification_.ChallengePlatform(
1105 pp::Var(service_id_str),
1107 &response->signed_data,
1108 &response->signed_data_signature,
1109 &response->platform_key_certificate,
1110 callback_factory_.NewCallback(&CdmAdapter::SendPlatformChallengeDone,
1112 challenge_var.Unmap();
1113 if (result == PP_OK_COMPLETIONPENDING)
1116 // Fall through on error and issue an empty OnPlatformChallengeResponse().
1117 PP_DCHECK(result != PP_OK);
1120 cdm::PlatformChallengeResponse platform_challenge_response = {};
1121 cdm_->OnPlatformChallengeResponse(platform_challenge_response);
1124 void CdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask) {
1125 #if defined(OS_CHROMEOS)
1126 int32_t result = output_protection_.EnableProtection(
1127 desired_protection_mask, callback_factory_.NewCallback(
1128 &CdmAdapter::EnableProtectionDone));
1130 // Errors are ignored since clients must call QueryOutputProtectionStatus() to
1131 // inspect the protection status on a regular basis.
1133 if (result != PP_OK && result != PP_OK_COMPLETIONPENDING)
1134 CDM_DLOG() << __FUNCTION__ << " failed!";
1138 void CdmAdapter::QueryOutputProtectionStatus() {
1139 #if defined(OS_CHROMEOS)
1140 PP_DCHECK(!query_output_protection_in_progress_);
1142 output_link_mask_ = output_protection_mask_ = 0;
1143 const int32_t result = output_protection_.QueryStatus(
1145 &output_protection_mask_,
1146 callback_factory_.NewCallback(
1147 &CdmAdapter::QueryOutputProtectionStatusDone));
1148 if (result == PP_OK_COMPLETIONPENDING) {
1149 query_output_protection_in_progress_ = true;
1150 ReportOutputProtectionQuery();
1154 // Fall through on error and issue an empty OnQueryOutputProtectionStatus().
1155 PP_DCHECK(result != PP_OK);
1158 cdm_->OnQueryOutputProtectionStatus(0, 0);
1161 void CdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type,
1162 cdm::Status decoder_status) {
1163 switch (stream_type) {
1164 case cdm::kStreamTypeAudio:
1165 PP_DCHECK(deferred_initialize_audio_decoder_);
1167 callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone,
1168 PP_DECRYPTORSTREAMTYPE_AUDIO,
1169 deferred_audio_decoder_config_id_,
1170 decoder_status == cdm::kSuccess));
1171 deferred_initialize_audio_decoder_ = false;
1172 deferred_audio_decoder_config_id_ = 0;
1174 case cdm::kStreamTypeVideo:
1175 PP_DCHECK(deferred_initialize_video_decoder_);
1177 callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone,
1178 PP_DECRYPTORSTREAMTYPE_VIDEO,
1179 deferred_video_decoder_config_id_,
1180 decoder_status == cdm::kSuccess));
1181 deferred_initialize_video_decoder_ = false;
1182 deferred_video_decoder_config_id_ = 0;
1187 // The CDM owns the returned object and must call FileIO::Close() to release it.
1188 cdm::FileIO* CdmAdapter::CreateFileIO(cdm::FileIOClient* client) {
1189 return new CdmFileIOImpl(client, pp_instance());
1192 #if defined(OS_CHROMEOS)
1193 void CdmAdapter::ReportOutputProtectionUMA(OutputProtectionStatus status) {
1194 pp::UMAPrivate uma_interface_(this);
1195 uma_interface_.HistogramEnumeration(
1196 "Media.EME.OutputProtection", status, OUTPUT_PROTECTION_MAX);
1199 void CdmAdapter::ReportOutputProtectionQuery() {
1200 if (uma_for_output_protection_query_reported_)
1203 ReportOutputProtectionUMA(OUTPUT_PROTECTION_QUERIED);
1204 uma_for_output_protection_query_reported_ = true;
1207 void CdmAdapter::ReportOutputProtectionQueryResult() {
1208 if (uma_for_output_protection_positive_result_reported_)
1211 // Report UMAs for output protection query result.
1212 uint32_t external_links = (output_link_mask_ & ~cdm::kLinkTypeInternal);
1214 if (!external_links) {
1215 ReportOutputProtectionUMA(OUTPUT_PROTECTION_NO_EXTERNAL_LINK);
1216 uma_for_output_protection_positive_result_reported_ = true;
1220 const uint32_t kProtectableLinks =
1221 cdm::kLinkTypeHDMI | cdm::kLinkTypeDVI | cdm::kLinkTypeDisplayPort;
1222 bool is_unprotectable_link_connected = external_links & ~kProtectableLinks;
1223 bool is_hdcp_enabled_on_all_protectable_links =
1224 output_protection_mask_ & cdm::kProtectionHDCP;
1226 if (!is_unprotectable_link_connected &&
1227 is_hdcp_enabled_on_all_protectable_links) {
1228 ReportOutputProtectionUMA(
1229 OUTPUT_PROTECTION_ALL_EXTERNAL_LINKS_PROTECTED);
1230 uma_for_output_protection_positive_result_reported_ = true;
1234 // Do not report a negative result because it could be a false negative.
1235 // Instead, we will calculate number of negatives using the total number of
1236 // queries and success results.
1239 void CdmAdapter::SendPlatformChallengeDone(
1241 const linked_ptr<PepperPlatformChallengeResponse>& response) {
1242 if (result != PP_OK) {
1243 CDM_DLOG() << __FUNCTION__ << ": Platform challenge failed!";
1244 cdm::PlatformChallengeResponse platform_challenge_response = {};
1245 cdm_->OnPlatformChallengeResponse(platform_challenge_response);
1249 pp::VarArrayBuffer signed_data_var(response->signed_data);
1250 pp::VarArrayBuffer signed_data_signature_var(response->signed_data_signature);
1251 std::string platform_key_certificate_string =
1252 response->platform_key_certificate.AsString();
1254 cdm::PlatformChallengeResponse platform_challenge_response = {
1255 static_cast<uint8_t*>(signed_data_var.Map()),
1256 signed_data_var.ByteLength(),
1257 static_cast<uint8_t*>(signed_data_signature_var.Map()),
1258 signed_data_signature_var.ByteLength(),
1259 reinterpret_cast<const uint8_t*>(platform_key_certificate_string.data()),
1260 static_cast<uint32_t>(platform_key_certificate_string.length())};
1261 cdm_->OnPlatformChallengeResponse(platform_challenge_response);
1263 signed_data_var.Unmap();
1264 signed_data_signature_var.Unmap();
1267 void CdmAdapter::EnableProtectionDone(int32_t result) {
1268 // Does nothing since clients must call QueryOutputProtectionStatus() to
1269 // inspect the protection status on a regular basis.
1270 CDM_DLOG() << __FUNCTION__ << " : " << result;
1273 void CdmAdapter::QueryOutputProtectionStatusDone(int32_t result) {
1274 PP_DCHECK(query_output_protection_in_progress_);
1275 query_output_protection_in_progress_ = false;
1277 // Return a protection status of none on error.
1278 if (result != PP_OK)
1279 output_link_mask_ = output_protection_mask_ = 0;
1281 ReportOutputProtectionQueryResult();
1283 cdm_->OnQueryOutputProtectionStatus(output_link_mask_,
1284 output_protection_mask_);
1288 CdmAdapter::SessionError::SessionError(cdm::Error error,
1289 uint32_t system_code,
1290 std::string error_description)
1292 system_code(system_code),
1293 error_description(error_description) {
1296 void* GetCdmHost(int host_interface_version, void* user_data) {
1297 if (!host_interface_version || !user_data)
1301 cdm::ContentDecryptionModule::Host::kVersion == cdm::Host_6::kVersion,
1304 // Ensure IsSupportedCdmHostVersion matches implementation of this function.
1305 // Always update this DCHECK when updating this function.
1306 // If this check fails, update this function and DCHECK or update
1307 // IsSupportedCdmHostVersion.
1310 // Future version is not supported.
1311 !IsSupportedCdmHostVersion(cdm::Host_6::kVersion + 1) &&
1312 // Current version is supported.
1313 IsSupportedCdmHostVersion(cdm::Host_6::kVersion) &&
1314 // Include all previous supported versions (if any) here.
1315 IsSupportedCdmHostVersion(cdm::Host_5::kVersion) &&
1316 IsSupportedCdmHostVersion(cdm::Host_4::kVersion) &&
1317 // One older than the oldest supported version is not supported.
1318 !IsSupportedCdmHostVersion(cdm::Host_4::kVersion - 1));
1319 PP_DCHECK(IsSupportedCdmHostVersion(host_interface_version));
1321 CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data);
1322 CDM_DLOG() << "Create CDM Host with version " << host_interface_version;
1323 switch (host_interface_version) {
1324 case cdm::Host_4::kVersion:
1325 return static_cast<cdm::Host_4*>(cdm_adapter);
1326 case cdm::Host_5::kVersion:
1327 return static_cast<cdm::Host_5*>(cdm_adapter);
1328 case cdm::Host_6::kVersion:
1329 return static_cast<cdm::Host_6*>(cdm_adapter);
1336 // This object is the global object representing this plugin library as long
1338 class CdmAdapterModule : public pp::Module {
1340 CdmAdapterModule() : pp::Module() {
1341 // This function blocks the renderer thread (PluginInstance::Initialize()).
1342 // Move this call to other places if this may be a concern in the future.
1343 INITIALIZE_CDM_MODULE();
1345 virtual ~CdmAdapterModule() {
1346 DeinitializeCdmModule();
1349 virtual pp::Instance* CreateInstance(PP_Instance instance) {
1350 return new CdmAdapter(instance, this);
1354 CdmFileIOImpl::ResourceTracker cdm_file_io_impl_resource_tracker;
1357 } // namespace media
1361 // Factory function for your specialization of the Module object.
1362 Module* CreateModule() {
1363 return new media::CdmAdapterModule();