cdm_adapter.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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. 4 5#include "media/cdm/ppapi/cdm_adapter.h" 6 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" 13 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) 18 19namespace { 20 21#if !defined(NDEBUG) 22 #define DLOG_TO_CONSOLE(message) LogToConsole(message); 23#else 24 #define DLOG_TO_CONSOLE(message) (void)(message); 25#endif 26 27bool IsMainThread() { 28 return pp::Module::Get()->core()->IsMainThread(); 29} 30 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. 33void PostOnMain(pp::CompletionCallback cb) { 34 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK); 35} 36 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. 39void 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. 42 if (IsMainThread()) 43 cb.Run(PP_OK); 44 else 45 PostOnMain(cb); 46} 47 48// Configures a cdm::InputBuffer. |subsamples| must exist as long as 49// |input_buffer| is in use. 50void 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()); 57 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); 61 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; 67 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; 72 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); 76 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)); 81 } 82 83 input_buffer->subsamples = &(*subsamples)[0]; 84 } 85 86 input_buffer->timestamp = encrypted_block_info.tracking_info.timestamp; 87} 88 89PP_DecryptResult CdmStatusToPpDecryptResult(cdm::Status status) { 90 switch (status) { 91 case cdm::kSuccess: 92 return PP_DECRYPTRESULT_SUCCESS; 93 case cdm::kNoKey: 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; 101 default: 102 PP_NOTREACHED(); 103 return PP_DECRYPTRESULT_DECODE_ERROR; 104 } 105} 106 107PP_DecryptedFrameFormat CdmVideoFormatToPpDecryptedFrameFormat( 108 cdm::VideoFormat format) { 109 switch (format) { 110 case cdm::kYv12: 111 return PP_DECRYPTEDFRAMEFORMAT_YV12; 112 case cdm::kI420: 113 return PP_DECRYPTEDFRAMEFORMAT_I420; 114 default: 115 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN; 116 } 117} 118 119PP_DecryptedSampleFormat CdmAudioFormatToPpDecryptedSampleFormat( 120 cdm::AudioFormat format) { 121 switch (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; 134 default: 135 return PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN; 136 } 137} 138 139cdm::AudioDecoderConfig::AudioCodec PpAudioCodecToCdmAudioCodec( 140 PP_AudioCodec codec) { 141 switch (codec) { 142 case PP_AUDIOCODEC_VORBIS: 143 return cdm::AudioDecoderConfig::kCodecVorbis; 144 case PP_AUDIOCODEC_AAC: 145 return cdm::AudioDecoderConfig::kCodecAac; 146 default: 147 return cdm::AudioDecoderConfig::kUnknownAudioCodec; 148 } 149} 150 151cdm::VideoDecoderConfig::VideoCodec PpVideoCodecToCdmVideoCodec( 152 PP_VideoCodec codec) { 153 switch (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; 160 default: 161 return cdm::VideoDecoderConfig::kUnknownVideoCodec; 162 } 163} 164 165cdm::VideoDecoderConfig::VideoCodecProfile PpVCProfileToCdmVCProfile( 166 PP_VideoCodecProfile profile) { 167 switch (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; 184 default: 185 return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile; 186 } 187} 188 189cdm::VideoFormat PpDecryptedFrameFormatToCdmVideoFormat( 190 PP_DecryptedFrameFormat format) { 191 switch (format) { 192 case PP_DECRYPTEDFRAMEFORMAT_YV12: 193 return cdm::kYv12; 194 case PP_DECRYPTEDFRAMEFORMAT_I420: 195 return cdm::kI420; 196 default: 197 return cdm::kUnknownVideoFormat; 198 } 199} 200 201cdm::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; 208 } 209 210 PP_NOTREACHED(); 211 return cdm::kStreamTypeVideo; 212} 213 214cdm::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; 220 default: 221 PP_NOTREACHED(); 222 return cdm::kTemporary; 223 } 224} 225 226PP_CdmExceptionCode CdmExceptionTypeToPpCdmExceptionType(cdm::Error error) { 227 switch (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; 242 default: 243 PP_NOTREACHED(); 244 return PP_CDMEXCEPTIONCODE_UNKNOWNERROR; 245 } 246} 247 248} // namespace 249 250namespace media { 251 252CdmAdapter::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), 263#endif 264 allocator_(this), 265 cdm_(NULL), 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); 271} 272 273CdmAdapter::~CdmAdapter() {} 274 275bool CdmAdapter::CreateCdmInstance(const std::string& key_system) { 276 PP_DCHECK(!cdm_); 277 cdm_ = make_linked_ptr(CdmWrapper::Create( 278 key_system.data(), key_system.size(), GetCdmHost, this)); 279 bool success = cdm_ != NULL; 280 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; 285 286 return success; 287} 288 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"). 296void CdmAdapter::Initialize(const std::string& key_system) { 297 PP_DCHECK(!key_system.empty()); 298 PP_DCHECK(key_system_.empty() || (key_system_ == key_system && cdm_)); 299 300#if defined(CHECK_DOCUMENT_URL) 301 PP_URLComponents_Dev url_components = {}; 302 const pp::URLUtil_Dev* url_util = pp::URLUtil_Dev::Get(); 303 if (!url_util) 304 return; 305 pp::Var href = url_util->GetDocumentURL(pp::InstanceHandle(pp_instance()), 306 &url_components); 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); 316 } 317#endif // defined(CHECK_DOCUMENT_URL) 318 319 if (!cdm_ && !CreateCdmInstance(key_system)) 320 return; 321 322 PP_DCHECK(cdm_); 323 key_system_ = key_system; 324} 325 326void 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. 335 if (!cdm_) { 336 RejectPromise(promise_id, 337 cdm::kInvalidStateError, 338 0, 339 "CDM has not been initialized."); 340 return; 341 } 342 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)); 349} 350 351void 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. 358 if (!cdm_) { 359 RejectPromise(promise_id, 360 cdm::kInvalidStateError, 361 0, 362 "CDM has not been initialized."); 363 return; 364 } 365 366 cdm_->LoadSession(promise_id, web_session_id.data(), web_session_id.size()); 367} 368 369void 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(); 374 375 PP_DCHECK(!web_session_id.empty()); 376 PP_DCHECK(response_ptr); 377 PP_DCHECK(response_size > 0); 378 379 cdm_->UpdateSession(promise_id, 380 web_session_id.data(), 381 web_session_id.length(), 382 response_ptr, 383 response_size); 384} 385 386void CdmAdapter::ReleaseSession(uint32_t promise_id, 387 const std::string& web_session_id) { 388 cdm_->ReleaseSession( 389 promise_id, web_session_id.data(), web_session_id.length()); 390} 391 392// Note: In the following decryption/decoding related functions, errors are NOT 393// reported via KeyError, but are reported via corresponding PPB calls. 394 395void CdmAdapter::Decrypt(pp::Buffer_Dev encrypted_buffer, 396 const PP_EncryptedBlockInfo& encrypted_block_info) { 397 PP_DCHECK(!encrypted_buffer.is_null()); 398 399 // Release a buffer that the caller indicated it is finished with. 400 allocator_.Release(encrypted_block_info.tracking_info.buffer_id); 401 402 cdm::Status status = cdm::kDecryptError; 403 LinkedDecryptedBlock decrypted_block(new DecryptedBlockImpl()); 404 405 if (cdm_) { 406 cdm::InputBuffer input_buffer; 407 std::vector<cdm::SubsampleEntry> subsamples; 408 ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples, 409 &input_buffer); 410 status = cdm_->Decrypt(input_buffer, decrypted_block.get()); 411 PP_DCHECK(status != cdm::kSuccess || 412 (decrypted_block->DecryptedBuffer() && 413 decrypted_block->DecryptedBuffer()->Size())); 414 } 415 416 CallOnMain(callback_factory_.NewCallback( 417 &CdmAdapter::DeliverBlock, 418 status, 419 decrypted_block, 420 encrypted_block_info.tracking_info)); 421} 422 423void CdmAdapter::InitializeAudioDecoder( 424 const PP_AudioDecoderConfig& decoder_config, 425 pp::Buffer_Dev extra_data_buffer) { 426 PP_DCHECK(!deferred_initialize_audio_decoder_); 427 PP_DCHECK(deferred_audio_decoder_config_id_ == 0); 428 cdm::Status status = cdm::kSessionError; 429 if (cdm_) { 430 cdm::AudioDecoderConfig cdm_decoder_config; 431 cdm_decoder_config.codec = 432 PpAudioCodecToCdmAudioCodec(decoder_config.codec); 433 cdm_decoder_config.channel_count = decoder_config.channel_count; 434 cdm_decoder_config.bits_per_channel = decoder_config.bits_per_channel; 435 cdm_decoder_config.samples_per_second = decoder_config.samples_per_second; 436 cdm_decoder_config.extra_data = 437 static_cast<uint8_t*>(extra_data_buffer.data()); 438 cdm_decoder_config.extra_data_size = extra_data_buffer.size(); 439 status = cdm_->InitializeAudioDecoder(cdm_decoder_config); 440 } 441 442 if (status == cdm::kDeferredInitialization) { 443 deferred_initialize_audio_decoder_ = true; 444 deferred_audio_decoder_config_id_ = decoder_config.request_id; 445 return; 446 } 447 448 CallOnMain(callback_factory_.NewCallback( 449 &CdmAdapter::DecoderInitializeDone, 450 PP_DECRYPTORSTREAMTYPE_AUDIO, 451 decoder_config.request_id, 452 status == cdm::kSuccess)); 453} 454 455void CdmAdapter::InitializeVideoDecoder( 456 const PP_VideoDecoderConfig& decoder_config, 457 pp::Buffer_Dev extra_data_buffer) { 458 PP_DCHECK(!deferred_initialize_video_decoder_); 459 PP_DCHECK(deferred_video_decoder_config_id_ == 0); 460 cdm::Status status = cdm::kSessionError; 461 if (cdm_) { 462 cdm::VideoDecoderConfig cdm_decoder_config; 463 cdm_decoder_config.codec = 464 PpVideoCodecToCdmVideoCodec(decoder_config.codec); 465 cdm_decoder_config.profile = 466 PpVCProfileToCdmVCProfile(decoder_config.profile); 467 cdm_decoder_config.format = 468 PpDecryptedFrameFormatToCdmVideoFormat(decoder_config.format); 469 cdm_decoder_config.coded_size.width = decoder_config.width; 470 cdm_decoder_config.coded_size.height = decoder_config.height; 471 cdm_decoder_config.extra_data = 472 static_cast<uint8_t*>(extra_data_buffer.data()); 473 cdm_decoder_config.extra_data_size = extra_data_buffer.size(); 474 status = cdm_->InitializeVideoDecoder(cdm_decoder_config); 475 } 476 477 if (status == cdm::kDeferredInitialization) { 478 deferred_initialize_video_decoder_ = true; 479 deferred_video_decoder_config_id_ = decoder_config.request_id; 480 return; 481 } 482 483 CallOnMain(callback_factory_.NewCallback( 484 &CdmAdapter::DecoderInitializeDone, 485 PP_DECRYPTORSTREAMTYPE_VIDEO, 486 decoder_config.request_id, 487 status == cdm::kSuccess)); 488} 489 490void CdmAdapter::DeinitializeDecoder(PP_DecryptorStreamType decoder_type, 491 uint32_t request_id) { 492 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded. 493 if (cdm_) { 494 cdm_->DeinitializeDecoder( 495 PpDecryptorStreamTypeToCdmStreamType(decoder_type)); 496 } 497 498 CallOnMain(callback_factory_.NewCallback( 499 &CdmAdapter::DecoderDeinitializeDone, 500 decoder_type, 501 request_id)); 502} 503 504void CdmAdapter::ResetDecoder(PP_DecryptorStreamType decoder_type, 505 uint32_t request_id) { 506 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded. 507 if (cdm_) 508 cdm_->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type)); 509 510 CallOnMain(callback_factory_.NewCallback(&CdmAdapter::DecoderResetDone, 511 decoder_type, 512 request_id)); 513} 514 515void CdmAdapter::DecryptAndDecode( 516 PP_DecryptorStreamType decoder_type, 517 pp::Buffer_Dev encrypted_buffer, 518 const PP_EncryptedBlockInfo& encrypted_block_info) { 519 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded. 520 // Release a buffer that the caller indicated it is finished with. 521 allocator_.Release(encrypted_block_info.tracking_info.buffer_id); 522 523 cdm::InputBuffer input_buffer; 524 std::vector<cdm::SubsampleEntry> subsamples; 525 if (cdm_ && !encrypted_buffer.is_null()) { 526 ConfigureInputBuffer(encrypted_buffer, 527 encrypted_block_info, 528 &subsamples, 529 &input_buffer); 530 } 531 532 cdm::Status status = cdm::kDecodeError; 533 534 switch (decoder_type) { 535 case PP_DECRYPTORSTREAMTYPE_VIDEO: { 536 LinkedVideoFrame video_frame(new VideoFrameImpl()); 537 if (cdm_) 538 status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get()); 539 CallOnMain(callback_factory_.NewCallback( 540 &CdmAdapter::DeliverFrame, 541 status, 542 video_frame, 543 encrypted_block_info.tracking_info)); 544 return; 545 } 546 547 case PP_DECRYPTORSTREAMTYPE_AUDIO: { 548 LinkedAudioFrames audio_frames(new AudioFramesImpl()); 549 if (cdm_) { 550 status = cdm_->DecryptAndDecodeSamples(input_buffer, 551 audio_frames.get()); 552 } 553 CallOnMain(callback_factory_.NewCallback( 554 &CdmAdapter::DeliverSamples, 555 status, 556 audio_frames, 557 encrypted_block_info.tracking_info)); 558 return; 559 } 560 561 default: 562 PP_NOTREACHED(); 563 return; 564 } 565} 566 567cdm::Buffer* CdmAdapter::Allocate(uint32_t capacity) { 568 return allocator_.Allocate(capacity); 569} 570 571void CdmAdapter::SetTimer(int64_t delay_ms, void* context) { 572 // NOTE: doesn't really need to run on the main thread; could just as well run 573 // on a helper thread if |cdm_| were thread-friendly and care was taken. We 574 // only use CallOnMainThread() here to get delayed-execution behavior. 575 pp::Module::Get()->core()->CallOnMainThread( 576 delay_ms, 577 callback_factory_.NewCallback(&CdmAdapter::TimerExpired, context), 578 PP_OK); 579} 580 581void CdmAdapter::TimerExpired(int32_t result, void* context) { 582 PP_DCHECK(result == PP_OK); 583 cdm_->TimerExpired(context); 584} 585 586// cdm::Host_4 methods 587 588double CdmAdapter::GetCurrentWallTimeInSeconds() { 589 return GetCurrentTime(); 590} 591 592void CdmAdapter::OnSessionCreated(uint32_t session_id, 593 const char* web_session_id, 594 uint32_t web_session_id_length) { 595 uint32_t promise_id = cdm_->LookupPromiseId(session_id); 596 cdm_->AssignWebSessionId(session_id, web_session_id, web_session_id_length); 597 OnResolveNewSessionPromise(promise_id, web_session_id, web_session_id_length); 598} 599 600void CdmAdapter::OnSessionMessage(uint32_t session_id, 601 const char* message, 602 uint32_t message_length, 603 const char* destination_url, 604 uint32_t destination_url_length) { 605 std::string web_session_id = cdm_->LookupWebSessionId(session_id); 606 OnSessionMessage(web_session_id.data(), 607 web_session_id.length(), 608 message, 609 message_length, 610 destination_url, 611 destination_url_length); 612} 613 614void CdmAdapter::OnSessionReady(uint32_t session_id) { 615 uint32_t promise_id = cdm_->LookupPromiseId(session_id); 616 if (promise_id) { 617 OnResolvePromise(promise_id); 618 } else { 619 std::string web_session_id = cdm_->LookupWebSessionId(session_id); 620 OnSessionReady(web_session_id.data(), web_session_id.length()); 621 } 622} 623 624void CdmAdapter::OnSessionClosed(uint32_t session_id) { 625 uint32_t promise_id = cdm_->LookupPromiseId(session_id); 626 std::string web_session_id = cdm_->LookupWebSessionId(session_id); 627 cdm_->DropWebSessionId(web_session_id); 628 if (promise_id) { 629 OnResolvePromise(promise_id); 630 } else { 631 OnSessionClosed(web_session_id.data(), web_session_id.length()); 632 } 633} 634 635void CdmAdapter::OnSessionError(uint32_t session_id, 636 cdm::MediaKeyError error_code, 637 uint32_t system_code) { 638 uint32_t promise_id = cdm_->LookupPromiseId(session_id); 639 640 // Existing cdm::MediaKeyError don't map to DOM error names. Convert them 641 // into non-standard names so that the prefixed API can extract them. 642 // TODO(jrummell): Remove this conversion and the inverse when CDM4 is gone. 643 cdm::Error error; 644 switch (error_code) { 645 case cdm::kPrefixedClientError: 646 error = cdm::kClientError; 647 break; 648 case cdm::kPrefixedOutputError: 649 error = cdm::kOutputError; 650 break; 651 case cdm::kPrefixedUnknownError: 652 default: 653 error = cdm::kUnknownError; 654 break; 655 } 656 657 if (promise_id) { 658 RejectPromise(promise_id, error, system_code, std::string()); 659 } else { 660 std::string web_session_id = cdm_->LookupWebSessionId(session_id); 661 OnSessionError(web_session_id.data(), 662 web_session_id.length(), 663 error, 664 system_code, 665 NULL, 666 0); 667 } 668} 669 670// cdm::Host_5 methods 671 672cdm::Time CdmAdapter::GetCurrentTime() { 673 return pp::Module::Get()->core()->GetTime(); 674} 675 676void CdmAdapter::OnResolvePromise(uint32_t promise_id) { 677 PostOnMain(callback_factory_.NewCallback( 678 &CdmAdapter::SendPromiseResolvedInternal, promise_id)); 679} 680 681void CdmAdapter::OnResolveNewSessionPromise(uint32_t promise_id, 682 const char* web_session_id, 683 uint32_t web_session_id_length) { 684 PostOnMain(callback_factory_.NewCallback( 685 &CdmAdapter::SendPromiseResolvedWithSessionInternal, 686 promise_id, 687 std::string(web_session_id, web_session_id_length))); 688} 689 690void CdmAdapter::OnRejectPromise(uint32_t promise_id, 691 cdm::Error error, 692 uint32_t system_code, 693 const char* error_message, 694 uint32_t error_message_length) { 695 RejectPromise(promise_id, 696 error, 697 system_code, 698 std::string(error_message, error_message_length)); 699} 700 701void CdmAdapter::RejectPromise(uint32_t promise_id, 702 cdm::Error error, 703 uint32_t system_code, 704 const std::string& error_message) { 705 PostOnMain(callback_factory_.NewCallback( 706 &CdmAdapter::SendPromiseRejectedInternal, 707 promise_id, 708 SessionError(error, system_code, error_message))); 709} 710 711void CdmAdapter::OnSessionMessage(const char* web_session_id, 712 uint32_t web_session_id_length, 713 const char* message, 714 uint32_t message_length, 715 const char* destination_url, 716 uint32_t destination_url_length) { 717 PostOnMain(callback_factory_.NewCallback( 718 &CdmAdapter::SendSessionMessageInternal, 719 std::string(web_session_id, web_session_id_length), 720 std::vector<uint8>(message, message + message_length), 721 std::string(destination_url, destination_url_length))); 722} 723 724void CdmAdapter::OnSessionKeysChange(const char* web_session_id, 725 uint32_t web_session_id_length, 726 bool has_additional_usable_key) { 727 // TODO(jrummell): Implement this event in subsequent CL 728 // (http://crbug.com/370251). 729 PP_NOTREACHED(); 730} 731 732void CdmAdapter::OnExpirationChange(const char* web_session_id, 733 uint32_t web_session_id_length, 734 cdm::Time new_expiry_time) { 735 // TODO(jrummell): Implement this event in subsequent CL 736 // (http://crbug.com/370251). 737 PP_NOTREACHED(); 738} 739 740void CdmAdapter::OnSessionReady(const char* web_session_id, 741 uint32_t web_session_id_length) { 742 PostOnMain(callback_factory_.NewCallback( 743 &CdmAdapter::SendSessionReadyInternal, 744 std::string(web_session_id, web_session_id_length))); 745} 746 747void CdmAdapter::OnSessionClosed(const char* web_session_id, 748 uint32_t web_session_id_length) { 749 PostOnMain(callback_factory_.NewCallback( 750 &CdmAdapter::SendSessionClosedInternal, 751 std::string(web_session_id, web_session_id_length))); 752} 753 754void CdmAdapter::OnSessionError(const char* web_session_id, 755 uint32_t web_session_id_length, 756 cdm::Error error, 757 uint32_t system_code, 758 const char* error_message, 759 uint32_t error_message_length) { 760 PostOnMain(callback_factory_.NewCallback( 761 &CdmAdapter::SendSessionErrorInternal, 762 std::string(web_session_id, web_session_id_length), 763 SessionError(error, 764 system_code, 765 std::string(error_message, error_message_length)))); 766} 767 768// Helpers to pass the event to Pepper. 769 770void CdmAdapter::SendPromiseResolvedInternal(int32_t result, 771 uint32_t promise_id) { 772 PP_DCHECK(result == PP_OK); 773 pp::ContentDecryptor_Private::PromiseResolved(promise_id); 774} 775 776void CdmAdapter::SendPromiseResolvedWithSessionInternal( 777 int32_t result, 778 uint32_t promise_id, 779 const std::string& web_session_id) { 780 PP_DCHECK(result == PP_OK); 781 pp::ContentDecryptor_Private::PromiseResolvedWithSession(promise_id, 782 web_session_id); 783} 784 785void CdmAdapter::SendPromiseRejectedInternal(int32_t result, 786 uint32_t promise_id, 787 const SessionError& error) { 788 PP_DCHECK(result == PP_OK); 789 pp::ContentDecryptor_Private::PromiseRejected( 790 promise_id, 791 CdmExceptionTypeToPpCdmExceptionType(error.error), 792 error.system_code, 793 error.error_description); 794} 795 796void CdmAdapter::SendSessionMessageInternal( 797 int32_t result, 798 const std::string& web_session_id, 799 const std::vector<uint8>& message, 800 const std::string& destination_url) { 801 PP_DCHECK(result == PP_OK); 802 803 pp::VarArrayBuffer message_array_buffer(message.size()); 804 if (message.size() > 0) { 805 memcpy(message_array_buffer.Map(), message.data(), message.size()); 806 } 807 808 pp::ContentDecryptor_Private::SessionMessage( 809 web_session_id, message_array_buffer, destination_url); 810} 811 812void CdmAdapter::SendSessionReadyInternal(int32_t result, 813 const std::string& web_session_id) { 814 PP_DCHECK(result == PP_OK); 815 pp::ContentDecryptor_Private::SessionReady(web_session_id); 816} 817 818void CdmAdapter::SendSessionClosedInternal(int32_t result, 819 const std::string& web_session_id) { 820 PP_DCHECK(result == PP_OK); 821 pp::ContentDecryptor_Private::SessionClosed(web_session_id); 822} 823 824void CdmAdapter::SendSessionErrorInternal(int32_t result, 825 const std::string& web_session_id, 826 const SessionError& error) { 827 PP_DCHECK(result == PP_OK); 828 pp::ContentDecryptor_Private::SessionError( 829 web_session_id, 830 CdmExceptionTypeToPpCdmExceptionType(error.error), 831 error.system_code, 832 error.error_description); 833} 834 835void CdmAdapter::DeliverBlock(int32_t result, 836 const cdm::Status& status, 837 const LinkedDecryptedBlock& decrypted_block, 838 const PP_DecryptTrackingInfo& tracking_info) { 839 PP_DCHECK(result == PP_OK); 840 PP_DecryptedBlockInfo decrypted_block_info = {}; 841 decrypted_block_info.tracking_info = tracking_info; 842 decrypted_block_info.tracking_info.timestamp = decrypted_block->Timestamp(); 843 decrypted_block_info.tracking_info.buffer_id = 0; 844 decrypted_block_info.data_size = 0; 845 decrypted_block_info.result = CdmStatusToPpDecryptResult(status); 846 847 pp::Buffer_Dev buffer; 848 849 if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) { 850 PP_DCHECK(decrypted_block.get() && decrypted_block->DecryptedBuffer()); 851 if (!decrypted_block.get() || !decrypted_block->DecryptedBuffer()) { 852 PP_NOTREACHED(); 853 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; 854 } else { 855 PpbBuffer* ppb_buffer = 856 static_cast<PpbBuffer*>(decrypted_block->DecryptedBuffer()); 857 decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); 858 decrypted_block_info.data_size = ppb_buffer->Size(); 859 860 buffer = ppb_buffer->TakeBuffer(); 861 } 862 } 863 864 pp::ContentDecryptor_Private::DeliverBlock(buffer, decrypted_block_info); 865} 866 867void CdmAdapter::DecoderInitializeDone(int32_t result, 868 PP_DecryptorStreamType decoder_type, 869 uint32_t request_id, 870 bool success) { 871 PP_DCHECK(result == PP_OK); 872 pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type, 873 request_id, 874 success); 875} 876 877void CdmAdapter::DecoderDeinitializeDone(int32_t result, 878 PP_DecryptorStreamType decoder_type, 879 uint32_t request_id) { 880 pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type, 881 request_id); 882} 883 884void CdmAdapter::DecoderResetDone(int32_t result, 885 PP_DecryptorStreamType decoder_type, 886 uint32_t request_id) { 887 pp::ContentDecryptor_Private::DecoderResetDone(decoder_type, request_id); 888} 889 890void CdmAdapter::DeliverFrame( 891 int32_t result, 892 const cdm::Status& status, 893 const LinkedVideoFrame& video_frame, 894 const PP_DecryptTrackingInfo& tracking_info) { 895 PP_DCHECK(result == PP_OK); 896 PP_DecryptedFrameInfo decrypted_frame_info = {}; 897 decrypted_frame_info.tracking_info.request_id = tracking_info.request_id; 898 decrypted_frame_info.tracking_info.buffer_id = 0; 899 decrypted_frame_info.result = CdmStatusToPpDecryptResult(status); 900 901 pp::Buffer_Dev buffer; 902 903 if (decrypted_frame_info.result == PP_DECRYPTRESULT_SUCCESS) { 904 if (!IsValidVideoFrame(video_frame)) { 905 PP_NOTREACHED(); 906 decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR; 907 } else { 908 PpbBuffer* ppb_buffer = 909 static_cast<PpbBuffer*>(video_frame->FrameBuffer()); 910 911 decrypted_frame_info.tracking_info.timestamp = video_frame->Timestamp(); 912 decrypted_frame_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); 913 decrypted_frame_info.format = 914 CdmVideoFormatToPpDecryptedFrameFormat(video_frame->Format()); 915 decrypted_frame_info.width = video_frame->Size().width; 916 decrypted_frame_info.height = video_frame->Size().height; 917 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y] = 918 video_frame->PlaneOffset(cdm::VideoFrame::kYPlane); 919 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_U] = 920 video_frame->PlaneOffset(cdm::VideoFrame::kUPlane); 921 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_V] = 922 video_frame->PlaneOffset(cdm::VideoFrame::kVPlane); 923 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_Y] = 924 video_frame->Stride(cdm::VideoFrame::kYPlane); 925 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_U] = 926 video_frame->Stride(cdm::VideoFrame::kUPlane); 927 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_V] = 928 video_frame->Stride(cdm::VideoFrame::kVPlane); 929 930 buffer = ppb_buffer->TakeBuffer(); 931 } 932 } 933 934 pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info); 935} 936 937void CdmAdapter::DeliverSamples(int32_t result, 938 const cdm::Status& status, 939 const LinkedAudioFrames& audio_frames, 940 const PP_DecryptTrackingInfo& tracking_info) { 941 PP_DCHECK(result == PP_OK); 942 943 PP_DecryptedSampleInfo decrypted_sample_info = {}; 944 decrypted_sample_info.tracking_info = tracking_info; 945 decrypted_sample_info.tracking_info.timestamp = 0; 946 decrypted_sample_info.tracking_info.buffer_id = 0; 947 decrypted_sample_info.data_size = 0; 948 decrypted_sample_info.result = CdmStatusToPpDecryptResult(status); 949 950 pp::Buffer_Dev buffer; 951 952 if (decrypted_sample_info.result == PP_DECRYPTRESULT_SUCCESS) { 953 PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer()); 954 if (!audio_frames.get() || !audio_frames->FrameBuffer()) { 955 PP_NOTREACHED(); 956 decrypted_sample_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; 957 } else { 958 PpbBuffer* ppb_buffer = 959 static_cast<PpbBuffer*>(audio_frames->FrameBuffer()); 960 961 decrypted_sample_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); 962 decrypted_sample_info.data_size = ppb_buffer->Size(); 963 decrypted_sample_info.format = 964 CdmAudioFormatToPpDecryptedSampleFormat(audio_frames->Format()); 965 966 buffer = ppb_buffer->TakeBuffer(); 967 } 968 } 969 970 pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_sample_info); 971} 972 973bool CdmAdapter::IsValidVideoFrame(const LinkedVideoFrame& video_frame) { 974 if (!video_frame.get() || 975 !video_frame->FrameBuffer() || 976 (video_frame->Format() != cdm::kI420 && 977 video_frame->Format() != cdm::kYv12)) { 978 CDM_DLOG() << "Invalid video frame!"; 979 return false; 980 } 981 982 PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer()); 983 984 for (uint32_t i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) { 985 int plane_height = (i == cdm::VideoFrame::kYPlane) ? 986 video_frame->Size().height : (video_frame->Size().height + 1) / 2; 987 cdm::VideoFrame::VideoPlane plane = 988 static_cast<cdm::VideoFrame::VideoPlane>(i); 989 if (ppb_buffer->Size() < video_frame->PlaneOffset(plane) + 990 plane_height * video_frame->Stride(plane)) { 991 return false; 992 } 993 } 994 995 return true; 996} 997 998#if !defined(NDEBUG) 999void CdmAdapter::LogToConsole(const pp::Var& value) { 1000 PP_DCHECK(IsMainThread()); 1001 const PPB_Console* console = reinterpret_cast<const PPB_Console*>( 1002 pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE)); 1003 console->Log(pp_instance(), PP_LOGLEVEL_LOG, value.pp_var()); 1004} 1005#endif // !defined(NDEBUG) 1006 1007void CdmAdapter::SendPlatformChallenge( 1008 const char* service_id, uint32_t service_id_length, 1009 const char* challenge, uint32_t challenge_length) { 1010#if defined(OS_CHROMEOS) 1011 pp::VarArrayBuffer challenge_var(challenge_length); 1012 uint8_t* var_data = static_cast<uint8_t*>(challenge_var.Map()); 1013 memcpy(var_data, challenge, challenge_length); 1014 1015 std::string service_id_str(service_id, service_id_length); 1016 1017 linked_ptr<PepperPlatformChallengeResponse> response( 1018 new PepperPlatformChallengeResponse()); 1019 1020 int32_t result = platform_verification_.ChallengePlatform( 1021 pp::Var(service_id_str), 1022 challenge_var, 1023 &response->signed_data, 1024 &response->signed_data_signature, 1025 &response->platform_key_certificate, 1026 callback_factory_.NewCallback(&CdmAdapter::SendPlatformChallengeDone, 1027 response)); 1028 challenge_var.Unmap(); 1029 if (result == PP_OK_COMPLETIONPENDING) 1030 return; 1031 1032 // Fall through on error and issue an empty OnPlatformChallengeResponse(). 1033 PP_DCHECK(result != PP_OK); 1034#endif 1035 1036 cdm::PlatformChallengeResponse platform_challenge_response = {}; 1037 cdm_->OnPlatformChallengeResponse(platform_challenge_response); 1038} 1039 1040void CdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask) { 1041#if defined(OS_CHROMEOS) 1042 int32_t result = output_protection_.EnableProtection( 1043 desired_protection_mask, callback_factory_.NewCallback( 1044 &CdmAdapter::EnableProtectionDone)); 1045 1046 // Errors are ignored since clients must call QueryOutputProtectionStatus() to 1047 // inspect the protection status on a regular basis. 1048 1049 if (result != PP_OK && result != PP_OK_COMPLETIONPENDING) 1050 CDM_DLOG() << __FUNCTION__ << " failed!"; 1051#endif 1052} 1053 1054void CdmAdapter::QueryOutputProtectionStatus() { 1055#if defined(OS_CHROMEOS) 1056 PP_DCHECK(!query_output_protection_in_progress_); 1057 1058 output_link_mask_ = output_protection_mask_ = 0; 1059 const int32_t result = output_protection_.QueryStatus( 1060 &output_link_mask_, 1061 &output_protection_mask_, 1062 callback_factory_.NewCallback( 1063 &CdmAdapter::QueryOutputProtectionStatusDone)); 1064 if (result == PP_OK_COMPLETIONPENDING) { 1065 query_output_protection_in_progress_ = true; 1066 ReportOutputProtectionQuery(); 1067 return; 1068 } 1069 1070 // Fall through on error and issue an empty OnQueryOutputProtectionStatus(). 1071 PP_DCHECK(result != PP_OK); 1072#endif 1073 1074 cdm_->OnQueryOutputProtectionStatus(0, 0); 1075} 1076 1077void CdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type, 1078 cdm::Status decoder_status) { 1079 switch (stream_type) { 1080 case cdm::kStreamTypeAudio: 1081 PP_DCHECK(deferred_initialize_audio_decoder_); 1082 CallOnMain( 1083 callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone, 1084 PP_DECRYPTORSTREAMTYPE_AUDIO, 1085 deferred_audio_decoder_config_id_, 1086 decoder_status == cdm::kSuccess)); 1087 deferred_initialize_audio_decoder_ = false; 1088 deferred_audio_decoder_config_id_ = 0; 1089 break; 1090 case cdm::kStreamTypeVideo: 1091 PP_DCHECK(deferred_initialize_video_decoder_); 1092 CallOnMain( 1093 callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone, 1094 PP_DECRYPTORSTREAMTYPE_VIDEO, 1095 deferred_video_decoder_config_id_, 1096 decoder_status == cdm::kSuccess)); 1097 deferred_initialize_video_decoder_ = false; 1098 deferred_video_decoder_config_id_ = 0; 1099 break; 1100 } 1101} 1102 1103// The CDM owns the returned object and must call FileIO::Close() to release it. 1104cdm::FileIO* CdmAdapter::CreateFileIO(cdm::FileIOClient* client) { 1105 return new CdmFileIOImpl(client, pp_instance()); 1106} 1107 1108#if defined(OS_CHROMEOS) 1109void CdmAdapter::ReportOutputProtectionUMA(OutputProtectionStatus status) { 1110 pp::UMAPrivate uma_interface_(this); 1111 uma_interface_.HistogramEnumeration( 1112 "Media.EME.OutputProtection", status, OUTPUT_PROTECTION_MAX); 1113} 1114 1115void CdmAdapter::ReportOutputProtectionQuery() { 1116 if (uma_for_output_protection_query_reported_) 1117 return; 1118 1119 ReportOutputProtectionUMA(OUTPUT_PROTECTION_QUERIED); 1120 uma_for_output_protection_query_reported_ = true; 1121} 1122 1123void CdmAdapter::ReportOutputProtectionQueryResult() { 1124 if (uma_for_output_protection_positive_result_reported_) 1125 return; 1126 1127 // Report UMAs for output protection query result. 1128 uint32_t external_links = (output_link_mask_ & ~cdm::kLinkTypeInternal); 1129 1130 if (!external_links) { 1131 ReportOutputProtectionUMA(OUTPUT_PROTECTION_NO_EXTERNAL_LINK); 1132 uma_for_output_protection_positive_result_reported_ = true; 1133 return; 1134 } 1135 1136 const uint32_t kProtectableLinks = 1137 cdm::kLinkTypeHDMI | cdm::kLinkTypeDVI | cdm::kLinkTypeDisplayPort; 1138 bool is_unprotectable_link_connected = external_links & ~kProtectableLinks; 1139 bool is_hdcp_enabled_on_all_protectable_links = 1140 output_protection_mask_ & cdm::kProtectionHDCP; 1141 1142 if (!is_unprotectable_link_connected && 1143 is_hdcp_enabled_on_all_protectable_links) { 1144 ReportOutputProtectionUMA( 1145 OUTPUT_PROTECTION_ALL_EXTERNAL_LINKS_PROTECTED); 1146 uma_for_output_protection_positive_result_reported_ = true; 1147 return; 1148 } 1149 1150 // Do not report a negative result because it could be a false negative. 1151 // Instead, we will calculate number of negatives using the total number of 1152 // queries and success results. 1153} 1154 1155void CdmAdapter::SendPlatformChallengeDone( 1156 int32_t result, 1157 const linked_ptr<PepperPlatformChallengeResponse>& response) { 1158 if (result != PP_OK) { 1159 CDM_DLOG() << __FUNCTION__ << ": Platform challenge failed!"; 1160 cdm::PlatformChallengeResponse platform_challenge_response = {}; 1161 cdm_->OnPlatformChallengeResponse(platform_challenge_response); 1162 return; 1163 } 1164 1165 pp::VarArrayBuffer signed_data_var(response->signed_data); 1166 pp::VarArrayBuffer signed_data_signature_var(response->signed_data_signature); 1167 std::string platform_key_certificate_string = 1168 response->platform_key_certificate.AsString(); 1169 1170 cdm::PlatformChallengeResponse platform_challenge_response = { 1171 static_cast<uint8_t*>(signed_data_var.Map()), 1172 signed_data_var.ByteLength(), 1173 static_cast<uint8_t*>(signed_data_signature_var.Map()), 1174 signed_data_signature_var.ByteLength(), 1175 reinterpret_cast<const uint8_t*>(platform_key_certificate_string.data()), 1176 static_cast<uint32_t>(platform_key_certificate_string.length())}; 1177 cdm_->OnPlatformChallengeResponse(platform_challenge_response); 1178 1179 signed_data_var.Unmap(); 1180 signed_data_signature_var.Unmap(); 1181} 1182 1183void CdmAdapter::EnableProtectionDone(int32_t result) { 1184 // Does nothing since clients must call QueryOutputProtectionStatus() to 1185 // inspect the protection status on a regular basis. 1186 CDM_DLOG() << __FUNCTION__ << " : " << result; 1187} 1188 1189void CdmAdapter::QueryOutputProtectionStatusDone(int32_t result) { 1190 PP_DCHECK(query_output_protection_in_progress_); 1191 query_output_protection_in_progress_ = false; 1192 1193 // Return a protection status of none on error. 1194 if (result != PP_OK) 1195 output_link_mask_ = output_protection_mask_ = 0; 1196 else 1197 ReportOutputProtectionQueryResult(); 1198 1199 cdm_->OnQueryOutputProtectionStatus(output_link_mask_, 1200 output_protection_mask_); 1201} 1202#endif 1203 1204CdmAdapter::SessionError::SessionError(cdm::Error error, 1205 uint32_t system_code, 1206 std::string error_description) 1207 : error(error), 1208 system_code(system_code), 1209 error_description(error_description) { 1210} 1211 1212void* GetCdmHost(int host_interface_version, void* user_data) { 1213 if (!host_interface_version || !user_data) 1214 return NULL; 1215 1216 COMPILE_ASSERT( 1217 cdm::ContentDecryptionModule::Host::kVersion == cdm::Host_5::kVersion, 1218 update_code_below); 1219 1220 // Ensure IsSupportedCdmHostVersion matches implementation of this function. 1221 // Always update this DCHECK when updating this function. 1222 // If this check fails, update this function and DCHECK or update 1223 // IsSupportedCdmHostVersion. 1224 1225 PP_DCHECK( 1226 // Future version is not supported. 1227 !IsSupportedCdmHostVersion(cdm::Host_5::kVersion + 1) && 1228 // Current version is supported. 1229 IsSupportedCdmHostVersion(cdm::Host_5::kVersion) && 1230 // Include all previous supported versions (if any) here. 1231 IsSupportedCdmHostVersion(cdm::Host_4::kVersion) && 1232 // One older than the oldest supported version is not supported. 1233 !IsSupportedCdmHostVersion(cdm::Host_4::kVersion - 1)); 1234 PP_DCHECK(IsSupportedCdmHostVersion(host_interface_version)); 1235 1236 CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data); 1237 CDM_DLOG() << "Create CDM Host with version " << host_interface_version; 1238 switch (host_interface_version) { 1239 case cdm::Host_4::kVersion: 1240 return static_cast<cdm::Host_4*>(cdm_adapter); 1241 case cdm::Host_5::kVersion: 1242 return static_cast<cdm::Host_5*>(cdm_adapter); 1243 default: 1244 PP_NOTREACHED(); 1245 return NULL; 1246 } 1247} 1248 1249// This object is the global object representing this plugin library as long 1250// as it is loaded. 1251class CdmAdapterModule : public pp::Module { 1252 public: 1253 CdmAdapterModule() : pp::Module() { 1254 // This function blocks the renderer thread (PluginInstance::Initialize()). 1255 // Move this call to other places if this may be a concern in the future. 1256 INITIALIZE_CDM_MODULE(); 1257 } 1258 virtual ~CdmAdapterModule() { 1259 DeinitializeCdmModule(); 1260 } 1261 1262 virtual pp::Instance* CreateInstance(PP_Instance instance) { 1263 return new CdmAdapter(instance, this); 1264 } 1265 1266 private: 1267 CdmFileIOImpl::ResourceTracker cdm_file_io_impl_resource_tracker; 1268}; 1269 1270} // namespace media 1271 1272namespace pp { 1273 1274// Factory function for your specialization of the Module object. 1275Module* CreateModule() { 1276 return new media::CdmAdapterModule(); 1277} 1278 1279} // namespace pp 1280