// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file exposes services from the cast browser to child processes.
#include "chromecast/browser/cast_content_browser_client.h"
#include <memory>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/sequence_local_storage_slot.h"
#include "build/build_config.h"
#include "chromecast/browser/application_media_info_manager.h"
#include "chromecast/browser/cast_browser_interface_binders.h"
#include "chromecast/browser/cast_browser_main_parts.h"
#include "chromecast/browser/cast_browser_process.h"
#include "chromecast/browser/media/media_caps_impl.h"
#include "chromecast/browser/metrics/metrics_helper_impl.h"
#include "chromecast/browser/service_connector.h"
#include "chromecast/chromecast_buildflags.h"
#include "chromecast/media/cdm/cast_cdm_factory.h"
#include "components/cdm/browser/media_drm_storage_impl.h"
#include "content/public/browser/render_process_host.h"
#include "media/mojo/buildflags.h"
#include "mojo/public/cpp/bindings/binder_map.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "url/origin.h"
#if BUILDFLAG(ENABLE_CAST_RENDERER)
#include "chromecast/media/service/cast_mojo_media_client.h"
#include "chromecast/media/service/video_geometry_setter_service.h"
#include "media/mojo/services/media_service.h" // nogncheck
#endif // BUILDFLAG(ENABLE_CAST_RENDERER)
#if !BUILDFLAG(IS_ANDROID)
#include "chromecast/browser/memory_pressure_controller_impl.h"
#endif // !BUILDFLAG(IS_ANDROID)
namespace chromecast {
namespace shell {
namespace {
void CreateOriginId(cdm::MediaDrmStorageImpl::OriginIdObtainedCB callback) {
std::move(callback).Run(true, base::UnguessableToken::Create());
}
void AllowEmptyOriginIdCB(base::OnceCallback<void(bool)> callback) {
std::move(callback).Run(false);
}
void CreateMediaDrmStorage(
content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<::media::mojom::MediaDrmStorage> receiver) {
DVLOG(1) << __func__;
PrefService* pref_service = CastBrowserProcess::GetInstance()->pref_service();
DCHECK(pref_service);
if (render_frame_host->GetLastCommittedOrigin().opaque()) {
DVLOG(1) << __func__ << ": Unique origin.";
return;
}
// The object will be deleted on connection error, or when the frame navigates
// away.
new cdm::MediaDrmStorageImpl(
*render_frame_host, pref_service, base::BindRepeating(&CreateOriginId),
base::BindRepeating(&AllowEmptyOriginIdCB), std::move(receiver));
}
} // namespace
void CastContentBrowserClient::ExposeInterfacesToRenderer(
service_manager::BinderRegistry* registry,
blink::AssociatedInterfaceRegistry* associated_registry,
content::RenderProcessHost* render_process_host) {
registry->AddInterface<media::mojom::MediaCaps>(
base::BindRepeating(
&media::MediaCapsImpl::AddReceiver,
base::Unretained(cast_browser_main_parts_->media_caps())),
base::SingleThreadTaskRunner::GetCurrentDefault());
registry->AddInterface<metrics::mojom::MetricsHelper>(
base::BindRepeating(
&metrics::MetricsHelperImpl::AddReceiver,
base::Unretained(cast_browser_main_parts_->metrics_helper())),
base::SingleThreadTaskRunner::GetCurrentDefault());
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
if (!memory_pressure_controller_) {
memory_pressure_controller_.reset(new MemoryPressureControllerImpl());
}
registry->AddInterface<mojom::MemoryPressureController>(
base::BindRepeating(&MemoryPressureControllerImpl::AddReceiver,
base::Unretained(memory_pressure_controller_.get())),
base::SingleThreadTaskRunner::GetCurrentDefault());
#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
}
void CastContentBrowserClient::BindMediaServiceReceiver(
content::RenderFrameHost* render_frame_host,
mojo::GenericPendingReceiver receiver) {
if (auto r = receiver.As<::media::mojom::MediaDrmStorage>()) {
CreateMediaDrmStorage(render_frame_host, std::move(r));
return;
}
if (auto r = receiver.As<mojom::ServiceConnector>()) {
ServiceConnector::BindReceiver(kMediaServiceClientId, std::move(r));
return;
}
if (auto r = receiver.As<::media::mojom::CastApplicationMediaInfoManager>()) {
std::string application_session_id;
bool mixer_audio_enabled;
GetApplicationMediaInfo(&application_session_id, &mixer_audio_enabled,
render_frame_host);
media::ApplicationMediaInfoManager::Create(
render_frame_host, std::move(application_session_id),
mixer_audio_enabled, std::move(r));
return;
}
}
void CastContentBrowserClient::RegisterBrowserInterfaceBindersForFrame(
content::RenderFrameHost* render_frame_host,
mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {
PopulateCastFrameBinders(render_frame_host, map);
}
mojo::Remote<::media::mojom::MediaService>
CastContentBrowserClient::RunSecondaryMediaService() {
mojo::Remote<::media::mojom::MediaService> remote;
#if BUILDFLAG(ENABLE_CAST_RENDERER)
GetMediaTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&CastContentBrowserClient::CreateMediaService,
base::Unretained(this),
remote.BindNewPipeAndPassReceiver()));
#endif // BUILDFLAG(ENABLE_CAST_RENDERER)
return remote;
}
#if BUILDFLAG(ENABLE_CAST_RENDERER)
void CastContentBrowserClient::CreateMediaService(
mojo::PendingReceiver<::media::mojom::MediaService> receiver) {
DCHECK(GetMediaTaskRunner() &&
GetMediaTaskRunner()->BelongsToCurrentThread());
if (!video_geometry_setter_service_) {
CreateVideoGeometrySetterServiceOnMediaThread();
}
// Using base::Unretained is safe here because this class will persist for
// the duration of the browser process' lifetime.
auto mojo_media_client = std::make_unique<media::CastMojoMediaClient>(
GetCmaBackendFactory(),
base::BindRepeating(&CastContentBrowserClient::CreateCdmFactory,
base::Unretained(this)),
GetVideoModeSwitcher(), GetVideoResolutionPolicy(),
base::BindRepeating(&CastContentBrowserClient::IsBufferingEnabled,
base::Unretained(this)));
mojo_media_client->SetVideoGeometrySetterService(
video_geometry_setter_service_.get());
static base::SequenceLocalStorageSlot<::media::MediaService> service;
service.emplace(std::move(mojo_media_client), std::move(receiver));
}
void CastContentBrowserClient::CreateVideoGeometrySetterServiceOnMediaThread() {
DCHECK(GetMediaTaskRunner() &&
GetMediaTaskRunner()->BelongsToCurrentThread());
DCHECK(!video_geometry_setter_service_);
video_geometry_setter_service_ =
std::unique_ptr<media::VideoGeometrySetterService,
base::OnTaskRunnerDeleter>(
new media::VideoGeometrySetterService,
base::OnTaskRunnerDeleter(
base::SingleThreadTaskRunner::GetCurrentDefault()));
}
void CastContentBrowserClient::BindVideoGeometrySetterServiceOnMediaThread(
mojo::GenericPendingReceiver receiver) {
DCHECK(GetMediaTaskRunner() &&
GetMediaTaskRunner()->BelongsToCurrentThread());
if (!video_geometry_setter_service_) {
CreateVideoGeometrySetterServiceOnMediaThread();
}
if (auto r = receiver.As<media::mojom::VideoGeometrySetter>()) {
video_geometry_setter_service_->GetVideoGeometrySetter(std::move(r));
}
}
void CastContentBrowserClient::BindGpuHostReceiver(
mojo::GenericPendingReceiver receiver) {
DCHECK(GetMediaTaskRunner());
GetMediaTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&CastContentBrowserClient::
BindVideoGeometrySetterServiceOnMediaThread,
base::Unretained(this), std::move(receiver)));
}
#endif // BUILDFLAG(ENABLE_CAST_RENDERER)
void CastContentBrowserClient::RunServiceInstance(
const service_manager::Identity& identity,
mojo::PendingReceiver<service_manager::mojom::Service>* receiver) {}
} // namespace shell
} // namespace chromecast