cdm_adapter.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 13#if defined(CHECK_DOCUMENT_URL) 14#include "ppapi/cpp/dev/url_util_dev.h" 15#include "ppapi/cpp/instance_handle.h" 16#endif // defined(CHECK_DOCUMENT_URL) 17 18namespace { 19 20#if !defined(NDEBUG) 21 #define DLOG_TO_CONSOLE(message) LogToConsole(message); 22#else 23 #define DLOG_TO_CONSOLE(message) (void)(message); 24#endif 25 26bool IsMainThread() { 27 return pp::Module::Get()->core()->IsMainThread(); 28} 29 30// Posts a task to run |cb| on the main thread. The task is posted even if the 31// current thread is the main thread. 32void PostOnMain(pp::CompletionCallback cb) { 33 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK); 34} 35 36// Ensures |cb| is called on the main thread, either because the current thread 37// is the main thread or by posting it to the main thread. 38void CallOnMain(pp::CompletionCallback cb) { 39 // TODO(tomfinegan): This is only necessary because PPAPI doesn't allow calls 40 // off the main thread yet. Remove this once the change lands. 41 if (IsMainThread()) 42 cb.Run(PP_OK); 43 else 44 PostOnMain(cb); 45} 46 47// Configures a cdm::InputBuffer. |subsamples| must exist as long as 48// |input_buffer| is in use. 49void ConfigureInputBuffer( 50 const pp::Buffer_Dev& encrypted_buffer, 51 const PP_EncryptedBlockInfo& encrypted_block_info, 52 std::vector<cdm::SubsampleEntry>* subsamples, 53 cdm::InputBuffer* input_buffer) { 54 PP_DCHECK(subsamples); 55 PP_DCHECK(!encrypted_buffer.is_null()); 56 57 input_buffer->data = static_cast<uint8_t*>(encrypted_buffer.data()); 58 input_buffer->data_size = encrypted_block_info.data_size; 59 PP_DCHECK(encrypted_buffer.size() >= input_buffer->data_size); 60 61 PP_DCHECK(encrypted_block_info.key_id_size <= 62 arraysize(encrypted_block_info.key_id)); 63 input_buffer->key_id_size = encrypted_block_info.key_id_size; 64 input_buffer->key_id = input_buffer->key_id_size > 0 ? 65 encrypted_block_info.key_id : NULL; 66 67 PP_DCHECK(encrypted_block_info.iv_size <= arraysize(encrypted_block_info.iv)); 68 input_buffer->iv_size = encrypted_block_info.iv_size; 69 input_buffer->iv = encrypted_block_info.iv_size > 0 ? 70 encrypted_block_info.iv : NULL; 71 72 input_buffer->num_subsamples = encrypted_block_info.num_subsamples; 73 if (encrypted_block_info.num_subsamples > 0) { 74 subsamples->reserve(encrypted_block_info.num_subsamples); 75 76 for (uint32_t i = 0; i < encrypted_block_info.num_subsamples; ++i) { 77 subsamples->push_back(cdm::SubsampleEntry( 78 encrypted_block_info.subsamples[i].clear_bytes, 79 encrypted_block_info.subsamples[i].cipher_bytes)); 80 } 81 82 input_buffer->subsamples = &(*subsamples)[0]; 83 } 84 85 input_buffer->timestamp = encrypted_block_info.tracking_info.timestamp; 86} 87 88PP_DecryptResult CdmStatusToPpDecryptResult(cdm::Status status) { 89 switch (status) { 90 case cdm::kSuccess: 91 return PP_DECRYPTRESULT_SUCCESS; 92 case cdm::kNoKey: 93 return PP_DECRYPTRESULT_DECRYPT_NOKEY; 94 case cdm::kNeedMoreData: 95 return PP_DECRYPTRESULT_NEEDMOREDATA; 96 case cdm::kDecryptError: 97 return PP_DECRYPTRESULT_DECRYPT_ERROR; 98 case cdm::kDecodeError: 99 return PP_DECRYPTRESULT_DECODE_ERROR; 100 default: 101 PP_NOTREACHED(); 102 return PP_DECRYPTRESULT_DECODE_ERROR; 103 } 104} 105 106PP_DecryptedFrameFormat CdmVideoFormatToPpDecryptedFrameFormat( 107 cdm::VideoFormat format) { 108 switch (format) { 109 case cdm::kYv12: 110 return PP_DECRYPTEDFRAMEFORMAT_YV12; 111 case cdm::kI420: 112 return PP_DECRYPTEDFRAMEFORMAT_I420; 113 default: 114 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN; 115 } 116} 117 118PP_DecryptedSampleFormat CdmAudioFormatToPpDecryptedSampleFormat( 119 cdm::AudioFormat format) { 120 switch (format) { 121 case cdm::kAudioFormatU8: 122 return PP_DECRYPTEDSAMPLEFORMAT_U8; 123 case cdm::kAudioFormatS16: 124 return PP_DECRYPTEDSAMPLEFORMAT_S16; 125 case cdm::kAudioFormatS32: 126 return PP_DECRYPTEDSAMPLEFORMAT_S32; 127 case cdm::kAudioFormatF32: 128 return PP_DECRYPTEDSAMPLEFORMAT_F32; 129 case cdm::kAudioFormatPlanarS16: 130 return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16; 131 case cdm::kAudioFormatPlanarF32: 132 return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32; 133 default: 134 return PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN; 135 } 136} 137 138cdm::AudioDecoderConfig::AudioCodec PpAudioCodecToCdmAudioCodec( 139 PP_AudioCodec codec) { 140 switch (codec) { 141 case PP_AUDIOCODEC_VORBIS: 142 return cdm::AudioDecoderConfig::kCodecVorbis; 143 case PP_AUDIOCODEC_AAC: 144 return cdm::AudioDecoderConfig::kCodecAac; 145 default: 146 return cdm::AudioDecoderConfig::kUnknownAudioCodec; 147 } 148} 149 150cdm::VideoDecoderConfig::VideoCodec PpVideoCodecToCdmVideoCodec( 151 PP_VideoCodec codec) { 152 switch (codec) { 153 case PP_VIDEOCODEC_VP8: 154 return cdm::VideoDecoderConfig::kCodecVp8; 155 case PP_VIDEOCODEC_H264: 156 return cdm::VideoDecoderConfig::kCodecH264; 157 default: 158 return cdm::VideoDecoderConfig::kUnknownVideoCodec; 159 } 160} 161 162cdm::VideoDecoderConfig::VideoCodecProfile PpVCProfileToCdmVCProfile( 163 PP_VideoCodecProfile profile) { 164 switch (profile) { 165 case PP_VIDEOCODECPROFILE_VP8_MAIN: 166 return cdm::VideoDecoderConfig::kVp8ProfileMain; 167 case PP_VIDEOCODECPROFILE_H264_BASELINE: 168 return cdm::VideoDecoderConfig::kH264ProfileBaseline; 169 case PP_VIDEOCODECPROFILE_H264_MAIN: 170 return cdm::VideoDecoderConfig::kH264ProfileMain; 171 case PP_VIDEOCODECPROFILE_H264_EXTENDED: 172 return cdm::VideoDecoderConfig::kH264ProfileExtended; 173 case PP_VIDEOCODECPROFILE_H264_HIGH: 174 return cdm::VideoDecoderConfig::kH264ProfileHigh; 175 case PP_VIDEOCODECPROFILE_H264_HIGH_10: 176 return cdm::VideoDecoderConfig::kH264ProfileHigh10; 177 case PP_VIDEOCODECPROFILE_H264_HIGH_422: 178 return cdm::VideoDecoderConfig::kH264ProfileHigh422; 179 case PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE: 180 return cdm::VideoDecoderConfig::kH264ProfileHigh444Predictive; 181 default: 182 return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile; 183 } 184} 185 186cdm::VideoFormat PpDecryptedFrameFormatToCdmVideoFormat( 187 PP_DecryptedFrameFormat format) { 188 switch (format) { 189 case PP_DECRYPTEDFRAMEFORMAT_YV12: 190 return cdm::kYv12; 191 case PP_DECRYPTEDFRAMEFORMAT_I420: 192 return cdm::kI420; 193 default: 194 return cdm::kUnknownVideoFormat; 195 } 196} 197 198cdm::StreamType PpDecryptorStreamTypeToCdmStreamType( 199 PP_DecryptorStreamType stream_type) { 200 switch (stream_type) { 201 case PP_DECRYPTORSTREAMTYPE_AUDIO: 202 return cdm::kStreamTypeAudio; 203 case PP_DECRYPTORSTREAMTYPE_VIDEO: 204 return cdm::kStreamTypeVideo; 205 } 206 207 PP_NOTREACHED(); 208 return cdm::kStreamTypeVideo; 209} 210 211} // namespace 212 213namespace media { 214 215CdmAdapter::CdmAdapter(PP_Instance instance, pp::Module* module) 216 : pp::Instance(instance), 217 pp::ContentDecryptor_Private(this), 218#if defined(OS_CHROMEOS) 219 output_protection_(this), 220 platform_verification_(this), 221 challenge_in_progress_(false), 222 output_link_mask_(0), 223 output_protection_mask_(0), 224 query_output_protection_in_progress_(false), 225#endif 226 allocator_(this), 227 cdm_(NULL), 228 deferred_initialize_audio_decoder_(false), 229 deferred_audio_decoder_config_id_(0), 230 deferred_initialize_video_decoder_(false), 231 deferred_video_decoder_config_id_(0) { 232 callback_factory_.Initialize(this); 233} 234 235CdmAdapter::~CdmAdapter() {} 236 237bool CdmAdapter::CreateCdmInstance(const std::string& key_system) { 238 PP_DCHECK(!cdm_); 239 cdm_ = make_linked_ptr(CdmWrapper::Create( 240 key_system.data(), key_system.size(), GetCdmHost, this)); 241 bool success = cdm_ != NULL; 242 243 const std::string message = "CDM instance for " + key_system + 244 (success ? "" : " could not be") + " created."; 245 DLOG_TO_CONSOLE(message); 246 CDM_DLOG() << message; 247 248 return success; 249} 250 251// No errors should be reported in this function because the spec says: 252// "Store this new error object internally with the MediaKeys instance being 253// created. This will be used to fire an error against any session created for 254// this instance." These errors will be reported during session creation 255// (CreateSession()) or session loading (LoadSession()). 256// TODO(xhwang): If necessary, we need to store the error here if we want to 257// support more specific error reporting (other than "Unknown"). 258void CdmAdapter::Initialize(const std::string& key_system) { 259 PP_DCHECK(!key_system.empty()); 260 PP_DCHECK(key_system_.empty() || (key_system_ == key_system && cdm_)); 261 262 if (!cdm_ && !CreateCdmInstance(key_system)) 263 return; 264 265 PP_DCHECK(cdm_); 266 key_system_ = key_system; 267} 268 269void CdmAdapter::CreateSession(uint32_t session_id, 270 const std::string& content_type, 271 pp::VarArrayBuffer init_data) { 272 // Initialize() doesn't report an error, so CreateSession() can be called 273 // even if Initialize() failed. 274 if (!cdm_) { 275 OnSessionError(session_id, cdm::kUnknownError, 0); 276 return; 277 } 278 279#if defined(CHECK_DOCUMENT_URL) 280 PP_URLComponents_Dev url_components = {}; 281 const pp::URLUtil_Dev* url_util = pp::URLUtil_Dev::Get(); 282 if (!url_util) { 283 OnSessionError(session_id, cdm::kUnknownError, 0); 284 return; 285 } 286 pp::Var href = url_util->GetDocumentURL( 287 pp::InstanceHandle(pp_instance()), &url_components); 288 PP_DCHECK(href.is_string()); 289 PP_DCHECK(!href.AsString().empty()); 290 PP_DCHECK(url_components.host.begin); 291 PP_DCHECK(0 < url_components.host.len); 292#endif // defined(CHECK_DOCUMENT_URL) 293 294 cdm_->CreateSession(session_id, 295 content_type.data(), 296 content_type.size(), 297 static_cast<const uint8_t*>(init_data.Map()), 298 init_data.ByteLength()); 299} 300 301void CdmAdapter::LoadSession(uint32_t session_id, 302 const std::string& web_session_id) { 303 // Initialize() doesn't report an error, so LoadSession() can be called 304 // even if Initialize() failed. 305 if (!cdm_) { 306 OnSessionError(session_id, cdm::kUnknownError, 0); 307 return; 308 } 309 310 if (!cdm_->LoadSession( 311 session_id, web_session_id.data(), web_session_id.size())) 312 OnSessionError(session_id, cdm::kUnknownError, 0); 313} 314 315void CdmAdapter::UpdateSession(uint32_t session_id, 316 pp::VarArrayBuffer response) { 317 // TODO(jrummell): In EME WD, AddKey() can only be called on valid sessions. 318 // We should be able to DCHECK(cdm_) when addressing http://crbug.com/249976. 319 if (!cdm_) { 320 OnSessionError(session_id, cdm::kUnknownError, 0); 321 return; 322 } 323 324 const uint8_t* response_ptr = static_cast<const uint8_t*>(response.Map()); 325 const uint32_t response_size = response.ByteLength(); 326 327 if (!response_ptr || response_size <= 0) { 328 OnSessionError(session_id, cdm::kUnknownError, 0); 329 return; 330 } 331 CdmWrapper::Result result = 332 cdm_->UpdateSession(session_id, response_ptr, response_size); 333 switch (result) { 334 case CdmWrapper::NO_ACTION: 335 break; 336 case CdmWrapper::CALL_KEY_ADDED: 337 OnSessionReady(session_id); 338 break; 339 case CdmWrapper::CALL_KEY_ERROR: 340 OnSessionError(session_id, cdm::kUnknownError, 0); 341 break; 342 } 343} 344 345void CdmAdapter::ReleaseSession(uint32_t session_id) { 346 // TODO(jrummell): In EME WD, AddKey() can only be called on valid sessions. 347 // We should be able to DCHECK(cdm_) when addressing http://crbug.com/249976. 348 if (!cdm_) { 349 OnSessionError(session_id, cdm::kUnknownError, 0); 350 return; 351 } 352 353 CdmWrapper::Result result = cdm_->ReleaseSession(session_id); 354 switch (result) { 355 case CdmWrapper::NO_ACTION: 356 break; 357 case CdmWrapper::CALL_KEY_ADDED: 358 PP_NOTREACHED(); 359 break; 360 case CdmWrapper::CALL_KEY_ERROR: 361 OnSessionError(session_id, cdm::kUnknownError, 0); 362 break; 363 } 364} 365 366// Note: In the following decryption/decoding related functions, errors are NOT 367// reported via KeyError, but are reported via corresponding PPB calls. 368 369void CdmAdapter::Decrypt(pp::Buffer_Dev encrypted_buffer, 370 const PP_EncryptedBlockInfo& encrypted_block_info) { 371 PP_DCHECK(!encrypted_buffer.is_null()); 372 373 // Release a buffer that the caller indicated it is finished with. 374 allocator_.Release(encrypted_block_info.tracking_info.buffer_id); 375 376 cdm::Status status = cdm::kDecryptError; 377 LinkedDecryptedBlock decrypted_block(new DecryptedBlockImpl()); 378 379 if (cdm_) { 380 cdm::InputBuffer input_buffer; 381 std::vector<cdm::SubsampleEntry> subsamples; 382 ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples, 383 &input_buffer); 384 status = cdm_->Decrypt(input_buffer, decrypted_block.get()); 385 PP_DCHECK(status != cdm::kSuccess || 386 (decrypted_block->DecryptedBuffer() && 387 decrypted_block->DecryptedBuffer()->Size())); 388 } 389 390 CallOnMain(callback_factory_.NewCallback( 391 &CdmAdapter::DeliverBlock, 392 status, 393 decrypted_block, 394 encrypted_block_info.tracking_info)); 395} 396 397void CdmAdapter::InitializeAudioDecoder( 398 const PP_AudioDecoderConfig& decoder_config, 399 pp::Buffer_Dev extra_data_buffer) { 400 PP_DCHECK(!deferred_initialize_audio_decoder_); 401 PP_DCHECK(deferred_audio_decoder_config_id_ == 0); 402 cdm::Status status = cdm::kSessionError; 403 if (cdm_) { 404 cdm::AudioDecoderConfig cdm_decoder_config; 405 cdm_decoder_config.codec = 406 PpAudioCodecToCdmAudioCodec(decoder_config.codec); 407 cdm_decoder_config.channel_count = decoder_config.channel_count; 408 cdm_decoder_config.bits_per_channel = decoder_config.bits_per_channel; 409 cdm_decoder_config.samples_per_second = decoder_config.samples_per_second; 410 cdm_decoder_config.extra_data = 411 static_cast<uint8_t*>(extra_data_buffer.data()); 412 cdm_decoder_config.extra_data_size = extra_data_buffer.size(); 413 status = cdm_->InitializeAudioDecoder(cdm_decoder_config); 414 } 415 416 if (status == cdm::kDeferredInitialization) { 417 deferred_initialize_audio_decoder_ = true; 418 deferred_audio_decoder_config_id_ = decoder_config.request_id; 419 return; 420 } 421 422 CallOnMain(callback_factory_.NewCallback( 423 &CdmAdapter::DecoderInitializeDone, 424 PP_DECRYPTORSTREAMTYPE_AUDIO, 425 decoder_config.request_id, 426 status == cdm::kSuccess)); 427} 428 429void CdmAdapter::InitializeVideoDecoder( 430 const PP_VideoDecoderConfig& decoder_config, 431 pp::Buffer_Dev extra_data_buffer) { 432 PP_DCHECK(!deferred_initialize_video_decoder_); 433 PP_DCHECK(deferred_video_decoder_config_id_ == 0); 434 cdm::Status status = cdm::kSessionError; 435 if (cdm_) { 436 cdm::VideoDecoderConfig cdm_decoder_config; 437 cdm_decoder_config.codec = 438 PpVideoCodecToCdmVideoCodec(decoder_config.codec); 439 cdm_decoder_config.profile = 440 PpVCProfileToCdmVCProfile(decoder_config.profile); 441 cdm_decoder_config.format = 442 PpDecryptedFrameFormatToCdmVideoFormat(decoder_config.format); 443 cdm_decoder_config.coded_size.width = decoder_config.width; 444 cdm_decoder_config.coded_size.height = decoder_config.height; 445 cdm_decoder_config.extra_data = 446 static_cast<uint8_t*>(extra_data_buffer.data()); 447 cdm_decoder_config.extra_data_size = extra_data_buffer.size(); 448 status = cdm_->InitializeVideoDecoder(cdm_decoder_config); 449 } 450 451 if (status == cdm::kDeferredInitialization) { 452 deferred_initialize_video_decoder_ = true; 453 deferred_video_decoder_config_id_ = decoder_config.request_id; 454 return; 455 } 456 457 CallOnMain(callback_factory_.NewCallback( 458 &CdmAdapter::DecoderInitializeDone, 459 PP_DECRYPTORSTREAMTYPE_VIDEO, 460 decoder_config.request_id, 461 status == cdm::kSuccess)); 462} 463 464void CdmAdapter::DeinitializeDecoder(PP_DecryptorStreamType decoder_type, 465 uint32_t request_id) { 466 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded. 467 if (cdm_) { 468 cdm_->DeinitializeDecoder( 469 PpDecryptorStreamTypeToCdmStreamType(decoder_type)); 470 } 471 472 CallOnMain(callback_factory_.NewCallback( 473 &CdmAdapter::DecoderDeinitializeDone, 474 decoder_type, 475 request_id)); 476} 477 478void CdmAdapter::ResetDecoder(PP_DecryptorStreamType decoder_type, 479 uint32_t request_id) { 480 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded. 481 if (cdm_) 482 cdm_->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type)); 483 484 CallOnMain(callback_factory_.NewCallback(&CdmAdapter::DecoderResetDone, 485 decoder_type, 486 request_id)); 487} 488 489void CdmAdapter::DecryptAndDecode( 490 PP_DecryptorStreamType decoder_type, 491 pp::Buffer_Dev encrypted_buffer, 492 const PP_EncryptedBlockInfo& encrypted_block_info) { 493 PP_DCHECK(cdm_); // InitializeXxxxxDecoder should have succeeded. 494 // Release a buffer that the caller indicated it is finished with. 495 allocator_.Release(encrypted_block_info.tracking_info.buffer_id); 496 497 cdm::InputBuffer input_buffer; 498 std::vector<cdm::SubsampleEntry> subsamples; 499 if (cdm_ && !encrypted_buffer.is_null()) { 500 ConfigureInputBuffer(encrypted_buffer, 501 encrypted_block_info, 502 &subsamples, 503 &input_buffer); 504 } 505 506 cdm::Status status = cdm::kDecodeError; 507 508 switch (decoder_type) { 509 case PP_DECRYPTORSTREAMTYPE_VIDEO: { 510 LinkedVideoFrame video_frame(new VideoFrameImpl()); 511 if (cdm_) 512 status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get()); 513 CallOnMain(callback_factory_.NewCallback( 514 &CdmAdapter::DeliverFrame, 515 status, 516 video_frame, 517 encrypted_block_info.tracking_info)); 518 return; 519 } 520 521 case PP_DECRYPTORSTREAMTYPE_AUDIO: { 522 LinkedAudioFrames audio_frames(new AudioFramesImpl()); 523 if (cdm_) { 524 status = cdm_->DecryptAndDecodeSamples(input_buffer, 525 audio_frames.get()); 526 } 527 CallOnMain(callback_factory_.NewCallback( 528 &CdmAdapter::DeliverSamples, 529 status, 530 audio_frames, 531 encrypted_block_info.tracking_info)); 532 return; 533 } 534 535 default: 536 PP_NOTREACHED(); 537 return; 538 } 539} 540 541cdm::Buffer* CdmAdapter::Allocate(uint32_t capacity) { 542 return allocator_.Allocate(capacity); 543} 544 545void CdmAdapter::SetTimer(int64_t delay_ms, void* context) { 546 // NOTE: doesn't really need to run on the main thread; could just as well run 547 // on a helper thread if |cdm_| were thread-friendly and care was taken. We 548 // only use CallOnMainThread() here to get delayed-execution behavior. 549 pp::Module::Get()->core()->CallOnMainThread( 550 delay_ms, 551 callback_factory_.NewCallback(&CdmAdapter::TimerExpired, context), 552 PP_OK); 553} 554 555void CdmAdapter::TimerExpired(int32_t result, void* context) { 556 PP_DCHECK(result == PP_OK); 557 cdm_->TimerExpired(context); 558} 559 560double CdmAdapter::GetCurrentWallTimeInSeconds() { 561 return pp::Module::Get()->core()->GetTime(); 562} 563 564void CdmAdapter::SendKeyMessage( 565 const char* session_id, uint32_t session_id_length, 566 const char* message, uint32_t message_length, 567 const char* default_url, uint32_t default_url_length) { 568 PP_DCHECK(!key_system_.empty()); 569 570 std::string session_id_str(session_id, session_id_length); 571 PP_DCHECK(!session_id_str.empty()); 572 uint32_t session_reference_id = cdm_->LookupSessionId(session_id_str); 573 574 OnSessionCreated(session_reference_id, session_id, session_id_length); 575 OnSessionMessage(session_reference_id, 576 message, message_length, 577 default_url, default_url_length); 578} 579 580void CdmAdapter::SendKeyError(const char* session_id, 581 uint32_t session_id_length, 582 cdm::MediaKeyError error_code, 583 uint32_t system_code) { 584 std::string session_id_str(session_id, session_id_length); 585 uint32_t session_reference_id = cdm_->LookupSessionId(session_id_str); 586 OnSessionError(session_reference_id, error_code, system_code); 587} 588 589void CdmAdapter::GetPrivateData(int32_t* instance, 590 GetPrivateInterface* get_interface) { 591 *instance = pp_instance(); 592 *get_interface = pp::Module::Get()->get_browser_interface(); 593} 594 595void CdmAdapter::OnSessionCreated(uint32_t session_id, 596 const char* web_session_id, 597 uint32_t web_session_id_length) { 598 PostOnMain(callback_factory_.NewCallback( 599 &CdmAdapter::SendSessionCreatedInternal, 600 session_id, 601 std::string(web_session_id, web_session_id_length))); 602} 603 604void CdmAdapter::OnSessionMessage(uint32_t session_id, 605 const char* message, 606 uint32_t message_length, 607 const char* destination_url, 608 uint32_t destination_url_length) { 609 PostOnMain(callback_factory_.NewCallback( 610 &CdmAdapter::SendSessionMessageInternal, 611 session_id, 612 std::vector<uint8>(message, message + message_length), 613 std::string(destination_url, destination_url_length))); 614} 615 616void CdmAdapter::OnSessionReady(uint32_t session_id) { 617 PostOnMain(callback_factory_.NewCallback( 618 &CdmAdapter::SendSessionReadyInternal, session_id)); 619} 620 621void CdmAdapter::OnSessionClosed(uint32_t session_id) { 622 PostOnMain(callback_factory_.NewCallback( 623 &CdmAdapter::SendSessionClosedInternal, session_id)); 624} 625 626void CdmAdapter::OnSessionError(uint32_t session_id, 627 cdm::MediaKeyError error_code, 628 uint32_t system_code) { 629 PostOnMain(callback_factory_.NewCallback( 630 &CdmAdapter::SendSessionErrorInternal, 631 session_id, 632 error_code, 633 system_code)); 634} 635 636void CdmAdapter::SendSessionCreatedInternal(int32_t result, 637 uint32_t session_id, 638 const std::string& web_session_id) { 639 PP_DCHECK(result == PP_OK); 640 pp::ContentDecryptor_Private::SessionCreated(session_id, web_session_id); 641} 642 643void CdmAdapter::SendSessionMessageInternal(int32_t result, 644 uint32_t session_id, 645 const std::vector<uint8>& message, 646 const std::string& default_url) { 647 PP_DCHECK(result == PP_OK); 648 649 pp::VarArrayBuffer message_array_buffer(message.size()); 650 if (message.size() > 0) { 651 memcpy(message_array_buffer.Map(), message.data(), message.size()); 652 } 653 654 pp::ContentDecryptor_Private::SessionMessage( 655 session_id, message_array_buffer, default_url); 656} 657 658void CdmAdapter::SendSessionReadyInternal(int32_t result, uint32_t session_id) { 659 PP_DCHECK(result == PP_OK); 660 pp::ContentDecryptor_Private::SessionReady(session_id); 661} 662 663void CdmAdapter::SendSessionClosedInternal(int32_t result, 664 uint32_t session_id) { 665 PP_DCHECK(result == PP_OK); 666 pp::ContentDecryptor_Private::SessionClosed(session_id); 667} 668 669void CdmAdapter::SendSessionErrorInternal(int32_t result, 670 uint32_t session_id, 671 cdm::MediaKeyError error_code, 672 uint32_t system_code) { 673 PP_DCHECK(result == PP_OK); 674 pp::ContentDecryptor_Private::SessionError( 675 session_id, error_code, system_code); 676} 677 678void CdmAdapter::DeliverBlock(int32_t result, 679 const cdm::Status& status, 680 const LinkedDecryptedBlock& decrypted_block, 681 const PP_DecryptTrackingInfo& tracking_info) { 682 PP_DCHECK(result == PP_OK); 683 PP_DecryptedBlockInfo decrypted_block_info; 684 decrypted_block_info.tracking_info = tracking_info; 685 decrypted_block_info.tracking_info.timestamp = decrypted_block->Timestamp(); 686 decrypted_block_info.tracking_info.buffer_id = 0; 687 decrypted_block_info.data_size = 0; 688 decrypted_block_info.result = CdmStatusToPpDecryptResult(status); 689 690 pp::Buffer_Dev buffer; 691 692 if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) { 693 PP_DCHECK(decrypted_block.get() && decrypted_block->DecryptedBuffer()); 694 if (!decrypted_block.get() || !decrypted_block->DecryptedBuffer()) { 695 PP_NOTREACHED(); 696 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; 697 } else { 698 PpbBuffer* ppb_buffer = 699 static_cast<PpbBuffer*>(decrypted_block->DecryptedBuffer()); 700 buffer = ppb_buffer->buffer_dev(); 701 decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); 702 decrypted_block_info.data_size = ppb_buffer->Size(); 703 } 704 } 705 706 pp::ContentDecryptor_Private::DeliverBlock(buffer, decrypted_block_info); 707} 708 709void CdmAdapter::DecoderInitializeDone(int32_t result, 710 PP_DecryptorStreamType decoder_type, 711 uint32_t request_id, 712 bool success) { 713 PP_DCHECK(result == PP_OK); 714 pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type, 715 request_id, 716 success); 717} 718 719void CdmAdapter::DecoderDeinitializeDone(int32_t result, 720 PP_DecryptorStreamType decoder_type, 721 uint32_t request_id) { 722 pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type, 723 request_id); 724} 725 726void CdmAdapter::DecoderResetDone(int32_t result, 727 PP_DecryptorStreamType decoder_type, 728 uint32_t request_id) { 729 pp::ContentDecryptor_Private::DecoderResetDone(decoder_type, request_id); 730} 731 732void CdmAdapter::DeliverFrame( 733 int32_t result, 734 const cdm::Status& status, 735 const LinkedVideoFrame& video_frame, 736 const PP_DecryptTrackingInfo& tracking_info) { 737 PP_DCHECK(result == PP_OK); 738 PP_DecryptedFrameInfo decrypted_frame_info; 739 decrypted_frame_info.tracking_info.request_id = tracking_info.request_id; 740 decrypted_frame_info.tracking_info.buffer_id = 0; 741 decrypted_frame_info.result = CdmStatusToPpDecryptResult(status); 742 743 pp::Buffer_Dev buffer; 744 745 if (decrypted_frame_info.result == PP_DECRYPTRESULT_SUCCESS) { 746 if (!IsValidVideoFrame(video_frame)) { 747 PP_NOTREACHED(); 748 decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR; 749 } else { 750 PpbBuffer* ppb_buffer = 751 static_cast<PpbBuffer*>(video_frame->FrameBuffer()); 752 753 buffer = ppb_buffer->buffer_dev(); 754 755 decrypted_frame_info.tracking_info.timestamp = video_frame->Timestamp(); 756 decrypted_frame_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); 757 decrypted_frame_info.format = 758 CdmVideoFormatToPpDecryptedFrameFormat(video_frame->Format()); 759 decrypted_frame_info.width = video_frame->Size().width; 760 decrypted_frame_info.height = video_frame->Size().height; 761 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y] = 762 video_frame->PlaneOffset(cdm::VideoFrame::kYPlane); 763 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_U] = 764 video_frame->PlaneOffset(cdm::VideoFrame::kUPlane); 765 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_V] = 766 video_frame->PlaneOffset(cdm::VideoFrame::kVPlane); 767 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_Y] = 768 video_frame->Stride(cdm::VideoFrame::kYPlane); 769 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_U] = 770 video_frame->Stride(cdm::VideoFrame::kUPlane); 771 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_V] = 772 video_frame->Stride(cdm::VideoFrame::kVPlane); 773 } 774 } 775 pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info); 776} 777 778void CdmAdapter::DeliverSamples(int32_t result, 779 const cdm::Status& status, 780 const LinkedAudioFrames& audio_frames, 781 const PP_DecryptTrackingInfo& tracking_info) { 782 PP_DCHECK(result == PP_OK); 783 784 PP_DecryptedSampleInfo decrypted_sample_info; 785 decrypted_sample_info.tracking_info = tracking_info; 786 decrypted_sample_info.tracking_info.timestamp = 0; 787 decrypted_sample_info.tracking_info.buffer_id = 0; 788 decrypted_sample_info.data_size = 0; 789 decrypted_sample_info.result = CdmStatusToPpDecryptResult(status); 790 791 pp::Buffer_Dev buffer; 792 793 if (decrypted_sample_info.result == PP_DECRYPTRESULT_SUCCESS) { 794 PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer()); 795 if (!audio_frames.get() || !audio_frames->FrameBuffer()) { 796 PP_NOTREACHED(); 797 decrypted_sample_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; 798 } else { 799 PpbBuffer* ppb_buffer = 800 static_cast<PpbBuffer*>(audio_frames->FrameBuffer()); 801 buffer = ppb_buffer->buffer_dev(); 802 decrypted_sample_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); 803 decrypted_sample_info.data_size = ppb_buffer->Size(); 804 decrypted_sample_info.format = 805 CdmAudioFormatToPpDecryptedSampleFormat(audio_frames->Format()); 806 } 807 } 808 809 pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_sample_info); 810} 811 812bool CdmAdapter::IsValidVideoFrame(const LinkedVideoFrame& video_frame) { 813 if (!video_frame.get() || 814 !video_frame->FrameBuffer() || 815 (video_frame->Format() != cdm::kI420 && 816 video_frame->Format() != cdm::kYv12)) { 817 CDM_DLOG() << "Invalid video frame!"; 818 return false; 819 } 820 821 PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer()); 822 823 for (uint32_t i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) { 824 int plane_height = (i == cdm::VideoFrame::kYPlane) ? 825 video_frame->Size().height : (video_frame->Size().height + 1) / 2; 826 cdm::VideoFrame::VideoPlane plane = 827 static_cast<cdm::VideoFrame::VideoPlane>(i); 828 if (ppb_buffer->Size() < video_frame->PlaneOffset(plane) + 829 plane_height * video_frame->Stride(plane)) { 830 return false; 831 } 832 } 833 834 return true; 835} 836 837#if !defined(NDEBUG) 838void CdmAdapter::LogToConsole(const pp::Var& value) { 839 PP_DCHECK(IsMainThread()); 840 const PPB_Console* console = reinterpret_cast<const PPB_Console*>( 841 pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE)); 842 console->Log(pp_instance(), PP_LOGLEVEL_LOG, value.pp_var()); 843} 844#endif // !defined(NDEBUG) 845 846void CdmAdapter::SendPlatformChallenge( 847 const char* service_id, uint32_t service_id_length, 848 const char* challenge, uint32_t challenge_length) { 849#if defined(OS_CHROMEOS) 850 PP_DCHECK(!challenge_in_progress_); 851 852 // Ensure member variables set by the callback are in a clean state. 853 signed_data_output_ = pp::Var(); 854 signed_data_signature_output_ = pp::Var(); 855 platform_key_certificate_output_ = pp::Var(); 856 857 pp::VarArrayBuffer challenge_var(challenge_length); 858 uint8_t* var_data = static_cast<uint8_t*>(challenge_var.Map()); 859 memcpy(var_data, challenge, challenge_length); 860 861 std::string service_id_str(service_id, service_id_length); 862 int32_t result = platform_verification_.ChallengePlatform( 863 pp::Var(service_id_str), challenge_var, &signed_data_output_, 864 &signed_data_signature_output_, &platform_key_certificate_output_, 865 callback_factory_.NewCallback(&CdmAdapter::SendPlatformChallengeDone)); 866 challenge_var.Unmap(); 867 if (result == PP_OK_COMPLETIONPENDING) { 868 challenge_in_progress_ = true; 869 return; 870 } 871 872 // Fall through on error and issue an empty OnPlatformChallengeResponse(). 873 PP_DCHECK(result != PP_OK); 874#endif 875 876 cdm::PlatformChallengeResponse response = {}; 877 cdm_->OnPlatformChallengeResponse(response); 878} 879 880void CdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask) { 881#if defined(OS_CHROMEOS) 882 int32_t result = output_protection_.EnableProtection( 883 desired_protection_mask, callback_factory_.NewCallback( 884 &CdmAdapter::EnableProtectionDone)); 885 886 // Errors are ignored since clients must call QueryOutputProtectionStatus() to 887 // inspect the protection status on a regular basis. 888 889 if (result != PP_OK && result != PP_OK_COMPLETIONPENDING) 890 CDM_DLOG() << __FUNCTION__ << " failed!"; 891#endif 892} 893 894void CdmAdapter::QueryOutputProtectionStatus() { 895#if defined(OS_CHROMEOS) 896 PP_DCHECK(!query_output_protection_in_progress_); 897 898 output_link_mask_ = output_protection_mask_ = 0; 899 const int32_t result = output_protection_.QueryStatus( 900 &output_link_mask_, 901 &output_protection_mask_, 902 callback_factory_.NewCallback( 903 &CdmAdapter::QueryOutputProtectionStatusDone)); 904 if (result == PP_OK_COMPLETIONPENDING) { 905 query_output_protection_in_progress_ = true; 906 return; 907 } 908 909 // Fall through on error and issue an empty OnQueryOutputProtectionStatus(). 910 PP_DCHECK(result != PP_OK); 911#endif 912 913 cdm_->OnQueryOutputProtectionStatus(0, 0); 914} 915 916void CdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type, 917 cdm::Status decoder_status) { 918 switch (stream_type) { 919 case cdm::kStreamTypeAudio: 920 PP_DCHECK(deferred_initialize_audio_decoder_); 921 CallOnMain( 922 callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone, 923 PP_DECRYPTORSTREAMTYPE_AUDIO, 924 deferred_audio_decoder_config_id_, 925 decoder_status == cdm::kSuccess)); 926 deferred_initialize_audio_decoder_ = false; 927 deferred_audio_decoder_config_id_ = 0; 928 break; 929 case cdm::kStreamTypeVideo: 930 PP_DCHECK(deferred_initialize_video_decoder_); 931 CallOnMain( 932 callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone, 933 PP_DECRYPTORSTREAMTYPE_VIDEO, 934 deferred_video_decoder_config_id_, 935 decoder_status == cdm::kSuccess)); 936 deferred_initialize_video_decoder_ = false; 937 deferred_video_decoder_config_id_ = 0; 938 break; 939 } 940} 941 942// The CDM owns the returned object and must call FileIO::Close() to release it. 943cdm::FileIO* CdmAdapter::CreateFileIO(cdm::FileIOClient* client) { 944 return new CdmFileIOImpl(client, pp_instance()); 945} 946 947#if defined(OS_CHROMEOS) 948void CdmAdapter::SendPlatformChallengeDone(int32_t result) { 949 challenge_in_progress_ = false; 950 951 if (result != PP_OK) { 952 CDM_DLOG() << __FUNCTION__ << ": Platform challenge failed!"; 953 cdm::PlatformChallengeResponse response = {}; 954 cdm_->OnPlatformChallengeResponse(response); 955 return; 956 } 957 958 pp::VarArrayBuffer signed_data_var(signed_data_output_); 959 pp::VarArrayBuffer signed_data_signature_var(signed_data_signature_output_); 960 std::string platform_key_certificate_string = 961 platform_key_certificate_output_.AsString(); 962 963 cdm::PlatformChallengeResponse response = { 964 static_cast<uint8_t*>(signed_data_var.Map()), 965 signed_data_var.ByteLength(), 966 967 static_cast<uint8_t*>(signed_data_signature_var.Map()), 968 signed_data_signature_var.ByteLength(), 969 970 reinterpret_cast<const uint8_t*>(platform_key_certificate_string.c_str()), 971 static_cast<uint32_t>(platform_key_certificate_string.length()) 972 }; 973 cdm_->OnPlatformChallengeResponse(response); 974 975 signed_data_var.Unmap(); 976 signed_data_signature_var.Unmap(); 977} 978 979void CdmAdapter::EnableProtectionDone(int32_t result) { 980 // Does nothing since clients must call QueryOutputProtectionStatus() to 981 // inspect the protection status on a regular basis. 982 CDM_DLOG() << __FUNCTION__ << " : " << result; 983} 984 985void CdmAdapter::QueryOutputProtectionStatusDone(int32_t result) { 986 PP_DCHECK(query_output_protection_in_progress_); 987 query_output_protection_in_progress_ = false; 988 989 // Return a protection status of none on error. 990 if (result != PP_OK) 991 output_link_mask_ = output_protection_mask_ = 0; 992 993 cdm_->OnQueryOutputProtectionStatus(output_link_mask_, 994 output_protection_mask_); 995} 996#endif 997 998void* GetCdmHost(int host_interface_version, void* user_data) { 999 if (!host_interface_version || !user_data) 1000 return NULL; 1001 1002 COMPILE_ASSERT(cdm::ContentDecryptionModule::Host::kVersion == 1003 cdm::ContentDecryptionModule_4::Host::kVersion, 1004 update_code_below); 1005 1006 // Ensure IsSupportedCdmHostVersion matches implementation of this function. 1007 // Always update this DCHECK when updating this function. 1008 // If this check fails, update this function and DCHECK or update 1009 // IsSupportedCdmHostVersion. 1010 PP_DCHECK( 1011 // Future version is not supported. 1012 !IsSupportedCdmHostVersion( 1013 cdm::ContentDecryptionModule::Host::kVersion + 1) && 1014 // Current version is supported. 1015 IsSupportedCdmHostVersion(cdm::ContentDecryptionModule::Host::kVersion) && 1016 // Include all previous supported versions here. 1017 IsSupportedCdmHostVersion(cdm::Host_1::kVersion) && 1018 // One older than the oldest supported version is not supported. 1019 !IsSupportedCdmHostVersion(cdm::Host_1::kVersion - 1)); 1020 PP_DCHECK(IsSupportedCdmHostVersion(host_interface_version)); 1021 1022 CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data); 1023 CDM_DLOG() << "Create CDM Host with version " << host_interface_version; 1024 switch (host_interface_version) { 1025 case cdm::Host_4::kVersion: 1026 return static_cast<cdm::Host_4*>(cdm_adapter); 1027 case cdm::Host_2::kVersion: 1028 return static_cast<cdm::Host_2*>(cdm_adapter); 1029 case cdm::Host_1::kVersion: 1030 return static_cast<cdm::Host_1*>(cdm_adapter); 1031 default: 1032 PP_NOTREACHED(); 1033 return NULL; 1034 } 1035} 1036 1037// This object is the global object representing this plugin library as long 1038// as it is loaded. 1039class CdmAdapterModule : public pp::Module { 1040 public: 1041 CdmAdapterModule() : pp::Module() { 1042 // This function blocks the renderer thread (PluginInstance::Initialize()). 1043 // Move this call to other places if this may be a concern in the future. 1044 INITIALIZE_CDM_MODULE(); 1045 } 1046 virtual ~CdmAdapterModule() { 1047 DeinitializeCdmModule(); 1048 } 1049 1050 virtual pp::Instance* CreateInstance(PP_Instance instance) { 1051 return new CdmAdapter(instance, this); 1052 } 1053 1054 private: 1055 CdmFileIOImpl::ResourceTracker cdm_file_io_impl_resource_tracker; 1056}; 1057 1058} // namespace media 1059 1060namespace pp { 1061 1062// Factory function for your specialization of the Module object. 1063Module* CreateModule() { 1064 return new media::CdmAdapterModule(); 1065} 1066 1067} // namespace pp 1068