Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / renderer / pepper / content_decryptor_delegate.cc
1 // Copyright (c) 2012 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 "content/renderer/pepper/content_decryptor_delegate.h"
6
7 #include "base/callback_helpers.h"
8 #include "base/debug/trace_event.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "content/renderer/pepper/ppb_buffer_impl.h"
12 #include "media/base/audio_buffer.h"
13 #include "media/base/audio_decoder_config.h"
14 #include "media/base/bind_to_current_loop.h"
15 #include "media/base/cdm_promise.h"
16 #include "media/base/channel_layout.h"
17 #include "media/base/data_buffer.h"
18 #include "media/base/decoder_buffer.h"
19 #include "media/base/decrypt_config.h"
20 #include "media/base/video_decoder_config.h"
21 #include "media/base/video_frame.h"
22 #include "media/base/video_util.h"
23 #include "ppapi/shared_impl/scoped_pp_resource.h"
24 #include "ppapi/shared_impl/var.h"
25 #include "ppapi/shared_impl/var_tracker.h"
26 #include "ppapi/thunk/enter.h"
27 #include "ppapi/thunk/ppb_buffer_api.h"
28 #include "ui/gfx/rect.h"
29
30 using media::CdmPromise;
31 using media::Decryptor;
32 using media::MediaKeys;
33 using media::NewSessionCdmPromise;
34 using media::SimpleCdmPromise;
35 using ppapi::ArrayBufferVar;
36 using ppapi::PpapiGlobals;
37 using ppapi::ScopedPPResource;
38 using ppapi::StringVar;
39 using ppapi::thunk::EnterResourceNoLock;
40 using ppapi::thunk::PPB_Buffer_API;
41
42 namespace content {
43
44 namespace {
45
46 // Fills |resource| with a PPB_Buffer_Impl and copies |data| into the buffer
47 // resource. The |*resource|, if valid, will be in the ResourceTracker with a
48 // reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns
49 // true upon success and false if any error happened.
50 bool MakeBufferResource(PP_Instance instance,
51                         const uint8* data,
52                         uint32_t size,
53                         scoped_refptr<PPB_Buffer_Impl>* resource) {
54   TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource");
55   DCHECK(resource);
56
57   if (!data || !size) {
58     DCHECK(!data && !size);
59     resource = NULL;
60     return true;
61   }
62
63   scoped_refptr<PPB_Buffer_Impl> buffer(
64       PPB_Buffer_Impl::CreateResource(instance, size));
65   if (!buffer.get())
66     return false;
67
68   BufferAutoMapper mapper(buffer.get());
69   if (!mapper.data() || mapper.size() < size)
70     return false;
71   memcpy(mapper.data(), data, size);
72
73   *resource = buffer;
74   return true;
75 }
76
77 // Copies the content of |str| into |array|.
78 // Returns true if copy succeeded. Returns false if copy failed, e.g. if the
79 // |array_size| is smaller than the |str| length.
80 template <uint32_t array_size>
81 bool CopyStringToArray(const std::string& str, uint8 (&array)[array_size]) {
82   if (array_size < str.size())
83     return false;
84
85   memcpy(array, str.data(), str.size());
86   return true;
87 }
88
89 // Fills the |block_info| with information from |encrypted_buffer|.
90 //
91 // Returns true if |block_info| is successfully filled. Returns false
92 // otherwise.
93 static bool MakeEncryptedBlockInfo(
94     const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
95     uint32_t request_id,
96     PP_EncryptedBlockInfo* block_info) {
97   // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and
98   // anywhere else.
99   memset(block_info, 0, sizeof(*block_info));
100   block_info->tracking_info.request_id = request_id;
101
102   // EOS buffers need a request ID and nothing more.
103   if (encrypted_buffer->end_of_stream())
104     return true;
105
106   DCHECK(encrypted_buffer->data_size())
107       << "DecryptConfig is set on an empty buffer";
108
109   block_info->tracking_info.timestamp =
110       encrypted_buffer->timestamp().InMicroseconds();
111   block_info->data_size = encrypted_buffer->data_size();
112
113   const media::DecryptConfig* decrypt_config =
114       encrypted_buffer->decrypt_config();
115
116   if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) ||
117       !CopyStringToArray(decrypt_config->iv(), block_info->iv))
118     return false;
119
120   block_info->key_id_size = decrypt_config->key_id().size();
121   block_info->iv_size = decrypt_config->iv().size();
122
123   if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples))
124     return false;
125
126   block_info->num_subsamples = decrypt_config->subsamples().size();
127   for (uint32_t i = 0; i < block_info->num_subsamples; ++i) {
128     block_info->subsamples[i].clear_bytes =
129         decrypt_config->subsamples()[i].clear_bytes;
130     block_info->subsamples[i].cipher_bytes =
131         decrypt_config->subsamples()[i].cypher_bytes;
132   }
133
134   return true;
135 }
136
137 PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) {
138   switch (codec) {
139     case media::kCodecVorbis:
140       return PP_AUDIOCODEC_VORBIS;
141     case media::kCodecAAC:
142       return PP_AUDIOCODEC_AAC;
143     default:
144       return PP_AUDIOCODEC_UNKNOWN;
145   }
146 }
147
148 PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) {
149   switch (codec) {
150     case media::kCodecVP8:
151       return PP_VIDEOCODEC_VP8;
152     case media::kCodecH264:
153       return PP_VIDEOCODEC_H264;
154     case media::kCodecVP9:
155       return PP_VIDEOCODEC_VP9;
156     default:
157       return PP_VIDEOCODEC_UNKNOWN;
158   }
159 }
160
161 PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile(
162     media::VideoCodecProfile profile) {
163   switch (profile) {
164     case media::VP8PROFILE_ANY:
165     case media::VP9PROFILE_ANY:
166       return PP_VIDEOCODECPROFILE_NOT_NEEDED;
167     case media::H264PROFILE_BASELINE:
168       return PP_VIDEOCODECPROFILE_H264_BASELINE;
169     case media::H264PROFILE_MAIN:
170       return PP_VIDEOCODECPROFILE_H264_MAIN;
171     case media::H264PROFILE_EXTENDED:
172       return PP_VIDEOCODECPROFILE_H264_EXTENDED;
173     case media::H264PROFILE_HIGH:
174       return PP_VIDEOCODECPROFILE_H264_HIGH;
175     case media::H264PROFILE_HIGH10PROFILE:
176       return PP_VIDEOCODECPROFILE_H264_HIGH_10;
177     case media::H264PROFILE_HIGH422PROFILE:
178       return PP_VIDEOCODECPROFILE_H264_HIGH_422;
179     case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
180       return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE;
181     default:
182       return PP_VIDEOCODECPROFILE_UNKNOWN;
183   }
184 }
185
186 PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat(
187     media::VideoFrame::Format format) {
188   switch (format) {
189     case media::VideoFrame::YV12:
190       return PP_DECRYPTEDFRAMEFORMAT_YV12;
191     case media::VideoFrame::I420:
192       return PP_DECRYPTEDFRAMEFORMAT_I420;
193     default:
194       return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
195   }
196 }
197
198 Decryptor::Status PpDecryptResultToMediaDecryptorStatus(
199     PP_DecryptResult result) {
200   switch (result) {
201     case PP_DECRYPTRESULT_SUCCESS:
202       return Decryptor::kSuccess;
203     case PP_DECRYPTRESULT_DECRYPT_NOKEY:
204       return Decryptor::kNoKey;
205     case PP_DECRYPTRESULT_NEEDMOREDATA:
206       return Decryptor::kNeedMoreData;
207     case PP_DECRYPTRESULT_DECRYPT_ERROR:
208       return Decryptor::kError;
209     case PP_DECRYPTRESULT_DECODE_ERROR:
210       return Decryptor::kError;
211     default:
212       NOTREACHED();
213       return Decryptor::kError;
214   }
215 }
216
217 PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType(
218     Decryptor::StreamType stream_type) {
219   switch (stream_type) {
220     case Decryptor::kAudio:
221       return PP_DECRYPTORSTREAMTYPE_AUDIO;
222     case Decryptor::kVideo:
223       return PP_DECRYPTORSTREAMTYPE_VIDEO;
224     default:
225       NOTREACHED();
226       return PP_DECRYPTORSTREAMTYPE_VIDEO;
227   }
228 }
229
230 media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat(
231     PP_DecryptedSampleFormat result) {
232   switch (result) {
233     case PP_DECRYPTEDSAMPLEFORMAT_U8:
234       return media::kSampleFormatU8;
235     case PP_DECRYPTEDSAMPLEFORMAT_S16:
236       return media::kSampleFormatS16;
237     case PP_DECRYPTEDSAMPLEFORMAT_S32:
238       return media::kSampleFormatS32;
239     case PP_DECRYPTEDSAMPLEFORMAT_F32:
240       return media::kSampleFormatF32;
241     case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16:
242       return media::kSampleFormatPlanarS16;
243     case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32:
244       return media::kSampleFormatPlanarF32;
245     default:
246       NOTREACHED();
247       return media::kUnknownSampleFormat;
248   }
249 }
250
251 PP_SessionType MediaSessionTypeToPpSessionType(
252     MediaKeys::SessionType session_type) {
253   switch (session_type) {
254     case MediaKeys::TEMPORARY_SESSION:
255       return PP_SESSIONTYPE_TEMPORARY;
256     case MediaKeys::PERSISTENT_SESSION:
257       return PP_SESSIONTYPE_PERSISTENT;
258     default:
259       NOTREACHED();
260       return PP_SESSIONTYPE_TEMPORARY;
261   }
262 }
263
264 MediaKeys::Exception PpExceptionTypeToMediaException(
265     PP_CdmExceptionCode exception_code) {
266   switch (exception_code) {
267     case PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR:
268       return MediaKeys::NOT_SUPPORTED_ERROR;
269     case PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR:
270       return MediaKeys::INVALID_STATE_ERROR;
271     case PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR:
272       return MediaKeys::INVALID_ACCESS_ERROR;
273     case PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR:
274       return MediaKeys::QUOTA_EXCEEDED_ERROR;
275     case PP_CDMEXCEPTIONCODE_UNKNOWNERROR:
276       return MediaKeys::UNKNOWN_ERROR;
277     case PP_CDMEXCEPTIONCODE_CLIENTERROR:
278       return MediaKeys::CLIENT_ERROR;
279     case PP_CDMEXCEPTIONCODE_OUTPUTERROR:
280       return MediaKeys::OUTPUT_ERROR;
281     default:
282       NOTREACHED();
283       return MediaKeys::UNKNOWN_ERROR;
284   }
285 }
286
287 }  // namespace
288
289 ContentDecryptorDelegate::ContentDecryptorDelegate(
290     PP_Instance pp_instance,
291     const PPP_ContentDecryptor_Private* plugin_decryption_interface)
292     : pp_instance_(pp_instance),
293       plugin_decryption_interface_(plugin_decryption_interface),
294       next_decryption_request_id_(1),
295       audio_samples_per_second_(0),
296       audio_channel_count_(0),
297       audio_channel_layout_(media::CHANNEL_LAYOUT_NONE),
298       next_promise_id_(1),
299       weak_ptr_factory_(this) {
300   weak_this_ = weak_ptr_factory_.GetWeakPtr();
301 }
302
303 ContentDecryptorDelegate::~ContentDecryptorDelegate() {
304   SatisfyAllPendingCallbacksOnError();
305 }
306
307 void ContentDecryptorDelegate::Initialize(
308     const std::string& key_system,
309     const media::SessionMessageCB& session_message_cb,
310     const media::SessionReadyCB& session_ready_cb,
311     const media::SessionClosedCB& session_closed_cb,
312     const media::SessionErrorCB& session_error_cb,
313     const base::Closure& fatal_plugin_error_cb) {
314   DCHECK(!key_system.empty());
315   DCHECK(key_system_.empty());
316   key_system_ = key_system;
317
318   session_message_cb_ = session_message_cb;
319   session_ready_cb_ = session_ready_cb;
320   session_closed_cb_ = session_closed_cb;
321   session_error_cb_ = session_error_cb;
322   fatal_plugin_error_cb_ = fatal_plugin_error_cb;
323
324   plugin_decryption_interface_->Initialize(
325       pp_instance_, StringVar::StringToPPVar(key_system_));
326 }
327
328 void ContentDecryptorDelegate::InstanceCrashed() {
329   fatal_plugin_error_cb_.Run();
330   SatisfyAllPendingCallbacksOnError();
331 }
332
333 void ContentDecryptorDelegate::CreateSession(
334     const std::string& init_data_type,
335     const uint8* init_data,
336     int init_data_length,
337     MediaKeys::SessionType session_type,
338     scoped_ptr<NewSessionCdmPromise> promise) {
339   uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
340   PP_Var init_data_array =
341       PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
342           init_data_length, init_data);
343   plugin_decryption_interface_->CreateSession(
344       pp_instance_,
345       promise_id,
346       StringVar::StringToPPVar(init_data_type),
347       init_data_array,
348       MediaSessionTypeToPpSessionType(session_type));
349 }
350
351 void ContentDecryptorDelegate::LoadSession(
352     const std::string& web_session_id,
353     scoped_ptr<NewSessionCdmPromise> promise) {
354   uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
355   plugin_decryption_interface_->LoadSession(
356       pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
357 }
358
359 void ContentDecryptorDelegate::UpdateSession(
360     const std::string& web_session_id,
361     const uint8* response,
362     int response_length,
363     scoped_ptr<SimpleCdmPromise> promise) {
364   uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
365   PP_Var response_array =
366       PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
367           response_length, response);
368   plugin_decryption_interface_->UpdateSession(
369       pp_instance_,
370       promise_id,
371       StringVar::StringToPPVar(web_session_id),
372       response_array);
373 }
374
375 void ContentDecryptorDelegate::ReleaseSession(
376     const std::string& web_session_id,
377     scoped_ptr<SimpleCdmPromise> promise) {
378   uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
379   plugin_decryption_interface_->ReleaseSession(
380       pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
381 }
382
383 // TODO(xhwang): Remove duplication of code in Decrypt(),
384 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
385 bool ContentDecryptorDelegate::Decrypt(
386     Decryptor::StreamType stream_type,
387     const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
388     const Decryptor::DecryptCB& decrypt_cb) {
389   DVLOG(3) << "Decrypt() - stream_type: " << stream_type;
390
391   // |{audio|video}_input_resource_| is not being used by the plugin
392   // now because there is only one pending audio/video decrypt request at any
393   // time. This is enforced by the media pipeline.
394   scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
395   if (!MakeMediaBufferResource(
396           stream_type, encrypted_buffer, &encrypted_resource) ||
397       !encrypted_resource.get()) {
398     return false;
399   }
400   ScopedPPResource pp_resource(encrypted_resource.get());
401
402   const uint32_t request_id = next_decryption_request_id_++;
403   DVLOG(2) << "Decrypt() - request_id " << request_id;
404
405   PP_EncryptedBlockInfo block_info = {};
406   DCHECK(encrypted_buffer->decrypt_config());
407   if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
408     return false;
409   }
410
411   // There is only one pending decrypt request at any time per stream. This is
412   // enforced by the media pipeline.
413   switch (stream_type) {
414     case Decryptor::kAudio:
415       audio_decrypt_cb_.Set(request_id, decrypt_cb);
416       break;
417     case Decryptor::kVideo:
418       video_decrypt_cb_.Set(request_id, decrypt_cb);
419       break;
420     default:
421       NOTREACHED();
422       return false;
423   }
424
425   SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
426
427   plugin_decryption_interface_->Decrypt(pp_instance_, pp_resource, &block_info);
428   return true;
429 }
430
431 bool ContentDecryptorDelegate::CancelDecrypt(
432     Decryptor::StreamType stream_type) {
433   DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type;
434
435   Decryptor::DecryptCB decrypt_cb;
436   switch (stream_type) {
437     case Decryptor::kAudio:
438       // Release the shared memory as it can still be in use by the plugin.
439       // The next Decrypt() call will need to allocate a new shared memory
440       // buffer.
441       audio_input_resource_ = NULL;
442       decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
443       break;
444     case Decryptor::kVideo:
445       // Release the shared memory as it can still be in use by the plugin.
446       // The next Decrypt() call will need to allocate a new shared memory
447       // buffer.
448       video_input_resource_ = NULL;
449       decrypt_cb = video_decrypt_cb_.ResetAndReturn();
450       break;
451     default:
452       NOTREACHED();
453       return false;
454   }
455
456   if (!decrypt_cb.is_null())
457     decrypt_cb.Run(Decryptor::kSuccess, NULL);
458
459   return true;
460 }
461
462 bool ContentDecryptorDelegate::InitializeAudioDecoder(
463     const media::AudioDecoderConfig& decoder_config,
464     const Decryptor::DecoderInitCB& init_cb) {
465   PP_AudioDecoderConfig pp_decoder_config;
466   pp_decoder_config.codec =
467       MediaAudioCodecToPpAudioCodec(decoder_config.codec());
468   pp_decoder_config.channel_count =
469       media::ChannelLayoutToChannelCount(decoder_config.channel_layout());
470   pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel();
471   pp_decoder_config.samples_per_second = decoder_config.samples_per_second();
472   pp_decoder_config.request_id = next_decryption_request_id_++;
473
474   audio_samples_per_second_ = pp_decoder_config.samples_per_second;
475   audio_channel_count_ = pp_decoder_config.channel_count;
476   audio_channel_layout_ = decoder_config.channel_layout();
477
478   scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
479   if (!MakeBufferResource(pp_instance_,
480                           decoder_config.extra_data(),
481                           decoder_config.extra_data_size(),
482                           &extra_data_resource)) {
483     return false;
484   }
485   ScopedPPResource pp_resource(extra_data_resource.get());
486
487   audio_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
488   plugin_decryption_interface_->InitializeAudioDecoder(
489       pp_instance_, &pp_decoder_config, pp_resource);
490   return true;
491 }
492
493 bool ContentDecryptorDelegate::InitializeVideoDecoder(
494     const media::VideoDecoderConfig& decoder_config,
495     const Decryptor::DecoderInitCB& init_cb) {
496   PP_VideoDecoderConfig pp_decoder_config;
497   pp_decoder_config.codec =
498       MediaVideoCodecToPpVideoCodec(decoder_config.codec());
499   pp_decoder_config.profile =
500       MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile());
501   pp_decoder_config.format =
502       MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format());
503   pp_decoder_config.width = decoder_config.coded_size().width();
504   pp_decoder_config.height = decoder_config.coded_size().height();
505   pp_decoder_config.request_id = next_decryption_request_id_++;
506
507   scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
508   if (!MakeBufferResource(pp_instance_,
509                           decoder_config.extra_data(),
510                           decoder_config.extra_data_size(),
511                           &extra_data_resource)) {
512     return false;
513   }
514   ScopedPPResource pp_resource(extra_data_resource.get());
515
516   video_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
517   natural_size_ = decoder_config.natural_size();
518
519   plugin_decryption_interface_->InitializeVideoDecoder(
520       pp_instance_, &pp_decoder_config, pp_resource);
521   return true;
522 }
523
524 bool ContentDecryptorDelegate::DeinitializeDecoder(
525     Decryptor::StreamType stream_type) {
526   CancelDecode(stream_type);
527
528   if (stream_type == Decryptor::kVideo)
529     natural_size_ = gfx::Size();
530
531   // TODO(tomfinegan): Add decoder deinitialize request tracking, and get
532   // stream type from media stack.
533   plugin_decryption_interface_->DeinitializeDecoder(
534       pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
535   return true;
536 }
537
538 bool ContentDecryptorDelegate::ResetDecoder(Decryptor::StreamType stream_type) {
539   CancelDecode(stream_type);
540
541   // TODO(tomfinegan): Add decoder reset request tracking.
542   plugin_decryption_interface_->ResetDecoder(
543       pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
544   return true;
545 }
546
547 bool ContentDecryptorDelegate::DecryptAndDecodeAudio(
548     const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
549     const Decryptor::AudioDecodeCB& audio_decode_cb) {
550   // |audio_input_resource_| is not being used by the plugin now
551   // because there is only one pending audio decode request at any time.
552   // This is enforced by the media pipeline.
553   scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
554   if (!MakeMediaBufferResource(
555           Decryptor::kAudio, encrypted_buffer, &encrypted_resource)) {
556     return false;
557   }
558
559   // The resource should not be NULL for non-EOS buffer.
560   if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
561     return false;
562
563   const uint32_t request_id = next_decryption_request_id_++;
564   DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id;
565
566   PP_EncryptedBlockInfo block_info = {};
567   if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
568     return false;
569   }
570
571   SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
572
573   // There is only one pending audio decode request at any time. This is
574   // enforced by the media pipeline. If this DCHECK is violated, our buffer
575   // reuse policy is not valid, and we may have race problems for the shared
576   // buffer.
577   audio_decode_cb_.Set(request_id, audio_decode_cb);
578
579   ScopedPPResource pp_resource(encrypted_resource.get());
580   plugin_decryption_interface_->DecryptAndDecode(
581       pp_instance_, PP_DECRYPTORSTREAMTYPE_AUDIO, pp_resource, &block_info);
582   return true;
583 }
584
585 bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
586     const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
587     const Decryptor::VideoDecodeCB& video_decode_cb) {
588   // |video_input_resource_| is not being used by the plugin now
589   // because there is only one pending video decode request at any time.
590   // This is enforced by the media pipeline.
591   scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
592   if (!MakeMediaBufferResource(
593           Decryptor::kVideo, encrypted_buffer, &encrypted_resource)) {
594     return false;
595   }
596
597   // The resource should not be 0 for non-EOS buffer.
598   if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
599     return false;
600
601   const uint32_t request_id = next_decryption_request_id_++;
602   DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id;
603   TRACE_EVENT_ASYNC_BEGIN0(
604       "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
605
606   PP_EncryptedBlockInfo block_info = {};
607   if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
608     return false;
609   }
610
611   SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
612
613   // Only one pending video decode request at any time. This is enforced by the
614   // media pipeline. If this DCHECK is violated, our buffer
615   // reuse policy is not valid, and we may have race problems for the shared
616   // buffer.
617   video_decode_cb_.Set(request_id, video_decode_cb);
618
619   // TODO(tomfinegan): Need to get stream type from media stack.
620   ScopedPPResource pp_resource(encrypted_resource.get());
621   plugin_decryption_interface_->DecryptAndDecode(
622       pp_instance_, PP_DECRYPTORSTREAMTYPE_VIDEO, pp_resource, &block_info);
623   return true;
624 }
625
626 void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) {
627   scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
628   if (promise) {
629     SimpleCdmPromise* simple_promise(
630         static_cast<SimpleCdmPromise*>(promise.get()));
631     simple_promise->resolve();
632   }
633 }
634
635 void ContentDecryptorDelegate::OnPromiseResolvedWithSession(
636     uint32 promise_id,
637     PP_Var web_session_id) {
638   scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
639
640   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
641   DCHECK(web_session_id_string);
642
643   if (promise) {
644     NewSessionCdmPromise* session_promise(
645         static_cast<NewSessionCdmPromise*>(promise.get()));
646     session_promise->resolve(web_session_id_string->value());
647   }
648 }
649
650 void ContentDecryptorDelegate::OnPromiseRejected(
651     uint32 promise_id,
652     PP_CdmExceptionCode exception_code,
653     uint32 system_code,
654     PP_Var error_description) {
655   StringVar* error_description_string = StringVar::FromPPVar(error_description);
656   DCHECK(error_description_string);
657
658   scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
659   if (promise) {
660     promise->reject(PpExceptionTypeToMediaException(exception_code),
661                     system_code,
662                     error_description_string->value());
663   }
664 }
665
666 void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id,
667                                                 PP_Var message,
668                                                 PP_Var destination_url) {
669   if (session_message_cb_.is_null())
670     return;
671
672   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
673   DCHECK(web_session_id_string);
674
675   ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message);
676   std::vector<uint8> message_vector;
677   if (message_array_buffer) {
678     const uint8* data = static_cast<const uint8*>(message_array_buffer->Map());
679     message_vector.assign(data, data + message_array_buffer->ByteLength());
680   }
681
682   StringVar* destination_url_string = StringVar::FromPPVar(destination_url);
683   DCHECK(destination_url_string);
684
685   GURL verified_gurl = GURL(destination_url_string->value());
686   if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) {
687     DLOG(WARNING) << "SessionMessage default_url is invalid : "
688                   << verified_gurl.possibly_invalid_spec();
689     verified_gurl = GURL::EmptyGURL();  // Replace invalid destination_url.
690   }
691
692   session_message_cb_.Run(
693       web_session_id_string->value(), message_vector, verified_gurl);
694 }
695
696 void ContentDecryptorDelegate::OnSessionReady(PP_Var web_session_id) {
697   if (session_ready_cb_.is_null())
698     return;
699
700   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
701   DCHECK(web_session_id_string);
702
703   session_ready_cb_.Run(web_session_id_string->value());
704 }
705
706 void ContentDecryptorDelegate::OnSessionClosed(PP_Var web_session_id) {
707   if (session_closed_cb_.is_null())
708     return;
709
710   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
711   DCHECK(web_session_id_string);
712
713   session_closed_cb_.Run(web_session_id_string->value());
714 }
715
716 void ContentDecryptorDelegate::OnSessionError(
717     PP_Var web_session_id,
718     PP_CdmExceptionCode exception_code,
719     uint32 system_code,
720     PP_Var error_description) {
721   if (session_error_cb_.is_null())
722     return;
723
724   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
725   DCHECK(web_session_id_string);
726
727   StringVar* error_description_string = StringVar::FromPPVar(error_description);
728   DCHECK(error_description_string);
729
730   session_error_cb_.Run(web_session_id_string->value(),
731                         PpExceptionTypeToMediaException(exception_code),
732                         system_code,
733                         error_description_string->value());
734 }
735
736 void ContentDecryptorDelegate::DecoderInitializeDone(
737     PP_DecryptorStreamType decoder_type,
738     uint32_t request_id,
739     PP_Bool success) {
740   if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) {
741     // If the request ID is not valid or does not match what's saved, do
742     // nothing.
743     if (request_id == 0 || !audio_decoder_init_cb_.Matches(request_id))
744       return;
745
746     audio_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
747   } else {
748     if (request_id == 0 || !video_decoder_init_cb_.Matches(request_id))
749       return;
750
751     if (!success)
752       natural_size_ = gfx::Size();
753
754     video_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
755   }
756 }
757
758 void ContentDecryptorDelegate::DecoderDeinitializeDone(
759     PP_DecryptorStreamType decoder_type,
760     uint32_t request_id) {
761   // TODO(tomfinegan): Add decoder stop completion handling.
762 }
763
764 void ContentDecryptorDelegate::DecoderResetDone(
765     PP_DecryptorStreamType decoder_type,
766     uint32_t request_id) {
767   // TODO(tomfinegan): Add decoder reset completion handling.
768 }
769
770 void ContentDecryptorDelegate::DeliverBlock(
771     PP_Resource decrypted_block,
772     const PP_DecryptedBlockInfo* block_info) {
773   DCHECK(block_info);
774
775   FreeBuffer(block_info->tracking_info.buffer_id);
776
777   const uint32_t request_id = block_info->tracking_info.request_id;
778   DVLOG(2) << "DeliverBlock() - request_id: " << request_id;
779
780   // If the request ID is not valid or does not match what's saved, do nothing.
781   if (request_id == 0) {
782     DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id;
783     return;
784   }
785
786   Decryptor::DecryptCB decrypt_cb;
787   if (audio_decrypt_cb_.Matches(request_id)) {
788     decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
789   } else if (video_decrypt_cb_.Matches(request_id)) {
790     decrypt_cb = video_decrypt_cb_.ResetAndReturn();
791   } else {
792     DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found";
793     return;
794   }
795
796   Decryptor::Status status =
797       PpDecryptResultToMediaDecryptorStatus(block_info->result);
798   if (status != Decryptor::kSuccess) {
799     decrypt_cb.Run(status, NULL);
800     return;
801   }
802
803   EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true);
804   if (!enter.succeeded()) {
805     decrypt_cb.Run(Decryptor::kError, NULL);
806     return;
807   }
808   BufferAutoMapper mapper(enter.object());
809   if (!mapper.data() || !mapper.size() ||
810       mapper.size() < block_info->data_size) {
811     decrypt_cb.Run(Decryptor::kError, NULL);
812     return;
813   }
814
815   // TODO(tomfinegan): Find a way to take ownership of the shared memory
816   // managed by the PPB_Buffer_Dev, and avoid the extra copy.
817   scoped_refptr<media::DecoderBuffer> decrypted_buffer(
818       media::DecoderBuffer::CopyFrom(static_cast<uint8*>(mapper.data()),
819                                      block_info->data_size));
820   decrypted_buffer->set_timestamp(
821       base::TimeDelta::FromMicroseconds(block_info->tracking_info.timestamp));
822   decrypt_cb.Run(Decryptor::kSuccess, decrypted_buffer);
823 }
824
825 // Use a non-class-member function here so that if for some reason
826 // ContentDecryptorDelegate is destroyed before VideoFrame calls this callback,
827 // we can still get the shared memory unmapped.
828 static void BufferNoLongerNeeded(
829     const scoped_refptr<PPB_Buffer_Impl>& ppb_buffer,
830     base::Closure buffer_no_longer_needed_cb) {
831   ppb_buffer->Unmap();
832   buffer_no_longer_needed_cb.Run();
833 }
834
835 // Enters |resource|, maps shared memory and returns pointer of mapped data.
836 // Returns NULL if any error occurs.
837 static uint8* GetMappedBuffer(PP_Resource resource,
838                               scoped_refptr<PPB_Buffer_Impl>* ppb_buffer) {
839   EnterResourceNoLock<PPB_Buffer_API> enter(resource, true);
840   if (!enter.succeeded())
841     return NULL;
842
843   uint8* mapped_data = static_cast<uint8*>(enter.object()->Map());
844   if (!enter.object()->IsMapped() || !mapped_data)
845     return NULL;
846
847   uint32_t mapped_size = 0;
848   if (!enter.object()->Describe(&mapped_size) || !mapped_size) {
849     enter.object()->Unmap();
850     return NULL;
851   }
852
853   *ppb_buffer = static_cast<PPB_Buffer_Impl*>(enter.object());
854
855   return mapped_data;
856 }
857
858 void ContentDecryptorDelegate::DeliverFrame(
859     PP_Resource decrypted_frame,
860     const PP_DecryptedFrameInfo* frame_info) {
861   DCHECK(frame_info);
862
863   const uint32_t request_id = frame_info->tracking_info.request_id;
864   DVLOG(2) << "DeliverFrame() - request_id: " << request_id;
865
866   // If the request ID is not valid or does not match what's saved, do nothing.
867   if (request_id == 0 || !video_decode_cb_.Matches(request_id)) {
868     DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found";
869     FreeBuffer(frame_info->tracking_info.buffer_id);
870     return;
871   }
872
873   TRACE_EVENT_ASYNC_END0(
874       "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
875
876   Decryptor::VideoDecodeCB video_decode_cb = video_decode_cb_.ResetAndReturn();
877
878   Decryptor::Status status =
879       PpDecryptResultToMediaDecryptorStatus(frame_info->result);
880   if (status != Decryptor::kSuccess) {
881     DCHECK(!frame_info->tracking_info.buffer_id);
882     video_decode_cb.Run(status, NULL);
883     return;
884   }
885
886   scoped_refptr<PPB_Buffer_Impl> ppb_buffer;
887   uint8* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer);
888   if (!frame_data) {
889     FreeBuffer(frame_info->tracking_info.buffer_id);
890     video_decode_cb.Run(Decryptor::kError, NULL);
891     return;
892   }
893
894   gfx::Size frame_size(frame_info->width, frame_info->height);
895   DCHECK_EQ(frame_info->format, PP_DECRYPTEDFRAMEFORMAT_YV12);
896
897   scoped_refptr<media::VideoFrame> decoded_frame =
898       media::VideoFrame::WrapExternalYuvData(
899           media::VideoFrame::YV12,
900           frame_size,
901           gfx::Rect(frame_size),
902           natural_size_,
903           frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y],
904           frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U],
905           frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V],
906           frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y],
907           frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U],
908           frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V],
909           base::TimeDelta::FromMicroseconds(
910               frame_info->tracking_info.timestamp),
911           media::BindToCurrentLoop(
912               base::Bind(&BufferNoLongerNeeded,
913                          ppb_buffer,
914                          base::Bind(&ContentDecryptorDelegate::FreeBuffer,
915                                     weak_this_,
916                                     frame_info->tracking_info.buffer_id))));
917
918   video_decode_cb.Run(Decryptor::kSuccess, decoded_frame);
919 }
920
921 void ContentDecryptorDelegate::DeliverSamples(
922     PP_Resource audio_frames,
923     const PP_DecryptedSampleInfo* sample_info) {
924   DCHECK(sample_info);
925
926   FreeBuffer(sample_info->tracking_info.buffer_id);
927
928   const uint32_t request_id = sample_info->tracking_info.request_id;
929   DVLOG(2) << "DeliverSamples() - request_id: " << request_id;
930
931   // If the request ID is not valid or does not match what's saved, do nothing.
932   if (request_id == 0 || !audio_decode_cb_.Matches(request_id)) {
933     DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found";
934     return;
935   }
936
937   Decryptor::AudioDecodeCB audio_decode_cb = audio_decode_cb_.ResetAndReturn();
938
939   const Decryptor::AudioBuffers empty_frames;
940
941   Decryptor::Status status =
942       PpDecryptResultToMediaDecryptorStatus(sample_info->result);
943   if (status != Decryptor::kSuccess) {
944     audio_decode_cb.Run(status, empty_frames);
945     return;
946   }
947
948   media::SampleFormat sample_format =
949       PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format);
950
951   Decryptor::AudioBuffers audio_frame_list;
952   if (!DeserializeAudioFrames(audio_frames,
953                               sample_info->data_size,
954                               sample_format,
955                               &audio_frame_list)) {
956     NOTREACHED() << "CDM did not serialize the buffer correctly.";
957     audio_decode_cb.Run(Decryptor::kError, empty_frames);
958     return;
959   }
960
961   audio_decode_cb.Run(Decryptor::kSuccess, audio_frame_list);
962 }
963
964 // TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt().
965 void ContentDecryptorDelegate::CancelDecode(Decryptor::StreamType stream_type) {
966   switch (stream_type) {
967     case Decryptor::kAudio:
968       // Release the shared memory as it can still be in use by the plugin.
969       // The next DecryptAndDecode() call will need to allocate a new shared
970       // memory buffer.
971       audio_input_resource_ = NULL;
972       if (!audio_decode_cb_.is_null())
973         audio_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess,
974                                               Decryptor::AudioBuffers());
975       break;
976     case Decryptor::kVideo:
977       // Release the shared memory as it can still be in use by the plugin.
978       // The next DecryptAndDecode() call will need to allocate a new shared
979       // memory buffer.
980       video_input_resource_ = NULL;
981       if (!video_decode_cb_.is_null())
982         video_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess, NULL);
983       break;
984     default:
985       NOTREACHED();
986   }
987 }
988
989 bool ContentDecryptorDelegate::MakeMediaBufferResource(
990     Decryptor::StreamType stream_type,
991     const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
992     scoped_refptr<PPB_Buffer_Impl>* resource) {
993   TRACE_EVENT0("media", "ContentDecryptorDelegate::MakeMediaBufferResource");
994
995   // End of stream buffers are represented as null resources.
996   if (encrypted_buffer->end_of_stream()) {
997     *resource = NULL;
998     return true;
999   }
1000
1001   DCHECK(stream_type == Decryptor::kAudio || stream_type == Decryptor::kVideo);
1002   scoped_refptr<PPB_Buffer_Impl>& media_resource =
1003       (stream_type == Decryptor::kAudio) ? audio_input_resource_
1004                                          : video_input_resource_;
1005
1006   const size_t data_size = static_cast<size_t>(encrypted_buffer->data_size());
1007   if (!media_resource.get() || media_resource->size() < data_size) {
1008     // Either the buffer hasn't been created yet, or we have one that isn't big
1009     // enough to fit |size| bytes.
1010
1011     // Media resource size starts from |kMinimumMediaBufferSize| and grows
1012     // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl,
1013     // which is usually expensive. Since input media buffers are compressed,
1014     // they are usually small (compared to outputs). The over-allocated memory
1015     // should be negligible.
1016     const uint32_t kMinimumMediaBufferSize = 1024;
1017     uint32_t media_resource_size =
1018         media_resource.get() ? media_resource->size() : kMinimumMediaBufferSize;
1019     while (media_resource_size < data_size)
1020       media_resource_size *= 2;
1021
1022     DVLOG(2) << "Size of media buffer for "
1023              << ((stream_type == Decryptor::kAudio) ? "audio" : "video")
1024              << " stream bumped to " << media_resource_size
1025              << " bytes to fit input.";
1026     media_resource =
1027         PPB_Buffer_Impl::CreateResource(pp_instance_, media_resource_size);
1028     if (!media_resource.get())
1029       return false;
1030   }
1031
1032   BufferAutoMapper mapper(media_resource.get());
1033   if (!mapper.data() || mapper.size() < data_size) {
1034     media_resource = NULL;
1035     return false;
1036   }
1037   memcpy(mapper.data(), encrypted_buffer->data(), data_size);
1038
1039   *resource = media_resource;
1040   return true;
1041 }
1042
1043 void ContentDecryptorDelegate::FreeBuffer(uint32_t buffer_id) {
1044   if (buffer_id)
1045     free_buffers_.push(buffer_id);
1046 }
1047
1048 void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo(
1049     PP_DecryptTrackingInfo* tracking_info) {
1050   DCHECK_EQ(tracking_info->buffer_id, 0u);
1051
1052   if (free_buffers_.empty())
1053     return;
1054
1055   tracking_info->buffer_id = free_buffers_.front();
1056   free_buffers_.pop();
1057 }
1058
1059 bool ContentDecryptorDelegate::DeserializeAudioFrames(
1060     PP_Resource audio_frames,
1061     size_t data_size,
1062     media::SampleFormat sample_format,
1063     Decryptor::AudioBuffers* frames) {
1064   DCHECK(frames);
1065   EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
1066   if (!enter.succeeded())
1067     return false;
1068
1069   BufferAutoMapper mapper(enter.object());
1070   if (!mapper.data() || !mapper.size() ||
1071       mapper.size() < static_cast<uint32_t>(data_size))
1072     return false;
1073
1074   // TODO(jrummell): Pass ownership of data() directly to AudioBuffer to avoid
1075   // the copy. Since it is possible to get multiple buffers, it would need to be
1076   // sliced and ref counted appropriately. http://crbug.com/255576.
1077   const uint8* cur = static_cast<uint8*>(mapper.data());
1078   size_t bytes_left = data_size;
1079
1080   const int audio_bytes_per_frame =
1081       media::SampleFormatToBytesPerChannel(sample_format) *
1082       audio_channel_count_;
1083   if (audio_bytes_per_frame <= 0)
1084     return false;
1085
1086   // Allocate space for the channel pointers given to AudioBuffer.
1087   std::vector<const uint8*> channel_ptrs(audio_channel_count_,
1088                                          static_cast<const uint8*>(NULL));
1089   do {
1090     int64 timestamp = 0;
1091     int64 frame_size = -1;
1092     const size_t kHeaderSize = sizeof(timestamp) + sizeof(frame_size);
1093
1094     if (bytes_left < kHeaderSize)
1095       return false;
1096
1097     memcpy(&timestamp, cur, sizeof(timestamp));
1098     cur += sizeof(timestamp);
1099     bytes_left -= sizeof(timestamp);
1100
1101     memcpy(&frame_size, cur, sizeof(frame_size));
1102     cur += sizeof(frame_size);
1103     bytes_left -= sizeof(frame_size);
1104
1105     // We should *not* have empty frames in the list.
1106     if (frame_size <= 0 ||
1107         bytes_left < base::checked_cast<size_t>(frame_size)) {
1108       return false;
1109     }
1110
1111     // Setup channel pointers.  AudioBuffer::CopyFrom() will only use the first
1112     // one in the case of interleaved data.
1113     const int size_per_channel = frame_size / audio_channel_count_;
1114     for (int i = 0; i < audio_channel_count_; ++i)
1115       channel_ptrs[i] = cur + i * size_per_channel;
1116
1117     const int frame_count = frame_size / audio_bytes_per_frame;
1118     scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom(
1119         sample_format,
1120         audio_channel_layout_,
1121         audio_channel_count_,
1122         audio_samples_per_second_,
1123         frame_count,
1124         &channel_ptrs[0],
1125         base::TimeDelta::FromMicroseconds(timestamp));
1126     frames->push_back(frame);
1127
1128     cur += frame_size;
1129     bytes_left -= frame_size;
1130   } while (bytes_left > 0);
1131
1132   return true;
1133 }
1134
1135 void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() {
1136   if (!audio_decoder_init_cb_.is_null())
1137     audio_decoder_init_cb_.ResetAndReturn().Run(false);
1138
1139   if (!video_decoder_init_cb_.is_null())
1140     video_decoder_init_cb_.ResetAndReturn().Run(false);
1141
1142   audio_input_resource_ = NULL;
1143   video_input_resource_ = NULL;
1144
1145   if (!audio_decrypt_cb_.is_null())
1146     audio_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1147
1148   if (!video_decrypt_cb_.is_null())
1149     video_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1150
1151   if (!audio_decode_cb_.is_null()) {
1152     const media::Decryptor::AudioBuffers empty_frames;
1153     audio_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError,
1154                                           empty_frames);
1155   }
1156
1157   if (!video_decode_cb_.is_null())
1158     video_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1159
1160   // Reject all outstanding promises.
1161   for (PromiseMap::iterator it = promises_.begin(); it != promises_.end();
1162        ++it) {
1163     it->second->reject(
1164         media::MediaKeys::UNKNOWN_ERROR, 0, "Failure calling plugin.");
1165   }
1166   promises_.clear();
1167 }
1168
1169 uint32_t ContentDecryptorDelegate::SavePromise(scoped_ptr<CdmPromise> promise) {
1170   uint32_t promise_id = next_promise_id_++;
1171   promises_.add(promise_id, promise.Pass());
1172   return promise_id;
1173 }
1174
1175 scoped_ptr<CdmPromise> ContentDecryptorDelegate::TakePromise(
1176     uint32_t promise_id) {
1177   PromiseMap::iterator it = promises_.find(promise_id);
1178   if (it == promises_.end())
1179     return scoped_ptr<CdmPromise>();
1180   return promises_.take_and_erase(it);
1181 }
1182
1183 }  // namespace content