1 // Copyright 2014 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.
5 #include "content/browser/media/cdm/browser_cdm_manager.h"
10 #include "base/lazy_instance.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/task_runner.h"
13 #include "content/public/browser/browser_context.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/content_browser_client.h"
16 #include "content/public/browser/permission_manager.h"
17 #include "content/public/browser/permission_type.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "content/public/browser/render_process_host_observer.h"
21 #include "content/public/browser/web_contents.h"
22 #include "media/base/browser_cdm.h"
23 #include "media/base/browser_cdm_factory.h"
24 #include "media/base/cdm_promise.h"
25 #include "media/base/limits.h"
27 #if defined(OS_ANDROID)
28 #include "content/public/common/renderer_preferences.h"
33 using media::BrowserCdm
;
34 using media::MediaKeys
;
38 #if defined(OS_ANDROID)
39 // Android only supports 128-bit key IDs.
40 const size_t kAndroidKeyIdBytes
= 128 / 8;
43 // The ID used in this class is a concatenation of |render_frame_id| and
44 // |cdm_id|, i.e. (render_frame_id << 32) + cdm_id.
46 uint64
GetId(int render_frame_id
, int cdm_id
) {
47 return (static_cast<uint64
>(render_frame_id
) << 32) +
48 static_cast<uint64
>(cdm_id
);
51 bool IdBelongsToFrame(uint64 id
, int render_frame_id
) {
52 return (id
>> 32) == static_cast<uint64
>(render_frame_id
);
55 // media::CdmPromiseTemplate implementation backed by a BrowserCdmManager.
56 template <typename
... T
>
57 class CdmPromiseInternal
: public media::CdmPromiseTemplate
<T
...> {
59 CdmPromiseInternal(const base::WeakPtr
<BrowserCdmManager
>& manager
,
64 render_frame_id_(render_frame_id
),
66 promise_id_(promise_id
) {
70 ~CdmPromiseInternal() final
{}
72 // CdmPromiseTemplate<> implementation.
73 void resolve(const T
&... result
) final
;
75 void reject(MediaKeys::Exception exception
,
77 const std::string
& error_message
) final
{
80 manager_
->RejectPromise(render_frame_id_
, cdm_id_
, promise_id_
, exception
,
81 system_code
, error_message
);
86 using media::CdmPromiseTemplate
<T
...>::MarkPromiseSettled
;
88 base::WeakPtr
<BrowserCdmManager
> const manager_
;
89 const int render_frame_id_
;
91 const uint32_t promise_id_
;
95 void CdmPromiseInternal
<>::resolve() {
98 manager_
->ResolvePromise(render_frame_id_
, cdm_id_
, promise_id_
);
102 void CdmPromiseInternal
<std::string
>::resolve(const std::string
& session_id
) {
103 MarkPromiseSettled();
105 manager_
->ResolvePromiseWithSession(render_frame_id_
, cdm_id_
, promise_id_
,
110 typedef CdmPromiseInternal
<> SimplePromise
;
111 typedef CdmPromiseInternal
<std::string
> NewSessionPromise
;
113 // Render process ID to BrowserCdmManager map.
114 typedef std::map
<int, BrowserCdmManager
*> BrowserCdmManagerMap
;
115 base::LazyInstance
<BrowserCdmManagerMap
>::Leaky g_browser_cdm_manager_map
=
116 LAZY_INSTANCE_INITIALIZER
;
118 // Keeps the BrowserCdmManager alive, and in the global map, for as long as the
119 // RenderProcessHost is connected to the child process. This class is a
120 // self-owned observer.
121 class BrowserCdmManagerProcessWatcher
: public RenderProcessHostObserver
{
123 BrowserCdmManagerProcessWatcher(
124 int render_process_id
,
125 const scoped_refptr
<BrowserCdmManager
>& manager
)
126 : browser_cdm_manager_(manager
) {
127 RenderProcessHost::FromID(render_process_id
)->AddObserver(this);
128 CHECK(g_browser_cdm_manager_map
.Get()
129 .insert(std::make_pair(render_process_id
, manager
.get()))
133 // RenderProcessHostObserver:
134 void RenderProcessExited(RenderProcessHost
* host
,
135 base::TerminationStatus
/* status */,
136 int /* exit_code */) override
{
137 RemoveHostObserverAndDestroy(host
);
140 void RenderProcessHostDestroyed(RenderProcessHost
* host
) override
{
141 RemoveHostObserverAndDestroy(host
);
145 void RemoveHostObserverAndDestroy(RenderProcessHost
* host
) {
146 CHECK(g_browser_cdm_manager_map
.Get().erase(host
->GetID()));
147 host
->RemoveObserver(this);
151 const scoped_refptr
<BrowserCdmManager
> browser_cdm_manager_
;
157 BrowserCdmManager
* BrowserCdmManager::FromProcess(int render_process_id
) {
158 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
159 auto& map
= g_browser_cdm_manager_map
.Get();
160 auto iterator
= map
.find(render_process_id
);
161 return (iterator
== map
.end()) ? nullptr : iterator
->second
;
164 BrowserCdmManager::BrowserCdmManager(
165 int render_process_id
,
166 const scoped_refptr
<base::TaskRunner
>& task_runner
)
167 : BrowserMessageFilter(CdmMsgStart
),
168 render_process_id_(render_process_id
),
169 task_runner_(task_runner
),
170 weak_ptr_factory_(this) {
171 DVLOG(1) << __FUNCTION__
<< ": " << render_process_id_
;
172 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
174 new BrowserCdmManagerProcessWatcher(render_process_id
, this);
176 if (!task_runner_
.get()) {
178 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI
);
182 BrowserCdmManager::~BrowserCdmManager() {
183 DVLOG(1) << __FUNCTION__
<< ": " << render_process_id_
;
184 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
187 // Makes sure BrowserCdmManager is always deleted on the Browser UI thread.
188 void BrowserCdmManager::OnDestruct() const {
189 DVLOG(1) << __FUNCTION__
<< ": " << render_process_id_
;
190 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
193 BrowserThread::DeleteSoon(BrowserThread::UI
, FROM_HERE
, this);
197 base::TaskRunner
* BrowserCdmManager::OverrideTaskRunnerForMessage(
198 const IPC::Message
& message
) {
199 // Only handles CDM messages.
200 if (IPC_MESSAGE_CLASS(message
) != CdmMsgStart
)
203 return task_runner_
.get();
206 bool BrowserCdmManager::OnMessageReceived(const IPC::Message
& msg
) {
207 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
209 IPC_BEGIN_MESSAGE_MAP(BrowserCdmManager
, msg
)
210 IPC_MESSAGE_HANDLER(CdmHostMsg_InitializeCdm
, OnInitializeCdm
)
211 IPC_MESSAGE_HANDLER(CdmHostMsg_SetServerCertificate
, OnSetServerCertificate
)
212 IPC_MESSAGE_HANDLER(CdmHostMsg_CreateSessionAndGenerateRequest
,
213 OnCreateSessionAndGenerateRequest
)
214 IPC_MESSAGE_HANDLER(CdmHostMsg_LoadSession
, OnLoadSession
)
215 IPC_MESSAGE_HANDLER(CdmHostMsg_UpdateSession
, OnUpdateSession
)
216 IPC_MESSAGE_HANDLER(CdmHostMsg_CloseSession
, OnCloseSession
)
217 IPC_MESSAGE_HANDLER(CdmHostMsg_RemoveSession
, OnRemoveSession
)
218 IPC_MESSAGE_HANDLER(CdmHostMsg_DestroyCdm
, OnDestroyCdm
)
219 IPC_MESSAGE_UNHANDLED(handled
= false)
220 IPC_END_MESSAGE_MAP()
224 media::BrowserCdm
* BrowserCdmManager::GetCdm(int render_frame_id
,
226 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
227 return cdm_map_
.get(GetId(render_frame_id
, cdm_id
));
230 void BrowserCdmManager::RenderFrameDeleted(int render_frame_id
) {
231 if (!task_runner_
->RunsTasksOnCurrentThread()) {
232 task_runner_
->PostTask(
234 base::Bind(&BrowserCdmManager::RemoveAllCdmForFrame
,
235 this, render_frame_id
));
238 RemoveAllCdmForFrame(render_frame_id
);
241 void BrowserCdmManager::ResolvePromise(int render_frame_id
,
243 uint32_t promise_id
) {
244 Send(new CdmMsg_ResolvePromise(render_frame_id
, cdm_id
, promise_id
));
247 void BrowserCdmManager::ResolvePromiseWithSession(
251 const std::string
& session_id
) {
252 if (session_id
.length() > media::limits::kMaxSessionIdLength
) {
253 RejectPromise(render_frame_id
, cdm_id
, promise_id
,
254 MediaKeys::INVALID_ACCESS_ERROR
, 0,
255 "Session ID is too long.");
259 Send(new CdmMsg_ResolvePromiseWithSession(render_frame_id
, cdm_id
, promise_id
,
263 void BrowserCdmManager::RejectPromise(int render_frame_id
,
266 media::MediaKeys::Exception exception
,
267 uint32_t system_code
,
268 const std::string
& error_message
) {
269 Send(new CdmMsg_RejectPromise(render_frame_id
, cdm_id
, promise_id
, exception
,
270 system_code
, error_message
));
273 void BrowserCdmManager::OnSessionMessage(
276 const std::string
& session_id
,
277 media::MediaKeys::MessageType message_type
,
278 const std::vector
<uint8
>& message
,
279 const GURL
& legacy_destination_url
) {
280 GURL verified_gurl
= legacy_destination_url
;
281 if (!verified_gurl
.is_valid() && !verified_gurl
.is_empty()) {
282 DLOG(WARNING
) << "SessionMessage legacy_destination_url is invalid : "
283 << legacy_destination_url
.possibly_invalid_spec();
285 GURL::EmptyGURL(); // Replace invalid legacy_destination_url.
288 Send(new CdmMsg_SessionMessage(render_frame_id
, cdm_id
, session_id
,
289 message_type
, message
, verified_gurl
));
292 void BrowserCdmManager::OnSessionClosed(int render_frame_id
,
294 const std::string
& session_id
) {
295 Send(new CdmMsg_SessionClosed(render_frame_id
, cdm_id
, session_id
));
298 void BrowserCdmManager::OnLegacySessionError(
301 const std::string
& session_id
,
302 MediaKeys::Exception exception_code
,
304 const std::string
& error_message
) {
305 Send(new CdmMsg_LegacySessionError(render_frame_id
, cdm_id
, session_id
,
306 exception_code
, system_code
,
310 void BrowserCdmManager::OnSessionKeysChange(int render_frame_id
,
312 const std::string
& session_id
,
313 bool has_additional_usable_key
,
314 media::CdmKeysInfo keys_info
) {
315 std::vector
<media::CdmKeyInformation
> key_info_vector
;
316 for (const auto& key_info
: keys_info
)
317 key_info_vector
.push_back(*key_info
);
318 Send(new CdmMsg_SessionKeysChange(render_frame_id
, cdm_id
, session_id
,
319 has_additional_usable_key
,
323 void BrowserCdmManager::OnSessionExpirationUpdate(
326 const std::string
& session_id
,
327 const base::Time
& new_expiry_time
) {
328 Send(new CdmMsg_SessionExpirationUpdate(render_frame_id
, cdm_id
, session_id
,
332 void BrowserCdmManager::OnInitializeCdm(
336 const CdmHostMsg_InitializeCdm_Params
& params
) {
337 if (params
.key_system
.size() > media::limits::kMaxKeySystemLength
) {
338 NOTREACHED() << "Invalid key system: " << params
.key_system
;
339 RejectPromise(render_frame_id
, cdm_id
, promise_id
,
340 MediaKeys::INVALID_ACCESS_ERROR
, 0, "Invalid key system.");
344 AddCdm(render_frame_id
, cdm_id
, promise_id
, params
.key_system
,
345 params
.security_origin
, params
.use_hw_secure_codecs
);
348 void BrowserCdmManager::OnSetServerCertificate(
352 const std::vector
<uint8_t>& certificate
) {
353 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
355 scoped_ptr
<SimplePromise
> promise(new SimplePromise(
356 weak_ptr_factory_
.GetWeakPtr(), render_frame_id
, cdm_id
, promise_id
));
358 BrowserCdm
* cdm
= GetCdm(render_frame_id
, cdm_id
);
360 promise
->reject(MediaKeys::INVALID_STATE_ERROR
, 0, "CDM not found.");
364 if (certificate
.empty()) {
365 promise
->reject(MediaKeys::INVALID_ACCESS_ERROR
, 0, "Empty certificate.");
369 cdm
->SetServerCertificate(certificate
, promise
.Pass());
372 void BrowserCdmManager::OnCreateSessionAndGenerateRequest(
373 const CdmHostMsg_CreateSessionAndGenerateRequest_Params
& params
) {
374 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
376 int render_frame_id
= params
.render_frame_id
;
377 int cdm_id
= params
.cdm_id
;
378 const std::vector
<uint8
>& init_data
= params
.init_data
;
379 scoped_ptr
<NewSessionPromise
> promise(
380 new NewSessionPromise(weak_ptr_factory_
.GetWeakPtr(),
381 render_frame_id
, cdm_id
, params
.promise_id
));
383 if (init_data
.size() > media::limits::kMaxInitDataLength
) {
384 LOG(WARNING
) << "InitData for ID: " << cdm_id
385 << " too long: " << init_data
.size();
386 promise
->reject(MediaKeys::INVALID_ACCESS_ERROR
, 0, "Init data too long.");
389 #if defined(OS_ANDROID)
390 // 'webm' initData is a single key ID. On Android the length is restricted.
391 if (params
.init_data_type
== INIT_DATA_TYPE_WEBM
&&
392 init_data
.size() != kAndroidKeyIdBytes
) {
393 promise
->reject(MediaKeys::INVALID_ACCESS_ERROR
, 0,
394 "'webm' initData is not the correct length.");
399 media::EmeInitDataType eme_init_data_type
;
400 switch (params
.init_data_type
) {
401 case INIT_DATA_TYPE_WEBM
:
402 eme_init_data_type
= media::EmeInitDataType::WEBM
;
404 #if defined(USE_PROPRIETARY_CODECS)
405 case INIT_DATA_TYPE_CENC
:
406 eme_init_data_type
= media::EmeInitDataType::CENC
;
411 promise
->reject(MediaKeys::INVALID_ACCESS_ERROR
, 0,
412 "Invalid init data type.");
416 BrowserCdm
* cdm
= GetCdm(render_frame_id
, cdm_id
);
418 DLOG(WARNING
) << "No CDM found for: " << render_frame_id
<< ", " << cdm_id
;
419 promise
->reject(MediaKeys::INVALID_STATE_ERROR
, 0, "CDM not found.");
423 CheckPermissionStatus(
424 render_frame_id
, cdm_id
,
425 base::Bind(&BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted
,
426 this, render_frame_id
, cdm_id
, params
.session_type
,
427 eme_init_data_type
, init_data
, base::Passed(&promise
)));
430 void BrowserCdmManager::OnLoadSession(
434 media::MediaKeys::SessionType session_type
,
435 const std::string
& session_id
) {
436 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
438 scoped_ptr
<NewSessionPromise
> promise(new NewSessionPromise(
439 weak_ptr_factory_
.GetWeakPtr(), render_frame_id
, cdm_id
, promise_id
));
441 BrowserCdm
* cdm
= GetCdm(render_frame_id
, cdm_id
);
443 DLOG(WARNING
) << "No CDM found for: " << render_frame_id
<< ", " << cdm_id
;
444 promise
->reject(MediaKeys::INVALID_STATE_ERROR
, 0, "CDM not found.");
448 CheckPermissionStatus(
449 render_frame_id
, cdm_id
,
450 base::Bind(&BrowserCdmManager::LoadSessionIfPermitted
,
451 this, render_frame_id
, cdm_id
, session_type
,
452 session_id
, base::Passed(&promise
)));
455 void BrowserCdmManager::OnUpdateSession(int render_frame_id
,
458 const std::string
& session_id
,
459 const std::vector
<uint8
>& response
) {
460 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
462 scoped_ptr
<SimplePromise
> promise(new SimplePromise(
463 weak_ptr_factory_
.GetWeakPtr(), render_frame_id
, cdm_id
, promise_id
));
465 BrowserCdm
* cdm
= GetCdm(render_frame_id
, cdm_id
);
467 promise
->reject(MediaKeys::INVALID_STATE_ERROR
, 0, "CDM not found.");
471 if (response
.size() > media::limits::kMaxSessionResponseLength
) {
472 LOG(WARNING
) << "Response for ID " << cdm_id
473 << " is too long: " << response
.size();
474 promise
->reject(MediaKeys::INVALID_ACCESS_ERROR
, 0, "Response too long.");
478 if (response
.empty()) {
479 promise
->reject(MediaKeys::INVALID_ACCESS_ERROR
, 0, "Response is empty.");
483 cdm
->UpdateSession(session_id
, response
, promise
.Pass());
486 void BrowserCdmManager::OnCloseSession(int render_frame_id
,
489 const std::string
& session_id
) {
490 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
492 scoped_ptr
<SimplePromise
> promise(new SimplePromise(
493 weak_ptr_factory_
.GetWeakPtr(), render_frame_id
, cdm_id
, promise_id
));
495 BrowserCdm
* cdm
= GetCdm(render_frame_id
, cdm_id
);
497 promise
->reject(MediaKeys::INVALID_STATE_ERROR
, 0, "CDM not found.");
501 cdm
->CloseSession(session_id
, promise
.Pass());
504 void BrowserCdmManager::OnRemoveSession(int render_frame_id
,
507 const std::string
& session_id
) {
508 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
510 scoped_ptr
<SimplePromise
> promise(new SimplePromise(
511 weak_ptr_factory_
.GetWeakPtr(), render_frame_id
, cdm_id
, promise_id
));
513 BrowserCdm
* cdm
= GetCdm(render_frame_id
, cdm_id
);
515 promise
->reject(MediaKeys::INVALID_STATE_ERROR
, 0, "CDM not found.");
519 cdm
->RemoveSession(session_id
, promise
.Pass());
522 void BrowserCdmManager::OnDestroyCdm(int render_frame_id
, int cdm_id
) {
523 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
524 RemoveCdm(GetId(render_frame_id
, cdm_id
));
527 // Use a weak pointer here instead of |this| to avoid circular references.
528 #define BROWSER_CDM_MANAGER_CB(func) \
529 base::Bind(&BrowserCdmManager::func, weak_ptr_factory_.GetWeakPtr(), \
530 render_frame_id, cdm_id)
532 void BrowserCdmManager::AddCdm(int render_frame_id
,
535 const std::string
& key_system
,
536 const GURL
& security_origin
,
537 bool use_hw_secure_codecs
) {
538 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
539 DCHECK(!GetCdm(render_frame_id
, cdm_id
));
541 scoped_ptr
<SimplePromise
> promise(new SimplePromise(
542 weak_ptr_factory_
.GetWeakPtr(), render_frame_id
, cdm_id
, promise_id
));
544 scoped_ptr
<BrowserCdm
> cdm(media::CreateBrowserCdm(
545 key_system
, use_hw_secure_codecs
,
546 BROWSER_CDM_MANAGER_CB(OnSessionMessage
),
547 BROWSER_CDM_MANAGER_CB(OnSessionClosed
),
548 BROWSER_CDM_MANAGER_CB(OnLegacySessionError
),
549 BROWSER_CDM_MANAGER_CB(OnSessionKeysChange
),
550 BROWSER_CDM_MANAGER_CB(OnSessionExpirationUpdate
)));
553 DVLOG(1) << "failed to create CDM.";
554 promise
->reject(MediaKeys::INVALID_STATE_ERROR
, 0, "Failed to create CDM.");
558 uint64 id
= GetId(render_frame_id
, cdm_id
);
559 cdm_map_
.add(id
, cdm
.Pass());
560 cdm_security_origin_map_
[id
] = security_origin
;
564 void BrowserCdmManager::RemoveAllCdmForFrame(int render_frame_id
) {
565 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
567 std::vector
<uint64
> ids_to_remove
;
568 for (CdmMap::iterator it
= cdm_map_
.begin(); it
!= cdm_map_
.end(); ++it
) {
569 if (IdBelongsToFrame(it
->first
, render_frame_id
))
570 ids_to_remove
.push_back(it
->first
);
573 for (size_t i
= 0; i
< ids_to_remove
.size(); ++i
)
574 RemoveCdm(ids_to_remove
[i
]);
577 void BrowserCdmManager::RemoveCdm(uint64 id
) {
578 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
581 cdm_security_origin_map_
.erase(id
);
584 void BrowserCdmManager::CheckPermissionStatus(
587 const PermissionStatusCB
& permission_status_cb
) {
588 // Always called on |task_runner_|, which may not be on the UI thread.
589 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
591 GURL security_origin
;
592 std::map
<uint64
, GURL
>::const_iterator iter
=
593 cdm_security_origin_map_
.find(GetId(render_frame_id
, cdm_id
));
594 DCHECK(iter
!= cdm_security_origin_map_
.end());
595 if (iter
!= cdm_security_origin_map_
.end())
596 security_origin
= iter
->second
;
598 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
599 BrowserThread::PostTask(
600 BrowserThread::UI
, FROM_HERE
,
601 base::Bind(&BrowserCdmManager::CheckPermissionStatusOnUIThread
, this,
602 render_frame_id
, security_origin
, permission_status_cb
));
604 CheckPermissionStatusOnUIThread(render_frame_id
, security_origin
,
605 permission_status_cb
);
609 // Note: This function runs on the UI thread, which may be different from
610 // |task_runner_|. Be careful about thread safety!
611 void BrowserCdmManager::CheckPermissionStatusOnUIThread(
613 const GURL
& security_origin
,
614 const base::Callback
<void(bool)>& permission_status_cb
) {
615 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
617 RenderFrameHost
* rfh
=
618 RenderFrameHost::FromID(render_process_id_
, render_frame_id
);
619 WebContents
* web_contents
= WebContents::FromRenderFrameHost(rfh
);
620 PermissionManager
* permission_manager
=
621 web_contents
->GetBrowserContext()->GetPermissionManager();
622 if (!permission_manager
) {
623 permission_status_cb
.Run(false);
627 PermissionStatus permission_status
= permission_manager
->GetPermissionStatus(
628 PermissionType::PROTECTED_MEDIA_IDENTIFIER
, security_origin
,
629 web_contents
->GetLastCommittedURL().GetOrigin());
631 bool allowed
= (permission_status
== PERMISSION_STATUS_GRANTED
);
632 if (!task_runner_
->RunsTasksOnCurrentThread()) {
633 task_runner_
->PostTask(FROM_HERE
,
634 base::Bind(permission_status_cb
, allowed
));
636 permission_status_cb
.Run(allowed
);
640 void BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted(
643 media::MediaKeys::SessionType session_type
,
644 media::EmeInitDataType init_data_type
,
645 const std::vector
<uint8
>& init_data
,
646 scoped_ptr
<media::NewSessionCdmPromise
> promise
,
647 bool permission_was_allowed
) {
648 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
650 if (!permission_was_allowed
) {
651 promise
->reject(MediaKeys::NOT_SUPPORTED_ERROR
, 0, "Permission denied.");
655 BrowserCdm
* cdm
= GetCdm(render_frame_id
, cdm_id
);
657 promise
->reject(MediaKeys::INVALID_STATE_ERROR
, 0, "CDM not found.");
661 cdm
->CreateSessionAndGenerateRequest(session_type
, init_data_type
,
662 init_data
, promise
.Pass());
665 void BrowserCdmManager::LoadSessionIfPermitted(
668 media::MediaKeys::SessionType session_type
,
669 const std::string
& session_id
,
670 scoped_ptr
<media::NewSessionCdmPromise
> promise
,
671 bool permission_was_allowed
) {
672 DCHECK_NE(media::MediaKeys::SessionType::TEMPORARY_SESSION
, session_type
);
673 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
675 if (!permission_was_allowed
) {
676 promise
->reject(MediaKeys::NOT_SUPPORTED_ERROR
, 0, "Permission denied.");
680 BrowserCdm
* cdm
= GetCdm(render_frame_id
, cdm_id
);
682 promise
->reject(MediaKeys::INVALID_STATE_ERROR
, 0, "CDM not found.");
686 cdm
->LoadSession(session_type
, session_id
, promise
.Pass());
689 } // namespace content