Upstream version 10.39.225.0
[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   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