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/mojo_cdm_service.h"
11 #include "base/functional/bind.h"
12 #include "base/synchronization/lock.h"
13 #include "base/types/optional_util.h"
14 #include "build/build_config.h"
15 #include "media/base/cdm_config.h"
16 #include "media/base/cdm_context.h"
17 #include "media/base/cdm_factory.h"
18 #include "media/base/cdm_key_information.h"
19 #include "media/base/key_systems.h"
20 #include "media/mojo/common/media_type_converters.h"
21 #include "media/mojo/services/mojo_cdm_service_context.h"
22 #include "mojo/public/cpp/bindings/callback_helpers.h"
23 #include "mojo/public/cpp/bindings/pending_remote.h"
27 using SimpleMojoCdmPromise = MojoCdmPromise<void(mojom::CdmPromiseResultPtr)>;
28 using KeyStatusMojoCdmPromise =
29 MojoCdmPromise<void(mojom::CdmPromiseResultPtr,
30 CdmKeyInformation::KeyStatus),
31 CdmKeyInformation::KeyStatus>;
32 using NewSessionMojoCdmPromise =
33 MojoCdmPromise<void(mojom::CdmPromiseResultPtr, const std::string&),
36 MojoCdmService::MojoCdmService(MojoCdmServiceContext* context)
42 MojoCdmService::~MojoCdmService() {
48 context_->UnregisterCdm(cdm_id_.value());
51 void MojoCdmService::Initialize(CdmFactory* cdm_factory,
52 const CdmConfig& cdm_config,
53 InitializeCB init_cb) {
54 auto weak_this = weak_factory_.GetWeakPtr();
57 base::BindRepeating(&MojoCdmService::OnSessionMessage, weak_this),
58 base::BindRepeating(&MojoCdmService::OnSessionClosed, weak_this),
59 base::BindRepeating(&MojoCdmService::OnSessionKeysChange, weak_this),
60 base::BindRepeating(&MojoCdmService::OnSessionExpirationUpdate,
62 base::BindOnce(&MojoCdmService::OnCdmCreated, weak_this,
63 mojo::WrapCallbackWithDefaultInvokeIfNotRun(
64 std::move(init_cb), nullptr,
65 "Mojo CDM Service creation aborted")));
68 void MojoCdmService::SetClient(
69 mojo::PendingAssociatedRemote<mojom::ContentDecryptionModuleClient>
71 client_.Bind(std::move(client));
74 void MojoCdmService::SetServerCertificate(
75 const std::vector<uint8_t>& certificate_data,
76 SetServerCertificateCallback callback) {
78 cdm_->SetServerCertificate(
80 std::make_unique<SimpleMojoCdmPromise>(std::move(callback)));
83 void MojoCdmService::GetStatusForPolicy(HdcpVersion min_hdcp_version,
84 GetStatusForPolicyCallback callback) {
86 cdm_->GetStatusForPolicy(
88 std::make_unique<KeyStatusMojoCdmPromise>(std::move(callback)));
91 void MojoCdmService::CreateSessionAndGenerateRequest(
92 CdmSessionType session_type,
93 EmeInitDataType init_data_type,
94 const std::vector<uint8_t>& init_data,
95 CreateSessionAndGenerateRequestCallback callback) {
97 cdm_->CreateSessionAndGenerateRequest(
98 session_type, init_data_type, init_data,
99 std::make_unique<NewSessionMojoCdmPromise>(std::move(callback)));
102 void MojoCdmService::LoadSession(CdmSessionType session_type,
103 const std::string& session_id,
104 LoadSessionCallback callback) {
105 DVLOG(2) << __func__;
107 session_type, session_id,
108 std::make_unique<NewSessionMojoCdmPromise>(std::move(callback)));
111 void MojoCdmService::UpdateSession(const std::string& session_id,
112 const std::vector<uint8_t>& response,
113 UpdateSessionCallback callback) {
114 DVLOG(2) << __func__;
116 session_id, response,
117 std::make_unique<SimpleMojoCdmPromise>(std::move(callback)));
120 void MojoCdmService::CloseSession(const std::string& session_id,
121 CloseSessionCallback callback) {
122 DVLOG(2) << __func__;
124 session_id, std::make_unique<SimpleMojoCdmPromise>(std::move(callback)));
127 void MojoCdmService::RemoveSession(const std::string& session_id,
128 RemoveSessionCallback callback) {
129 DVLOG(2) << __func__;
131 session_id, std::make_unique<SimpleMojoCdmPromise>(std::move(callback)));
134 scoped_refptr<ContentDecryptionModule> MojoCdmService::GetCdm() {
138 void MojoCdmService::OnCdmCreated(
139 InitializeCB init_cb,
140 const scoped_refptr<::media::ContentDecryptionModule>& cdm,
141 const std::string& error_message) {
142 // TODO(xhwang): This should not happen when KeySystemInfo is properly
143 // populated. See http://crbug.com/469366
145 // Make sure the error string is non-empty on failure.
146 auto non_empty_error_message =
147 error_message.empty() ? "CDM creation failed" : error_message;
148 DVLOG(1) << __func__ << ": " << non_empty_error_message;
149 std::move(init_cb).Run(nullptr, non_empty_error_message);
154 cdm_id_ = context_->RegisterCdm(this);
155 DVLOG(1) << __func__ << ": CDM successfully registered with ID "
156 << CdmContext::CdmIdToString(base::OptionalToPtr(cdm_id_));
158 auto mojo_cdm_context = mojom::CdmContext::New();
159 mojo_cdm_context->cdm_id = cdm_id();
161 CdmContext* const cdm_context = cdm_->GetCdmContext();
163 // If |cdm| has a decryptor, create the MojoDecryptorService
164 // and pass the connection back to the client.
165 if (cdm_context->GetDecryptor()) {
166 DVLOG(2) << __func__ << ": CDM supports Decryptor.";
167 mojo::PendingRemote<mojom::Decryptor> decryptor_remote;
168 // Both |cdm_| and |decryptor_| are owned by |this|, so we don't need to
169 // pass in a CdmContextRef.
170 decryptor_ = std::make_unique<MojoDecryptorService>(
171 cdm_context->GetDecryptor(), /*cdm_context_ref=*/nullptr);
172 decryptor_receiver_ = std::make_unique<mojo::Receiver<mojom::Decryptor>>(
173 decryptor_.get(), decryptor_remote.InitWithNewPipeAndPassReceiver());
174 // base::Unretained is safe because |decryptor_receiver_| is owned by
175 // |this|. If |this| is destructed, |decryptor_receiver_| will be
176 // destructed as well and the error handler should never be called.
177 // The disconnection can happen due to race conditions during render
178 // process teardown or crash.
179 decryptor_receiver_->set_disconnect_handler(base::BindOnce(
180 &MojoCdmService::OnDecryptorConnectionError, base::Unretained(this)));
181 mojo_cdm_context->decryptor = std::move(decryptor_remote);
184 #if BUILDFLAG(IS_WIN)
185 mojo_cdm_context->requires_media_foundation_renderer =
186 cdm_context->RequiresMediaFoundationRenderer();
187 #endif // BUILDFLAG(IS_WIN)
190 std::move(init_cb).Run(std::move(mojo_cdm_context), "");
193 void MojoCdmService::OnSessionMessage(const std::string& session_id,
194 ::media::CdmMessageType message_type,
195 const std::vector<uint8_t>& message) {
196 DVLOG(2) << __func__;
198 client_->OnSessionMessage(session_id, message_type, message);
202 void MojoCdmService::OnSessionKeysChange(const std::string& session_id,
203 bool has_additional_usable_key,
204 CdmKeysInfo keys_info) {
206 << " has_additional_usable_key = " << has_additional_usable_key;
208 client_->OnSessionKeysChange(session_id, has_additional_usable_key,
209 std::move(keys_info));
213 void MojoCdmService::OnSessionExpirationUpdate(const std::string& session_id,
214 base::Time new_expiry_time_sec) {
215 DVLOG(2) << __func__ << " expiry = " << new_expiry_time_sec;
217 client_->OnSessionExpirationUpdate(
218 session_id, new_expiry_time_sec.InSecondsFSinceUnixEpoch());
222 void MojoCdmService::OnSessionClosed(const std::string& session_id,
223 CdmSessionClosedReason reason) {
224 DVLOG(2) << __func__;
226 client_->OnSessionClosed(session_id, reason);
230 void MojoCdmService::OnDecryptorConnectionError() {
231 DVLOG(2) << __func__;
233 // MojoDecryptorService has lost connectivity to it's client, so it can be
234 // freed. This could happen due to render process teardown or crash. No need