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/base/limits.h"
      8 #include "media/cdm/ppapi/cdm_file_io_impl.h"
      9 #include "media/cdm/ppapi/cdm_helpers.h"
     10 #include "media/cdm/ppapi/cdm_logging.h"
     11 #include "media/cdm/ppapi/supported_cdm_versions.h"
     12 #include "ppapi/c/ppb_console.h"
     13 #include "ppapi/cpp/private/uma_private.h"
     14 
     15 #if defined(CHECK_DOCUMENT_URL)
     16 #include "ppapi/cpp/dev/url_util_dev.h"
     17 #include "ppapi/cpp/instance_handle.h"
     18 #endif  // defined(CHECK_DOCUMENT_URL)
     19 
     20 namespace {
     21 
     22 // Constants for UMA reporting of file size (in KB) via HistogramCustomCounts().
     23 // Note that the histogram is log-scaled (rather than linear).
     24 const uint32_t kSizeKBMin = 1;
     25 const uint32_t kSizeKBMax = 512 * 1024;  // 512MB
     26 const uint32_t kSizeKBBuckets = 100;
     27 
     28 #if !defined(NDEBUG)
     29   #define DLOG_TO_CONSOLE(message) LogToConsole(message);
     30 #else
     31   #define DLOG_TO_CONSOLE(message) (void)(message);
     32 #endif
     33 
     34 bool IsMainThread() {
     35   return pp::Module::Get()->core()->IsMainThread();
     36 }
     37 
     38 // Posts a task to run |cb| on the main thread. The task is posted even if the
     39 // current thread is the main thread.
     40 void PostOnMain(pp::CompletionCallback cb) {
     41   pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK);
     42 }
     43 
     44 // Ensures |cb| is called on the main thread, either because the current thread
     45 // is the main thread or by posting it to the main thread.
     46 void CallOnMain(pp::CompletionCallback cb) {
     47   // TODO(tomfinegan): This is only necessary because PPAPI doesn't allow calls
     48   // off the main thread yet. Remove this once the change lands.
     49   if (IsMainThread())
     50     cb.Run(PP_OK);
     51   else
     52     PostOnMain(cb);
     53 }
     54 
     55 // Configures a cdm::InputBuffer. |subsamples| must exist as long as
     56 // |input_buffer| is in use.
     57 void ConfigureInputBuffer(
     58     const pp::Buffer_Dev& encrypted_buffer,
     59     const PP_EncryptedBlockInfo& encrypted_block_info,
     60     std::vector<cdm::SubsampleEntry>* subsamples,
     61     cdm::InputBuffer* input_buffer) {
     62   PP_DCHECK(subsamples);
     63   PP_DCHECK(!encrypted_buffer.is_null());
     64 
     65   input_buffer->data = static_cast<uint8_t*>(encrypted_buffer.data());
     66   input_buffer->data_size = encrypted_block_info.data_size;
     67   PP_DCHECK(encrypted_buffer.size() >= input_buffer->data_size);
     68 
     69   PP_DCHECK(encrypted_block_info.key_id_size <=
     70             arraysize(encrypted_block_info.key_id));
     71   input_buffer->key_id_size = encrypted_block_info.key_id_size;
     72   input_buffer->key_id = input_buffer->key_id_size > 0 ?
     73       encrypted_block_info.key_id : NULL;
     74 
     75   PP_DCHECK(encrypted_block_info.iv_size <= arraysize(encrypted_block_info.iv));
     76   input_buffer->iv_size = encrypted_block_info.iv_size;
     77   input_buffer->iv = encrypted_block_info.iv_size > 0 ?
     78       encrypted_block_info.iv : NULL;
     79 
     80   input_buffer->num_subsamples = encrypted_block_info.num_subsamples;
     81   if (encrypted_block_info.num_subsamples > 0) {
     82     subsamples->reserve(encrypted_block_info.num_subsamples);
     83 
     84     for (uint32_t i = 0; i < encrypted_block_info.num_subsamples; ++i) {
     85       subsamples->push_back(cdm::SubsampleEntry(
     86           encrypted_block_info.subsamples[i].clear_bytes,
     87           encrypted_block_info.subsamples[i].cipher_bytes));
     88     }
     89 
     90     input_buffer->subsamples = &(*subsamples)[0];
     91   }
     92 
     93   input_buffer->timestamp = encrypted_block_info.tracking_info.timestamp;
     94 }
     95 
     96 PP_DecryptResult CdmStatusToPpDecryptResult(cdm::Status status) {
     97   switch (status) {
     98     case cdm::kSuccess:
     99       return PP_DECRYPTRESULT_SUCCESS;
    100     case cdm::kNoKey:
    101       return PP_DECRYPTRESULT_DECRYPT_NOKEY;
    102     case cdm::kNeedMoreData:
    103       return PP_DECRYPTRESULT_NEEDMOREDATA;
    104     case cdm::kDecryptError:
    105       return PP_DECRYPTRESULT_DECRYPT_ERROR;
    106     case cdm::kDecodeError:
    107       return PP_DECRYPTRESULT_DECODE_ERROR;
    108     default:
    109       PP_NOTREACHED();
    110       return PP_DECRYPTRESULT_DECODE_ERROR;
    111   }
    112 }
    113 
    114 PP_DecryptedFrameFormat CdmVideoFormatToPpDecryptedFrameFormat(
    115     cdm::VideoFormat format) {
    116   switch (format) {
    117     case cdm::kYv12:
    118       return PP_DECRYPTEDFRAMEFORMAT_YV12;
    119     case cdm::kI420:
    120       return PP_DECRYPTEDFRAMEFORMAT_I420;
    121     default:
    122       return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
    123   }
    124 }
    125 
    126 PP_DecryptedSampleFormat CdmAudioFormatToPpDecryptedSampleFormat(
    127     cdm::AudioFormat format) {
    128   switch (format) {
    129     case cdm::kAudioFormatU8:
    130       return PP_DECRYPTEDSAMPLEFORMAT_U8;
    131     case cdm::kAudioFormatS16:
    132       return PP_DECRYPTEDSAMPLEFORMAT_S16;
    133     case cdm::kAudioFormatS32:
    134       return PP_DECRYPTEDSAMPLEFORMAT_S32;
    135     case cdm::kAudioFormatF32:
    136       return PP_DECRYPTEDSAMPLEFORMAT_F32;
    137     case cdm::kAudioFormatPlanarS16:
    138       return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16;
    139     case cdm::kAudioFormatPlanarF32:
    140       return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32;
    141     default:
    142       return PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN;
    143   }
    144 }
    145 
    146 cdm::AudioDecoderConfig::AudioCodec PpAudioCodecToCdmAudioCodec(
    147     PP_AudioCodec codec) {
    148   switch (codec) {
    149     case PP_AUDIOCODEC_VORBIS:
    150       return cdm::AudioDecoderConfig::kCodecVorbis;
    151     case PP_AUDIOCODEC_AAC:
    152       return cdm::AudioDecoderConfig::kCodecAac;
    153     default:
    154       return cdm::AudioDecoderConfig::kUnknownAudioCodec;
    155   }
    156 }
    157 
    158 cdm::VideoDecoderConfig::VideoCodec PpVideoCodecToCdmVideoCodec(
    159     PP_VideoCodec codec) {
    160   switch (codec) {
    161     case PP_VIDEOCODEC_VP8:
    162       return cdm::VideoDecoderConfig::kCodecVp8;
    163     case PP_VIDEOCODEC_H264:
    164       return cdm::VideoDecoderConfig::kCodecH264;
    165     case PP_VIDEOCODEC_VP9:
    166       return cdm::VideoDecoderConfig::kCodecVp9;
    167     default:
    168       return cdm::VideoDecoderConfig::kUnknownVideoCodec;
    169   }
    170 }
    171 
    172 cdm::VideoDecoderConfig::VideoCodecProfile PpVCProfileToCdmVCProfile(
    173     PP_VideoCodecProfile profile) {
    174   switch (profile) {
    175     case PP_VIDEOCODECPROFILE_NOT_NEEDED:
    176       return cdm::VideoDecoderConfig::kProfileNotNeeded;
    177     case PP_VIDEOCODECPROFILE_H264_BASELINE:
    178       return cdm::VideoDecoderConfig::kH264ProfileBaseline;
    179     case PP_VIDEOCODECPROFILE_H264_MAIN:
    180       return cdm::VideoDecoderConfig::kH264ProfileMain;
    181     case PP_VIDEOCODECPROFILE_H264_EXTENDED:
    182       return cdm::VideoDecoderConfig::kH264ProfileExtended;
    183     case PP_VIDEOCODECPROFILE_H264_HIGH:
    184       return cdm::VideoDecoderConfig::kH264ProfileHigh;
    185     case PP_VIDEOCODECPROFILE_H264_HIGH_10:
    186       return cdm::VideoDecoderConfig::kH264ProfileHigh10;
    187     case PP_VIDEOCODECPROFILE_H264_HIGH_422:
    188       return cdm::VideoDecoderConfig::kH264ProfileHigh422;
    189     case PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE:
    190       return cdm::VideoDecoderConfig::kH264ProfileHigh444Predictive;
    191     default:
    192       return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile;
    193   }
    194 }
    195 
    196 cdm::VideoFormat PpDecryptedFrameFormatToCdmVideoFormat(
    197     PP_DecryptedFrameFormat format) {
    198   switch (format) {
    199     case PP_DECRYPTEDFRAMEFORMAT_YV12:
    200       return cdm::kYv12;
    201     case PP_DECRYPTEDFRAMEFORMAT_I420:
    202       return cdm::kI420;
    203     default:
    204       return cdm::kUnknownVideoFormat;
    205   }
    206 }
    207 
    208 cdm::StreamType PpDecryptorStreamTypeToCdmStreamType(
    209     PP_DecryptorStreamType stream_type) {
    210   switch (stream_type) {
    211     case PP_DECRYPTORSTREAMTYPE_AUDIO:
    212       return cdm::kStreamTypeAudio;
    213     case PP_DECRYPTORSTREAMTYPE_VIDEO:
    214       return cdm::kStreamTypeVideo;
    215   }
    216 
    217   PP_NOTREACHED();
    218   return cdm::kStreamTypeVideo;
    219 }
    220 
    221 cdm::SessionType PpSessionTypeToCdmSessionType(PP_SessionType session_type) {
    222   switch (session_type) {
    223     case PP_SESSIONTYPE_TEMPORARY:
    224       return cdm::kTemporary;
    225     case PP_SESSIONTYPE_PERSISTENT:
    226       return cdm::kPersistent;
    227     default:
    228       PP_NOTREACHED();
    229       return cdm::kTemporary;
    230   }
    231 }
    232 
    233 PP_CdmExceptionCode CdmExceptionTypeToPpCdmExceptionType(cdm::Error error) {
    234   switch (error) {
    235     case cdm::kNotSupportedError:
    236       return PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR;
    237     case cdm::kInvalidStateError:
    238       return PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR;
    239     case cdm::kInvalidAccessError:
    240       return PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR;
    241     case cdm::kQuotaExceededError:
    242       return PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR;
    243     case cdm::kUnknownError:
    244       return PP_CDMEXCEPTIONCODE_UNKNOWNERROR;
    245     case cdm::kClientError:
    246       return PP_CDMEXCEPTIONCODE_CLIENTERROR;
    247     case cdm::kOutputError:
    248       return PP_CDMEXCEPTIONCODE_OUTPUTERROR;
    249     default:
    250       PP_NOTREACHED();
    251       return PP_CDMEXCEPTIONCODE_UNKNOWNERROR;
    252   }
    253 }
    254 
    255 }  // namespace
    256 
    257 namespace media {
    258 
    259 CdmAdapter::CdmAdapter(PP_Instance instance, pp::Module* module)
    260     : pp::Instance(instance),
    261       pp::ContentDecryptor_Private(this),
    262 #if defined(OS_CHROMEOS)
    263       output_protection_(this),
    264       platform_verification_(this),
    265       output_link_mask_(0),
    266       output_protection_mask_(0),
    267       query_output_protection_in_progress_(false),
    268       uma_for_output_protection_query_reported_(false),
    269       uma_for_output_protection_positive_result_reported_(false),
    270 #endif
    271       allocator_(this),
    272       cdm_(NULL),
    273       deferred_initialize_audio_decoder_(false),
    274       deferred_audio_decoder_config_id_(0),
    275       deferred_initialize_video_decoder_(false),
    276       deferred_video_decoder_config_id_(0),
    277       last_read_file_size_kb_(0),
    278       file_size_uma_reported_(false) {
    279   callback_factory_.Initialize(this);
    280 }
    281 
    282 CdmAdapter::~CdmAdapter() {}
    283 
    284 bool CdmAdapter::CreateCdmInstance(const std::string& key_system) {
    285   PP_DCHECK(!cdm_);
    286   cdm_ = make_linked_ptr(CdmWrapper::Create(
    287       key_system.data(), key_system.size(), GetCdmHost, this));
    288   bool success = cdm_ != NULL;
    289 
    290   const std::string message = "CDM instance for " + key_system +
    291                               (success ? "" : " could not be") + " created.";
    292   DLOG_TO_CONSOLE(message);
    293   CDM_DLOG() << message;
    294 
    295   return success;
    296 }
    297 
    298 // No errors should be reported in this function because the spec says:
    299 // "Store this new error object internally with the MediaKeys instance being
    300 // created. This will be used to fire an error against any session created for
    301 // this instance." These errors will be reported during session creation
    302 // (CreateSession()) or session loading (LoadSession()).
    303 // TODO(xhwang): If necessary, we need to store the error here if we want to
    304 // support more specific error reporting (other than "Unknown").
    305 void CdmAdapter::Initialize(const std::string& key_system) {
    306   PP_DCHECK(!key_system.empty());
    307   PP_DCHECK(key_system_.empty() || (key_system_ == key_system && cdm_));
    308 
    309 #if defined(CHECK_DOCUMENT_URL)
    310   PP_URLComponents_Dev url_components = {};
    311   const pp::URLUtil_Dev* url_util = pp::URLUtil_Dev::Get();
    312   if (!url_util)
    313     return;
    314   pp::Var href = url_util->GetDocumentURL(pp::InstanceHandle(pp_instance()),
    315                                           &url_components);
    316   PP_DCHECK(href.is_string());
    317   std::string url = href.AsString();
    318   PP_DCHECK(!url.empty());
    319   std::string url_scheme =
    320       url.substr(url_components.scheme.begin, url_components.scheme.len);
    321   if (url_scheme != "file") {
    322     // Skip this check for file:// URLs as they don't have a host component.
    323     PP_DCHECK(url_components.host.begin);
    324     PP_DCHECK(0 < url_components.host.len);
    325   }
    326 #endif  // defined(CHECK_DOCUMENT_URL)
    327 
    328   if (!cdm_ && !CreateCdmInstance(key_system))
    329     return;
    330 
    331   PP_DCHECK(cdm_);
    332   key_system_ = key_system;
    333 }
    334 
    335 void CdmAdapter::SetServerCertificate(uint32_t promise_id,
    336                                       pp::VarArrayBuffer server_certificate) {
    337   const uint8_t* server_certificate_ptr =
    338       static_cast<const uint8_t*>(server_certificate.Map());
    339   const uint32_t server_certificate_size = server_certificate.ByteLength();
    340 
    341   if (!server_certificate_ptr ||
    342       server_certificate_size < media::limits::kMinCertificateLength ||
    343       server_certificate_size > media::limits::kMaxCertificateLength) {
    344     RejectPromise(
    345         promise_id, cdm::kInvalidAccessError, 0, "Incorrect certificate.");
    346     return;
    347   }
    348 
    349   // Initialize() doesn't report an error, so SetServerCertificate() can be
    350   // called even if Initialize() failed.
    351   // TODO(jrummell): Remove this code when prefixed EME gets removed.
    352   if (!cdm_) {
    353     RejectPromise(promise_id,
    354                   cdm::kInvalidStateError,
    355                   0,
    356                   "CDM has not been initialized.");
    357     return;
    358   }
    359 
    360   if (!cdm_->SetServerCertificate(
    361           promise_id, server_certificate_ptr, server_certificate_size)) {
    362     // CDM_4 and CDM_5 don't support this method, so reject the promise.
    363     RejectPromise(promise_id, cdm::kNotSupportedError, 0, "Not implemented.");
    364   }
    365 }
    366 
    367 void CdmAdapter::CreateSession(uint32_t promise_id,
    368                                const std::string& init_data_type,
    369                                pp::VarArrayBuffer init_data,
    370                                PP_SessionType session_type) {
    371   // Initialize() doesn't report an error, so CreateSession() can be called
    372   // even if Initialize() failed.
    373   // TODO(jrummell): Remove this code when prefixed EME gets removed.
    374   // TODO(jrummell): Verify that Initialize() failing does not resolve the
    375   // MediaKeys.create() promise.
    376   if (!cdm_) {
    377     RejectPromise(promise_id,
    378                   cdm::kInvalidStateError,
    379                   0,
    380                   "CDM has not been initialized.");
    381     return;
    382   }
    383 
    384   cdm_->CreateSession(promise_id,
    385                       init_data_type.data(),
    386                       init_data_type.size(),
    387                       static_cast<const uint8_t*>(init_data.Map()),
    388                       init_data.ByteLength(),
    389                       PpSessionTypeToCdmSessionType(session_type));
    390 }
    391 
    392 void CdmAdapter::LoadSession(uint32_t promise_id,
    393                              const std::string& web_session_id) {
    394   // Initialize() doesn't report an error, so LoadSession() can be called
    395   // even if Initialize() failed.
    396   // TODO(jrummell): Remove this code when prefixed EME gets removed.
    397   // TODO(jrummell): Verify that Initialize() failing does not resolve the
    398   // MediaKeys.create() promise.
    399   if (!cdm_) {
    400     RejectPromise(promise_id,
    401                   cdm::kInvalidStateError,
    402                   0,
    403                   "CDM has not been initialized.");
    404     return;
    405   }
    406 
    407   cdm_->LoadSession(promise_id, web_session_id.data(), web_session_id.size());
    408 }
    409 
    410 void CdmAdapter::UpdateSession(uint32_t promise_id,
    411                                const std::string& web_session_id,
    412                                pp::VarArrayBuffer response) {
    413   const uint8_t* response_ptr = static_cast<const uint8_t*>(response.Map());
    414   const uint32_t response_size = response.ByteLength();
    415 
    416   PP_DCHECK(!web_session_id.empty());
    417   PP_DCHECK(response_ptr);
    418   PP_DCHECK(response_size > 0);
    419 
    420   cdm_->UpdateSession(promise_id,
    421                       web_session_id.data(),
    422                       web_session_id.length(),
    423                       response_ptr,
    424                       response_size);
    425 }
    426 
    427 void CdmAdapter::CloseSession(uint32_t promise_id,
    428                               const std::string& web_session_id) {
    429   if (!cdm_->CloseSession(
    430           promise_id, web_session_id.data(), web_session_id.length())) {
    431     // CDM_4 doesn't support this method, so reject the promise.
    432     RejectPromise(promise_id, cdm::kNotSupportedError, 0, "Not implemented.");
    433   }
    434 }
    435 
    436 void CdmAdapter::RemoveSession(uint32_t promise_id,
    437                                const std::string& web_session_id) {
    438   cdm_->RemoveSession(
    439       promise_id, web_session_id.data(), web_session_id.length());
    440 }
    441 
    442 void CdmAdapter::GetUsableKeyIds(uint32_t promise_id,
    443                                  const std::string& web_session_id) {
    444   if (!cdm_->GetUsableKeyIds(
    445           promise_id, web_session_id.data(), web_session_id.length())) {
    446     // CDM_4 doesn't support this method, so reject the promise.
    447     RejectPromise(promise_id, cdm::kNotSupportedError, 0, "Not implemented.");
    448   }
    449 }
    450 
    451 // Note: In the following decryption/decoding related functions, errors are NOT
    452 // reported via KeyError, but are reported via corresponding PPB calls.
    453 
    454 void CdmAdapter::Decrypt(pp::Buffer_Dev encrypted_buffer,
    455                          const PP_EncryptedBlockInfo& encrypted_block_info) {
    456   PP_DCHECK(!encrypted_buffer.is_null());
    457 
    458   // Release a buffer that the caller indicated it is finished with.
    459   allocator_.Release(encrypted_block_info.tracking_info.buffer_id);
    460 
    461   cdm::Status status = cdm::kDecryptError;
    462   LinkedDecryptedBlock decrypted_block(new DecryptedBlockImpl());
    463 
    464   if (cdm_) {
    465     cdm::InputBuffer input_buffer;
    466     std::vector<cdm::SubsampleEntry> subsamples;
    467     ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples,
    468                          &input_buffer);
    469     status = cdm_->Decrypt(input_buffer, decrypted_block.get());
    470     PP_DCHECK(status != cdm::kSuccess ||
    471               (decrypted_block->DecryptedBuffer() &&
    472                decrypted_block->DecryptedBuffer()->Size()));
    473   }
    474 
    475   CallOnMain(callback_factory_.NewCallback(
    476       &CdmAdapter::DeliverBlock,
    477       status,
    478       decrypted_block,
    479       encrypted_block_info.tracking_info));
    480 }
    481 
    482 void CdmAdapter::InitializeAudioDecoder(
    483     const PP_AudioDecoderConfig& decoder_config,
    484     pp::Buffer_Dev extra_data_buffer) {
    485   PP_DCHECK(!deferred_initialize_audio_decoder_);
    486   PP_DCHECK(deferred_audio_decoder_config_id_ == 0);
    487   cdm::Status status = cdm::kSessionError;
    488   if (cdm_) {
    489     cdm::AudioDecoderConfig cdm_decoder_config;
    490     cdm_decoder_config.codec =
    491         PpAudioCodecToCdmAudioCodec(decoder_config.codec);
    492     cdm_decoder_config.channel_count = decoder_config.channel_count;
    493     cdm_decoder_config.bits_per_channel = decoder_config.bits_per_channel;
    494     cdm_decoder_config.samples_per_second = decoder_config.samples_per_second;
    495     cdm_decoder_config.extra_data =
    496         static_cast<uint8_t*>(extra_data_buffer.data());
    497     cdm_decoder_config.extra_data_size = extra_data_buffer.size();
    498     status = cdm_->InitializeAudioDecoder(cdm_decoder_config);
    499   }
    500 
    501   if (status == cdm::kDeferredInitialization) {
    502     deferred_initialize_audio_decoder_ = true;
    503     deferred_audio_decoder_config_id_ = decoder_config.request_id;
    504     return;
    505   }
    506 
    507   CallOnMain(callback_factory_.NewCallback(
    508       &CdmAdapter::DecoderInitializeDone,
    509       PP_DECRYPTORSTREAMTYPE_AUDIO,
    510       decoder_config.request_id,
    511       status == cdm::kSuccess));
    512 }
    513 
    514 void CdmAdapter::InitializeVideoDecoder(
    515     const PP_VideoDecoderConfig& decoder_config,
    516     pp::Buffer_Dev extra_data_buffer) {
    517   PP_DCHECK(!deferred_initialize_video_decoder_);
    518   PP_DCHECK(deferred_video_decoder_config_id_ == 0);
    519   cdm::Status status = cdm::kSessionError;
    520   if (cdm_) {
    521     cdm::VideoDecoderConfig cdm_decoder_config;
    522     cdm_decoder_config.codec =
    523         PpVideoCodecToCdmVideoCodec(decoder_config.codec);
    524     cdm_decoder_config.profile =
    525         PpVCProfileToCdmVCProfile(decoder_config.profile);
    526     cdm_decoder_config.format =
    527         PpDecryptedFrameFormatToCdmVideoFormat(decoder_config.format);
    528     cdm_decoder_config.coded_size.width = decoder_config.width;
    529     cdm_decoder_config.coded_size.height = decoder_config.height;
    530     cdm_decoder_config.extra_data =
    531         static_cast<uint8_t*>(extra_data_buffer.data());
    532     cdm_decoder_config.extra_data_size = extra_data_buffer.size();
    533     status = cdm_->InitializeVideoDecoder(cdm_decoder_config);
    534   }
    535 
    536   if (status == cdm::kDeferredInitialization) {
    537     deferred_initialize_video_decoder_ = true;
    538     deferred_video_decoder_config_id_ = decoder_config.request_id;
    539     return;
    540   }
    541 
    542   CallOnMain(callback_factory_.NewCallback(
    543       &CdmAdapter::DecoderInitializeDone,
    544       PP_DECRYPTORSTREAMTYPE_VIDEO,
    545       decoder_config.request_id,
    546       status == cdm::kSuccess));
    547 }
    548 
    549 void CdmAdapter::DeinitializeDecoder(PP_DecryptorStreamType decoder_type,
    550                                      uint32_t request_id) {
    551   PP_DCHECK(cdm_);  // InitializeXxxxxDecoder should have succeeded.
    552   if (cdm_) {
    553     cdm_->DeinitializeDecoder(
    554         PpDecryptorStreamTypeToCdmStreamType(decoder_type));
    555   }
    556 
    557   CallOnMain(callback_factory_.NewCallback(
    558       &CdmAdapter::DecoderDeinitializeDone,
    559       decoder_type,
    560       request_id));
    561 }
    562 
    563 void CdmAdapter::ResetDecoder(PP_DecryptorStreamType decoder_type,
    564                               uint32_t request_id) {
    565   PP_DCHECK(cdm_);  // InitializeXxxxxDecoder should have succeeded.
    566   if (cdm_)
    567     cdm_->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type));
    568 
    569   CallOnMain(callback_factory_.NewCallback(&CdmAdapter::DecoderResetDone,
    570                                            decoder_type,
    571                                            request_id));
    572 }
    573 
    574 void CdmAdapter::DecryptAndDecode(
    575     PP_DecryptorStreamType decoder_type,
    576     pp::Buffer_Dev encrypted_buffer,
    577     const PP_EncryptedBlockInfo& encrypted_block_info) {
    578   PP_DCHECK(cdm_);  // InitializeXxxxxDecoder should have succeeded.
    579   // Release a buffer that the caller indicated it is finished with.
    580   allocator_.Release(encrypted_block_info.tracking_info.buffer_id);
    581 
    582   cdm::InputBuffer input_buffer;
    583   std::vector<cdm::SubsampleEntry> subsamples;
    584   if (cdm_ && !encrypted_buffer.is_null()) {
    585     ConfigureInputBuffer(encrypted_buffer,
    586                          encrypted_block_info,
    587                          &subsamples,
    588                          &input_buffer);
    589   }
    590 
    591   cdm::Status status = cdm::kDecodeError;
    592 
    593   switch (decoder_type) {
    594     case PP_DECRYPTORSTREAMTYPE_VIDEO: {
    595       LinkedVideoFrame video_frame(new VideoFrameImpl());
    596       if (cdm_)
    597         status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get());
    598       CallOnMain(callback_factory_.NewCallback(
    599           &CdmAdapter::DeliverFrame,
    600           status,
    601           video_frame,
    602           encrypted_block_info.tracking_info));
    603       return;
    604     }
    605 
    606     case PP_DECRYPTORSTREAMTYPE_AUDIO: {
    607       LinkedAudioFrames audio_frames(new AudioFramesImpl());
    608       if (cdm_) {
    609         status = cdm_->DecryptAndDecodeSamples(input_buffer,
    610                                                audio_frames.get());
    611       }
    612       CallOnMain(callback_factory_.NewCallback(
    613           &CdmAdapter::DeliverSamples,
    614           status,
    615           audio_frames,
    616           encrypted_block_info.tracking_info));
    617       return;
    618     }
    619 
    620     default:
    621       PP_NOTREACHED();
    622       return;
    623   }
    624 }
    625 
    626 cdm::Buffer* CdmAdapter::Allocate(uint32_t capacity) {
    627   return allocator_.Allocate(capacity);
    628 }
    629 
    630 void CdmAdapter::SetTimer(int64_t delay_ms, void* context) {
    631   // NOTE: doesn't really need to run on the main thread; could just as well run
    632   // on a helper thread if |cdm_| were thread-friendly and care was taken.  We
    633   // only use CallOnMainThread() here to get delayed-execution behavior.
    634   pp::Module::Get()->core()->CallOnMainThread(
    635       delay_ms,
    636       callback_factory_.NewCallback(&CdmAdapter::TimerExpired, context),
    637       PP_OK);
    638 }
    639 
    640 void CdmAdapter::TimerExpired(int32_t result, void* context) {
    641   PP_DCHECK(result == PP_OK);
    642   cdm_->TimerExpired(context);
    643 }
    644 
    645 // cdm::Host_4 methods
    646 
    647 double CdmAdapter::GetCurrentWallTimeInSeconds() {
    648   return GetCurrentWallTime();
    649 }
    650 
    651 void CdmAdapter::OnSessionCreated(uint32_t session_id,
    652                                   const char* web_session_id,
    653                                   uint32_t web_session_id_length) {
    654   uint32_t promise_id = cdm_->LookupPromiseId(session_id);
    655   cdm_->AssignWebSessionId(session_id, web_session_id, web_session_id_length);
    656   OnResolveNewSessionPromise(promise_id, web_session_id, web_session_id_length);
    657 }
    658 
    659 void CdmAdapter::OnSessionMessage(uint32_t session_id,
    660                                   const char* message,
    661                                   uint32_t message_length,
    662                                   const char* destination_url,
    663                                   uint32_t destination_url_length) {
    664   std::string web_session_id = cdm_->LookupWebSessionId(session_id);
    665   OnSessionMessage(web_session_id.data(),
    666                    web_session_id.length(),
    667                    message,
    668                    message_length,
    669                    destination_url,
    670                    destination_url_length);
    671 }
    672 
    673 void CdmAdapter::OnSessionReady(uint32_t session_id) {
    674   uint32_t promise_id = cdm_->LookupPromiseId(session_id);
    675   if (promise_id) {
    676     OnResolvePromise(promise_id);
    677   } else {
    678     std::string web_session_id = cdm_->LookupWebSessionId(session_id);
    679     PostOnMain(callback_factory_.NewCallback(
    680         &CdmAdapter::SendSessionReadyInternal, web_session_id));
    681   }
    682 }
    683 
    684 void CdmAdapter::OnSessionClosed(uint32_t session_id) {
    685   uint32_t promise_id = cdm_->LookupPromiseId(session_id);
    686   std::string web_session_id = cdm_->LookupWebSessionId(session_id);
    687   cdm_->DropWebSessionId(web_session_id);
    688   if (promise_id) {
    689     OnResolvePromise(promise_id);
    690   } else {
    691     OnSessionClosed(web_session_id.data(), web_session_id.length());
    692   }
    693 }
    694 
    695 void CdmAdapter::OnSessionError(uint32_t session_id,
    696                                 cdm::MediaKeyError error_code,
    697                                 uint32_t system_code) {
    698   uint32_t promise_id = cdm_->LookupPromiseId(session_id);
    699 
    700   // Existing cdm::MediaKeyError don't map to DOM error names. Convert them
    701   // into non-standard names so that the prefixed API can extract them.
    702   // TODO(jrummell): Remove this conversion and the inverse when CDM4 is gone.
    703   cdm::Error error;
    704   switch (error_code) {
    705     case cdm::kPrefixedClientError:
    706       error = cdm::kClientError;
    707       break;
    708     case cdm::kPrefixedOutputError:
    709       error = cdm::kOutputError;
    710       break;
    711     case cdm::kPrefixedUnknownError:
    712     default:
    713       error = cdm::kUnknownError;
    714       break;
    715   }
    716 
    717   if (promise_id) {
    718     RejectPromise(promise_id, error, system_code, std::string());
    719   } else {
    720     std::string web_session_id = cdm_->LookupWebSessionId(session_id);
    721     OnSessionError(web_session_id.data(),
    722                    web_session_id.length(),
    723                    error,
    724                    system_code,
    725                    NULL,
    726                    0);
    727   }
    728 }
    729 
    730 // cdm::Host_6 methods
    731 
    732 cdm::Time CdmAdapter::GetCurrentWallTime() {
    733   return pp::Module::Get()->core()->GetTime();
    734 }
    735 
    736 void CdmAdapter::OnResolveNewSessionPromise(uint32_t promise_id,
    737                                             const char* web_session_id,
    738                                             uint32_t web_session_id_length) {
    739   PostOnMain(callback_factory_.NewCallback(
    740       &CdmAdapter::SendPromiseResolvedWithSessionInternal,
    741       promise_id,
    742       std::string(web_session_id, web_session_id_length)));
    743 }
    744 
    745 void CdmAdapter::OnResolvePromise(uint32_t promise_id) {
    746   PostOnMain(callback_factory_.NewCallback(
    747       &CdmAdapter::SendPromiseResolvedInternal, promise_id));
    748 }
    749 
    750 void CdmAdapter::OnResolveKeyIdsPromise(uint32_t promise_id,
    751                                         const cdm::BinaryData* usable_key_ids,
    752                                         uint32_t usable_key_ids_length) {
    753   std::vector<std::vector<uint8> > key_ids;
    754   for (uint32_t i = 0; i < usable_key_ids_length; ++i) {
    755     key_ids.push_back(
    756         std::vector<uint8>(usable_key_ids[i].data,
    757                            usable_key_ids[i].data + usable_key_ids[i].length));
    758   }
    759   PostOnMain(callback_factory_.NewCallback(
    760       &CdmAdapter::SendPromiseResolvedWithUsableKeyIdsInternal,
    761       promise_id,
    762       key_ids));
    763 }
    764 
    765 void CdmAdapter::OnRejectPromise(uint32_t promise_id,
    766                                  cdm::Error error,
    767                                  uint32_t system_code,
    768                                  const char* error_message,
    769                                  uint32_t error_message_length) {
    770   // UMA to investigate http://crbug.com/410630
    771   // TODO(xhwang): Remove after bug is fixed.
    772   if (system_code == 0x27) {
    773     pp::UMAPrivate uma_interface(this);
    774     uma_interface.HistogramCustomCounts("Media.EME.CdmFileIO.FileSizeKBOnError",
    775                                         last_read_file_size_kb_,
    776                                         kSizeKBMin,
    777                                         kSizeKBMax,
    778                                         kSizeKBBuckets);
    779   }
    780 
    781   RejectPromise(promise_id,
    782                 error,
    783                 system_code,
    784                 std::string(error_message, error_message_length));
    785 }
    786 
    787 void CdmAdapter::RejectPromise(uint32_t promise_id,
    788                                cdm::Error error,
    789                                uint32_t system_code,
    790                                const std::string& error_message) {
    791   PostOnMain(callback_factory_.NewCallback(
    792       &CdmAdapter::SendPromiseRejectedInternal,
    793       promise_id,
    794       SessionError(error, system_code, error_message)));
    795 }
    796 
    797 void CdmAdapter::OnSessionMessage(const char* web_session_id,
    798                                   uint32_t web_session_id_length,
    799                                   const char* message,
    800                                   uint32_t message_length,
    801                                   const char* destination_url,
    802                                   uint32_t destination_url_length) {
    803   PostOnMain(callback_factory_.NewCallback(
    804       &CdmAdapter::SendSessionMessageInternal,
    805       std::string(web_session_id, web_session_id_length),
    806       std::vector<uint8>(message, message + message_length),
    807       std::string(destination_url, destination_url_length)));
    808 }
    809 
    810 void CdmAdapter::OnSessionUsableKeysChange(const char* web_session_id,
    811                                            uint32_t web_session_id_length,
    812                                            bool has_additional_usable_key) {
    813   PostOnMain(callback_factory_.NewCallback(
    814       &CdmAdapter::SendSessionUsableKeysChangeInternal,
    815       std::string(web_session_id, web_session_id_length),
    816       has_additional_usable_key));
    817 }
    818 
    819 void CdmAdapter::OnExpirationChange(const char* web_session_id,
    820                                     uint32_t web_session_id_length,
    821                                     cdm::Time new_expiry_time) {
    822   PostOnMain(callback_factory_.NewCallback(
    823       &CdmAdapter::SendExpirationChangeInternal,
    824       std::string(web_session_id, web_session_id_length),
    825       new_expiry_time));
    826 }
    827 
    828 void CdmAdapter::OnSessionClosed(const char* web_session_id,
    829                                  uint32_t web_session_id_length) {
    830   PostOnMain(callback_factory_.NewCallback(
    831       &CdmAdapter::SendSessionClosedInternal,
    832       std::string(web_session_id, web_session_id_length)));
    833 }
    834 
    835 void CdmAdapter::OnSessionError(const char* web_session_id,
    836                                 uint32_t web_session_id_length,
    837                                 cdm::Error error,
    838                                 uint32_t system_code,
    839                                 const char* error_message,
    840                                 uint32_t error_message_length) {
    841   PostOnMain(callback_factory_.NewCallback(
    842       &CdmAdapter::SendSessionErrorInternal,
    843       std::string(web_session_id, web_session_id_length),
    844       SessionError(error,
    845                    system_code,
    846                    std::string(error_message, error_message_length))));
    847 }
    848 
    849 // Helpers to pass the event to Pepper.
    850 
    851 void CdmAdapter::SendPromiseResolvedInternal(int32_t result,
    852                                              uint32_t promise_id) {
    853   PP_DCHECK(result == PP_OK);
    854   pp::ContentDecryptor_Private::PromiseResolved(promise_id);
    855 }
    856 
    857 void CdmAdapter::SendPromiseResolvedWithSessionInternal(
    858     int32_t result,
    859     uint32_t promise_id,
    860     const std::string& web_session_id) {
    861   PP_DCHECK(result == PP_OK);
    862   pp::ContentDecryptor_Private::PromiseResolvedWithSession(promise_id,
    863                                                            web_session_id);
    864 }
    865 
    866 void CdmAdapter::SendPromiseResolvedWithUsableKeyIdsInternal(
    867     int32_t result,
    868     uint32_t promise_id,
    869     std::vector<std::vector<uint8> > key_ids) {
    870   PP_DCHECK(result == PP_OK);
    871   pp::ContentDecryptor_Private::PromiseResolvedWithKeyIds(promise_id, key_ids);
    872 }
    873 
    874 void CdmAdapter::SendPromiseRejectedInternal(int32_t result,
    875                                              uint32_t promise_id,
    876                                              const SessionError& error) {
    877   PP_DCHECK(result == PP_OK);
    878   pp::ContentDecryptor_Private::PromiseRejected(
    879       promise_id,
    880       CdmExceptionTypeToPpCdmExceptionType(error.error),
    881       error.system_code,
    882       error.error_description);
    883 }
    884 
    885 void CdmAdapter::SendSessionMessageInternal(
    886     int32_t result,
    887     const std::string& web_session_id,
    888     const std::vector<uint8>& message,
    889     const std::string& destination_url) {
    890   PP_DCHECK(result == PP_OK);
    891 
    892   pp::VarArrayBuffer message_array_buffer(message.size());
    893   if (message.size() > 0) {
    894     memcpy(message_array_buffer.Map(), message.data(), message.size());
    895   }
    896 
    897   pp::ContentDecryptor_Private::SessionMessage(
    898       web_session_id, message_array_buffer, destination_url);
    899 }
    900 
    901 void CdmAdapter::SendSessionReadyInternal(int32_t result,
    902                                           const std::string& web_session_id) {
    903   PP_DCHECK(result == PP_OK);
    904   pp::ContentDecryptor_Private::SessionReady(web_session_id);
    905 }
    906 
    907 void CdmAdapter::SendSessionClosedInternal(int32_t result,
    908                                            const std::string& web_session_id) {
    909   PP_DCHECK(result == PP_OK);
    910   pp::ContentDecryptor_Private::SessionClosed(web_session_id);
    911 }
    912 
    913 void CdmAdapter::SendSessionErrorInternal(int32_t result,
    914                                           const std::string& web_session_id,
    915                                           const SessionError& error) {
    916   PP_DCHECK(result == PP_OK);
    917   pp::ContentDecryptor_Private::SessionError(
    918       web_session_id,
    919       CdmExceptionTypeToPpCdmExceptionType(error.error),
    920       error.system_code,
    921       error.error_description);
    922 }
    923 
    924 void CdmAdapter::SendSessionUsableKeysChangeInternal(
    925     int32_t result,
    926     const std::string& web_session_id,
    927     bool has_additional_usable_key) {
    928   PP_DCHECK(result == PP_OK);
    929   pp::ContentDecryptor_Private::SessionKeysChange(web_session_id,
    930                                                   has_additional_usable_key);
    931 }
    932 
    933 void CdmAdapter::SendExpirationChangeInternal(int32_t result,
    934                                               const std::string& web_session_id,
    935                                               cdm::Time new_expiry_time) {
    936   PP_DCHECK(result == PP_OK);
    937   pp::ContentDecryptor_Private::SessionExpirationChange(web_session_id,
    938                                                         new_expiry_time);
    939 }
    940 
    941 void CdmAdapter::DeliverBlock(int32_t result,
    942                               const cdm::Status& status,
    943                               const LinkedDecryptedBlock& decrypted_block,
    944                               const PP_DecryptTrackingInfo& tracking_info) {
    945   PP_DCHECK(result == PP_OK);
    946   PP_DecryptedBlockInfo decrypted_block_info = {};
    947   decrypted_block_info.tracking_info = tracking_info;
    948   decrypted_block_info.tracking_info.timestamp = decrypted_block->Timestamp();
    949   decrypted_block_info.tracking_info.buffer_id = 0;
    950   decrypted_block_info.data_size = 0;
    951   decrypted_block_info.result = CdmStatusToPpDecryptResult(status);
    952 
    953   pp::Buffer_Dev buffer;
    954 
    955   if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) {
    956     PP_DCHECK(decrypted_block.get() && decrypted_block->DecryptedBuffer());
    957     if (!decrypted_block.get() || !decrypted_block->DecryptedBuffer()) {
    958       PP_NOTREACHED();
    959       decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
    960     } else {
    961       PpbBuffer* ppb_buffer =
    962           static_cast<PpbBuffer*>(decrypted_block->DecryptedBuffer());
    963       decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
    964       decrypted_block_info.data_size = ppb_buffer->Size();
    965 
    966       buffer = ppb_buffer->TakeBuffer();
    967     }
    968   }
    969 
    970   pp::ContentDecryptor_Private::DeliverBlock(buffer, decrypted_block_info);
    971 }
    972 
    973 void CdmAdapter::DecoderInitializeDone(int32_t result,
    974                                        PP_DecryptorStreamType decoder_type,
    975                                        uint32_t request_id,
    976                                        bool success) {
    977   PP_DCHECK(result == PP_OK);
    978   pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type,
    979                                                       request_id,
    980                                                       success);
    981 }
    982 
    983 void CdmAdapter::DecoderDeinitializeDone(int32_t result,
    984                                          PP_DecryptorStreamType decoder_type,
    985                                          uint32_t request_id) {
    986   pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type,
    987                                                         request_id);
    988 }
    989 
    990 void CdmAdapter::DecoderResetDone(int32_t result,
    991                                   PP_DecryptorStreamType decoder_type,
    992                                   uint32_t request_id) {
    993   pp::ContentDecryptor_Private::DecoderResetDone(decoder_type, request_id);
    994 }
    995 
    996 void CdmAdapter::DeliverFrame(
    997     int32_t result,
    998     const cdm::Status& status,
    999     const LinkedVideoFrame& video_frame,
   1000     const PP_DecryptTrackingInfo& tracking_info) {
   1001   PP_DCHECK(result == PP_OK);
   1002   PP_DecryptedFrameInfo decrypted_frame_info = {};
   1003   decrypted_frame_info.tracking_info.request_id = tracking_info.request_id;
   1004   decrypted_frame_info.tracking_info.buffer_id = 0;
   1005   decrypted_frame_info.result = CdmStatusToPpDecryptResult(status);
   1006 
   1007   pp::Buffer_Dev buffer;
   1008 
   1009   if (decrypted_frame_info.result == PP_DECRYPTRESULT_SUCCESS) {
   1010     if (!IsValidVideoFrame(video_frame)) {
   1011       PP_NOTREACHED();
   1012       decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR;
   1013     } else {
   1014       PpbBuffer* ppb_buffer =
   1015           static_cast<PpbBuffer*>(video_frame->FrameBuffer());
   1016 
   1017       decrypted_frame_info.tracking_info.timestamp = video_frame->Timestamp();
   1018       decrypted_frame_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
   1019       decrypted_frame_info.format =
   1020           CdmVideoFormatToPpDecryptedFrameFormat(video_frame->Format());
   1021       decrypted_frame_info.width = video_frame->Size().width;
   1022       decrypted_frame_info.height = video_frame->Size().height;
   1023       decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y] =
   1024           video_frame->PlaneOffset(cdm::VideoFrame::kYPlane);
   1025       decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_U] =
   1026           video_frame->PlaneOffset(cdm::VideoFrame::kUPlane);
   1027       decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_V] =
   1028           video_frame->PlaneOffset(cdm::VideoFrame::kVPlane);
   1029       decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_Y] =
   1030           video_frame->Stride(cdm::VideoFrame::kYPlane);
   1031       decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_U] =
   1032           video_frame->Stride(cdm::VideoFrame::kUPlane);
   1033       decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_V] =
   1034           video_frame->Stride(cdm::VideoFrame::kVPlane);
   1035 
   1036       buffer = ppb_buffer->TakeBuffer();
   1037     }
   1038   }
   1039 
   1040   pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info);
   1041 }
   1042 
   1043 void CdmAdapter::DeliverSamples(int32_t result,
   1044                                 const cdm::Status& status,
   1045                                 const LinkedAudioFrames& audio_frames,
   1046                                 const PP_DecryptTrackingInfo& tracking_info) {
   1047   PP_DCHECK(result == PP_OK);
   1048 
   1049   PP_DecryptedSampleInfo decrypted_sample_info = {};
   1050   decrypted_sample_info.tracking_info = tracking_info;
   1051   decrypted_sample_info.tracking_info.timestamp = 0;
   1052   decrypted_sample_info.tracking_info.buffer_id = 0;
   1053   decrypted_sample_info.data_size = 0;
   1054   decrypted_sample_info.result = CdmStatusToPpDecryptResult(status);
   1055 
   1056   pp::Buffer_Dev buffer;
   1057 
   1058   if (decrypted_sample_info.result == PP_DECRYPTRESULT_SUCCESS) {
   1059     PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer());
   1060     if (!audio_frames.get() || !audio_frames->FrameBuffer()) {
   1061       PP_NOTREACHED();
   1062       decrypted_sample_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
   1063     } else {
   1064       PpbBuffer* ppb_buffer =
   1065           static_cast<PpbBuffer*>(audio_frames->FrameBuffer());
   1066 
   1067       decrypted_sample_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
   1068       decrypted_sample_info.data_size = ppb_buffer->Size();
   1069       decrypted_sample_info.format =
   1070           CdmAudioFormatToPpDecryptedSampleFormat(audio_frames->Format());
   1071 
   1072       buffer = ppb_buffer->TakeBuffer();
   1073     }
   1074   }
   1075 
   1076   pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_sample_info);
   1077 }
   1078 
   1079 bool CdmAdapter::IsValidVideoFrame(const LinkedVideoFrame& video_frame) {
   1080   if (!video_frame.get() ||
   1081       !video_frame->FrameBuffer() ||
   1082       (video_frame->Format() != cdm::kI420 &&
   1083        video_frame->Format() != cdm::kYv12)) {
   1084     CDM_DLOG() << "Invalid video frame!";
   1085     return false;
   1086   }
   1087 
   1088   PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer());
   1089 
   1090   for (uint32_t i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) {
   1091     int plane_height = (i == cdm::VideoFrame::kYPlane) ?
   1092         video_frame->Size().height : (video_frame->Size().height + 1) / 2;
   1093     cdm::VideoFrame::VideoPlane plane =
   1094         static_cast<cdm::VideoFrame::VideoPlane>(i);
   1095     if (ppb_buffer->Size() < video_frame->PlaneOffset(plane) +
   1096                              plane_height * video_frame->Stride(plane)) {
   1097       return false;
   1098     }
   1099   }
   1100 
   1101   return true;
   1102 }
   1103 
   1104 void CdmAdapter::OnFirstFileRead(int32_t file_size_bytes) {
   1105   PP_DCHECK(IsMainThread());
   1106   PP_DCHECK(file_size_bytes >= 0);
   1107 
   1108   last_read_file_size_kb_ = file_size_bytes / 1024;
   1109 
   1110   if (file_size_uma_reported_)
   1111     return;
   1112 
   1113   pp::UMAPrivate uma_interface(this);
   1114   uma_interface.HistogramCustomCounts(
   1115       "Media.EME.CdmFileIO.FileSizeKBOnFirstRead",
   1116       last_read_file_size_kb_,
   1117       kSizeKBMin,
   1118       kSizeKBMax,
   1119       kSizeKBBuckets);
   1120   file_size_uma_reported_ = true;
   1121 }
   1122 
   1123 #if !defined(NDEBUG)
   1124 void CdmAdapter::LogToConsole(const pp::Var& value) {
   1125   PP_DCHECK(IsMainThread());
   1126   const PPB_Console* console = reinterpret_cast<const PPB_Console*>(
   1127       pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE));
   1128   console->Log(pp_instance(), PP_LOGLEVEL_LOG, value.pp_var());
   1129 }
   1130 #endif  // !defined(NDEBUG)
   1131 
   1132 void CdmAdapter::SendPlatformChallenge(
   1133     const char* service_id, uint32_t service_id_length,
   1134     const char* challenge, uint32_t challenge_length) {
   1135 #if defined(OS_CHROMEOS)
   1136   pp::VarArrayBuffer challenge_var(challenge_length);
   1137   uint8_t* var_data = static_cast<uint8_t*>(challenge_var.Map());
   1138   memcpy(var_data, challenge, challenge_length);
   1139 
   1140   std::string service_id_str(service_id, service_id_length);
   1141 
   1142   linked_ptr<PepperPlatformChallengeResponse> response(
   1143       new PepperPlatformChallengeResponse());
   1144 
   1145   int32_t result = platform_verification_.ChallengePlatform(
   1146       pp::Var(service_id_str),
   1147       challenge_var,
   1148       &response->signed_data,
   1149       &response->signed_data_signature,
   1150       &response->platform_key_certificate,
   1151       callback_factory_.NewCallback(&CdmAdapter::SendPlatformChallengeDone,
   1152                                     response));
   1153   challenge_var.Unmap();
   1154   if (result == PP_OK_COMPLETIONPENDING)
   1155     return;
   1156 
   1157   // Fall through on error and issue an empty OnPlatformChallengeResponse().
   1158   PP_DCHECK(result != PP_OK);
   1159 #endif
   1160 
   1161   cdm::PlatformChallengeResponse platform_challenge_response = {};
   1162   cdm_->OnPlatformChallengeResponse(platform_challenge_response);
   1163 }
   1164 
   1165 void CdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask) {
   1166 #if defined(OS_CHROMEOS)
   1167   int32_t result = output_protection_.EnableProtection(
   1168       desired_protection_mask, callback_factory_.NewCallback(
   1169           &CdmAdapter::EnableProtectionDone));
   1170 
   1171   // Errors are ignored since clients must call QueryOutputProtectionStatus() to
   1172   // inspect the protection status on a regular basis.
   1173 
   1174   if (result != PP_OK && result != PP_OK_COMPLETIONPENDING)
   1175     CDM_DLOG() << __FUNCTION__ << " failed!";
   1176 #endif
   1177 }
   1178 
   1179 void CdmAdapter::QueryOutputProtectionStatus() {
   1180 #if defined(OS_CHROMEOS)
   1181   PP_DCHECK(!query_output_protection_in_progress_);
   1182 
   1183   output_link_mask_ = output_protection_mask_ = 0;
   1184   const int32_t result = output_protection_.QueryStatus(
   1185       &output_link_mask_,
   1186       &output_protection_mask_,
   1187       callback_factory_.NewCallback(
   1188           &CdmAdapter::QueryOutputProtectionStatusDone));
   1189   if (result == PP_OK_COMPLETIONPENDING) {
   1190     query_output_protection_in_progress_ = true;
   1191     ReportOutputProtectionQuery();
   1192     return;
   1193   }
   1194 
   1195   // Fall through on error and issue an empty OnQueryOutputProtectionStatus().
   1196   PP_DCHECK(result != PP_OK);
   1197 #endif
   1198 
   1199   cdm_->OnQueryOutputProtectionStatus(0, 0);
   1200 }
   1201 
   1202 void CdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type,
   1203                                               cdm::Status decoder_status) {
   1204   switch (stream_type) {
   1205     case cdm::kStreamTypeAudio:
   1206       PP_DCHECK(deferred_initialize_audio_decoder_);
   1207       CallOnMain(
   1208           callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone,
   1209                                         PP_DECRYPTORSTREAMTYPE_AUDIO,
   1210                                         deferred_audio_decoder_config_id_,
   1211                                         decoder_status == cdm::kSuccess));
   1212       deferred_initialize_audio_decoder_ = false;
   1213       deferred_audio_decoder_config_id_ = 0;
   1214       break;
   1215     case cdm::kStreamTypeVideo:
   1216       PP_DCHECK(deferred_initialize_video_decoder_);
   1217       CallOnMain(
   1218           callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone,
   1219                                         PP_DECRYPTORSTREAMTYPE_VIDEO,
   1220                                         deferred_video_decoder_config_id_,
   1221                                         decoder_status == cdm::kSuccess));
   1222       deferred_initialize_video_decoder_ = false;
   1223       deferred_video_decoder_config_id_ = 0;
   1224       break;
   1225   }
   1226 }
   1227 
   1228 // The CDM owns the returned object and must call FileIO::Close() to release it.
   1229 cdm::FileIO* CdmAdapter::CreateFileIO(cdm::FileIOClient* client) {
   1230   return new CdmFileIOImpl(
   1231       client,
   1232       pp_instance(),
   1233       callback_factory_.NewCallback(&CdmAdapter::OnFirstFileRead));
   1234 }
   1235 
   1236 #if defined(OS_CHROMEOS)
   1237 void CdmAdapter::ReportOutputProtectionUMA(OutputProtectionStatus status) {
   1238   pp::UMAPrivate uma_interface(this);
   1239   uma_interface.HistogramEnumeration(
   1240       "Media.EME.OutputProtection", status, OUTPUT_PROTECTION_MAX);
   1241 }
   1242 
   1243 void CdmAdapter::ReportOutputProtectionQuery() {
   1244   if (uma_for_output_protection_query_reported_)
   1245     return;
   1246 
   1247   ReportOutputProtectionUMA(OUTPUT_PROTECTION_QUERIED);
   1248   uma_for_output_protection_query_reported_ = true;
   1249 }
   1250 
   1251 void CdmAdapter::ReportOutputProtectionQueryResult() {
   1252   if (uma_for_output_protection_positive_result_reported_)
   1253     return;
   1254 
   1255   // Report UMAs for output protection query result.
   1256   uint32_t external_links = (output_link_mask_ & ~cdm::kLinkTypeInternal);
   1257 
   1258   if (!external_links) {
   1259     ReportOutputProtectionUMA(OUTPUT_PROTECTION_NO_EXTERNAL_LINK);
   1260     uma_for_output_protection_positive_result_reported_ = true;
   1261     return;
   1262   }
   1263 
   1264   const uint32_t kProtectableLinks =
   1265       cdm::kLinkTypeHDMI | cdm::kLinkTypeDVI | cdm::kLinkTypeDisplayPort;
   1266   bool is_unprotectable_link_connected = external_links & ~kProtectableLinks;
   1267   bool is_hdcp_enabled_on_all_protectable_links =
   1268       output_protection_mask_ & cdm::kProtectionHDCP;
   1269 
   1270   if (!is_unprotectable_link_connected &&
   1271       is_hdcp_enabled_on_all_protectable_links) {
   1272     ReportOutputProtectionUMA(
   1273         OUTPUT_PROTECTION_ALL_EXTERNAL_LINKS_PROTECTED);
   1274     uma_for_output_protection_positive_result_reported_ = true;
   1275     return;
   1276   }
   1277 
   1278   // Do not report a negative result because it could be a false negative.
   1279   // Instead, we will calculate number of negatives using the total number of
   1280   // queries and success results.
   1281 }
   1282 
   1283 void CdmAdapter::SendPlatformChallengeDone(
   1284     int32_t result,
   1285     const linked_ptr<PepperPlatformChallengeResponse>& response) {
   1286   if (result != PP_OK) {
   1287     CDM_DLOG() << __FUNCTION__ << ": Platform challenge failed!";
   1288     cdm::PlatformChallengeResponse platform_challenge_response = {};
   1289     cdm_->OnPlatformChallengeResponse(platform_challenge_response);
   1290     return;
   1291   }
   1292 
   1293   pp::VarArrayBuffer signed_data_var(response->signed_data);
   1294   pp::VarArrayBuffer signed_data_signature_var(response->signed_data_signature);
   1295   std::string platform_key_certificate_string =
   1296       response->platform_key_certificate.AsString();
   1297 
   1298   cdm::PlatformChallengeResponse platform_challenge_response = {
   1299       static_cast<uint8_t*>(signed_data_var.Map()),
   1300       signed_data_var.ByteLength(),
   1301       static_cast<uint8_t*>(signed_data_signature_var.Map()),
   1302       signed_data_signature_var.ByteLength(),
   1303       reinterpret_cast<const uint8_t*>(platform_key_certificate_string.data()),
   1304       static_cast<uint32_t>(platform_key_certificate_string.length())};
   1305   cdm_->OnPlatformChallengeResponse(platform_challenge_response);
   1306 
   1307   signed_data_var.Unmap();
   1308   signed_data_signature_var.Unmap();
   1309 }
   1310 
   1311 void CdmAdapter::EnableProtectionDone(int32_t result) {
   1312   // Does nothing since clients must call QueryOutputProtectionStatus() to
   1313   // inspect the protection status on a regular basis.
   1314   CDM_DLOG() << __FUNCTION__ << " : " << result;
   1315 }
   1316 
   1317 void CdmAdapter::QueryOutputProtectionStatusDone(int32_t result) {
   1318   PP_DCHECK(query_output_protection_in_progress_);
   1319   query_output_protection_in_progress_ = false;
   1320 
   1321   // Return a protection status of none on error.
   1322   if (result != PP_OK)
   1323     output_link_mask_ = output_protection_mask_ = 0;
   1324   else
   1325     ReportOutputProtectionQueryResult();
   1326 
   1327   cdm_->OnQueryOutputProtectionStatus(output_link_mask_,
   1328                                       output_protection_mask_);
   1329 }
   1330 #endif
   1331 
   1332 CdmAdapter::SessionError::SessionError(cdm::Error error,
   1333                                        uint32_t system_code,
   1334                                        std::string error_description)
   1335     : error(error),
   1336       system_code(system_code),
   1337       error_description(error_description) {
   1338 }
   1339 
   1340 void* GetCdmHost(int host_interface_version, void* user_data) {
   1341   if (!host_interface_version || !user_data)
   1342     return NULL;
   1343 
   1344   COMPILE_ASSERT(
   1345       cdm::ContentDecryptionModule::Host::kVersion == cdm::Host_6::kVersion,
   1346       update_code_below);
   1347 
   1348   // Ensure IsSupportedCdmHostVersion matches implementation of this function.
   1349   // Always update this DCHECK when updating this function.
   1350   // If this check fails, update this function and DCHECK or update
   1351   // IsSupportedCdmHostVersion.
   1352 
   1353   PP_DCHECK(
   1354       // Future version is not supported.
   1355       !IsSupportedCdmHostVersion(cdm::Host_6::kVersion + 1) &&
   1356       // Current version is supported.
   1357       IsSupportedCdmHostVersion(cdm::Host_6::kVersion) &&
   1358       // Include all previous supported versions (if any) here.
   1359       // Host_5 is not supported.
   1360       IsSupportedCdmHostVersion(cdm::Host_4::kVersion) &&
   1361       // One older than the oldest supported version is not supported.
   1362       !IsSupportedCdmHostVersion(cdm::Host_4::kVersion - 1));
   1363   PP_DCHECK(IsSupportedCdmHostVersion(host_interface_version));
   1364 
   1365   CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data);
   1366   CDM_DLOG() << "Create CDM Host with version " << host_interface_version;
   1367   switch (host_interface_version) {
   1368     case cdm::Host_4::kVersion:
   1369       return static_cast<cdm::Host_4*>(cdm_adapter);
   1370     case cdm::Host_6::kVersion:
   1371       return static_cast<cdm::Host_6*>(cdm_adapter);
   1372     default:
   1373       PP_NOTREACHED();
   1374       return NULL;
   1375   }
   1376 }
   1377 
   1378 // This object is the global object representing this plugin library as long
   1379 // as it is loaded.
   1380 class CdmAdapterModule : public pp::Module {
   1381  public:
   1382   CdmAdapterModule() : pp::Module() {
   1383     // This function blocks the renderer thread (PluginInstance::Initialize()).
   1384     // Move this call to other places if this may be a concern in the future.
   1385     INITIALIZE_CDM_MODULE();
   1386   }
   1387   virtual ~CdmAdapterModule() {
   1388     DeinitializeCdmModule();
   1389   }
   1390 
   1391   virtual pp::Instance* CreateInstance(PP_Instance instance) {
   1392     return new CdmAdapter(instance, this);
   1393   }
   1394 
   1395  private:
   1396   CdmFileIOImpl::ResourceTracker cdm_file_io_impl_resource_tracker;
   1397 };
   1398 
   1399 }  // namespace media
   1400 
   1401 namespace pp {
   1402 
   1403 // Factory function for your specialization of the Module object.
   1404 Module* CreateModule() {
   1405   return new media::CdmAdapterModule();
   1406 }
   1407 
   1408 }  // namespace pp
   1409