blob: 2f997d078cab44930716cb60510a15ff8b7c50f4 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/media/cdm/browser_cdm_manager.h"
#include <stddef.h>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h"
#include "base/task_runner.h"
#include "build/build_config.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/permission_manager.h"
#include "content/public/browser/permission_type.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/web_contents.h"
#include "media/base/cdm_config.h"
#include "media/base/cdm_factory.h"
#include "media/base/cdm_promise.h"
#include "media/base/limits.h"
#if defined(OS_ANDROID)
#include "content/public/browser/android/provision_fetcher_factory.h"
#include "content/public/common/renderer_preferences.h"
#include "media/base/android/android_cdm_factory.h"
#endif
namespace content {
using media::MediaKeys;
namespace {
#if defined(OS_ANDROID)
// Android only supports 128-bit key IDs.
const size_t kAndroidKeyIdBytes = 128 / 8;
#endif
// The ID used in this class is a concatenation of |render_frame_id| and
// |cdm_id|, i.e. (render_frame_id << 32) + cdm_id.
uint64_t GetId(int render_frame_id, int cdm_id) {
return (static_cast<uint64_t>(render_frame_id) << 32) +
static_cast<uint64_t>(cdm_id);
}
bool IdBelongsToFrame(uint64_t id, int render_frame_id) {
return (id >> 32) == static_cast<uint64_t>(render_frame_id);
}
// media::CdmPromiseTemplate implementation backed by a BrowserCdmManager.
template <typename... T>
class CdmPromiseInternal : public media::CdmPromiseTemplate<T...> {
public:
CdmPromiseInternal(const base::WeakPtr<BrowserCdmManager>& manager,
int render_frame_id,
int cdm_id,
uint32_t promise_id)
: manager_(manager),
render_frame_id_(render_frame_id),
cdm_id_(cdm_id),
promise_id_(promise_id) {
DCHECK(manager_);
}
~CdmPromiseInternal() final {}
// CdmPromiseTemplate<> implementation.
void resolve(const T&... result) final;
void reject(MediaKeys::Exception exception,
uint32_t system_code,
const std::string& error_message) final {
MarkPromiseSettled();
if (manager_) {
manager_->RejectPromise(render_frame_id_, cdm_id_, promise_id_, exception,
system_code, error_message);
}
}
private:
using media::CdmPromiseTemplate<T...>::MarkPromiseSettled;
base::WeakPtr<BrowserCdmManager> const manager_;
const int render_frame_id_;
const int cdm_id_;
const uint32_t promise_id_;
};
template <>
void CdmPromiseInternal<>::resolve() {
MarkPromiseSettled();
if (manager_)
manager_->ResolvePromise(render_frame_id_, cdm_id_, promise_id_);
}
template <>
void CdmPromiseInternal<std::string>::resolve(const std::string& session_id) {
MarkPromiseSettled();
if (manager_) {
manager_->ResolvePromiseWithSession(render_frame_id_, cdm_id_, promise_id_,
session_id);
}
}
typedef CdmPromiseInternal<> SimplePromise;
typedef CdmPromiseInternal<std::string> NewSessionPromise;
// Render process ID to BrowserCdmManager map.
typedef std::map<int, BrowserCdmManager*> BrowserCdmManagerMap;
base::LazyInstance<BrowserCdmManagerMap>::Leaky g_browser_cdm_manager_map =
LAZY_INSTANCE_INITIALIZER;
// Keeps the BrowserCdmManager alive, and in the global map, for as long as the
// RenderProcessHost is connected to the child process. This class is a
// self-owned observer.
class BrowserCdmManagerProcessWatcher : public RenderProcessHostObserver {
public:
BrowserCdmManagerProcessWatcher(
int render_process_id,
const scoped_refptr<BrowserCdmManager>& manager)
: browser_cdm_manager_(manager) {
RenderProcessHost::FromID(render_process_id)->AddObserver(this);
CHECK(g_browser_cdm_manager_map.Get()
.insert(std::make_pair(render_process_id, manager.get()))
.second);
}
// RenderProcessHostObserver:
void RenderProcessExited(RenderProcessHost* host,
base::TerminationStatus /* status */,
int /* exit_code */) override {
RemoveHostObserverAndDestroy(host);
}
void RenderProcessHostDestroyed(RenderProcessHost* host) override {
RemoveHostObserverAndDestroy(host);
}
private:
void RemoveHostObserverAndDestroy(RenderProcessHost* host) {
CHECK(g_browser_cdm_manager_map.Get().erase(host->GetID()));
host->RemoveObserver(this);
delete this;
}
const scoped_refptr<BrowserCdmManager> browser_cdm_manager_;
};
} // namespace
// static
BrowserCdmManager* BrowserCdmManager::FromProcess(int render_process_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto& map = g_browser_cdm_manager_map.Get();
auto iterator = map.find(render_process_id);
return (iterator == map.end()) ? nullptr : iterator->second;
}
BrowserCdmManager::BrowserCdmManager(
int render_process_id,
const scoped_refptr<base::TaskRunner>& task_runner)
: BrowserMessageFilter(CdmMsgStart),
render_process_id_(render_process_id),
task_runner_(task_runner),
weak_ptr_factory_(this) {
DVLOG(1) << __FUNCTION__ << ": " << render_process_id_;
DCHECK_CURRENTLY_ON(BrowserThread::UI);
new BrowserCdmManagerProcessWatcher(render_process_id, this);
if (!task_runner_.get()) {
task_runner_ =
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
}
}
BrowserCdmManager::~BrowserCdmManager() {
DVLOG(1) << __FUNCTION__ << ": " << render_process_id_;
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
// Makes sure BrowserCdmManager is always deleted on the Browser UI thread.
void BrowserCdmManager::OnDestruct() const {
DVLOG(1) << __FUNCTION__ << ": " << render_process_id_;
if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
delete this;
} else {
BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
}
}
base::TaskRunner* BrowserCdmManager::OverrideTaskRunnerForMessage(
const IPC::Message& message) {
// Only handles CDM messages.
if (IPC_MESSAGE_CLASS(message) != CdmMsgStart)
return NULL;
return task_runner_.get();
}
bool BrowserCdmManager::OnMessageReceived(const IPC::Message& msg) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(BrowserCdmManager, msg)
IPC_MESSAGE_HANDLER(CdmHostMsg_InitializeCdm, OnInitializeCdm)
IPC_MESSAGE_HANDLER(CdmHostMsg_SetServerCertificate, OnSetServerCertificate)
IPC_MESSAGE_HANDLER(CdmHostMsg_CreateSessionAndGenerateRequest,
OnCreateSessionAndGenerateRequest)
IPC_MESSAGE_HANDLER(CdmHostMsg_LoadSession, OnLoadSession)
IPC_MESSAGE_HANDLER(CdmHostMsg_UpdateSession, OnUpdateSession)
IPC_MESSAGE_HANDLER(CdmHostMsg_CloseSession, OnCloseSession)
IPC_MESSAGE_HANDLER(CdmHostMsg_RemoveSession, OnRemoveSession)
IPC_MESSAGE_HANDLER(CdmHostMsg_DestroyCdm, OnDestroyCdm)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
scoped_refptr<MediaKeys> BrowserCdmManager::GetCdm(int render_frame_id,
int cdm_id) const {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
const auto& iter = cdm_map_.find(GetId(render_frame_id, cdm_id));
return iter == cdm_map_.end() ? nullptr : iter->second;
}
void BrowserCdmManager::RenderFrameDeleted(int render_frame_id) {
if (!task_runner_->RunsTasksOnCurrentThread()) {
task_runner_->PostTask(
FROM_HERE,
base::Bind(&BrowserCdmManager::RemoveAllCdmForFrame,
this, render_frame_id));
return;
}
RemoveAllCdmForFrame(render_frame_id);
}
void BrowserCdmManager::ResolvePromise(int render_frame_id,
int cdm_id,
uint32_t promise_id) {
Send(new CdmMsg_ResolvePromise(render_frame_id, cdm_id, promise_id));
}
void BrowserCdmManager::ResolvePromiseWithSession(
int render_frame_id,
int cdm_id,
uint32_t promise_id,
const std::string& session_id) {
if (session_id.length() > media::limits::kMaxSessionIdLength) {
RejectPromise(render_frame_id, cdm_id, promise_id,
MediaKeys::INVALID_ACCESS_ERROR, 0,
"Session ID is too long.");
return;
}
Send(new CdmMsg_ResolvePromiseWithSession(render_frame_id, cdm_id, promise_id,
session_id));
}
void BrowserCdmManager::RejectPromise(int render_frame_id,
int cdm_id,
uint32_t promise_id,
MediaKeys::Exception exception,
uint32_t system_code,
const std::string& error_message) {
Send(new CdmMsg_RejectPromise(render_frame_id, cdm_id, promise_id, exception,
system_code, error_message));
}
media::CdmFactory* BrowserCdmManager::GetCdmFactory() {
if (!cdm_factory_) {
// Create a new CdmFactory.
cdm_factory_ = GetContentClient()->browser()->CreateCdmFactory();
#if defined(OS_ANDROID)
if (!cdm_factory_) {
// Obtain http request context for the current render process.
net::URLRequestContextGetter* context_getter =
RenderProcessHost::FromID(render_process_id_)
->GetBrowserContext()
->GetRequestContext();
DCHECK(context_getter);
cdm_factory_.reset(new media::AndroidCdmFactory(
base::Bind(&CreateProvisionFetcher, context_getter)));
}
#endif
}
return cdm_factory_.get();
}
void BrowserCdmManager::OnSessionMessage(int render_frame_id,
int cdm_id,
const std::string& session_id,
MediaKeys::MessageType message_type,
const std::vector<uint8_t>& message,
const GURL& legacy_destination_url) {
GURL verified_gurl = legacy_destination_url;
if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) {
DLOG(WARNING) << "SessionMessage legacy_destination_url is invalid : "
<< legacy_destination_url.possibly_invalid_spec();
verified_gurl =
GURL::EmptyGURL(); // Replace invalid legacy_destination_url.
}
Send(new CdmMsg_SessionMessage(render_frame_id, cdm_id, session_id,
message_type, message, verified_gurl));
}
void BrowserCdmManager::OnSessionClosed(int render_frame_id,
int cdm_id,
const std::string& session_id) {
Send(new CdmMsg_SessionClosed(render_frame_id, cdm_id, session_id));
}
void BrowserCdmManager::OnLegacySessionError(
int render_frame_id,
int cdm_id,
const std::string& session_id,
MediaKeys::Exception exception_code,
uint32_t system_code,
const std::string& error_message) {
Send(new CdmMsg_LegacySessionError(render_frame_id, cdm_id, session_id,
exception_code, system_code,
error_message));
}
void BrowserCdmManager::OnSessionKeysChange(int render_frame_id,
int cdm_id,
const std::string& session_id,
bool has_additional_usable_key,
media::CdmKeysInfo keys_info) {
std::vector<media::CdmKeyInformation> key_info_vector;
for (const auto& key_info : keys_info)
key_info_vector.push_back(*key_info);
Send(new CdmMsg_SessionKeysChange(render_frame_id, cdm_id, session_id,
has_additional_usable_key,
key_info_vector));
}
void BrowserCdmManager::OnSessionExpirationUpdate(
int render_frame_id,
int cdm_id,
const std::string& session_id,
const base::Time& new_expiry_time) {
Send(new CdmMsg_SessionExpirationUpdate(render_frame_id, cdm_id, session_id,
new_expiry_time));
}
// Use a weak pointer here instead of |this| to avoid circular references.
#define BROWSER_CDM_MANAGER_CB(func, ...) \
base::Bind(&BrowserCdmManager::func, weak_ptr_factory_.GetWeakPtr(), \
render_frame_id, cdm_id, ##__VA_ARGS__)
void BrowserCdmManager::OnInitializeCdm(
int render_frame_id,
int cdm_id,
uint32_t promise_id,
const CdmHostMsg_InitializeCdm_Params& params) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
DCHECK(!GetCdm(render_frame_id, cdm_id));
scoped_ptr<SimplePromise> promise(new SimplePromise(
weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
if (params.key_system.size() > media::limits::kMaxKeySystemLength) {
NOTREACHED() << "Invalid key system: " << params.key_system;
promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Invalid key system.");
return;
}
if (!GetCdmFactory()) {
NOTREACHED() << "CDM not supported.";
promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "CDM not supported.");
return;
}
// The render process makes sure |allow_distinctive_identifier| and
// |allow_persistent_state| are true. See RenderCdmFactory::Create().
// TODO(xhwang): Pass |allow_distinctive_identifier| and
// |allow_persistent_state| from the render process.
media::CdmConfig cdm_config;
cdm_config.allow_distinctive_identifier = true;
cdm_config.allow_persistent_state = true;
cdm_config.use_hw_secure_codecs = params.use_hw_secure_codecs;
GetCdmFactory()->Create(
params.key_system, params.security_origin, cdm_config,
BROWSER_CDM_MANAGER_CB(OnSessionMessage),
BROWSER_CDM_MANAGER_CB(OnSessionClosed),
BROWSER_CDM_MANAGER_CB(OnLegacySessionError),
BROWSER_CDM_MANAGER_CB(OnSessionKeysChange),
BROWSER_CDM_MANAGER_CB(OnSessionExpirationUpdate),
BROWSER_CDM_MANAGER_CB(OnCdmCreated, params.security_origin,
base::Passed(&promise)));
}
void BrowserCdmManager::OnSetServerCertificate(
int render_frame_id,
int cdm_id,
uint32_t promise_id,
const std::vector<uint8_t>& certificate) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
scoped_ptr<SimplePromise> promise(new SimplePromise(
weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
return;
}
if (certificate.empty()) {
promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Empty certificate.");
return;
}
cdm->SetServerCertificate(certificate, std::move(promise));
}
void BrowserCdmManager::OnCreateSessionAndGenerateRequest(
const CdmHostMsg_CreateSessionAndGenerateRequest_Params& params) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
int render_frame_id = params.render_frame_id;
int cdm_id = params.cdm_id;
const std::vector<uint8_t>& init_data = params.init_data;
scoped_ptr<NewSessionPromise> promise(
new NewSessionPromise(weak_ptr_factory_.GetWeakPtr(),
render_frame_id, cdm_id, params.promise_id));
if (init_data.size() > media::limits::kMaxInitDataLength) {
LOG(WARNING) << "InitData for ID: " << cdm_id
<< " too long: " << init_data.size();
promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Init data too long.");
return;
}
#if defined(OS_ANDROID)
// 'webm' initData is a single key ID. On Android the length is restricted.
if (params.init_data_type == INIT_DATA_TYPE_WEBM &&
init_data.size() != kAndroidKeyIdBytes) {
promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0,
"'webm' initData is not the correct length.");
return;
}
#endif
media::EmeInitDataType eme_init_data_type;
switch (params.init_data_type) {
case INIT_DATA_TYPE_WEBM:
eme_init_data_type = media::EmeInitDataType::WEBM;
break;
#if defined(USE_PROPRIETARY_CODECS)
case INIT_DATA_TYPE_CENC:
eme_init_data_type = media::EmeInitDataType::CENC;
break;
#endif
default:
NOTREACHED();
promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0,
"Invalid init data type.");
return;
}
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
return;
}
CheckPermissionStatus(
render_frame_id, cdm_id,
base::Bind(&BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted,
this, render_frame_id, cdm_id, params.session_type,
eme_init_data_type, init_data, base::Passed(&promise)));
}
void BrowserCdmManager::OnLoadSession(
int render_frame_id,
int cdm_id,
uint32_t promise_id,
media::MediaKeys::SessionType session_type,
const std::string& session_id) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
scoped_ptr<NewSessionPromise> promise(new NewSessionPromise(
weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
return;
}
CheckPermissionStatus(
render_frame_id, cdm_id,
base::Bind(&BrowserCdmManager::LoadSessionIfPermitted,
this, render_frame_id, cdm_id, session_type,
session_id, base::Passed(&promise)));
}
void BrowserCdmManager::OnUpdateSession(int render_frame_id,
int cdm_id,
uint32_t promise_id,
const std::string& session_id,
const std::vector<uint8_t>& response) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
scoped_ptr<SimplePromise> promise(new SimplePromise(
weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
return;
}
if (response.size() > media::limits::kMaxSessionResponseLength) {
LOG(WARNING) << "Response for ID " << cdm_id
<< " is too long: " << response.size();
promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response too long.");
return;
}
if (response.empty()) {
promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response is empty.");
return;
}
cdm->UpdateSession(session_id, response, std::move(promise));
}
void BrowserCdmManager::OnCloseSession(int render_frame_id,
int cdm_id,
uint32_t promise_id,
const std::string& session_id) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
scoped_ptr<SimplePromise> promise(new SimplePromise(
weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
return;
}
cdm->CloseSession(session_id, std::move(promise));
}
void BrowserCdmManager::OnRemoveSession(int render_frame_id,
int cdm_id,
uint32_t promise_id,
const std::string& session_id) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
scoped_ptr<SimplePromise> promise(new SimplePromise(
weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
return;
}
cdm->RemoveSession(session_id, std::move(promise));
}
void BrowserCdmManager::OnDestroyCdm(int render_frame_id, int cdm_id) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
RemoveCdm(GetId(render_frame_id, cdm_id));
}
void BrowserCdmManager::OnCdmCreated(
int render_frame_id,
int cdm_id,
const GURL& security_origin,
scoped_ptr<media::SimpleCdmPromise> promise,
const scoped_refptr<media::MediaKeys>& cdm,
const std::string& error_message) {
if (!cdm) {
DVLOG(1) << "Failed to create CDM: " << error_message;
promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, error_message);
return;
}
uint64_t id = GetId(render_frame_id, cdm_id);
cdm_map_[id] = cdm;
cdm_security_origin_map_[id] = security_origin;
promise->resolve();
}
void BrowserCdmManager::RemoveAllCdmForFrame(int render_frame_id) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
std::vector<uint64_t> ids_to_remove;
for (const auto& entry : cdm_map_) {
if (IdBelongsToFrame(entry.first, render_frame_id))
ids_to_remove.push_back(entry.first);
}
for (const auto& id_to_remove : ids_to_remove)
RemoveCdm(id_to_remove);
}
void BrowserCdmManager::RemoveCdm(uint64_t id) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
cdm_map_.erase(id);
cdm_security_origin_map_.erase(id);
}
void BrowserCdmManager::CheckPermissionStatus(
int render_frame_id,
int cdm_id,
const PermissionStatusCB& permission_status_cb) {
// Always called on |task_runner_|, which may not be on the UI thread.
DCHECK(task_runner_->RunsTasksOnCurrentThread());
GURL security_origin;
std::map<uint64_t, GURL>::const_iterator iter =
cdm_security_origin_map_.find(GetId(render_frame_id, cdm_id));
DCHECK(iter != cdm_security_origin_map_.end());
if (iter != cdm_security_origin_map_.end())
security_origin = iter->second;
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&BrowserCdmManager::CheckPermissionStatusOnUIThread, this,
render_frame_id, security_origin, permission_status_cb));
} else {
CheckPermissionStatusOnUIThread(render_frame_id, security_origin,
permission_status_cb);
}
}
// Note: This function runs on the UI thread, which may be different from
// |task_runner_|. Be careful about thread safety!
void BrowserCdmManager::CheckPermissionStatusOnUIThread(
int render_frame_id,
const GURL& security_origin,
const base::Callback<void(bool)>& permission_status_cb) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderFrameHost* rfh =
RenderFrameHost::FromID(render_process_id_, render_frame_id);
WebContents* web_contents = WebContents::FromRenderFrameHost(rfh);
PermissionManager* permission_manager =
web_contents->GetBrowserContext()->GetPermissionManager();
if (!permission_manager) {
permission_status_cb.Run(false);
return;
}
PermissionStatus permission_status = permission_manager->GetPermissionStatus(
PermissionType::PROTECTED_MEDIA_IDENTIFIER, security_origin,
web_contents->GetLastCommittedURL().GetOrigin());
bool allowed = (permission_status == PERMISSION_STATUS_GRANTED);
if (!task_runner_->RunsTasksOnCurrentThread()) {
task_runner_->PostTask(FROM_HERE,
base::Bind(permission_status_cb, allowed));
} else {
permission_status_cb.Run(allowed);
}
}
void BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted(
int render_frame_id,
int cdm_id,
media::MediaKeys::SessionType session_type,
media::EmeInitDataType init_data_type,
const std::vector<uint8_t>& init_data,
scoped_ptr<media::NewSessionCdmPromise> promise,
bool permission_was_allowed) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
if (!permission_was_allowed) {
promise->reject(MediaKeys::NOT_SUPPORTED_ERROR, 0, "Permission denied.");
return;
}
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
return;
}
cdm->CreateSessionAndGenerateRequest(session_type, init_data_type, init_data,
std::move(promise));
}
void BrowserCdmManager::LoadSessionIfPermitted(
int render_frame_id,
int cdm_id,
media::MediaKeys::SessionType session_type,
const std::string& session_id,
scoped_ptr<media::NewSessionCdmPromise> promise,
bool permission_was_allowed) {
DCHECK_NE(media::MediaKeys::SessionType::TEMPORARY_SESSION, session_type);
DCHECK(task_runner_->RunsTasksOnCurrentThread());
if (!permission_was_allowed) {
promise->reject(MediaKeys::NOT_SUPPORTED_ERROR, 0, "Permission denied.");
return;
}
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
return;
}
cdm->LoadSession(session_type, session_id, std::move(promise));
}
} // namespace content