1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "webcontentdecryptionmodulesession_impl.h"
8 #include "base/callback_helpers.h"
9 #include "base/logging.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "media/base/cdm_promise.h"
14 #include "media/base/media_keys.h"
15 #include "media/blink/cdm_result_promise.h"
16 #include "media/blink/cdm_session_adapter.h"
17 #include "media/blink/new_session_cdm_result_promise.h"
18 #include "third_party/WebKit/public/platform/WebString.h"
19 #include "third_party/WebKit/public/platform/WebURL.h"
23 const char kCreateSessionUMAName
[] = "CreateSession";
24 const char kLoadSessionUMAName
[] = "LoadSession";
26 // TODO(jrummell): Pass an enum from blink. http://crbug.com/418239.
27 const char kTemporarySessionType
[] = "temporary";
28 const char kPersistentLicenseSessionType
[] = "persistent-license";
29 const char kPersistentReleaseMessageSessionType
[] =
30 "persistent-release-message";
32 static blink::WebContentDecryptionModuleSession::Client::MessageType
33 convertMessageType(MediaKeys::MessageType message_type
) {
34 switch (message_type
) {
35 case media::MediaKeys::LICENSE_REQUEST
:
36 return blink::WebContentDecryptionModuleSession::Client::MessageType::
38 case media::MediaKeys::LICENSE_RENEWAL
:
39 return blink::WebContentDecryptionModuleSession::Client::MessageType::
41 case media::MediaKeys::LICENSE_RELEASE
:
42 return blink::WebContentDecryptionModuleSession::Client::MessageType::
47 return blink::WebContentDecryptionModuleSession::Client::MessageType::
51 WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl(
52 const scoped_refptr
<CdmSessionAdapter
>& adapter
)
53 : adapter_(adapter
), is_closed_(false), weak_ptr_factory_(this) {
56 WebContentDecryptionModuleSessionImpl::
57 ~WebContentDecryptionModuleSessionImpl() {
58 if (!web_session_id_
.empty())
59 adapter_
->UnregisterSession(web_session_id_
);
62 void WebContentDecryptionModuleSessionImpl::setClientInterface(Client
* client
) {
66 blink::WebString
WebContentDecryptionModuleSessionImpl::sessionId() const {
67 return blink::WebString::fromUTF8(web_session_id_
);
70 void WebContentDecryptionModuleSessionImpl::initializeNewSession(
71 const blink::WebString
& init_data_type
,
72 const uint8
* init_data
,
73 size_t init_data_length
) {
74 // TODO(jrummell): Remove once blink updated.
78 void WebContentDecryptionModuleSessionImpl::update(const uint8
* response
,
79 size_t response_length
) {
80 // TODO(jrummell): Remove once blink updated.
84 void WebContentDecryptionModuleSessionImpl::release() {
85 // TODO(jrummell): Remove once blink updated.
89 void WebContentDecryptionModuleSessionImpl::initializeNewSession(
90 const blink::WebString
& init_data_type
,
91 const uint8
* init_data
,
92 size_t init_data_length
,
93 const blink::WebString
& session_type
,
94 blink::WebContentDecryptionModuleResult result
) {
95 DCHECK(web_session_id_
.empty());
97 // TODO(ddorwin): Guard against this in supported types check and remove this.
98 // Chromium only supports ASCII MIME types.
99 if (!base::IsStringASCII(init_data_type
)) {
101 std::string message
= "The initialization data type " +
102 init_data_type
.utf8() +
103 " is not supported by the key system.";
104 result
.completeWithError(
105 blink::WebContentDecryptionModuleExceptionNotSupportedError
, 0,
106 blink::WebString::fromUTF8(message
));
110 std::string init_data_type_as_ascii
= base::UTF16ToASCII(init_data_type
);
111 DLOG_IF(WARNING
, init_data_type_as_ascii
.find('/') != std::string::npos
)
112 << "init_data_type '" << init_data_type_as_ascii
113 << "' may be a MIME type";
115 MediaKeys::SessionType session_type_enum
;
116 if (session_type
== kPersistentLicenseSessionType
) {
117 session_type_enum
= MediaKeys::PERSISTENT_LICENSE_SESSION
;
118 } else if (session_type
== kPersistentReleaseMessageSessionType
) {
119 session_type_enum
= MediaKeys::PERSISTENT_RELEASE_MESSAGE_SESSION
;
121 DCHECK(session_type
== kTemporarySessionType
);
122 session_type_enum
= MediaKeys::TEMPORARY_SESSION
;
125 adapter_
->InitializeNewSession(
126 init_data_type_as_ascii
, init_data
,
127 base::saturated_cast
<int>(init_data_length
), session_type_enum
,
128 scoped_ptr
<NewSessionCdmPromise
>(new NewSessionCdmResultPromise(
129 result
, adapter_
->GetKeySystemUMAPrefix() + kCreateSessionUMAName
,
131 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized
,
132 base::Unretained(this)))));
135 void WebContentDecryptionModuleSessionImpl::load(
136 const blink::WebString
& session_id
,
137 blink::WebContentDecryptionModuleResult result
) {
138 DCHECK(!session_id
.isEmpty());
139 DCHECK(web_session_id_
.empty());
141 // TODO(jrummell): Now that there are 2 types of persistent sessions, the
142 // session type should be passed from blink. Type should also be passed in the
143 // constructor (and removed from initializeNewSession()).
144 adapter_
->LoadSession(
145 MediaKeys::PERSISTENT_LICENSE_SESSION
, base::UTF16ToASCII(session_id
),
146 scoped_ptr
<NewSessionCdmPromise
>(new NewSessionCdmResultPromise(
147 result
, adapter_
->GetKeySystemUMAPrefix() + kLoadSessionUMAName
,
149 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized
,
150 base::Unretained(this)))));
153 void WebContentDecryptionModuleSessionImpl::update(
154 const uint8
* response
,
155 size_t response_length
,
156 blink::WebContentDecryptionModuleResult result
) {
158 DCHECK(!web_session_id_
.empty());
159 adapter_
->UpdateSession(web_session_id_
, response
,
160 base::saturated_cast
<int>(response_length
),
161 scoped_ptr
<SimpleCdmPromise
>(
162 new CdmResultPromise
<>(result
, std::string())));
165 void WebContentDecryptionModuleSessionImpl::close(
166 blink::WebContentDecryptionModuleResult result
) {
167 DCHECK(!web_session_id_
.empty());
168 adapter_
->CloseSession(web_session_id_
,
169 scoped_ptr
<SimpleCdmPromise
>(
170 new CdmResultPromise
<>(result
, std::string())));
173 void WebContentDecryptionModuleSessionImpl::remove(
174 blink::WebContentDecryptionModuleResult result
) {
175 DCHECK(!web_session_id_
.empty());
176 adapter_
->RemoveSession(web_session_id_
,
177 scoped_ptr
<SimpleCdmPromise
>(
178 new CdmResultPromise
<>(result
, std::string())));
181 void WebContentDecryptionModuleSessionImpl::release(
182 blink::WebContentDecryptionModuleResult result
) {
186 void WebContentDecryptionModuleSessionImpl::OnSessionMessage(
187 MediaKeys::MessageType message_type
,
188 const std::vector
<uint8
>& message
) {
189 DCHECK(client_
) << "Client not set before message event";
190 client_
->message(convertMessageType(message_type
),
191 message
.empty() ? NULL
: &message
[0], message
.size());
194 void WebContentDecryptionModuleSessionImpl::OnSessionKeysChange(
195 bool has_additional_usable_key
) {
196 // TODO(jrummell): Update this once Blink client supports this.
199 void WebContentDecryptionModuleSessionImpl::OnSessionExpirationUpdate(
200 const base::Time
& new_expiry_time
) {
201 client_
->expirationChanged(new_expiry_time
.ToJsTime());
204 void WebContentDecryptionModuleSessionImpl::OnSessionClosed() {
212 blink::WebContentDecryptionModuleResult::SessionStatus
213 WebContentDecryptionModuleSessionImpl::OnSessionInitialized(
214 const std::string
& web_session_id
) {
215 // CDM will return NULL if the session to be loaded can't be found.
216 if (web_session_id
.empty())
217 return blink::WebContentDecryptionModuleResult::SessionNotFound
;
219 DCHECK(web_session_id_
.empty()) << "Session ID may not be changed once set.";
220 web_session_id_
= web_session_id
;
221 return adapter_
->RegisterSession(web_session_id_
,
222 weak_ptr_factory_
.GetWeakPtr())
223 ? blink::WebContentDecryptionModuleResult::NewSession
224 : blink::WebContentDecryptionModuleResult::SessionAlreadyExists
;