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