cdm_adapter.cc revision f2477e01787aa58f445919b809d89e252beef54f
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_helpers.h"
8#include "media/cdm/ppapi/supported_cdm_versions.h"
9
10#if defined(CHECK_DOCUMENT_URL)
11#include "ppapi/cpp/dev/url_util_dev.h"
12#include "ppapi/cpp/instance_handle.h"
13#endif  // defined(CHECK_DOCUMENT_URL)
14
15namespace {
16
17bool IsMainThread() {
18  return pp::Module::Get()->core()->IsMainThread();
19}
20
21// Posts a task to run |cb| on the main thread. The task is posted even if the
22// current thread is the main thread.
23void PostOnMain(pp::CompletionCallback cb) {
24  pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK);
25}
26
27// Ensures |cb| is called on the main thread, either because the current thread
28// is the main thread or by posting it to the main thread.
29void CallOnMain(pp::CompletionCallback cb) {
30  // TODO(tomfinegan): This is only necessary because PPAPI doesn't allow calls
31  // off the main thread yet. Remove this once the change lands.
32  if (IsMainThread())
33    cb.Run(PP_OK);
34  else
35    PostOnMain(cb);
36}
37
38// Configures a cdm::InputBuffer. |subsamples| must exist as long as
39// |input_buffer| is in use.
40void ConfigureInputBuffer(
41    const pp::Buffer_Dev& encrypted_buffer,
42    const PP_EncryptedBlockInfo& encrypted_block_info,
43    std::vector<cdm::SubsampleEntry>* subsamples,
44    cdm::InputBuffer* input_buffer) {
45  PP_DCHECK(subsamples);
46  PP_DCHECK(!encrypted_buffer.is_null());
47
48  input_buffer->data = static_cast<uint8_t*>(encrypted_buffer.data());
49  input_buffer->data_size = encrypted_block_info.data_size;
50  PP_DCHECK(encrypted_buffer.size() >= input_buffer->data_size);
51  input_buffer->data_offset = encrypted_block_info.data_offset;
52
53  PP_DCHECK(encrypted_block_info.key_id_size <=
54            arraysize(encrypted_block_info.key_id));
55  input_buffer->key_id_size = encrypted_block_info.key_id_size;
56  input_buffer->key_id = input_buffer->key_id_size > 0 ?
57      encrypted_block_info.key_id : NULL;
58
59  PP_DCHECK(encrypted_block_info.iv_size <= arraysize(encrypted_block_info.iv));
60  input_buffer->iv_size = encrypted_block_info.iv_size;
61  input_buffer->iv = encrypted_block_info.iv_size > 0 ?
62      encrypted_block_info.iv : NULL;
63
64  input_buffer->num_subsamples = encrypted_block_info.num_subsamples;
65  if (encrypted_block_info.num_subsamples > 0) {
66    subsamples->reserve(encrypted_block_info.num_subsamples);
67
68    for (uint32_t i = 0; i < encrypted_block_info.num_subsamples; ++i) {
69      subsamples->push_back(cdm::SubsampleEntry(
70          encrypted_block_info.subsamples[i].clear_bytes,
71          encrypted_block_info.subsamples[i].cipher_bytes));
72    }
73
74    input_buffer->subsamples = &(*subsamples)[0];
75  }
76
77  input_buffer->timestamp = encrypted_block_info.tracking_info.timestamp;
78}
79
80PP_DecryptResult CdmStatusToPpDecryptResult(cdm::Status status) {
81  switch (status) {
82    case cdm::kSuccess:
83      return PP_DECRYPTRESULT_SUCCESS;
84    case cdm::kNoKey:
85      return PP_DECRYPTRESULT_DECRYPT_NOKEY;
86    case cdm::kNeedMoreData:
87      return PP_DECRYPTRESULT_NEEDMOREDATA;
88    case cdm::kDecryptError:
89      return PP_DECRYPTRESULT_DECRYPT_ERROR;
90    case cdm::kDecodeError:
91      return PP_DECRYPTRESULT_DECODE_ERROR;
92    default:
93      PP_NOTREACHED();
94      return PP_DECRYPTRESULT_DECODE_ERROR;
95  }
96}
97
98PP_DecryptedFrameFormat CdmVideoFormatToPpDecryptedFrameFormat(
99    cdm::VideoFormat format) {
100  switch (format) {
101    case cdm::kYv12:
102      return PP_DECRYPTEDFRAMEFORMAT_YV12;
103    case cdm::kI420:
104      return PP_DECRYPTEDFRAMEFORMAT_I420;
105    default:
106      return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
107  }
108}
109
110PP_DecryptedSampleFormat CdmAudioFormatToPpDecryptedSampleFormat(
111    cdm::AudioFormat format) {
112  switch (format) {
113    case cdm::kAudioFormatU8:
114      return PP_DECRYPTEDSAMPLEFORMAT_U8;
115    case cdm::kAudioFormatS16:
116      return PP_DECRYPTEDSAMPLEFORMAT_S16;
117    case cdm::kAudioFormatS32:
118      return PP_DECRYPTEDSAMPLEFORMAT_S32;
119    case cdm::kAudioFormatF32:
120      return PP_DECRYPTEDSAMPLEFORMAT_F32;
121    case cdm::kAudioFormatPlanarS16:
122      return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16;
123    case cdm::kAudioFormatPlanarF32:
124      return PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32;
125    default:
126      return PP_DECRYPTEDSAMPLEFORMAT_UNKNOWN;
127  }
128}
129
130cdm::AudioDecoderConfig::AudioCodec PpAudioCodecToCdmAudioCodec(
131    PP_AudioCodec codec) {
132  switch (codec) {
133    case PP_AUDIOCODEC_VORBIS:
134      return cdm::AudioDecoderConfig::kCodecVorbis;
135    case PP_AUDIOCODEC_AAC:
136      return cdm::AudioDecoderConfig::kCodecAac;
137    default:
138      return cdm::AudioDecoderConfig::kUnknownAudioCodec;
139  }
140}
141
142cdm::VideoDecoderConfig::VideoCodec PpVideoCodecToCdmVideoCodec(
143    PP_VideoCodec codec) {
144  switch (codec) {
145    case PP_VIDEOCODEC_VP8:
146      return cdm::VideoDecoderConfig::kCodecVp8;
147    case PP_VIDEOCODEC_H264:
148      return cdm::VideoDecoderConfig::kCodecH264;
149    default:
150      return cdm::VideoDecoderConfig::kUnknownVideoCodec;
151  }
152}
153
154cdm::VideoDecoderConfig::VideoCodecProfile PpVCProfileToCdmVCProfile(
155    PP_VideoCodecProfile profile) {
156  switch (profile) {
157    case PP_VIDEOCODECPROFILE_VP8_MAIN:
158      return cdm::VideoDecoderConfig::kVp8ProfileMain;
159    case PP_VIDEOCODECPROFILE_H264_BASELINE:
160      return cdm::VideoDecoderConfig::kH264ProfileBaseline;
161    case PP_VIDEOCODECPROFILE_H264_MAIN:
162      return cdm::VideoDecoderConfig::kH264ProfileMain;
163    case PP_VIDEOCODECPROFILE_H264_EXTENDED:
164      return cdm::VideoDecoderConfig::kH264ProfileExtended;
165    case PP_VIDEOCODECPROFILE_H264_HIGH:
166      return cdm::VideoDecoderConfig::kH264ProfileHigh;
167    case PP_VIDEOCODECPROFILE_H264_HIGH_10:
168      return cdm::VideoDecoderConfig::kH264ProfileHigh10;
169    case PP_VIDEOCODECPROFILE_H264_HIGH_422:
170      return cdm::VideoDecoderConfig::kH264ProfileHigh422;
171    case PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE:
172      return cdm::VideoDecoderConfig::kH264ProfileHigh444Predictive;
173    default:
174      return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile;
175  }
176}
177
178cdm::VideoFormat PpDecryptedFrameFormatToCdmVideoFormat(
179    PP_DecryptedFrameFormat format) {
180  switch (format) {
181    case PP_DECRYPTEDFRAMEFORMAT_YV12:
182      return cdm::kYv12;
183    case PP_DECRYPTEDFRAMEFORMAT_I420:
184      return cdm::kI420;
185    default:
186      return cdm::kUnknownVideoFormat;
187  }
188}
189
190cdm::StreamType PpDecryptorStreamTypeToCdmStreamType(
191    PP_DecryptorStreamType stream_type) {
192  switch (stream_type) {
193    case PP_DECRYPTORSTREAMTYPE_AUDIO:
194      return cdm::kStreamTypeAudio;
195    case PP_DECRYPTORSTREAMTYPE_VIDEO:
196      return cdm::kStreamTypeVideo;
197  }
198
199  PP_NOTREACHED();
200  return cdm::kStreamTypeVideo;
201}
202
203}  // namespace
204
205namespace media {
206
207CdmAdapter::CdmAdapter(PP_Instance instance, pp::Module* module)
208    : pp::Instance(instance),
209      pp::ContentDecryptor_Private(this),
210#if defined(OS_CHROMEOS)
211      output_protection_(this),
212      platform_verification_(this),
213      challenge_in_progress_(false),
214      output_link_mask_(0),
215      output_protection_mask_(0),
216      query_output_protection_in_progress_(false),
217#endif
218      allocator_(this),
219      cdm_(NULL),
220      deferred_initialize_audio_decoder_(false),
221      deferred_audio_decoder_config_id_(0),
222      deferred_initialize_video_decoder_(false),
223      deferred_video_decoder_config_id_(0) {
224  callback_factory_.Initialize(this);
225}
226
227CdmAdapter::~CdmAdapter() {}
228
229bool CdmAdapter::CreateCdmInstance(const std::string& key_system) {
230  PP_DCHECK(!cdm_);
231  cdm_ = make_linked_ptr(CdmWrapper::Create(
232      key_system.data(), key_system.size(), GetCdmHost, this));
233  return (cdm_ != NULL);
234}
235
236// No KeyErrors should be reported in this function because they cannot be
237// bubbled up in the WD EME API. Those errors will be reported during session
238// creation (aka GenerateKeyRequest).
239void CdmAdapter::Initialize(const std::string& key_system) {
240  PP_DCHECK(!key_system.empty());
241  PP_DCHECK(key_system_.empty() || (key_system_ == key_system && cdm_));
242
243  if (!cdm_ && !CreateCdmInstance(key_system))
244    return;
245
246  PP_DCHECK(cdm_);
247  key_system_ = key_system;
248}
249
250void CdmAdapter::GenerateKeyRequest(uint32_t reference_id,
251                                    const std::string& type,
252                                    pp::VarArrayBuffer init_data) {
253  // Initialize() doesn't report an error, so GenerateKeyRequest() can be called
254  // even if Initialize() failed.
255  if (!cdm_) {
256    SendUnknownKeyError(reference_id);
257    return;
258  }
259
260#if defined(CHECK_DOCUMENT_URL)
261  PP_URLComponents_Dev url_components = {};
262  const pp::URLUtil_Dev* url_util = pp::URLUtil_Dev::Get();
263  if (!url_util) {
264    SendUnknownKeyError(reference_id);
265    return;
266  }
267  pp::Var href = url_util->GetDocumentURL(
268      pp::InstanceHandle(pp_instance()), &url_components);
269  PP_DCHECK(href.is_string());
270  PP_DCHECK(!href.AsString().empty());
271  PP_DCHECK(url_components.host.begin);
272  PP_DCHECK(0 < url_components.host.len);
273#endif  // defined(CHECK_DOCUMENT_URL)
274
275  cdm_->GenerateKeyRequest(reference_id,
276                           type.data(),
277                           type.size(),
278                           static_cast<const uint8_t*>(init_data.Map()),
279                           init_data.ByteLength());
280}
281
282void CdmAdapter::AddKey(uint32_t reference_id,
283                        pp::VarArrayBuffer key,
284                        pp::VarArrayBuffer init_data) {
285  // TODO(jrummell): In EME WD, AddKey() can only be called on valid sessions.
286  // We should be able to DCHECK(cdm_) when addressing http://crbug.com/249976.
287  if (!cdm_) {
288    SendUnknownKeyError(reference_id);
289    return;
290  }
291
292  const uint8_t* key_ptr = static_cast<const uint8_t*>(key.Map());
293  const uint32_t key_size = key.ByteLength();
294  const uint8_t* init_data_ptr = static_cast<const uint8_t*>(init_data.Map());
295  const uint32_t init_data_size = init_data.ByteLength();
296  PP_DCHECK(!init_data_ptr == !init_data_size);
297
298  if (!key_ptr || key_size <= 0) {
299    SendUnknownKeyError(reference_id);
300    return;
301  }
302  CdmWrapper::Result result = cdm_->AddKey(
303      reference_id, key_ptr, key_size, init_data_ptr, init_data_size);
304  switch (result) {
305    case CdmWrapper::NO_ACTION:
306      break;
307    case CdmWrapper::CALL_KEY_ADDED:
308      SendKeyAdded(reference_id);
309      break;
310    case CdmWrapper::CALL_KEY_ERROR:
311      SendUnknownKeyError(reference_id);
312      break;
313  }
314}
315
316void CdmAdapter::CancelKeyRequest(uint32_t reference_id) {
317  // TODO(jrummell): In EME WD, AddKey() can only be called on valid sessions.
318  // We should be able to DCHECK(cdm_) when addressing http://crbug.com/249976.
319  if (!cdm_) {
320    SendUnknownKeyError(reference_id);
321    return;
322  }
323
324  CdmWrapper::Result result = cdm_->CancelKeyRequest(reference_id);
325  switch (result) {
326    case CdmWrapper::NO_ACTION:
327      break;
328    case CdmWrapper::CALL_KEY_ADDED:
329      PP_NOTREACHED();
330      break;
331    case CdmWrapper::CALL_KEY_ERROR:
332      SendUnknownKeyError(reference_id);
333      break;
334  }
335}
336
337// Note: In the following decryption/decoding related functions, errors are NOT
338// reported via KeyError, but are reported via corresponding PPB calls.
339
340void CdmAdapter::Decrypt(pp::Buffer_Dev encrypted_buffer,
341                         const PP_EncryptedBlockInfo& encrypted_block_info) {
342  PP_DCHECK(!encrypted_buffer.is_null());
343
344  // Release a buffer that the caller indicated it is finished with.
345  allocator_.Release(encrypted_block_info.tracking_info.buffer_id);
346
347  cdm::Status status = cdm::kDecryptError;
348  LinkedDecryptedBlock decrypted_block(new DecryptedBlockImpl());
349
350  if (cdm_) {
351    cdm::InputBuffer input_buffer;
352    std::vector<cdm::SubsampleEntry> subsamples;
353    ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples,
354                         &input_buffer);
355    status = cdm_->Decrypt(input_buffer, decrypted_block.get());
356    PP_DCHECK(status != cdm::kSuccess ||
357              (decrypted_block->DecryptedBuffer() &&
358               decrypted_block->DecryptedBuffer()->Size()));
359  }
360
361  CallOnMain(callback_factory_.NewCallback(
362      &CdmAdapter::DeliverBlock,
363      status,
364      decrypted_block,
365      encrypted_block_info.tracking_info));
366}
367
368void CdmAdapter::InitializeAudioDecoder(
369    const PP_AudioDecoderConfig& decoder_config,
370    pp::Buffer_Dev extra_data_buffer) {
371  PP_DCHECK(!deferred_initialize_audio_decoder_);
372  PP_DCHECK(deferred_audio_decoder_config_id_ == 0);
373  cdm::Status status = cdm::kSessionError;
374  if (cdm_) {
375    cdm::AudioDecoderConfig cdm_decoder_config;
376    cdm_decoder_config.codec =
377        PpAudioCodecToCdmAudioCodec(decoder_config.codec);
378    cdm_decoder_config.channel_count = decoder_config.channel_count;
379    cdm_decoder_config.bits_per_channel = decoder_config.bits_per_channel;
380    cdm_decoder_config.samples_per_second = decoder_config.samples_per_second;
381    cdm_decoder_config.extra_data =
382        static_cast<uint8_t*>(extra_data_buffer.data());
383    cdm_decoder_config.extra_data_size = extra_data_buffer.size();
384    status = cdm_->InitializeAudioDecoder(cdm_decoder_config);
385  }
386
387  if (status == cdm::kDeferredInitialization) {
388    deferred_initialize_audio_decoder_ = true;
389    deferred_audio_decoder_config_id_ = decoder_config.request_id;
390    return;
391  }
392
393  CallOnMain(callback_factory_.NewCallback(
394      &CdmAdapter::DecoderInitializeDone,
395      PP_DECRYPTORSTREAMTYPE_AUDIO,
396      decoder_config.request_id,
397      status == cdm::kSuccess));
398}
399
400void CdmAdapter::InitializeVideoDecoder(
401    const PP_VideoDecoderConfig& decoder_config,
402    pp::Buffer_Dev extra_data_buffer) {
403  PP_DCHECK(!deferred_initialize_video_decoder_);
404  PP_DCHECK(deferred_video_decoder_config_id_ == 0);
405  cdm::Status status = cdm::kSessionError;
406  if (cdm_) {
407    cdm::VideoDecoderConfig cdm_decoder_config;
408    cdm_decoder_config.codec =
409        PpVideoCodecToCdmVideoCodec(decoder_config.codec);
410    cdm_decoder_config.profile =
411        PpVCProfileToCdmVCProfile(decoder_config.profile);
412    cdm_decoder_config.format =
413        PpDecryptedFrameFormatToCdmVideoFormat(decoder_config.format);
414    cdm_decoder_config.coded_size.width = decoder_config.width;
415    cdm_decoder_config.coded_size.height = decoder_config.height;
416    cdm_decoder_config.extra_data =
417        static_cast<uint8_t*>(extra_data_buffer.data());
418    cdm_decoder_config.extra_data_size = extra_data_buffer.size();
419    status = cdm_->InitializeVideoDecoder(cdm_decoder_config);
420  }
421
422  if (status == cdm::kDeferredInitialization) {
423    deferred_initialize_video_decoder_ = true;
424    deferred_video_decoder_config_id_ = decoder_config.request_id;
425    return;
426  }
427
428  CallOnMain(callback_factory_.NewCallback(
429      &CdmAdapter::DecoderInitializeDone,
430      PP_DECRYPTORSTREAMTYPE_VIDEO,
431      decoder_config.request_id,
432      status == cdm::kSuccess));
433}
434
435void CdmAdapter::DeinitializeDecoder(PP_DecryptorStreamType decoder_type,
436                                     uint32_t request_id) {
437  PP_DCHECK(cdm_);  // InitializeXxxxxDecoder should have succeeded.
438  if (cdm_) {
439    cdm_->DeinitializeDecoder(
440        PpDecryptorStreamTypeToCdmStreamType(decoder_type));
441  }
442
443  CallOnMain(callback_factory_.NewCallback(
444      &CdmAdapter::DecoderDeinitializeDone,
445      decoder_type,
446      request_id));
447}
448
449void CdmAdapter::ResetDecoder(PP_DecryptorStreamType decoder_type,
450                              uint32_t request_id) {
451  PP_DCHECK(cdm_);  // InitializeXxxxxDecoder should have succeeded.
452  if (cdm_)
453    cdm_->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type));
454
455  CallOnMain(callback_factory_.NewCallback(&CdmAdapter::DecoderResetDone,
456                                           decoder_type,
457                                           request_id));
458}
459
460void CdmAdapter::DecryptAndDecode(
461    PP_DecryptorStreamType decoder_type,
462    pp::Buffer_Dev encrypted_buffer,
463    const PP_EncryptedBlockInfo& encrypted_block_info) {
464  PP_DCHECK(cdm_);  // InitializeXxxxxDecoder should have succeeded.
465  // Release a buffer that the caller indicated it is finished with.
466  allocator_.Release(encrypted_block_info.tracking_info.buffer_id);
467
468  cdm::InputBuffer input_buffer;
469  std::vector<cdm::SubsampleEntry> subsamples;
470  if (cdm_ && !encrypted_buffer.is_null()) {
471    ConfigureInputBuffer(encrypted_buffer,
472                         encrypted_block_info,
473                         &subsamples,
474                         &input_buffer);
475  }
476
477  cdm::Status status = cdm::kDecodeError;
478
479  switch (decoder_type) {
480    case PP_DECRYPTORSTREAMTYPE_VIDEO: {
481      LinkedVideoFrame video_frame(new VideoFrameImpl());
482      if (cdm_)
483        status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get());
484      CallOnMain(callback_factory_.NewCallback(
485          &CdmAdapter::DeliverFrame,
486          status,
487          video_frame,
488          encrypted_block_info.tracking_info));
489      return;
490    }
491
492    case PP_DECRYPTORSTREAMTYPE_AUDIO: {
493      LinkedAudioFrames audio_frames(new AudioFramesImpl());
494      if (cdm_) {
495        status = cdm_->DecryptAndDecodeSamples(input_buffer,
496                                               audio_frames.get());
497      }
498      CallOnMain(callback_factory_.NewCallback(
499          &CdmAdapter::DeliverSamples,
500          status,
501          audio_frames,
502          encrypted_block_info.tracking_info));
503      return;
504    }
505
506    default:
507      PP_NOTREACHED();
508      return;
509  }
510}
511
512cdm::Buffer* CdmAdapter::Allocate(uint32_t capacity) {
513  return allocator_.Allocate(capacity);
514}
515
516void CdmAdapter::SetTimer(int64_t delay_ms, void* context) {
517  // NOTE: doesn't really need to run on the main thread; could just as well run
518  // on a helper thread if |cdm_| were thread-friendly and care was taken.  We
519  // only use CallOnMainThread() here to get delayed-execution behavior.
520  pp::Module::Get()->core()->CallOnMainThread(
521      delay_ms,
522      callback_factory_.NewCallback(&CdmAdapter::TimerExpired, context),
523      PP_OK);
524}
525
526void CdmAdapter::TimerExpired(int32_t result, void* context) {
527  PP_DCHECK(result == PP_OK);
528  cdm_->TimerExpired(context);
529}
530
531double CdmAdapter::GetCurrentWallTimeInSeconds() {
532  return pp::Module::Get()->core()->GetTime();
533}
534
535void CdmAdapter::SendKeyMessage(
536    const char* session_id, uint32_t session_id_length,
537    const char* message, uint32_t message_length,
538    const char* default_url, uint32_t default_url_length) {
539  PP_DCHECK(!key_system_.empty());
540
541  std::string session_id_str(session_id, session_id_length);
542  PP_DCHECK(!session_id_str.empty());
543  uint32_t reference_id = cdm_->DetermineReferenceId(session_id_str);
544
545  PostOnMain(callback_factory_.NewCallback(
546      &CdmAdapter::SetSessionId, reference_id, session_id_str));
547
548  PostOnMain(callback_factory_.NewCallback(
549      &CdmAdapter::KeyMessage,
550      reference_id,
551      std::vector<uint8>(message, message + message_length),
552      std::string(default_url, default_url_length)));
553}
554
555void CdmAdapter::SendKeyError(const char* session_id,
556                              uint32_t session_id_length,
557                              cdm::MediaKeyError error_code,
558                              uint32_t system_code) {
559  std::string session_id_str(session_id, session_id_length);
560  uint32_t reference_id = cdm_->DetermineReferenceId(session_id_str);
561
562  SendKeyErrorInternal(reference_id, error_code, system_code);
563}
564
565void CdmAdapter::GetPrivateData(int32_t* instance,
566                                GetPrivateInterface* get_interface) {
567  *instance = pp_instance();
568  *get_interface = pp::Module::Get()->get_browser_interface();
569}
570
571void CdmAdapter::SendUnknownKeyError(uint32_t reference_id) {
572  SendKeyErrorInternal(reference_id, cdm::kUnknownError, 0);
573}
574
575void CdmAdapter::SendKeyAdded(uint32_t reference_id) {
576  PostOnMain(
577      callback_factory_.NewCallback(&CdmAdapter::KeyAdded, reference_id));
578}
579
580void CdmAdapter::SendKeyErrorInternal(uint32_t reference_id,
581                                      cdm::MediaKeyError error_code,
582                                      uint32_t system_code) {
583  PostOnMain(callback_factory_.NewCallback(
584      &CdmAdapter::KeyError, reference_id, error_code, system_code));
585}
586
587void CdmAdapter::KeyAdded(int32_t result, uint32_t reference_id) {
588  PP_DCHECK(result == PP_OK);
589  pp::ContentDecryptor_Private::KeyAdded(reference_id);
590}
591
592void CdmAdapter::KeyMessage(int32_t result,
593                            uint32_t reference_id,
594                            const std::vector<uint8>& message,
595                            const std::string& default_url) {
596  PP_DCHECK(result == PP_OK);
597
598  pp::VarArrayBuffer message_array_buffer(message.size());
599  if (message.size() > 0) {
600    memcpy(message_array_buffer.Map(), message.data(), message.size());
601  }
602
603  pp::ContentDecryptor_Private::KeyMessage(
604      reference_id,
605      message_array_buffer,
606      default_url);
607}
608
609void CdmAdapter::KeyError(int32_t result,
610                          uint32_t reference_id,
611                          cdm::MediaKeyError error_code,
612                          uint32_t system_code) {
613  PP_DCHECK(result == PP_OK);
614  pp::ContentDecryptor_Private::KeyError(reference_id, error_code, system_code);
615}
616
617void CdmAdapter::SetSessionId(int32_t result,
618                              uint32_t reference_id,
619                              const std::string& session_id) {
620  PP_DCHECK(result == PP_OK);
621  pp::ContentDecryptor_Private::SetSessionId(reference_id, session_id);
622}
623
624void CdmAdapter::DeliverBlock(int32_t result,
625                              const cdm::Status& status,
626                              const LinkedDecryptedBlock& decrypted_block,
627                              const PP_DecryptTrackingInfo& tracking_info) {
628  PP_DCHECK(result == PP_OK);
629  PP_DecryptedBlockInfo decrypted_block_info;
630  decrypted_block_info.tracking_info = tracking_info;
631  decrypted_block_info.tracking_info.timestamp = decrypted_block->Timestamp();
632  decrypted_block_info.tracking_info.buffer_id = 0;
633  decrypted_block_info.data_size = 0;
634  decrypted_block_info.result = CdmStatusToPpDecryptResult(status);
635
636  pp::Buffer_Dev buffer;
637
638  if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) {
639    PP_DCHECK(decrypted_block.get() && decrypted_block->DecryptedBuffer());
640    if (!decrypted_block.get() || !decrypted_block->DecryptedBuffer()) {
641      PP_NOTREACHED();
642      decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
643    } else {
644      PpbBuffer* ppb_buffer =
645          static_cast<PpbBuffer*>(decrypted_block->DecryptedBuffer());
646      buffer = ppb_buffer->buffer_dev();
647      decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
648      decrypted_block_info.data_size = ppb_buffer->Size();
649    }
650  }
651
652  pp::ContentDecryptor_Private::DeliverBlock(buffer, decrypted_block_info);
653}
654
655void CdmAdapter::DecoderInitializeDone(int32_t result,
656                                       PP_DecryptorStreamType decoder_type,
657                                       uint32_t request_id,
658                                       bool success) {
659  PP_DCHECK(result == PP_OK);
660  pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type,
661                                                      request_id,
662                                                      success);
663}
664
665void CdmAdapter::DecoderDeinitializeDone(int32_t result,
666                                         PP_DecryptorStreamType decoder_type,
667                                         uint32_t request_id) {
668  pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type,
669                                                        request_id);
670}
671
672void CdmAdapter::DecoderResetDone(int32_t result,
673                                  PP_DecryptorStreamType decoder_type,
674                                  uint32_t request_id) {
675  pp::ContentDecryptor_Private::DecoderResetDone(decoder_type, request_id);
676}
677
678void CdmAdapter::DeliverFrame(
679    int32_t result,
680    const cdm::Status& status,
681    const LinkedVideoFrame& video_frame,
682    const PP_DecryptTrackingInfo& tracking_info) {
683  PP_DCHECK(result == PP_OK);
684  PP_DecryptedFrameInfo decrypted_frame_info;
685  decrypted_frame_info.tracking_info.request_id = tracking_info.request_id;
686  decrypted_frame_info.tracking_info.buffer_id = 0;
687  decrypted_frame_info.result = CdmStatusToPpDecryptResult(status);
688
689  pp::Buffer_Dev buffer;
690
691  if (decrypted_frame_info.result == PP_DECRYPTRESULT_SUCCESS) {
692    if (!IsValidVideoFrame(video_frame)) {
693      PP_NOTREACHED();
694      decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR;
695    } else {
696      PpbBuffer* ppb_buffer =
697          static_cast<PpbBuffer*>(video_frame->FrameBuffer());
698
699      buffer = ppb_buffer->buffer_dev();
700
701      decrypted_frame_info.tracking_info.timestamp = video_frame->Timestamp();
702      decrypted_frame_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
703      decrypted_frame_info.format =
704          CdmVideoFormatToPpDecryptedFrameFormat(video_frame->Format());
705      decrypted_frame_info.width = video_frame->Size().width;
706      decrypted_frame_info.height = video_frame->Size().height;
707      decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y] =
708          video_frame->PlaneOffset(cdm::VideoFrame::kYPlane);
709      decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_U] =
710          video_frame->PlaneOffset(cdm::VideoFrame::kUPlane);
711      decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_V] =
712          video_frame->PlaneOffset(cdm::VideoFrame::kVPlane);
713      decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_Y] =
714          video_frame->Stride(cdm::VideoFrame::kYPlane);
715      decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_U] =
716          video_frame->Stride(cdm::VideoFrame::kUPlane);
717      decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_V] =
718          video_frame->Stride(cdm::VideoFrame::kVPlane);
719    }
720  }
721  pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info);
722}
723
724void CdmAdapter::DeliverSamples(int32_t result,
725                                const cdm::Status& status,
726                                const LinkedAudioFrames& audio_frames,
727                                const PP_DecryptTrackingInfo& tracking_info) {
728  PP_DCHECK(result == PP_OK);
729
730  PP_DecryptedSampleInfo decrypted_sample_info;
731  decrypted_sample_info.tracking_info = tracking_info;
732  decrypted_sample_info.tracking_info.timestamp = 0;
733  decrypted_sample_info.tracking_info.buffer_id = 0;
734  decrypted_sample_info.data_size = 0;
735  decrypted_sample_info.result = CdmStatusToPpDecryptResult(status);
736
737  pp::Buffer_Dev buffer;
738
739  if (decrypted_sample_info.result == PP_DECRYPTRESULT_SUCCESS) {
740    PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer());
741    if (!audio_frames.get() || !audio_frames->FrameBuffer()) {
742      PP_NOTREACHED();
743      decrypted_sample_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR;
744    } else {
745      PpbBuffer* ppb_buffer =
746          static_cast<PpbBuffer*>(audio_frames->FrameBuffer());
747      buffer = ppb_buffer->buffer_dev();
748      decrypted_sample_info.tracking_info.buffer_id = ppb_buffer->buffer_id();
749      decrypted_sample_info.data_size = ppb_buffer->Size();
750      decrypted_sample_info.format =
751          CdmAudioFormatToPpDecryptedSampleFormat(audio_frames->Format());
752    }
753  }
754
755  pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_sample_info);
756}
757
758bool CdmAdapter::IsValidVideoFrame(const LinkedVideoFrame& video_frame) {
759  if (!video_frame.get() ||
760      !video_frame->FrameBuffer() ||
761      (video_frame->Format() != cdm::kI420 &&
762       video_frame->Format() != cdm::kYv12)) {
763    return false;
764  }
765
766  PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer());
767
768  for (uint32_t i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) {
769    int plane_height = (i == cdm::VideoFrame::kYPlane) ?
770        video_frame->Size().height : (video_frame->Size().height + 1) / 2;
771    cdm::VideoFrame::VideoPlane plane =
772        static_cast<cdm::VideoFrame::VideoPlane>(i);
773    if (ppb_buffer->Size() < video_frame->PlaneOffset(plane) +
774                             plane_height * video_frame->Stride(plane)) {
775      return false;
776    }
777  }
778
779  return true;
780}
781
782void CdmAdapter::SendPlatformChallenge(
783    const char* service_id, uint32_t service_id_length,
784    const char* challenge, uint32_t challenge_length) {
785#if defined(OS_CHROMEOS)
786  PP_DCHECK(!challenge_in_progress_);
787
788  // Ensure member variables set by the callback are in a clean state.
789  signed_data_output_ = pp::Var();
790  signed_data_signature_output_ = pp::Var();
791  platform_key_certificate_output_ = pp::Var();
792
793  pp::VarArrayBuffer challenge_var(challenge_length);
794  uint8_t* var_data = static_cast<uint8_t*>(challenge_var.Map());
795  memcpy(var_data, challenge, challenge_length);
796
797  std::string service_id_str(service_id, service_id_length);
798  int32_t result = platform_verification_.ChallengePlatform(
799      pp::Var(service_id_str), challenge_var, &signed_data_output_,
800      &signed_data_signature_output_, &platform_key_certificate_output_,
801      callback_factory_.NewCallback(&CdmAdapter::SendPlatformChallengeDone));
802  challenge_var.Unmap();
803  if (result == PP_OK_COMPLETIONPENDING) {
804    challenge_in_progress_ = true;
805    return;
806  }
807
808  // Fall through on error and issue an empty OnPlatformChallengeResponse().
809  PP_DCHECK(result != PP_OK);
810#endif
811
812  cdm::PlatformChallengeResponse response = {};
813  cdm_->OnPlatformChallengeResponse(response);
814}
815
816void CdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask) {
817#if defined(OS_CHROMEOS)
818  output_protection_.EnableProtection(
819      desired_protection_mask, callback_factory_.NewCallback(
820          &CdmAdapter::EnableProtectionDone));
821
822  // Errors are ignored since clients must call QueryOutputProtectionStatus() to
823  // inspect the protection status on a regular basis.
824  // TODO(dalecurtis): It'd be nice to log a message or non-fatal error here...
825#endif
826}
827
828void CdmAdapter::QueryOutputProtectionStatus() {
829#if defined(OS_CHROMEOS)
830  PP_DCHECK(!query_output_protection_in_progress_);
831
832  output_link_mask_ = output_protection_mask_ = 0;
833  const int32_t result = output_protection_.QueryStatus(
834      &output_link_mask_,
835      &output_protection_mask_,
836      callback_factory_.NewCallback(
837          &CdmAdapter::QueryOutputProtectionStatusDone));
838  if (result == PP_OK_COMPLETIONPENDING) {
839    query_output_protection_in_progress_ = true;
840    return;
841  }
842
843  // Fall through on error and issue an empty OnQueryOutputProtectionStatus().
844  PP_DCHECK(result != PP_OK);
845#endif
846
847  cdm_->OnQueryOutputProtectionStatus(0, 0);
848}
849
850void CdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type,
851                                              cdm::Status decoder_status) {
852  switch (stream_type) {
853    case cdm::kStreamTypeAudio:
854      PP_DCHECK(deferred_initialize_audio_decoder_);
855      CallOnMain(
856          callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone,
857                                        PP_DECRYPTORSTREAMTYPE_AUDIO,
858                                        deferred_audio_decoder_config_id_,
859                                        decoder_status == cdm::kSuccess));
860      deferred_initialize_audio_decoder_ = false;
861      deferred_audio_decoder_config_id_ = 0;
862      break;
863    case cdm::kStreamTypeVideo:
864      PP_DCHECK(deferred_initialize_video_decoder_);
865      CallOnMain(
866          callback_factory_.NewCallback(&CdmAdapter::DecoderInitializeDone,
867                                        PP_DECRYPTORSTREAMTYPE_VIDEO,
868                                        deferred_video_decoder_config_id_,
869                                        decoder_status == cdm::kSuccess));
870      deferred_initialize_video_decoder_ = false;
871      deferred_video_decoder_config_id_ = 0;
872      break;
873  }
874}
875
876#if defined(OS_CHROMEOS)
877void CdmAdapter::SendPlatformChallengeDone(int32_t result) {
878  challenge_in_progress_ = false;
879
880  if (result != PP_OK) {
881    cdm::PlatformChallengeResponse response = {};
882    cdm_->OnPlatformChallengeResponse(response);
883    return;
884  }
885
886  pp::VarArrayBuffer signed_data_var(signed_data_output_);
887  pp::VarArrayBuffer signed_data_signature_var(signed_data_signature_output_);
888  std::string platform_key_certificate_string =
889      platform_key_certificate_output_.AsString();
890
891  cdm::PlatformChallengeResponse response = {
892    static_cast<uint8_t*>(signed_data_var.Map()),
893    signed_data_var.ByteLength(),
894
895    static_cast<uint8_t*>(signed_data_signature_var.Map()),
896    signed_data_signature_var.ByteLength(),
897
898    reinterpret_cast<const uint8_t*>(platform_key_certificate_string.c_str()),
899    static_cast<uint32_t>(platform_key_certificate_string.length())
900  };
901  cdm_->OnPlatformChallengeResponse(response);
902
903  signed_data_var.Unmap();
904  signed_data_signature_var.Unmap();
905}
906
907void CdmAdapter::EnableProtectionDone(int32_t result) {
908  // Does nothing since clients must call QueryOutputProtectionStatus() to
909  // inspect the protection status on a regular basis.
910  // TODO(dalecurtis): It'd be nice to log a message or non-fatal error here...
911}
912
913void CdmAdapter::QueryOutputProtectionStatusDone(int32_t result) {
914  PP_DCHECK(query_output_protection_in_progress_);
915  query_output_protection_in_progress_ = false;
916
917  // Return a protection status of none on error.
918  if (result != PP_OK)
919    output_link_mask_ = output_protection_mask_ = 0;
920
921  cdm_->OnQueryOutputProtectionStatus(output_link_mask_,
922                                      output_protection_mask_);
923}
924#endif
925
926void* GetCdmHost(int host_interface_version, void* user_data) {
927  if (!host_interface_version || !user_data)
928    return NULL;
929
930  COMPILE_ASSERT(cdm::ContentDecryptionModule::Host::kVersion ==
931                 cdm::ContentDecryptionModule_2::Host::kVersion,
932                 update_code_below);
933
934  // Ensure IsSupportedCdmHostVersion matches implementation of this function.
935  // Always update this DCHECK when updating this function.
936  // If this check fails, update this function and DCHECK or update
937  // IsSupportedCdmHostVersion.
938  PP_DCHECK(
939      // Future version is not supported.
940      !IsSupportedCdmHostVersion(
941          cdm::ContentDecryptionModule::Host::kVersion + 1) &&
942      // Current version is supported.
943      IsSupportedCdmHostVersion(cdm::ContentDecryptionModule::Host::kVersion) &&
944      // Include all previous supported versions here.
945      IsSupportedCdmHostVersion(cdm::Host_1::kVersion) &&
946      // One older than the oldest supported version is not supported.
947      !IsSupportedCdmHostVersion(cdm::Host_1::kVersion - 1));
948  PP_DCHECK(IsSupportedCdmHostVersion(host_interface_version));
949
950  CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data);
951  switch (host_interface_version) {
952    // The latest CDM host version.
953    case cdm::ContentDecryptionModule::Host::kVersion:
954      return static_cast<cdm::ContentDecryptionModule::Host*>(cdm_adapter);
955    // Older supported version(s) of the CDM host.
956    case cdm::Host_1::kVersion:
957      return static_cast<cdm::Host_1*>(cdm_adapter);
958    default:
959      PP_NOTREACHED();
960      return NULL;
961  }
962}
963
964// This object is the global object representing this plugin library as long
965// as it is loaded.
966class CdmAdapterModule : public pp::Module {
967 public:
968  CdmAdapterModule() : pp::Module() {
969    // This function blocks the renderer thread (PluginInstance::Initialize()).
970    // Move this call to other places if this may be a concern in the future.
971    INITIALIZE_CDM_MODULE();
972  }
973  virtual ~CdmAdapterModule() {
974    DeinitializeCdmModule();
975  }
976
977  virtual pp::Instance* CreateInstance(PP_Instance instance) {
978    return new CdmAdapter(instance, this);
979  }
980};
981
982}  // namespace media
983
984namespace pp {
985
986// Factory function for your specialization of the Module object.
987Module* CreateModule() {
988  return new media::CdmAdapterModule();
989}
990
991}  // namespace pp
992