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.
4
5 #include "content/renderer/media/webcontentdecryptionmodulesession_impl.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/logging.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "content/renderer/media/cdm_result_promise.h"
13 #include "content/renderer/media/cdm_session_adapter.h"
14 #include "media/base/cdm_promise.h"
15 #include "third_party/WebKit/public/platform/WebURL.h"
16
17 namespace content {
18
19 const char kCreateSessionUMAName[] = "CreateSession";
20
21 typedef base::Callback<blink::WebContentDecryptionModuleResult::SessionStatus(
22 const std::string& web_session_id)> SessionInitializedCB;
23
24 class NewSessionCdmResultPromise : public CdmResultPromise<std::string> {
25 public:
NewSessionCdmResultPromise(blink::WebContentDecryptionModuleResult result,std::string uma_name,const SessionInitializedCB & new_session_created_cb)26 NewSessionCdmResultPromise(blink::WebContentDecryptionModuleResult result,
27 std::string uma_name,
28 const SessionInitializedCB& new_session_created_cb)
29 : CdmResultPromise<std::string>(result, uma_name),
30 new_session_created_cb_(new_session_created_cb) {}
31
32 protected:
OnResolve(const std::string & web_session_id)33 virtual void OnResolve(const std::string& web_session_id) OVERRIDE {
34 blink::WebContentDecryptionModuleResult::SessionStatus status =
35 new_session_created_cb_.Run(web_session_id);
36 web_cdm_result_.completeWithSession(status);
37 }
38
39 private:
40 SessionInitializedCB new_session_created_cb_;
41 };
42
WebContentDecryptionModuleSessionImpl(const scoped_refptr<CdmSessionAdapter> & adapter)43 WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl(
44 const scoped_refptr<CdmSessionAdapter>& adapter)
45 : adapter_(adapter),
46 is_closed_(false),
47 weak_ptr_factory_(this) {
48 }
49
50 WebContentDecryptionModuleSessionImpl::
~WebContentDecryptionModuleSessionImpl()51 ~WebContentDecryptionModuleSessionImpl() {
52 if (!web_session_id_.empty())
53 adapter_->UnregisterSession(web_session_id_);
54 }
55
setClientInterface(Client * client)56 void WebContentDecryptionModuleSessionImpl::setClientInterface(Client* client) {
57 client_ = client;
58 }
59
sessionId() const60 blink::WebString WebContentDecryptionModuleSessionImpl::sessionId() const {
61 return blink::WebString::fromUTF8(web_session_id_);
62 }
63
initializeNewSession(const blink::WebString & init_data_type,const uint8 * init_data,size_t init_data_length)64 void WebContentDecryptionModuleSessionImpl::initializeNewSession(
65 const blink::WebString& init_data_type,
66 const uint8* init_data,
67 size_t init_data_length) {
68 // TODO(jrummell): Remove once blink updated.
69 NOTREACHED();
70 }
71
update(const uint8 * response,size_t response_length)72 void WebContentDecryptionModuleSessionImpl::update(const uint8* response,
73 size_t response_length) {
74 // TODO(jrummell): Remove once blink updated.
75 NOTREACHED();
76 }
77
release()78 void WebContentDecryptionModuleSessionImpl::release() {
79 // TODO(jrummell): Remove once blink updated.
80 NOTREACHED();
81 }
82
initializeNewSession(const blink::WebString & init_data_type,const uint8 * init_data,size_t init_data_length,const blink::WebString & session_type,blink::WebContentDecryptionModuleResult result)83 void WebContentDecryptionModuleSessionImpl::initializeNewSession(
84 const blink::WebString& init_data_type,
85 const uint8* init_data,
86 size_t init_data_length,
87 const blink::WebString& session_type,
88 blink::WebContentDecryptionModuleResult result) {
89
90 // TODO(ddorwin): Guard against this in supported types check and remove this.
91 // Chromium only supports ASCII MIME types.
92 if (!base::IsStringASCII(init_data_type)) {
93 NOTREACHED();
94 std::string message = "The initialization data type " +
95 init_data_type.utf8() +
96 " is not supported by the key system.";
97 result.completeWithError(
98 blink::WebContentDecryptionModuleExceptionNotSupportedError,
99 0,
100 blink::WebString::fromUTF8(message));
101 return;
102 }
103
104 std::string init_data_type_as_ascii = base::UTF16ToASCII(init_data_type);
105 DLOG_IF(WARNING, init_data_type_as_ascii.find('/') != std::string::npos)
106 << "init_data_type '" << init_data_type_as_ascii
107 << "' may be a MIME type";
108
109 adapter_->InitializeNewSession(
110 init_data_type_as_ascii,
111 init_data,
112 init_data_length,
113 media::MediaKeys::TEMPORARY_SESSION,
114 scoped_ptr<media::NewSessionCdmPromise>(new NewSessionCdmResultPromise(
115 result,
116 adapter_->GetKeySystemUMAPrefix() + kCreateSessionUMAName,
117 base::Bind(
118 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized,
119 base::Unretained(this)))));
120 }
121
update(const uint8 * response,size_t response_length,blink::WebContentDecryptionModuleResult result)122 void WebContentDecryptionModuleSessionImpl::update(
123 const uint8* response,
124 size_t response_length,
125 blink::WebContentDecryptionModuleResult result) {
126 DCHECK(response);
127 DCHECK(!web_session_id_.empty());
128 adapter_->UpdateSession(
129 web_session_id_,
130 response,
131 response_length,
132 scoped_ptr<media::SimpleCdmPromise>(new SimpleCdmResultPromise(result)));
133 }
134
close(blink::WebContentDecryptionModuleResult result)135 void WebContentDecryptionModuleSessionImpl::close(
136 blink::WebContentDecryptionModuleResult result) {
137 DCHECK(!web_session_id_.empty());
138 adapter_->CloseSession(
139 web_session_id_,
140 scoped_ptr<media::SimpleCdmPromise>(new SimpleCdmResultPromise(result)));
141 }
142
remove(blink::WebContentDecryptionModuleResult result)143 void WebContentDecryptionModuleSessionImpl::remove(
144 blink::WebContentDecryptionModuleResult result) {
145 DCHECK(!web_session_id_.empty());
146 adapter_->RemoveSession(
147 web_session_id_,
148 scoped_ptr<media::SimpleCdmPromise>(new SimpleCdmResultPromise(result)));
149 }
150
getUsableKeyIds(blink::WebContentDecryptionModuleResult result)151 void WebContentDecryptionModuleSessionImpl::getUsableKeyIds(
152 blink::WebContentDecryptionModuleResult result) {
153 DCHECK(!web_session_id_.empty());
154 adapter_->GetUsableKeyIds(
155 web_session_id_,
156 scoped_ptr<media::KeyIdsPromise>(
157 new CdmResultPromise<media::KeyIdsVector>(result)));
158 }
159
release(blink::WebContentDecryptionModuleResult result)160 void WebContentDecryptionModuleSessionImpl::release(
161 blink::WebContentDecryptionModuleResult result) {
162 close(result);
163 }
164
OnSessionMessage(const std::vector<uint8> & message,const GURL & destination_url)165 void WebContentDecryptionModuleSessionImpl::OnSessionMessage(
166 const std::vector<uint8>& message,
167 const GURL& destination_url) {
168 DCHECK(client_) << "Client not set before message event";
169 client_->message(
170 message.empty() ? NULL : &message[0], message.size(), destination_url);
171 }
172
OnSessionKeysChange(bool has_additional_usable_key)173 void WebContentDecryptionModuleSessionImpl::OnSessionKeysChange(
174 bool has_additional_usable_key) {
175 // TODO(jrummell): Update this once Blink client supports this.
176 }
177
OnSessionExpirationUpdate(const base::Time & new_expiry_time)178 void WebContentDecryptionModuleSessionImpl::OnSessionExpirationUpdate(
179 const base::Time& new_expiry_time) {
180 // TODO(jrummell): Update this once Blink client supports this.
181 // The EME spec has expiration attribute as the time in milliseconds, so use
182 // InMillisecondsF() to convert.
183 }
184
OnSessionReady()185 void WebContentDecryptionModuleSessionImpl::OnSessionReady() {
186 client_->ready();
187 }
188
OnSessionClosed()189 void WebContentDecryptionModuleSessionImpl::OnSessionClosed() {
190 if (!is_closed_) {
191 is_closed_ = true;
192 client_->close();
193 }
194 }
195
OnSessionError(media::MediaKeys::Exception exception_code,uint32 system_code,const std::string & error_message)196 void WebContentDecryptionModuleSessionImpl::OnSessionError(
197 media::MediaKeys::Exception exception_code,
198 uint32 system_code,
199 const std::string& error_message) {
200 // Convert |exception_code| back to MediaKeyErrorCode if possible.
201 // TODO(jrummell): Update this conversion when promises flow
202 // back into blink:: (as blink:: will have its own error definition).
203 switch (exception_code) {
204 case media::MediaKeys::CLIENT_ERROR:
205 client_->error(Client::MediaKeyErrorCodeClient, system_code);
206 break;
207 default:
208 // This will include all other CDM4 errors and any error generated
209 // by CDM5 or later.
210 client_->error(Client::MediaKeyErrorCodeUnknown, system_code);
211 break;
212 }
213 }
214
215 blink::WebContentDecryptionModuleResult::SessionStatus
OnSessionInitialized(const std::string & web_session_id)216 WebContentDecryptionModuleSessionImpl::OnSessionInitialized(
217 const std::string& web_session_id) {
218 // CDM will return NULL if the session to be loaded can't be found.
219 if (web_session_id.empty())
220 return blink::WebContentDecryptionModuleResult::SessionNotFound;
221
222 DCHECK(web_session_id_.empty()) << "Session ID may not be changed once set.";
223 web_session_id_ = web_session_id;
224 return adapter_->RegisterSession(web_session_id_,
225 weak_ptr_factory_.GetWeakPtr())
226 ? blink::WebContentDecryptionModuleResult::NewSession
227 : blink::WebContentDecryptionModuleResult::SessionAlreadyExists;
228 }
229
230 } // namespace content
231