blob: 2676ec342d44858c4e5ba63af3af10d0606ea48b [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/media/media_permission_dispatcher.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/task/bind_post_task.h"
#include "base/task/single_thread_task_runner.h"
#include "base/types/cxx23_to_underlying.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "url/gurl.h"
#if BUILDFLAG(IS_WIN)
#include "base/functional/callback_forward.h"
#endif // BUILDFLAG(IS_WIN)
namespace {
using Type = media::MediaPermission::Type;
blink::mojom::PermissionDescriptorPtr MediaPermissionTypeToPermissionDescriptor(
Type type) {
auto descriptor = blink::mojom::PermissionDescriptor::New();
switch (type) {
case Type::kProtectedMediaIdentifier:
descriptor->name =
blink::mojom::PermissionName::PROTECTED_MEDIA_IDENTIFIER;
break;
case Type::kAudioCapture:
descriptor->name = blink::mojom::PermissionName::AUDIO_CAPTURE;
break;
case Type::kVideoCapture:
descriptor->name = blink::mojom::PermissionName::VIDEO_CAPTURE;
break;
default:
NOTREACHED() << base::to_underlying(type);
}
return descriptor;
}
} // namespace
namespace content {
MediaPermissionDispatcher::MediaPermissionDispatcher(
RenderFrameImpl* render_frame)
: task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()),
next_request_id_(0),
render_frame_(render_frame) {
DCHECK(render_frame_);
weak_ptr_ = weak_factory_.GetWeakPtr();
}
MediaPermissionDispatcher::~MediaPermissionDispatcher() {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
// Clean up pending requests.
OnPermissionServiceConnectionError();
}
void MediaPermissionDispatcher::OnNavigation() {
// Behave as if there were a connection error. The browser process will be
// closing the connection imminently.
OnPermissionServiceConnectionError();
}
void MediaPermissionDispatcher::HasPermission(
Type type,
PermissionStatusCB permission_status_cb) {
if (!task_runner_->RunsTasksInCurrentSequence()) {
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&MediaPermissionDispatcher::HasPermission,
weak_ptr_, type,
base::BindPostTaskToCurrentDefault(
std::move(permission_status_cb))));
return;
}
DCHECK(task_runner_->RunsTasksInCurrentSequence());
int request_id = RegisterCallback(std::move(permission_status_cb));
DVLOG(2) << __func__ << ": request ID " << request_id;
GetPermissionService()->HasPermission(
MediaPermissionTypeToPermissionDescriptor(type),
base::BindOnce(&MediaPermissionDispatcher::OnPermissionStatus, weak_ptr_,
request_id));
}
void MediaPermissionDispatcher::RequestPermission(
Type type,
PermissionStatusCB permission_status_cb) {
if (!task_runner_->RunsTasksInCurrentSequence()) {
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&MediaPermissionDispatcher::RequestPermission,
weak_ptr_, type,
base::BindPostTaskToCurrentDefault(
std::move(permission_status_cb))));
return;
}
DCHECK(task_runner_->RunsTasksInCurrentSequence());
int request_id = RegisterCallback(std::move(permission_status_cb));
DVLOG(2) << __func__ << ": request ID " << request_id;
GetPermissionService()->RequestPermission(
MediaPermissionTypeToPermissionDescriptor(type),
render_frame_->GetWebFrame()->HasTransientUserActivation(),
base::BindOnce(&MediaPermissionDispatcher::OnPermissionStatus, weak_ptr_,
request_id));
}
bool MediaPermissionDispatcher::IsEncryptedMediaEnabled() {
return render_frame_->GetRendererPreferences().enable_encrypted_media;
}
uint32_t MediaPermissionDispatcher::RegisterCallback(
PermissionStatusCB permission_status_cb) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
uint32_t request_id = next_request_id_++;
DCHECK(!requests_.count(request_id));
requests_[request_id] = std::move(permission_status_cb);
return request_id;
}
blink::mojom::PermissionService*
MediaPermissionDispatcher::GetPermissionService() {
if (!permission_service_) {
render_frame_->GetBrowserInterfaceBroker().GetInterface(
permission_service_.BindNewPipeAndPassReceiver());
permission_service_.set_disconnect_handler(base::BindOnce(
&MediaPermissionDispatcher::OnPermissionServiceConnectionError,
base::Unretained(this)));
}
return permission_service_.get();
}
void MediaPermissionDispatcher::OnPermissionStatus(
uint32_t request_id,
blink::mojom::PermissionStatus status) {
DVLOG(2) << __func__ << ": (" << request_id << ", " << status << ")";
DCHECK(task_runner_->RunsTasksInCurrentSequence());
auto iter = requests_.find(request_id);
CHECK(iter != requests_.end());
PermissionStatusCB permission_status_cb = std::move(iter->second);
requests_.erase(iter);
std::move(permission_status_cb)
.Run(status == blink::mojom::PermissionStatus::GRANTED);
}
#if BUILDFLAG(IS_WIN)
void MediaPermissionDispatcher::IsHardwareSecureDecryptionAllowed(
IsHardwareSecureDecryptionAllowedCB cb) {
GetMediaFoundationPreferences()->IsHardwareSecureDecryptionAllowed(
std::move(cb));
}
media::mojom::MediaFoundationPreferences*
MediaPermissionDispatcher::GetMediaFoundationPreferences() {
if (!mf_preferences_) {
render_frame_->GetBrowserInterfaceBroker().GetInterface(
mf_preferences_.BindNewPipeAndPassReceiver());
mf_preferences_.set_disconnect_handler(base::BindOnce(
&MediaPermissionDispatcher::OnMediaFoundationPreferencesConnectionError,
base::Unretained(this)));
}
return mf_preferences_.get();
}
void MediaPermissionDispatcher::OnMediaFoundationPreferencesConnectionError() {
mf_preferences_.reset();
}
#endif // BUILDFLAG(IS_WIN)
void MediaPermissionDispatcher::OnPermissionServiceConnectionError() {
permission_service_.reset();
// Fire all pending callbacks with |false|.
RequestMap requests;
requests.swap(requests_);
for (auto& request : requests)
std::move(request.second).Run(false);
}
} // namespace content