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