1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/mojo/services/cdm_service.h"
9 #include "base/functional/bind.h"
10 #include "base/logging.h"
11 #include "base/memory/raw_ptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "media/base/cdm_factory.h"
14 #include "media/mojo/services/mojo_cdm_service.h"
15 #include "media/mojo/services/mojo_cdm_service_context.h"
16 #include "mojo/public/cpp/bindings/remote.h"
17 #include "mojo/public/cpp/bindings/unique_receiver_set.h"
23 // Implementation of mojom::CdmFactory that creates and hosts MojoCdmServices
24 // which then host CDMs created by the media::CdmFactory provided by the
25 // CdmService::Client.
28 // 1. CdmFactoryImpl instances are owned by a DeferredDestroyUniqueReceiverSet
29 // directly, which is owned by CdmService.
30 // 2. CdmFactoryImpl is destroyed in any of the following two cases:
31 // - CdmService is destroyed. Because of (2) this should not happen except for
32 // during browser shutdown, when the Cdservice could be destroyed directly,
33 // ignoring any outstanding interface connections.
34 // - mojo::CdmFactory disconnection happens, AND CdmFactoryImpl doesn't own
35 // any CDMs (|cdm_receivers_| is empty). This is to prevent destroying the
36 // CDMs too early (e.g. during page navigation) which could cause errors
37 // (session closed) on the client side. See https://crbug.com/821171 for
39 class CdmFactoryImpl final : public DeferredDestroy<mojom::CdmFactory> {
41 CdmFactoryImpl(CdmService::Client* client,
42 mojo::PendingRemote<mojom::FrameInterfaceFactory> interfaces)
43 : client_(client), interfaces_(std::move(interfaces)) {
46 // base::Unretained is safe because |cdm_receivers_| is owned by |this|. If
47 // |this| is destructed, |cdm_receivers_| will be destructed as well and the
48 // error handler should never be called.
49 cdm_receivers_.set_disconnect_handler(base::BindRepeating(
50 &CdmFactoryImpl::OnReceiverDisconnect, base::Unretained(this)));
53 CdmFactoryImpl(const CdmFactoryImpl&) = delete;
54 CdmFactoryImpl operator=(const CdmFactoryImpl&) = delete;
55 ~CdmFactoryImpl() final { DVLOG(1) << __func__; }
57 // mojom::CdmFactory implementation.
58 void CreateCdm(const CdmConfig& cdm_config,
59 CreateCdmCallback callback) final {
62 auto* cdm_factory = GetCdmFactory();
64 std::move(callback).Run(mojo::NullRemote(), nullptr,
65 "CDM Factory creation failed");
69 auto mojo_cdm_service =
70 std::make_unique<MojoCdmService>(&cdm_service_context_);
71 auto* raw_mojo_cdm_service = mojo_cdm_service.get();
72 DCHECK(!pending_mojo_cdm_services_.count(raw_mojo_cdm_service));
73 pending_mojo_cdm_services_[raw_mojo_cdm_service] =
74 std::move(mojo_cdm_service);
75 raw_mojo_cdm_service->Initialize(
76 cdm_factory, cdm_config,
77 base::BindOnce(&CdmFactoryImpl::OnCdmServiceInitialized,
78 weak_ptr_factory_.GetWeakPtr(), raw_mojo_cdm_service,
79 std::move(callback)));
82 // DeferredDestroy<mojom::CdmFactory> implemenation.
83 void OnDestroyPending(base::OnceClosure destroy_cb) final {
84 destroy_cb_ = std::move(destroy_cb);
85 if (cdm_receivers_.empty())
86 std::move(destroy_cb_).Run();
87 // else the callback will be called when |cdm_receivers_| become empty.
91 media::CdmFactory* GetCdmFactory() {
93 cdm_factory_ = client_->CreateCdmFactory(interfaces_.get());
94 DLOG_IF(ERROR, !cdm_factory_) << "CdmFactory not available.";
96 return cdm_factory_.get();
99 void OnReceiverDisconnect() {
100 if (destroy_cb_ && cdm_receivers_.empty())
101 std::move(destroy_cb_).Run();
104 void OnCdmServiceInitialized(MojoCdmService* raw_mojo_cdm_service,
105 CreateCdmCallback callback,
106 mojom::CdmContextPtr cdm_context,
107 const std::string& error_message) {
108 DCHECK(raw_mojo_cdm_service);
110 // Remove pending MojoCdmService from the mapping in all cases.
111 DCHECK(pending_mojo_cdm_services_.count(raw_mojo_cdm_service));
112 auto mojo_cdm_service =
113 std::move(pending_mojo_cdm_services_[raw_mojo_cdm_service]);
114 pending_mojo_cdm_services_.erase(raw_mojo_cdm_service);
117 std::move(callback).Run(mojo::NullRemote(), nullptr, error_message);
121 mojo::PendingRemote<mojom::ContentDecryptionModule> remote;
122 cdm_receivers_.Add(std::move(mojo_cdm_service),
123 remote.InitWithNewPipeAndPassReceiver());
124 std::move(callback).Run(std::move(remote), std::move(cdm_context), "");
127 // Must be declared before the receivers below because the bound objects might
128 // take a raw pointer of |cdm_service_context_| and assume it's always
130 MojoCdmServiceContext cdm_service_context_;
132 raw_ptr<CdmService::Client> client_;
133 mojo::Remote<mojom::FrameInterfaceFactory> interfaces_;
134 mojo::UniqueReceiverSet<mojom::ContentDecryptionModule> cdm_receivers_;
135 std::unique_ptr<media::CdmFactory> cdm_factory_;
136 base::OnceClosure destroy_cb_;
138 // MojoCdmServices pending initialization.
139 std::map<MojoCdmService*, std::unique_ptr<MojoCdmService>>
140 pending_mojo_cdm_services_;
142 // NOTE: Weak pointers must be invalidated before all other member variables.
143 base::WeakPtrFactory<CdmFactoryImpl> weak_ptr_factory_{this};
148 CdmService::CdmService(std::unique_ptr<Client> client,
149 mojo::PendingReceiver<mojom::CdmService> receiver)
150 : receiver_(this, std::move(receiver)), client_(std::move(client)) {
151 DVLOG(1) << __func__;
155 CdmService::~CdmService() {
156 DVLOG(1) << __func__;
159 void CdmService::CreateCdmFactory(
160 mojo::PendingReceiver<mojom::CdmFactory> receiver,
161 mojo::PendingRemote<mojom::FrameInterfaceFactory> frame_interfaces) {
162 // Ignore receiver if service has already stopped.
166 cdm_factory_receivers_.Add(std::make_unique<CdmFactoryImpl>(
167 client_.get(), std::move(frame_interfaces)),
168 std::move(receiver));