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