[M120 Migration][MM][CAPI] Fix the logic for media using capi player.
[platform/framework/web/chromium-efl.git] / media / mojo / services / mojo_cdm_service.cc
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.
4
5 #include "media/mojo/services/mojo_cdm_service.h"
6
7 #include <map>
8 #include <memory>
9 #include <utility>
10
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"
24
25 namespace media {
26
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&),
34                    std::string>;
35
36 MojoCdmService::MojoCdmService(MojoCdmServiceContext* context)
37     : context_(context) {
38   DVLOG(1) << __func__;
39   DCHECK(context_);
40 }
41
42 MojoCdmService::~MojoCdmService() {
43   DVLOG(1) << __func__;
44
45   if (!cdm_id_)
46     return;
47
48   context_->UnregisterCdm(cdm_id_.value());
49 }
50
51 void MojoCdmService::Initialize(CdmFactory* cdm_factory,
52                                 const CdmConfig& cdm_config,
53                                 InitializeCB init_cb) {
54   auto weak_this = weak_factory_.GetWeakPtr();
55   cdm_factory->Create(
56       cdm_config,
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,
61                           weak_this),
62       base::BindOnce(&MojoCdmService::OnCdmCreated, weak_this,
63                      mojo::WrapCallbackWithDefaultInvokeIfNotRun(
64                          std::move(init_cb), nullptr,
65                          "Mojo CDM Service creation aborted")));
66 }
67
68 void MojoCdmService::SetClient(
69     mojo::PendingAssociatedRemote<mojom::ContentDecryptionModuleClient>
70         client) {
71   client_.Bind(std::move(client));
72 }
73
74 void MojoCdmService::SetServerCertificate(
75     const std::vector<uint8_t>& certificate_data,
76     SetServerCertificateCallback callback) {
77   DVLOG(2) << __func__;
78   cdm_->SetServerCertificate(
79       certificate_data,
80       std::make_unique<SimpleMojoCdmPromise>(std::move(callback)));
81 }
82
83 void MojoCdmService::GetStatusForPolicy(HdcpVersion min_hdcp_version,
84                                         GetStatusForPolicyCallback callback) {
85   DVLOG(2) << __func__;
86   cdm_->GetStatusForPolicy(
87       min_hdcp_version,
88       std::make_unique<KeyStatusMojoCdmPromise>(std::move(callback)));
89 }
90
91 void MojoCdmService::CreateSessionAndGenerateRequest(
92     CdmSessionType session_type,
93     EmeInitDataType init_data_type,
94     const std::vector<uint8_t>& init_data,
95     CreateSessionAndGenerateRequestCallback callback) {
96   DVLOG(2) << __func__;
97   cdm_->CreateSessionAndGenerateRequest(
98       session_type, init_data_type, init_data,
99       std::make_unique<NewSessionMojoCdmPromise>(std::move(callback)));
100 }
101
102 void MojoCdmService::LoadSession(CdmSessionType session_type,
103                                  const std::string& session_id,
104                                  LoadSessionCallback callback) {
105   DVLOG(2) << __func__;
106   cdm_->LoadSession(
107       session_type, session_id,
108       std::make_unique<NewSessionMojoCdmPromise>(std::move(callback)));
109 }
110
111 void MojoCdmService::UpdateSession(const std::string& session_id,
112                                    const std::vector<uint8_t>& response,
113                                    UpdateSessionCallback callback) {
114   DVLOG(2) << __func__;
115   cdm_->UpdateSession(
116       session_id, response,
117       std::make_unique<SimpleMojoCdmPromise>(std::move(callback)));
118 }
119
120 void MojoCdmService::CloseSession(const std::string& session_id,
121                                   CloseSessionCallback callback) {
122   DVLOG(2) << __func__;
123   cdm_->CloseSession(
124       session_id, std::make_unique<SimpleMojoCdmPromise>(std::move(callback)));
125 }
126
127 void MojoCdmService::RemoveSession(const std::string& session_id,
128                                    RemoveSessionCallback callback) {
129   DVLOG(2) << __func__;
130   cdm_->RemoveSession(
131       session_id, std::make_unique<SimpleMojoCdmPromise>(std::move(callback)));
132 }
133
134 scoped_refptr<ContentDecryptionModule> MojoCdmService::GetCdm() {
135   return cdm_;
136 }
137
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
144   if (!cdm) {
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);
150     return;
151   }
152
153   cdm_ = cdm;
154   cdm_id_ = context_->RegisterCdm(this);
155   DVLOG(1) << __func__ << ": CDM successfully registered with ID "
156            << CdmContext::CdmIdToString(base::OptionalToPtr(cdm_id_));
157
158   auto mojo_cdm_context = mojom::CdmContext::New();
159   mojo_cdm_context->cdm_id = cdm_id();
160
161   CdmContext* const cdm_context = cdm_->GetCdmContext();
162   if (cdm_context) {
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);
182     }
183
184 #if BUILDFLAG(IS_WIN)
185     mojo_cdm_context->requires_media_foundation_renderer =
186         cdm_context->RequiresMediaFoundationRenderer();
187 #endif  // BUILDFLAG(IS_WIN)
188   }
189
190   std::move(init_cb).Run(std::move(mojo_cdm_context), "");
191 }
192
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__;
197   if (client_) {
198     client_->OnSessionMessage(session_id, message_type, message);
199   }
200 }
201
202 void MojoCdmService::OnSessionKeysChange(const std::string& session_id,
203                                          bool has_additional_usable_key,
204                                          CdmKeysInfo keys_info) {
205   DVLOG(2) << __func__
206            << " has_additional_usable_key = " << has_additional_usable_key;
207   if (client_) {
208     client_->OnSessionKeysChange(session_id, has_additional_usable_key,
209                                  std::move(keys_info));
210   }
211 }
212
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;
216   if (client_) {
217     client_->OnSessionExpirationUpdate(
218         session_id, new_expiry_time_sec.InSecondsFSinceUnixEpoch());
219   }
220 }
221
222 void MojoCdmService::OnSessionClosed(const std::string& session_id,
223                                      CdmSessionClosedReason reason) {
224   DVLOG(2) << __func__;
225   if (client_) {
226     client_->OnSessionClosed(session_id, reason);
227   }
228 }
229
230 void MojoCdmService::OnDecryptorConnectionError() {
231   DVLOG(2) << __func__;
232
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
235   // for recovery.
236   decryptor_.reset();
237 }
238
239 }  // namespace media