OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/media/webcontentdecryptionmodulesession_impl.h" | 5 #include "content/renderer/media/webcontentdecryptionmodulesession_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
12 #include "content/renderer/media/cdm_session_adapter.h" | 12 #include "content/renderer/media/cdm_session_adapter.h" |
13 #include "content/renderer/media/webcontentdecryptionmoduleresult_helper.h" | |
13 #include "media/base/cdm_promise.h" | 14 #include "media/base/cdm_promise.h" |
14 #include "third_party/WebKit/public/platform/WebURL.h" | 15 #include "third_party/WebKit/public/platform/WebURL.h" |
15 | 16 |
16 namespace content { | 17 namespace content { |
17 | 18 |
18 const char kCreateSessionUMAName[] = "CreateSession"; | 19 const char kCreateSessionUMAName[] = "CreateSession"; |
19 | 20 |
20 // For backwards compatibility with blink not using | 21 typedef base::Callback<blink::WebContentDecryptionModuleResult::SessionStatus( |
21 // WebContentDecryptionModuleResult, reserve an index for |outstanding_results_| | 22 const std::string& web_session_id)> SessionInitializedCB; |
22 // that will not be used when adding a WebContentDecryptionModuleResult. | |
23 // TODO(jrummell): Remove once blink always uses | |
24 // WebContentDecryptionModuleResult. | |
25 const uint32 kReservedIndex = 0; | |
26 | 23 |
27 static blink::WebContentDecryptionModuleException ConvertException( | 24 class WebNewSessionCdmPromise : public BlinkCdmPromiseTemplate<std::string> { |
28 media::MediaKeys::Exception exception_code) { | 25 public: |
29 switch (exception_code) { | 26 WebNewSessionCdmPromise(blink::WebContentDecryptionModuleResult result, |
30 case media::MediaKeys::NOT_SUPPORTED_ERROR: | 27 std::string uma_name, |
31 return blink::WebContentDecryptionModuleExceptionNotSupportedError; | 28 const SessionInitializedCB& new_session_created_cb) |
32 case media::MediaKeys::INVALID_STATE_ERROR: | 29 : BlinkCdmPromiseTemplate<std::string>(result, uma_name), |
33 return blink::WebContentDecryptionModuleExceptionInvalidStateError; | 30 new_session_created_cb_(new_session_created_cb) {} |
34 case media::MediaKeys::INVALID_ACCESS_ERROR: | 31 |
35 return blink::WebContentDecryptionModuleExceptionInvalidAccessError; | 32 protected: |
36 case media::MediaKeys::QUOTA_EXCEEDED_ERROR: | 33 virtual void OnResolve(const std::string& web_session_id) OVERRIDE { |
37 return blink::WebContentDecryptionModuleExceptionQuotaExceededError; | 34 blink::WebContentDecryptionModuleResult::SessionStatus status = |
38 case media::MediaKeys::UNKNOWN_ERROR: | 35 new_session_created_cb_.Run(web_session_id); |
39 return blink::WebContentDecryptionModuleExceptionUnknownError; | 36 webCDMResult_.completeWithSession(status); |
40 case media::MediaKeys::CLIENT_ERROR: | |
41 return blink::WebContentDecryptionModuleExceptionClientError; | |
42 case media::MediaKeys::OUTPUT_ERROR: | |
43 return blink::WebContentDecryptionModuleExceptionOutputError; | |
44 default: | |
45 NOTREACHED(); | |
46 return blink::WebContentDecryptionModuleExceptionUnknownError; | |
47 } | 37 } |
48 } | 38 |
39 private: | |
40 SessionInitializedCB new_session_created_cb_; | |
41 }; | |
49 | 42 |
50 WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl( | 43 WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl( |
51 const scoped_refptr<CdmSessionAdapter>& adapter) | 44 const scoped_refptr<CdmSessionAdapter>& adapter) |
52 : adapter_(adapter), | 45 : adapter_(adapter), |
53 is_closed_(false), | 46 is_closed_(false), |
54 next_available_result_index_(1), | |
55 weak_ptr_factory_(this) { | 47 weak_ptr_factory_(this) { |
56 } | 48 } |
57 | 49 |
58 WebContentDecryptionModuleSessionImpl:: | 50 WebContentDecryptionModuleSessionImpl:: |
59 ~WebContentDecryptionModuleSessionImpl() { | 51 ~WebContentDecryptionModuleSessionImpl() { |
60 if (!web_session_id_.empty()) | 52 if (!web_session_id_.empty()) |
61 adapter_->RemoveSession(web_session_id_); | 53 adapter_->UnregisterSession(web_session_id_); |
62 | |
63 // Release any WebContentDecryptionModuleResult objects that are left. Their | |
64 // index will have been passed down via a CdmPromise, but it uses a WeakPtr. | |
65 DLOG_IF(WARNING, outstanding_results_.size() > 0) | |
66 << "Clearing " << outstanding_results_.size() << " results"; | |
67 for (ResultMap::iterator it = outstanding_results_.begin(); | |
68 it != outstanding_results_.end(); | |
69 ++it) { | |
70 it->second.completeWithError( | |
71 blink::WebContentDecryptionModuleExceptionInvalidStateError, | |
72 0, | |
73 "Outstanding request being cancelled."); | |
74 } | |
75 outstanding_results_.clear(); | |
76 } | 54 } |
77 | 55 |
78 void WebContentDecryptionModuleSessionImpl::setClientInterface(Client* client) { | 56 void WebContentDecryptionModuleSessionImpl::setClientInterface(Client* client) { |
79 client_ = client; | 57 client_ = client; |
80 } | 58 } |
81 | 59 |
82 blink::WebString WebContentDecryptionModuleSessionImpl::sessionId() const { | 60 blink::WebString WebContentDecryptionModuleSessionImpl::sessionId() const { |
83 return blink::WebString::fromUTF8(web_session_id_); | 61 return blink::WebString::fromUTF8(web_session_id_); |
84 } | 62 } |
85 | 63 |
86 void WebContentDecryptionModuleSessionImpl::initializeNewSession( | 64 void WebContentDecryptionModuleSessionImpl::initializeNewSession( |
87 const blink::WebString& init_data_type, | 65 const blink::WebString& init_data_type, |
88 const uint8* init_data, | 66 const uint8* init_data, |
89 size_t init_data_length) { | 67 size_t init_data_length) { |
90 DCHECK(base::IsStringASCII(init_data_type)); | 68 NOTREACHED(); |
91 | |
92 std::string init_data_type_as_ascii = base::UTF16ToASCII(init_data_type); | |
93 DLOG_IF(WARNING, init_data_type_as_ascii.find('/') != std::string::npos) | |
94 << "init_data_type '" << init_data_type_as_ascii | |
95 << "' may be a MIME type"; | |
96 | |
97 // Attempt to translate content types. | |
98 // TODO(sandersd): Remove once tests stop using content types. | |
99 // http://crbug.com/385874 | |
100 std::string content_type = base::StringToLowerASCII(init_data_type_as_ascii); | |
101 if (content_type == "audio/mp4" || content_type == "video/mp4") { | |
102 init_data_type_as_ascii = "cenc"; | |
103 } else if (content_type == "audio/webm" || content_type == "video/webm") { | |
104 init_data_type_as_ascii = "webm"; | |
105 } | |
106 | |
107 scoped_ptr<media::NewSessionCdmPromise> promise( | |
108 new media::NewSessionCdmPromise( | |
109 base::Bind(&WebContentDecryptionModuleSessionImpl::SessionCreated, | |
110 weak_ptr_factory_.GetWeakPtr(), | |
111 kReservedIndex), | |
112 base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionError, | |
113 weak_ptr_factory_.GetWeakPtr()), | |
114 adapter_->GetKeySystemUMAPrefix() + kCreateSessionUMAName)); | |
115 adapter_->InitializeNewSession(init_data_type_as_ascii, | |
116 init_data, | |
117 init_data_length, | |
118 media::MediaKeys::TEMPORARY_SESSION, | |
119 promise.Pass()); | |
120 } | 69 } |
121 | 70 |
122 void WebContentDecryptionModuleSessionImpl::update(const uint8* response, | 71 void WebContentDecryptionModuleSessionImpl::update(const uint8* response, |
123 size_t response_length) { | 72 size_t response_length) { |
124 DCHECK(response); | 73 NOTREACHED(); |
125 scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise( | |
126 base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionReady, | |
127 weak_ptr_factory_.GetWeakPtr()), | |
128 base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionError, | |
129 weak_ptr_factory_.GetWeakPtr()))); | |
130 adapter_->UpdateSession( | |
131 web_session_id_, response, response_length, promise.Pass()); | |
132 } | 74 } |
133 | 75 |
134 void WebContentDecryptionModuleSessionImpl::release() { | 76 void WebContentDecryptionModuleSessionImpl::release() { |
135 scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise( | 77 NOTREACHED(); |
136 base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionClosed, | |
137 weak_ptr_factory_.GetWeakPtr()), | |
138 base::Bind(&WebContentDecryptionModuleSessionImpl::OnSessionError, | |
139 weak_ptr_factory_.GetWeakPtr()))); | |
140 adapter_->ReleaseSession(web_session_id_, promise.Pass()); | |
141 } | 78 } |
142 | 79 |
143 void WebContentDecryptionModuleSessionImpl::initializeNewSession( | 80 void WebContentDecryptionModuleSessionImpl::initializeNewSession( |
144 const blink::WebString& init_data_type, | 81 const blink::WebString& init_data_type, |
145 const uint8* init_data, | 82 const uint8* init_data, |
146 size_t init_data_length, | 83 size_t init_data_length, |
147 const blink::WebString& session_type, | 84 const blink::WebString& session_type, |
148 blink::WebContentDecryptionModuleResult result) { | 85 blink::WebContentDecryptionModuleResult result) { |
149 uint32 result_index = AddResult(result); | |
150 | 86 |
151 // TODO(ddorwin): Guard against this in supported types check and remove this. | 87 // TODO(ddorwin): Guard against this in supported types check and remove this. |
152 // Chromium only supports ASCII MIME types. | 88 // Chromium only supports ASCII MIME types. |
153 if (!base::IsStringASCII(init_data_type)) { | 89 if (!base::IsStringASCII(init_data_type)) { |
154 NOTREACHED(); | 90 NOTREACHED(); |
155 SessionError(result_index, | 91 std::string message = "The initialization data type " + |
156 media::MediaKeys::NOT_SUPPORTED_ERROR, | 92 init_data_type.utf8() + |
157 0, | 93 " is not supported by the key system."; |
158 "The initialization data type " + init_data_type.utf8() + | 94 result.completeWithError( |
159 " is not supported by the key system."); | 95 blink::WebContentDecryptionModuleExceptionNotSupportedError, |
96 0, | |
97 blink::WebString::fromUTF8(message)); | |
160 return; | 98 return; |
161 } | 99 } |
162 | 100 |
163 std::string init_data_type_as_ascii = base::UTF16ToASCII(init_data_type); | 101 std::string init_data_type_as_ascii = base::UTF16ToASCII(init_data_type); |
164 DLOG_IF(WARNING, init_data_type_as_ascii.find('/') != std::string::npos) | 102 DLOG_IF(WARNING, init_data_type_as_ascii.find('/') != std::string::npos) |
165 << "init_data_type '" << init_data_type_as_ascii | 103 << "init_data_type '" << init_data_type_as_ascii |
166 << "' may be a MIME type"; | 104 << "' may be a MIME type"; |
167 | 105 |
168 scoped_ptr<media::NewSessionCdmPromise> promise( | 106 scoped_ptr<media::NewSessionCdmPromise> promise = |
169 new media::NewSessionCdmPromise( | 107 make_scoped_ptr<media::NewSessionCdmPromise>(new WebNewSessionCdmPromise( |
ddorwin
2014/09/23 23:14:21
ditto. here and below. WDYT?
jrummell
2014/09/24 00:49:32
Done.
| |
170 base::Bind(&WebContentDecryptionModuleSessionImpl::SessionCreated, | 108 result, |
171 weak_ptr_factory_.GetWeakPtr(), | 109 adapter_->GetKeySystemUMAPrefix() + kCreateSessionUMAName, |
172 result_index), | 110 base::Bind( |
173 base::Bind(&WebContentDecryptionModuleSessionImpl::SessionError, | 111 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized, |
174 weak_ptr_factory_.GetWeakPtr(), | 112 base::Unretained(this)))); |
175 result_index), | |
176 adapter_->GetKeySystemUMAPrefix() + kCreateSessionUMAName)); | |
177 adapter_->InitializeNewSession(init_data_type_as_ascii, | 113 adapter_->InitializeNewSession(init_data_type_as_ascii, |
178 init_data, | 114 init_data, |
179 init_data_length, | 115 init_data_length, |
180 media::MediaKeys::TEMPORARY_SESSION, | 116 media::MediaKeys::TEMPORARY_SESSION, |
181 promise.Pass()); | 117 promise.Pass()); |
182 } | 118 } |
183 | 119 |
184 void WebContentDecryptionModuleSessionImpl::update( | 120 void WebContentDecryptionModuleSessionImpl::update( |
185 const uint8* response, | 121 const uint8* response, |
186 size_t response_length, | 122 size_t response_length, |
187 blink::WebContentDecryptionModuleResult result) { | 123 blink::WebContentDecryptionModuleResult result) { |
188 DCHECK(response); | 124 DCHECK(response); |
189 uint32 result_index = AddResult(result); | 125 DCHECK(!web_session_id_.empty()); |
190 scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise( | 126 scoped_ptr<media::SimpleCdmPromise> promise = |
191 base::Bind( | 127 make_scoped_ptr<media::SimpleCdmPromise>( |
192 &WebContentDecryptionModuleSessionImpl::SessionUpdatedOrReleased, | 128 new BlinkCdmPromiseTemplate<void>(result)); |
ddorwin
2014/09/23 23:14:21
Feel free to typedef this one. :)
jrummell
2014/09/24 00:49:32
Not sure there is much benefit now that it is inli
ddorwin
2014/09/24 17:37:46
Agreed - it was mainly for readability.
| |
193 weak_ptr_factory_.GetWeakPtr(), | |
194 result_index), | |
195 base::Bind(&WebContentDecryptionModuleSessionImpl::SessionError, | |
196 weak_ptr_factory_.GetWeakPtr(), | |
197 result_index))); | |
198 adapter_->UpdateSession( | 129 adapter_->UpdateSession( |
199 web_session_id_, response, response_length, promise.Pass()); | 130 web_session_id_, response, response_length, promise.Pass()); |
200 } | 131 } |
201 | 132 |
133 void WebContentDecryptionModuleSessionImpl::close( | |
134 blink::WebContentDecryptionModuleResult result) { | |
135 DCHECK(!web_session_id_.empty()); | |
136 scoped_ptr<media::SimpleCdmPromise> promise = | |
137 make_scoped_ptr<media::SimpleCdmPromise>( | |
138 new BlinkCdmPromiseTemplate<void>(result)); | |
139 adapter_->CloseSession(web_session_id_, promise.Pass()); | |
140 } | |
141 | |
142 void WebContentDecryptionModuleSessionImpl::remove( | |
143 blink::WebContentDecryptionModuleResult result) { | |
144 DCHECK(!web_session_id_.empty()); | |
145 scoped_ptr<media::SimpleCdmPromise> promise = | |
146 make_scoped_ptr<media::SimpleCdmPromise>( | |
147 new BlinkCdmPromiseTemplate<void>(result)); | |
148 adapter_->RemoveSession(web_session_id_, promise.Pass()); | |
149 } | |
150 | |
151 void WebContentDecryptionModuleSessionImpl::getUsableKeyIds( | |
152 blink::WebContentDecryptionModuleResult result) { | |
153 DCHECK(!web_session_id_.empty()); | |
154 scoped_ptr<media::KeyIdsPromise> promise = | |
155 make_scoped_ptr<media::KeyIdsPromise>( | |
156 new BlinkCdmPromiseTemplate<media::KeyIdsVector>(result)); | |
157 adapter_->GetUsableKeyIds(web_session_id_, promise.Pass()); | |
158 } | |
159 | |
202 void WebContentDecryptionModuleSessionImpl::release( | 160 void WebContentDecryptionModuleSessionImpl::release( |
203 blink::WebContentDecryptionModuleResult result) { | 161 blink::WebContentDecryptionModuleResult result) { |
204 uint32 result_index = AddResult(result); | 162 close(result); |
205 scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise( | |
206 base::Bind( | |
207 &WebContentDecryptionModuleSessionImpl::SessionUpdatedOrReleased, | |
208 weak_ptr_factory_.GetWeakPtr(), | |
209 result_index), | |
210 base::Bind(&WebContentDecryptionModuleSessionImpl::SessionError, | |
211 weak_ptr_factory_.GetWeakPtr(), | |
212 result_index))); | |
213 adapter_->ReleaseSession(web_session_id_, promise.Pass()); | |
214 } | 163 } |
215 | 164 |
216 void WebContentDecryptionModuleSessionImpl::OnSessionMessage( | 165 void WebContentDecryptionModuleSessionImpl::OnSessionMessage( |
217 const std::vector<uint8>& message, | 166 const std::vector<uint8>& message, |
218 const GURL& destination_url) { | 167 const GURL& destination_url) { |
219 DCHECK(client_) << "Client not set before message event"; | 168 DCHECK(client_) << "Client not set before message event"; |
220 client_->message( | 169 client_->message( |
221 message.empty() ? NULL : &message[0], message.size(), destination_url); | 170 message.empty() ? NULL : &message[0], message.size(), destination_url); |
222 } | 171 } |
223 | 172 |
173 void WebContentDecryptionModuleSessionImpl::OnSessionKeysChange( | |
174 bool has_additional_usable_key) { | |
175 // TODO(jrummell): Update this once Blink client supports this. | |
176 } | |
177 | |
178 void WebContentDecryptionModuleSessionImpl::OnSessionExpirationChange( | |
179 double new_expiry_time) { | |
180 // TODO(jrummell): Update this once Blink client supports this. | |
181 } | |
182 | |
224 void WebContentDecryptionModuleSessionImpl::OnSessionReady() { | 183 void WebContentDecryptionModuleSessionImpl::OnSessionReady() { |
225 client_->ready(); | 184 client_->ready(); |
226 } | 185 } |
227 | 186 |
228 void WebContentDecryptionModuleSessionImpl::OnSessionClosed() { | 187 void WebContentDecryptionModuleSessionImpl::OnSessionClosed() { |
229 if (!is_closed_) { | 188 if (!is_closed_) { |
230 is_closed_ = true; | 189 is_closed_ = true; |
231 client_->close(); | 190 client_->close(); |
232 } | 191 } |
233 } | 192 } |
(...skipping 10 matching lines...) Expand all Loading... | |
244 client_->error(Client::MediaKeyErrorCodeClient, system_code); | 203 client_->error(Client::MediaKeyErrorCodeClient, system_code); |
245 break; | 204 break; |
246 default: | 205 default: |
247 // This will include all other CDM4 errors and any error generated | 206 // This will include all other CDM4 errors and any error generated |
248 // by CDM5 or later. | 207 // by CDM5 or later. |
249 client_->error(Client::MediaKeyErrorCodeUnknown, system_code); | 208 client_->error(Client::MediaKeyErrorCodeUnknown, system_code); |
250 break; | 209 break; |
251 } | 210 } |
252 } | 211 } |
253 | 212 |
254 void WebContentDecryptionModuleSessionImpl::SessionCreated( | 213 blink::WebContentDecryptionModuleResult::SessionStatus |
255 uint32 result_index, | 214 WebContentDecryptionModuleSessionImpl::OnSessionInitialized( |
256 const std::string& web_session_id) { | 215 const std::string& web_session_id) { |
257 blink::WebContentDecryptionModuleResult::SessionStatus status; | 216 // CDM will return NULL if the session to be loaded can't be found. |
217 if (web_session_id.empty()) | |
218 return blink::WebContentDecryptionModuleResult::SessionNotFound; | |
258 | 219 |
259 // CDM will return NULL if the session to be loaded can't be found. | 220 DCHECK(web_session_id_.empty()) << "Session ID may not be changed once set."; |
260 if (web_session_id.empty()) { | 221 web_session_id_ = web_session_id; |
261 status = blink::WebContentDecryptionModuleResult::SessionNotFound; | 222 return adapter_->RegisterSession(web_session_id_, |
262 } else { | 223 weak_ptr_factory_.GetWeakPtr()) |
263 DCHECK(web_session_id_.empty()) | 224 ? blink::WebContentDecryptionModuleResult::NewSession |
264 << "Session ID may not be changed once set."; | 225 : blink::WebContentDecryptionModuleResult::SessionAlreadyExists; |
265 web_session_id_ = web_session_id; | |
266 status = | |
267 adapter_->RegisterSession(web_session_id_, | |
268 weak_ptr_factory_.GetWeakPtr()) | |
269 ? blink::WebContentDecryptionModuleResult::NewSession | |
270 : blink::WebContentDecryptionModuleResult::SessionAlreadyExists; | |
271 } | |
272 | |
273 ResultMap::iterator it = outstanding_results_.find(result_index); | |
274 if (it != outstanding_results_.end()) { | |
275 blink::WebContentDecryptionModuleResult& result = it->second; | |
276 result.completeWithSession(status); | |
277 outstanding_results_.erase(result_index); | |
278 } | |
279 } | |
280 | |
281 void WebContentDecryptionModuleSessionImpl::SessionUpdatedOrReleased( | |
282 uint32 result_index) { | |
283 ResultMap::iterator it = outstanding_results_.find(result_index); | |
284 DCHECK(it != outstanding_results_.end()); | |
285 blink::WebContentDecryptionModuleResult& result = it->second; | |
286 result.complete(); | |
287 outstanding_results_.erase(it); | |
288 } | |
289 | |
290 void WebContentDecryptionModuleSessionImpl::SessionError( | |
291 uint32 result_index, | |
292 media::MediaKeys::Exception exception_code, | |
293 uint32 system_code, | |
294 const std::string& error_message) { | |
295 ResultMap::iterator it = outstanding_results_.find(result_index); | |
296 DCHECK(it != outstanding_results_.end()); | |
297 blink::WebContentDecryptionModuleResult& result = it->second; | |
298 result.completeWithError(ConvertException(exception_code), | |
299 system_code, | |
300 blink::WebString::fromUTF8(error_message)); | |
301 outstanding_results_.erase(it); | |
302 } | |
303 | |
304 uint32 WebContentDecryptionModuleSessionImpl::AddResult( | |
305 blink::WebContentDecryptionModuleResult result) { | |
306 uint32 result_index = next_available_result_index_++; | |
307 DCHECK(result_index != kReservedIndex); | |
308 outstanding_results_.insert(std::make_pair(result_index, result)); | |
309 return result_index; | |
310 } | 226 } |
311 | 227 |
312 } // namespace content | 228 } // namespace content |
OLD | NEW |