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