cdm_adapter.cc revision 010d83a9304c5a91596085d917d248abff47903a
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
214}  // namespace
215
216namespace media {
217
218CdmAdapter::CdmAdapter(PP_Instance instance, pp::Module* module)
219    : pp::Instance(instance),
220      pp::ContentDecryptor_Private(this),
221#if defined(OS_CHROMEOS)
222      output_protection_(this),
223      platform_verification_(this),
224      challenge_in_progress_(false),
225      output_link_mask_(0),
226      output_protection_mask_(0),
227      query_output_protection_in_progress_(false),
228      uma_for_output_protection_query_reported_(false),
229      uma_for_output_protection_positive_result_reported_(false),
230#endif
231      allocator_(this),
232      cdm_(NULL),
233      deferred_initialize_audio_decoder_(false),
234      deferred_audio_decoder_config_id_(0),
235      deferred_initialize_video_decoder_(false),
236      deferred_video_decoder_config_id_(0) {
237  callback_factory_.Initialize(this);
238}
239
240CdmAdapter::~CdmAdapter() {}
241
242bool CdmAdapter::CreateCdmInstance(const std::string& key_system) {
243  PP_DCHECK(!cdm_);
244  cdm_ = make_linked_ptr(CdmWrapper::Create(
245      key_system.data(), key_system.size(), GetCdmHost, this));
246  bool success = cdm_ != NULL;
247
248  const std::string message = "CDM instance for " + key_system +
249                              (success ? "" : " could not be") + " created.";
250  DLOG_TO_CONSOLE(message);
251  CDM_DLOG() << message;
252
253  return success;
254}
255
256// No errors should be reported in this function because the spec says:
257// "Store this new error object internally with the MediaKeys instance being
258// created. This will be used to fire an error against any session created for
259// this instance." These errors will be reported during session creation
260// (CreateSession()) or session loading (LoadSession()).
261// TODO(xhwang): If necessary, we need to store the error here if we want to
262// support more specific error reporting (other than "Unknown").
263void CdmAdapter::Initialize(const std::string& key_system) {
264  PP_DCHECK(!key_system.empty());
265  PP_DCHECK(key_system_.empty() || (key_system_ == key_system && cdm_));
266
267#if defined(CHECK_DOCUMENT_URL)
268  PP_URLComponents_Dev url_components = {};
269  const pp::URLUtil_Dev* url_util = pp::URLUtil_Dev::Get();
270  if (!url_util)
271    return;
272  pp::Var href = url_util->GetDocumentURL(pp::InstanceHandle(pp_instance()),
273                                          &url_components);
274  PP_DCHECK(href.is_string());
275  std::string url = href.AsString();
276  PP_DCHECK(!url.empty());
277  std::string url_scheme =
278      url.substr(url_components.scheme.begin, url_components.scheme.len);
279  if (url_scheme != "file") {
280    // Skip this check for file:// URLs as they don't have a host component.
281    PP_DCHECK(url_components.host.begin);
282    PP_DCHECK(0 < url_components.host.len);
283  }
284#endif  // defined(CHECK_DOCUMENT_URL)
285
286  if (!cdm_ && !CreateCdmInstance(key_system))
287    return;
288
289  PP_DCHECK(cdm_);
290  key_system_ = key_system;
291}
292
293void CdmAdapter::CreateSession(uint32_t session_id,
294                               const std::string& content_type,
295                               pp::VarArrayBuffer init_data) {
296  // Initialize() doesn't report an error, so CreateSession() can be called
297  // even if Initialize() failed.
298  if (!cdm_) {
299    OnSessionError(session_id, cdm::kUnknownError, 0);
300    return;
301  }
302
303  cdm_->CreateSession(session_id,
304                      content_type.data(),
305                      content_type.size(),
306                      static_cast<const uint8_t*>(init_data.Map()),
307                      init_data.ByteLength());
308}
309
310void CdmAdapter::LoadSession(uint32_t session_id,
311                             const std::string& web_session_id) {
312  // Initialize() doesn't report an error, so LoadSession() can be called
313  // even if Initialize() failed.
314  if (!cdm_) {
315    OnSessionError(session_id, cdm::kUnknownError, 0);
316    return;
317  }
318
319  cdm_->LoadSession(session_id, web_session_id.data(), web_session_id.size());
320}
321
322void CdmAdapter::UpdateSession(uint32_t session_id,
323                               pp::VarArrayBuffer response) {
324  const uint8_t* response_ptr = static_cast<const uint8_t*>(response.Map());
325  const uint32_t response_size = response.ByteLength();
326
327  if (!response_ptr || response_size <= 0) {
328    OnSessionError(session_id, cdm::kUnknownError, 0);
329    return;
330  }
331  cdm_->UpdateSession(session_id, response_ptr, response_size);
332}
333
334void CdmAdapter::ReleaseSession(uint32_t session_id) {
335  cdm_->ReleaseSession(session_id);
336}
337
338// Note: In the following decryption/decoding related functions, errors are NOT
339// reported via KeyError, but are reported via corresponding PPB calls.
340
341void CdmAdapter::Decrypt(pp::Buffer_Dev encrypted_buffer,
342                         const PP_EncryptedBlockInfo& encrypted_block_info) {
343  PP_DCHECK(!encrypted_buffer.is_null());
344
345  // Release a buffer that the caller indicated it is finished with.
346  allocator_.Release(encrypted_block_info.tracking_info.buffer_id);
347
348  cdm::Status status = cdm::kDecryptError;
349  LinkedDecryptedBlock decrypted_block(new DecryptedBlockImpl());
350
351  if (cdm_) {
352    cdm::InputBuffer input_buffer;
353    std::vector<cdm::SubsampleEntry> subsamples;
354    ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples,
355                         &input_buffer);
356    status = cdm_->Decrypt(input_buffer, decrypted_block.get());
357    PP_DCHECK(status != cdm::kSuccess ||
358              (decrypted_block->DecryptedBuffer() &&
359               decrypted_block->DecryptedBuffer()->Size()));
360  }
361
362  CallOnMain(callback_factory_.NewCallback(
363      &CdmAdapter::DeliverBlock,
364      status,
365      decrypted_block,
366      encrypted_block_info.tracking_info));
367}
368
369void CdmAdapter::InitializeAudioDecoder(
370    const PP_AudioDecoderConfig& decoder_config,
371    pp::Buffer_Dev extra_data_buffer) {
372  PP_DCHECK(!deferred_initialize_audio_decoder_);
373  PP_DCHECK(deferred_audio_decoder_config_id_ == 0);
374  cdm::Status status = cdm::kSessionError;
375  if (cdm_) {
376    cdm::AudioDecoderConfig cdm_decoder_config;
377    cdm_decoder_config.codec =
378        PpAudioCodecToCdmAudioCodec(decoder_config.codec);
379    cdm_decoder_config.channel_count = decoder_config.channel_count;
380    cdm_decoder_config.bits_per_channel = decoder_config.bits_per_channel;
381    cdm_decoder_config.samples_per_second = decoder_config.samples_per_second;
382    cdm_decoder_config.extra_data =
383        static_cast<uint8_t*>(extra_data_buffer.data());
384    cdm_decoder_config.extra_data_size = extra_data_buffer.size();
385    status = cdm_->InitializeAudioDecoder(cdm_decoder_config);
386  }
387
388  if (status == cdm::kDeferredInitialization) {
389    deferred_initialize_audio_decoder_ = true;
390    deferred_audio_decoder_config_id_ = decoder_config.request_id;
391    return;
392  }
393
394  CallOnMain(callback_factory_.NewCallback(
395      &CdmAdapter::DecoderInitializeDone,
396      PP_DECRYPTORSTREAMTYPE_AUDIO,
397      decoder_config.request_id,
398      status == cdm::kSuccess));
399}
400
401void CdmAdapter::InitializeVideoDecoder(
402    const PP_VideoDecoderConfig& decoder_config,
403    pp::Buffer_Dev extra_data_buffer) {
404  PP_DCHECK(!deferred_initialize_video_decoder_);
405  PP_DCHECK(deferred_video_decoder_config_id_ == 0);
406  cdm::Status status = cdm::kSessionError;
407  if (cdm_) {
408    cdm::VideoDecoderConfig cdm_decoder_config;
409    cdm_decoder_config.codec =
410        PpVideoCodecToCdmVideoCodec(decoder_config.codec);
411    cdm_decoder_config.profile =
412        PpVCProfileToCdmVCProfile(decoder_config.profile);
413    cdm_decoder_config.format =
414        PpDecryptedFrameFormatToCdmVideoFormat(decoder_config.format);
415    cdm_decoder_config.coded_size.width = decoder_config.width;
416    cdm_decoder_config.coded_size.height = decoder_config.height;
417    cdm_decoder_config.extra_data =
418        static_cast<uint8_t*>(extra_data_buffer.data());
419    cdm_decoder_config.extra_data_size = extra_data_buffer.size();
420    status = cdm_->InitializeVideoDecoder(cdm_decoder_config);
421  }
422
423  if (status == cdm::kDeferredInitialization) {
424    deferred_initialize_video_decoder_ = true;
425    deferred_video_decoder_config_id_ = decoder_config.request_id;
426    return;
427  }
428
429  CallOnMain(callback_factory_.NewCallback(
430      &CdmAdapter::DecoderInitializeDone,
431      PP_DECRYPTORSTREAMTYPE_VIDEO,
432      decoder_config.request_id,
433      status == cdm::kSuccess));
434}
435
436void CdmAdapter::DeinitializeDecoder(PP_DecryptorStreamType decoder_type,
437                                     uint32_t request_id) {
438  PP_DCHECK(cdm_);  // InitializeXxxxxDecoder should have succeeded.
439  if (cdm_) {
440    cdm_->DeinitializeDecoder(
441        PpDecryptorStreamTypeToCdmStreamType(decoder_type));
442  }
443
444  CallOnMain(callback_factory_.NewCallback(
445      &CdmAdapter::DecoderDeinitializeDone,
446      decoder_type,
447      request_id));
448}
449
450void CdmAdapter::ResetDecoder(PP_DecryptorStreamType decoder_type,
451                              uint32_t request_id) {
452  PP_DCHECK(cdm_);  // InitializeXxxxxDecoder should have succeeded.
453  if (cdm_)
454    cdm_->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type));
455
456  CallOnMain(callback_factory_.NewCallback(&CdmAdapter::DecoderResetDone,
457                                           decoder_type,
458                                           request_id));
459}
460
461void CdmAdapter::DecryptAndDecode(
462    PP_DecryptorStreamType decoder_type,
463    pp::Buffer_Dev encrypted_buffer,
464    const PP_EncryptedBlockInfo& encrypted_block_info) {
465  PP_DCHECK(cdm_);  // InitializeXxxxxDecoder should have succeeded.
466  // Release a buffer that the caller indicated it is finished with.
467  allocator_.Release(encrypted_block_info.tracking_info.buffer_id);
468
469  cdm::InputBuffer input_buffer;
470  std::vector<cdm::SubsampleEntry> subsamples;
471  if (cdm_ && !encrypted_buffer.is_null()) {
472    ConfigureInputBuffer(encrypted_buffer,
473                         encrypted_block_info,
474                         &subsamples,
475                         &input_buffer);
476  }
477
478  cdm::Status status = cdm::kDecodeError;
479
480  switch (decoder_type) {
481    case PP_DECRYPTORSTREAMTYPE_VIDEO: {
482      LinkedVideoFrame video_frame(new VideoFrameImpl());
483      if (cdm_)
484        status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get());
485      CallOnMain(callback_factory_.NewCallback(
486          &CdmAdapter::DeliverFrame,
487          status,
488          video_frame,
489          encrypted_block_info.tracking_info));
490      return;
491    }
492
493    case PP_DECRYPTORSTREAMTYPE_AUDIO: {
494      LinkedAudioFrames audio_frames(new AudioFramesImpl());
495      if (cdm_) {
496        status = cdm_->DecryptAndDecodeSamples(input_buffer,
497                                               audio_frames.get());
498      }
499      CallOnMain(callback_factory_.NewCallback(
500          &CdmAdapter::DeliverSamples,
501          status,
502          audio_frames,
503          encrypted_block_info.tracking_info));
504      return;
505    }
506
507    default:
508      PP_NOTREACHED();
509      return;
510  }
511}
512
513cdm::Buffer* CdmAdapter::Allocate(uint32_t capacity) {
514  return allocator_.Allocate(capacity);
515}
516
517void CdmAdapter::SetTimer(int64_t delay_ms, void* context) {
518  // NOTE: doesn't really need to run on the main thread; could just as well run
519  // on a helper thread if |cdm_| were thread-friendly and care was taken.  We
520  // only use CallOnMainThread() here to get delayed-execution behavior.
521  pp::Module::Get()->core()->CallOnMainThread(
522      delay_ms,
523      callback_factory_.NewCallback(&CdmAdapter::TimerExpired, context),
524      PP_OK);
525}
526
527void CdmAdapter::TimerExpired(int32_t result, void* context) {
528  PP_DCHECK(result == PP_OK);
529  cdm_->TimerExpired(context);
530}
531
532double CdmAdapter::GetCurrentWallTimeInSeconds() {
533  return pp::Module::Get()->core()->GetTime();
534}
535
536void CdmAdapter::OnSessionCreated(uint32_t session_id,
537                                  const char* web_session_id,
538                                  uint32_t web_session_id_length) {
539  PostOnMain(callback_factory_.NewCallback(
540      &CdmAdapter::SendSessionCreatedInternal,
541      session_id,
542      std::string(web_session_id, web_session_id_length)));
543}
544
545void CdmAdapter::OnSessionMessage(uint32_t session_id,
546                                  const char* message,
547                                  uint32_t message_length,
548                                  const char* destination_url,
549                                  uint32_t destination_url_length) {
550  PostOnMain(callback_factory_.NewCallback(
551      &CdmAdapter::SendSessionMessageInternal,
552      session_id,
553      std::vector<uint8>(message, message + message_length),
554      std::string(destination_url, destination_url_length)));
555}
556
557void CdmAdapter::OnSessionReady(uint32_t session_id) {
558  PostOnMain(callback_factory_.NewCallback(
559      &CdmAdapter::SendSessionReadyInternal, session_id));
560}
561
562void CdmAdapter::OnSessionClosed(uint32_t session_id) {
563  PostOnMain(callback_factory_.NewCallback(
564      &CdmAdapter::SendSessionClosedInternal, session_id));
565}
566
567void CdmAdapter::OnSessionError(uint32_t session_id,
568                                cdm::MediaKeyError error_code,
569                                uint32_t system_code) {
570  PostOnMain(callback_factory_.NewCallback(
571      &CdmAdapter::SendSessionErrorInternal,
572      session_id,
573      error_code,
574      system_code));
575}
576
577void CdmAdapter::SendSessionCreatedInternal(int32_t result,
578                                            uint32_t session_id,
579                                            const std::string& web_session_id) {
580  PP_DCHECK(result == PP_OK);
581  pp::ContentDecryptor_Private::SessionCreated(session_id, web_session_id);
582}
583
584void CdmAdapter::SendSessionMessageInternal(int32_t result,
585                                            uint32_t session_id,
586                                            const std::vector<uint8>& message,
587                                            const std::string& default_url) {
588  PP_DCHECK(result == PP_OK);
589
590  pp::VarArrayBuffer message_array_buffer(message.size());
591  if (message.size() > 0) {
592    memcpy(message_array_buffer.Map(), message.data(), message.size());
593  }
594
595  pp::ContentDecryptor_Private::SessionMessage(
596      session_id, message_array_buffer, default_url);
597}
598
599void CdmAdapter::SendSessionReadyInternal(int32_t result, uint32_t session_id) {
600  PP_DCHECK(result == PP_OK);
601  pp::ContentDecryptor_Private::SessionReady(session_id);
602}
603
604void CdmAdapter::SendSessionClosedInternal(int32_t result,
605                                           uint32_t session_id) {
606  PP_DCHECK(result == PP_OK);
607  pp::ContentDecryptor_Private::SessionClosed(session_id);
608}
609
610void CdmAdapter::SendSessionErrorInternal(int32_t result,
611                                          uint32_t session_id,
612                                          cdm::MediaKeyError error_code,
613                                          uint32_t system_code) {
614  PP_DCHECK(result == PP_OK);
615  pp::ContentDecryptor_Private::SessionError(
616      session_id, error_code, system_code);
617}
618
619void CdmAdapter::DeliverBlock(int32_t result,
620                              const cdm::Status& status,
621                              const LinkedDecryptedBlock& decrypted_block,
622                              const PP_DecryptTrackingInfo& tracking_info) {
623  PP_DCHECK(result == PP_OK);
624  PP_DecryptedBlockInfo decrypted_block_info;
625  decrypted_block_info.tracking_info = tracking_info;
626  decrypted_block_info.tracking_info.timestamp = decrypted_block->Timestamp();
627  decrypted_block_info.tracking_info.buffer_id = 0;
628  decrypted_block_info.data_size = 0;
629  decrypted_block_info.result = CdmStatusToPpDecryptResult(status);
630
631  pp::Buffer_Dev buffer;
632
633  if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) {
634    PP_DCHECK(decrypted_block.get() && decrypted_block->DecryptedBuffer());
635    if (!decrypted_block.get() || !decrypted_block->DecryptedBuffer()) {
636      PP_NOTREACHED();
637      decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
638    } else {
639      PpbBuffer* ppb_buffer =
640          static_cast<PpbBuffer*>(decrypted_block->DecryptedBuffer());
641      buffer = ppb_buffer->buffer_dev();
642      decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
643      decrypted_block_info.data_size = ppb_buffer->Size();
644    }
645  }
646
647  pp::ContentDecryptor_Private::DeliverBlock(buffer, decrypted_block_info);
648}
649
650void CdmAdapter::DecoderInitializeDone(int32_t result,
651                                       PP_DecryptorStreamType decoder_type,
652                                       uint32_t request_id,
653                                       bool success) {
654  PP_DCHECK(result == PP_OK);
655  pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type,
656                                                      request_id,
657                                                      success);
658}
659
660void CdmAdapter::DecoderDeinitializeDone(int32_t result,
661                                         PP_DecryptorStreamType decoder_type,
662                                         uint32_t request_id) {
663  pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type,
664                                                        request_id);
665}
666
667void CdmAdapter::DecoderResetDone(int32_t result,
668                                  PP_DecryptorStreamType decoder_type,
669                                  uint32_t request_id) {
670  pp::ContentDecryptor_Private::DecoderResetDone(decoder_type, request_id);
671}
672
673void CdmAdapter::DeliverFrame(
674    int32_t result,
675    const cdm::Status& status,
676    const LinkedVideoFrame& video_frame,
677    const PP_DecryptTrackingInfo& tracking_info) {
678  PP_DCHECK(result == PP_OK);
679  PP_DecryptedFrameInfo decrypted_frame_info;
680  decrypted_frame_info.tracking_info.request_id = tracking_info.request_id;
681  decrypted_frame_info.tracking_info.buffer_id = 0;
682  decrypted_frame_info.result = CdmStatusToPpDecryptResult(status);
683
684  pp::Buffer_Dev buffer;
685
686  if (decrypted_frame_info.result == PP_DECRYPTRESULT_SUCCESS) {
687    if (!IsValidVideoFrame(video_frame)) {
688      PP_NOTREACHED();
689      decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR;
690    } else {
691      PpbBuffer* ppb_buffer =
692          static_cast<PpbBuffer*>(video_frame->FrameBuffer());
693
694      buffer = ppb_buffer->buffer_dev();
695
696      decrypted_frame_info.tracking_info.timestamp = video_frame->Timestamp();
697      decrypted_frame_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
698      decrypted_frame_info.format =
699          CdmVideoFormatToPpDecryptedFrameFormat(video_frame->Format());
700      decrypted_frame_info.width = video_frame->Size().width;
701      decrypted_frame_info.height = video_frame->Size().height;
702      decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y] =
703          video_frame->PlaneOffset(cdm::VideoFrame::kYPlane);
704      decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_U] =
705          video_frame->PlaneOffset(cdm::VideoFrame::kUPlane);
706      decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_V] =
707          video_frame->PlaneOffset(cdm::VideoFrame::kVPlane);
708      decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_Y] =
709          video_frame->Stride(cdm::VideoFrame::kYPlane);
710      decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_U] =
711          video_frame->Stride(cdm::VideoFrame::kUPlane);
712      decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_V] =
713          video_frame->Stride(cdm::VideoFrame::kVPlane);
714    }
715  }
716  pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info);
717}
718
719void CdmAdapter::DeliverSamples(int32_t result,
720                                const cdm::Status& status,
721                                const LinkedAudioFrames& audio_frames,
722                                const PP_DecryptTrackingInfo& tracking_info) {
723  PP_DCHECK(result == PP_OK);
724
725  PP_DecryptedSampleInfo decrypted_sample_info;
726  decrypted_sample_info.tracking_info = tracking_info;
727  decrypted_sample_info.tracking_info.timestamp = 0;
728  decrypted_sample_info.tracking_info.buffer_id = 0;
729  decrypted_sample_info.data_size = 0;
730  decrypted_sample_info.result = CdmStatusToPpDecryptResult(status);
731
732  pp::Buffer_Dev buffer;
733
734  if (decrypted_sample_info.result == PP_DECRYPTRESULT_SUCCESS) {
735    PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer());
736    if (!audio_frames.get() || !audio_frames->FrameBuffer()) {
737      PP_NOTREACHED();
738      decrypted_sample_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
739    } else {
740      PpbBuffer* ppb_buffer =
741          static_cast<PpbBuffer*>(audio_frames->FrameBuffer());
742      buffer = ppb_buffer->buffer_dev();
743      decrypted_sample_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
744      decrypted_sample_info.data_size = ppb_buffer->Size();
745      decrypted_sample_info.format =
746          CdmAudioFormatToPpDecryptedSampleFormat(audio_frames->Format());
747    }
748  }
749
750  pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_sample_info);
751}
752
753bool CdmAdapter::IsValidVideoFrame(const LinkedVideoFrame& video_frame) {
754  if (!video_frame.get() ||
755      !video_frame->FrameBuffer() ||
756      (video_frame->Format() != cdm::kI420 &&
757       video_frame->Format() != cdm::kYv12)) {
758    CDM_DLOG() << "Invalid video frame!";
759    return false;
760  }
761
762  PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer());
763
764  for (uint32_t i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) {
765    int plane_height = (i == cdm::VideoFrame::kYPlane) ?
766        video_frame->Size().height : (video_frame->Size().height + 1) / 2;
767    cdm::VideoFrame::VideoPlane plane =
768        static_cast<cdm::VideoFrame::VideoPlane>(i);
769    if (ppb_buffer->Size() < video_frame->PlaneOffset(plane) +
770                             plane_height * video_frame->Stride(plane)) {
771      return false;
772    }
773  }
774
775  return true;
776}
777
778#if !defined(NDEBUG)
779void CdmAdapter::LogToConsole(const pp::Var& value) {
780  PP_DCHECK(IsMainThread());
781  const PPB_Console* console = reinterpret_cast<const PPB_Console*>(
782      pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE));
783  console->Log(pp_instance(), PP_LOGLEVEL_LOG, value.pp_var());
784}
785#endif  // !defined(NDEBUG)
786
787void CdmAdapter::SendPlatformChallenge(
788    const char* service_id, uint32_t service_id_length,
789    const char* challenge, uint32_t challenge_length) {
790#if defined(OS_CHROMEOS)
791  PP_DCHECK(!challenge_in_progress_);
792
793  // Ensure member variables set by the callback are in a clean state.
794  signed_data_output_ = pp::Var();
795  signed_data_signature_output_ = pp::Var();
796  platform_key_certificate_output_ = pp::Var();
797
798  pp::VarArrayBuffer challenge_var(challenge_length);
799  uint8_t* var_data = static_cast<uint8_t*>(challenge_var.Map());
800  memcpy(var_data, challenge, challenge_length);
801
802  std::string service_id_str(service_id, service_id_length);
803  int32_t result = platform_verification_.ChallengePlatform(
804      pp::Var(service_id_str), challenge_var, &signed_data_output_,
805      &signed_data_signature_output_, &platform_key_certificate_output_,
806      callback_factory_.NewCallback(&CdmAdapter::SendPlatformChallengeDone));
807  challenge_var.Unmap();
808  if (result == PP_OK_COMPLETIONPENDING) {
809    challenge_in_progress_ = true;
810    return;
811  }
812
813  // Fall through on error and issue an empty OnPlatformChallengeResponse().
814  PP_DCHECK(result != PP_OK);
815#endif
816
817  cdm::PlatformChallengeResponse response = {};
818  cdm_->OnPlatformChallengeResponse(response);
819}
820
821void CdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask) {
822#if defined(OS_CHROMEOS)
823  int32_t result = output_protection_.EnableProtection(
824      desired_protection_mask, callback_factory_.NewCallback(
825          &CdmAdapter::EnableProtectionDone));
826
827  // Errors are ignored since clients must call QueryOutputProtectionStatus() to
828  // inspect the protection status on a regular basis.
829
830  if (result != PP_OK && result != PP_OK_COMPLETIONPENDING)
831    CDM_DLOG() << __FUNCTION__ << " failed!";
832#endif
833}
834
835void CdmAdapter::QueryOutputProtectionStatus() {
836#if defined(OS_CHROMEOS)
837  PP_DCHECK(!query_output_protection_in_progress_);
838
839  output_link_mask_ = output_protection_mask_ = 0;
840  const int32_t result = output_protection_.QueryStatus(
841      &output_link_mask_,
842      &output_protection_mask_,
843      callback_factory_.NewCallback(
844          &CdmAdapter::QueryOutputProtectionStatusDone));
845  if (result == PP_OK_COMPLETIONPENDING) {
846    query_output_protection_in_progress_ = true;
847    ReportOutputProtectionQuery();
848    return;
849  }
850
851  // Fall through on error and issue an empty OnQueryOutputProtectionStatus().
852  PP_DCHECK(result != PP_OK);
853#endif
854
855  cdm_->OnQueryOutputProtectionStatus(0, 0);
856}
857
858void CdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type,
859                                              cdm::Status decoder_status) {
860  switch (stream_type) {
861    case cdm::kStreamTypeAudio:
862      PP_DCHECK(deferred_initialize_audio_decoder_);
863      CallOnMain(
864          callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone,
865                                        PP_DECRYPTORSTREAMTYPE_AUDIO,
866                                        deferred_audio_decoder_config_id_,
867                                        decoder_status == cdm::kSuccess));
868      deferred_initialize_audio_decoder_ = false;
869      deferred_audio_decoder_config_id_ = 0;
870      break;
871    case cdm::kStreamTypeVideo:
872      PP_DCHECK(deferred_initialize_video_decoder_);
873      CallOnMain(
874          callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone,
875                                        PP_DECRYPTORSTREAMTYPE_VIDEO,
876                                        deferred_video_decoder_config_id_,
877                                        decoder_status == cdm::kSuccess));
878      deferred_initialize_video_decoder_ = false;
879      deferred_video_decoder_config_id_ = 0;
880      break;
881  }
882}
883
884// The CDM owns the returned object and must call FileIO::Close() to release it.
885cdm::FileIO* CdmAdapter::CreateFileIO(cdm::FileIOClient* client) {
886  return new CdmFileIOImpl(client, pp_instance());
887}
888
889#if defined(OS_CHROMEOS)
890void CdmAdapter::ReportOutputProtectionUMA(OutputProtectionStatus status) {
891  pp::UMAPrivate uma_interface_(this);
892  uma_interface_.HistogramEnumeration(
893      "Media.EME.OutputProtection", status, OUTPUT_PROTECTION_MAX);
894}
895
896void CdmAdapter::ReportOutputProtectionQuery() {
897  if (uma_for_output_protection_query_reported_)
898    return;
899
900  ReportOutputProtectionUMA(OUTPUT_PROTECTION_QUERIED);
901  uma_for_output_protection_query_reported_ = true;
902}
903
904void CdmAdapter::ReportOutputProtectionQueryResult() {
905  if (uma_for_output_protection_positive_result_reported_)
906    return;
907
908  // Report UMAs for output protection query result.
909  uint32_t external_links = (output_link_mask_ & ~cdm::kLinkTypeInternal);
910
911  if (!external_links) {
912    ReportOutputProtectionUMA(OUTPUT_PROTECTION_NO_EXTERNAL_LINK);
913    uma_for_output_protection_positive_result_reported_ = true;
914    return;
915  }
916
917  if ((output_protection_mask_ & external_links) == external_links) {
918    ReportOutputProtectionUMA(
919        OUTPUT_PROTECTION_ALL_EXTERNAL_LINKS_PROTECTED);
920    uma_for_output_protection_positive_result_reported_ = true;
921    return;
922  }
923
924  // Do not report a negative result because it could be a false negative.
925  // Instead, we will calculate number of negatives using the total number of
926  // queries and success results.
927}
928
929void CdmAdapter::SendPlatformChallengeDone(int32_t result) {
930  challenge_in_progress_ = false;
931
932  if (result != PP_OK) {
933    CDM_DLOG() << __FUNCTION__ << ": Platform challenge failed!";
934    cdm::PlatformChallengeResponse response = {};
935    cdm_->OnPlatformChallengeResponse(response);
936    return;
937  }
938
939  pp::VarArrayBuffer signed_data_var(signed_data_output_);
940  pp::VarArrayBuffer signed_data_signature_var(signed_data_signature_output_);
941  std::string platform_key_certificate_string =
942      platform_key_certificate_output_.AsString();
943
944  cdm::PlatformChallengeResponse response = {
945    static_cast<uint8_t*>(signed_data_var.Map()),
946    signed_data_var.ByteLength(),
947
948    static_cast<uint8_t*>(signed_data_signature_var.Map()),
949    signed_data_signature_var.ByteLength(),
950
951    reinterpret_cast<const uint8_t*>(platform_key_certificate_string.c_str()),
952    static_cast<uint32_t>(platform_key_certificate_string.length())
953  };
954  cdm_->OnPlatformChallengeResponse(response);
955
956  signed_data_var.Unmap();
957  signed_data_signature_var.Unmap();
958}
959
960void CdmAdapter::EnableProtectionDone(int32_t result) {
961  // Does nothing since clients must call QueryOutputProtectionStatus() to
962  // inspect the protection status on a regular basis.
963  CDM_DLOG() << __FUNCTION__ << " : " << result;
964}
965
966void CdmAdapter::QueryOutputProtectionStatusDone(int32_t result) {
967  PP_DCHECK(query_output_protection_in_progress_);
968  query_output_protection_in_progress_ = false;
969
970  // Return a protection status of none on error.
971  if (result != PP_OK)
972    output_link_mask_ = output_protection_mask_ = 0;
973  else
974    ReportOutputProtectionQueryResult();
975
976  cdm_->OnQueryOutputProtectionStatus(output_link_mask_,
977                                      output_protection_mask_);
978}
979#endif
980
981void* GetCdmHost(int host_interface_version, void* user_data) {
982  if (!host_interface_version || !user_data)
983    return NULL;
984
985  COMPILE_ASSERT(
986      cdm::ContentDecryptionModule::Host::kVersion == cdm::Host_4::kVersion,
987      update_code_below);
988
989  // Ensure IsSupportedCdmHostVersion matches implementation of this function.
990  // Always update this DCHECK when updating this function.
991  // If this check fails, update this function and DCHECK or update
992  // IsSupportedCdmHostVersion.
993
994  PP_DCHECK(
995      // Future version is not supported.
996      !IsSupportedCdmHostVersion(cdm::Host_4::kVersion + 1) &&
997      // Current version is supported.
998      IsSupportedCdmHostVersion(cdm::Host_4::kVersion) &&
999      // Include all previous supported versions (if any) here.
1000      // No supported previous versions.
1001      // One older than the oldest supported version is not supported.
1002      !IsSupportedCdmHostVersion(cdm::Host_4::kVersion - 1));
1003  PP_DCHECK(IsSupportedCdmHostVersion(host_interface_version));
1004
1005  CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data);
1006  CDM_DLOG() << "Create CDM Host with version " << host_interface_version;
1007  switch (host_interface_version) {
1008    case cdm::Host_4::kVersion:
1009      return static_cast<cdm::Host_4*>(cdm_adapter);
1010    default:
1011      PP_NOTREACHED();
1012      return NULL;
1013  }
1014}
1015
1016// This object is the global object representing this plugin library as long
1017// as it is loaded.
1018class CdmAdapterModule : public pp::Module {
1019 public:
1020  CdmAdapterModule() : pp::Module() {
1021    // This function blocks the renderer thread (PluginInstance::Initialize()).
1022    // Move this call to other places if this may be a concern in the future.
1023    INITIALIZE_CDM_MODULE();
1024  }
1025  virtual ~CdmAdapterModule() {
1026    DeinitializeCdmModule();
1027  }
1028
1029  virtual pp::Instance* CreateInstance(PP_Instance instance) {
1030    return new CdmAdapter(instance, this);
1031  }
1032
1033 private:
1034  CdmFileIOImpl::ResourceTracker cdm_file_io_impl_resource_tracker;
1035};
1036
1037}  // namespace media
1038
1039namespace pp {
1040
1041// Factory function for your specialization of the Module object.
1042Module* CreateModule() {
1043  return new media::CdmAdapterModule();
1044}
1045
1046}  // namespace pp
1047