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/android/proxy_media_keys.h" | 5 #include "content/renderer/media/android/proxy_media_keys.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/stl_util.h" | |
11 #include "content/renderer/media/android/renderer_media_player_manager.h" | 12 #include "content/renderer/media/android/renderer_media_player_manager.h" |
12 #include "content/renderer/media/crypto/key_systems.h" | 13 #include "content/renderer/media/crypto/key_systems.h" |
14 #include "media/base/cdm_promise.h" | |
13 | 15 |
14 namespace content { | 16 namespace content { |
15 | 17 |
16 int ProxyMediaKeys::next_cdm_id_ = | 18 int ProxyMediaKeys::next_cdm_id_ = |
17 RendererMediaPlayerManager::kInvalidCdmId + 1; | 19 RendererMediaPlayerManager::kInvalidCdmId + 1; |
18 | 20 |
19 scoped_ptr<ProxyMediaKeys> ProxyMediaKeys::Create( | 21 scoped_ptr<ProxyMediaKeys> ProxyMediaKeys::Create( |
20 const std::string& key_system, | 22 const std::string& key_system, |
21 const GURL& security_origin, | 23 const GURL& security_origin, |
22 RendererMediaPlayerManager* manager, | 24 RendererMediaPlayerManager* manager, |
23 const media::SessionCreatedCB& session_created_cb, | |
24 const media::SessionMessageCB& session_message_cb, | 25 const media::SessionMessageCB& session_message_cb, |
25 const media::SessionReadyCB& session_ready_cb, | 26 const media::SessionReadyCB& session_ready_cb, |
26 const media::SessionClosedCB& session_closed_cb, | 27 const media::SessionClosedCB& session_closed_cb, |
27 const media::SessionErrorCB& session_error_cb) { | 28 const media::SessionErrorCB& session_error_cb) { |
28 DCHECK(manager); | 29 DCHECK(manager); |
29 scoped_ptr<ProxyMediaKeys> proxy_media_keys( | 30 scoped_ptr<ProxyMediaKeys> proxy_media_keys( |
30 new ProxyMediaKeys(manager, | 31 new ProxyMediaKeys(manager, |
31 session_created_cb, | |
32 session_message_cb, | 32 session_message_cb, |
33 session_ready_cb, | 33 session_ready_cb, |
34 session_closed_cb, | 34 session_closed_cb, |
35 session_error_cb)); | 35 session_error_cb)); |
36 proxy_media_keys->InitializeCdm(key_system, security_origin); | 36 proxy_media_keys->InitializeCdm(key_system, security_origin); |
37 return proxy_media_keys.Pass(); | 37 return proxy_media_keys.Pass(); |
38 } | 38 } |
39 | 39 |
40 ProxyMediaKeys::~ProxyMediaKeys() { | 40 ProxyMediaKeys::~ProxyMediaKeys() { |
41 manager_->DestroyCdm(cdm_id_); | 41 manager_->DestroyCdm(cdm_id_); |
42 | |
43 // Reject any outstanding promises. | |
44 for (PromiseMap::iterator it = session_id_to_promise_map_.begin(); | |
45 it != session_id_to_promise_map_.end(); | |
46 ++it) { | |
47 it->second->reject( | |
48 media::MediaKeys::NOT_SUPPORTED_ERROR, 0, "The operation was aborted."); | |
49 } | |
50 session_id_to_promise_map_.clear(); | |
42 } | 51 } |
43 | 52 |
44 bool ProxyMediaKeys::CreateSession(uint32 session_id, | 53 void ProxyMediaKeys::CreateSession( |
45 const std::string& content_type, | 54 const std::string& init_data_type, |
46 const uint8* init_data, | 55 const uint8* init_data, |
47 int init_data_length) { | 56 int init_data_length, |
57 SessionType session_type, | |
58 scoped_ptr<media::NewSessionCdmPromise> promise) { | |
48 // TODO(xhwang): Move these checks up to blink and DCHECK here. | 59 // TODO(xhwang): Move these checks up to blink and DCHECK here. |
49 // See http://crbug.com/342510 | 60 // See http://crbug.com/342510 |
50 CdmHostMsg_CreateSession_ContentType session_type; | 61 CdmHostMsg_CreateSession_ContentType create_session_content_type; |
51 if (content_type == "audio/mp4" || content_type == "video/mp4") { | 62 if (init_data_type == "audio/mp4" || init_data_type == "video/mp4") { |
52 session_type = CREATE_SESSION_TYPE_MP4; | 63 create_session_content_type = CREATE_SESSION_TYPE_MP4; |
53 } else if (content_type == "audio/webm" || content_type == "video/webm") { | 64 } else if (init_data_type == "audio/webm" || init_data_type == "video/webm") { |
54 session_type = CREATE_SESSION_TYPE_WEBM; | 65 create_session_content_type = CREATE_SESSION_TYPE_WEBM; |
55 } else { | 66 } else { |
56 DLOG(ERROR) << "Unsupported EME CreateSession content type of " | 67 DLOG(ERROR) << "Unsupported EME CreateSession content type of " |
57 << content_type; | 68 << init_data_type; |
58 return false; | 69 promise->reject( |
70 NOT_SUPPORTED_ERROR, | |
71 0, | |
72 "Unsupported EME CreateSession init data type of " + init_data_type); | |
73 return; | |
59 } | 74 } |
60 | 75 |
76 const uint32 session_id = CreateSessionId(); | |
xhwang
2014/05/29 23:44:38
nit: there's nothing wrong with this but typically
jrummell
2014/05/30 18:04:25
Done.
| |
77 SavePromise(session_id, promise.PassAs<media::CdmPromise>()); | |
61 manager_->CreateSession( | 78 manager_->CreateSession( |
62 cdm_id_, | 79 cdm_id_, |
63 session_id, | 80 session_id, |
64 session_type, | 81 create_session_content_type, |
65 std::vector<uint8>(init_data, init_data + init_data_length)); | 82 std::vector<uint8>(init_data, init_data + init_data_length)); |
66 return true; | |
67 } | 83 } |
68 | 84 |
69 void ProxyMediaKeys::LoadSession(uint32 session_id, | 85 void ProxyMediaKeys::LoadSession( |
70 const std::string& web_session_id) { | 86 const std::string& web_session_id, |
87 scoped_ptr<media::NewSessionCdmPromise> promise) { | |
71 // TODO(xhwang): Check key system and platform support for LoadSession in | 88 // TODO(xhwang): Check key system and platform support for LoadSession in |
72 // blink and add NOTREACHED() here. | 89 // blink and add NOTREACHED() here. |
73 DLOG(ERROR) << "ProxyMediaKeys doesn't support session loading."; | 90 DLOG(ERROR) << "ProxyMediaKeys doesn't support session loading."; |
74 OnSessionError(session_id, media::MediaKeys::kUnknownError, 0); | 91 promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported."); |
75 } | 92 } |
76 | 93 |
77 void ProxyMediaKeys::UpdateSession(uint32 session_id, | 94 void ProxyMediaKeys::UpdateSession( |
78 const uint8* response, | 95 const std::string& web_session_id, |
79 int response_length) { | 96 const uint8* response, |
97 int response_length, | |
98 scoped_ptr<media::SimpleCdmPromise> promise) { | |
99 const uint32 session_id = LookupSessionId(web_session_id); | |
100 if (!session_id) { | |
101 promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist."); | |
102 return; | |
103 } | |
104 | |
105 SavePromise(session_id, promise.PassAs<media::CdmPromise>()); | |
80 manager_->UpdateSession( | 106 manager_->UpdateSession( |
81 cdm_id_, | 107 cdm_id_, |
82 session_id, | 108 session_id, |
83 std::vector<uint8>(response, response + response_length)); | 109 std::vector<uint8>(response, response + response_length)); |
84 } | 110 } |
85 | 111 |
86 void ProxyMediaKeys::ReleaseSession(uint32 session_id) { | 112 void ProxyMediaKeys::ReleaseSession( |
113 const std::string& web_session_id, | |
114 scoped_ptr<media::SimpleCdmPromise> promise) { | |
115 const uint32 session_id = LookupSessionId(web_session_id); | |
116 if (!session_id) { | |
117 promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist."); | |
118 return; | |
119 } | |
120 | |
121 SavePromise(session_id, promise.PassAs<media::CdmPromise>()); | |
87 manager_->ReleaseSession(cdm_id_, session_id); | 122 manager_->ReleaseSession(cdm_id_, session_id); |
88 } | 123 } |
89 | 124 |
90 void ProxyMediaKeys::OnSessionCreated(uint32 session_id, | 125 void ProxyMediaKeys::OnSessionCreated(uint32 session_id, |
91 const std::string& web_session_id) { | 126 const std::string& web_session_id) { |
92 session_created_cb_.Run(session_id, web_session_id); | 127 AssignWebSessionId(session_id, web_session_id); |
128 scoped_ptr<media::CdmPromise> promise = TakePromise(session_id); | |
129 if (promise) { | |
130 NewSessionCdmPromise* session_promise( | |
131 static_cast<NewSessionCdmPromise*>(promise.get())); | |
132 session_promise->resolve(web_session_id); | |
133 } | |
93 } | 134 } |
94 | 135 |
95 void ProxyMediaKeys::OnSessionMessage(uint32 session_id, | 136 void ProxyMediaKeys::OnSessionMessage(uint32 session_id, |
96 const std::vector<uint8>& message, | 137 const std::vector<uint8>& message, |
97 const GURL& destination_url) { | 138 const GURL& destination_url) { |
98 session_message_cb_.Run(session_id, message, destination_url); | 139 session_message_cb_.Run( |
140 LookupWebSessionId(session_id), message, destination_url); | |
99 } | 141 } |
100 | 142 |
101 void ProxyMediaKeys::OnSessionReady(uint32 session_id) { | 143 void ProxyMediaKeys::OnSessionReady(uint32 session_id) { |
102 session_ready_cb_.Run(session_id); | 144 scoped_ptr<media::CdmPromise> promise = TakePromise(session_id); |
145 if (promise) { | |
146 SimpleCdmPromise* simple_promise( | |
147 static_cast<SimpleCdmPromise*>(promise.get())); | |
148 simple_promise->resolve(); | |
149 } else { | |
150 // Still needed for keyadded. | |
151 const std::string web_session_id = LookupWebSessionId(session_id); | |
152 session_ready_cb_.Run(web_session_id); | |
153 } | |
103 } | 154 } |
104 | 155 |
105 void ProxyMediaKeys::OnSessionClosed(uint32 session_id) { | 156 void ProxyMediaKeys::OnSessionClosed(uint32 session_id) { |
106 session_closed_cb_.Run(session_id); | 157 const std::string web_session_id = LookupWebSessionId(session_id); |
158 DropWebSessionId(web_session_id); | |
159 scoped_ptr<media::CdmPromise> promise = TakePromise(session_id); | |
160 if (promise) { | |
161 SimpleCdmPromise* simple_promise( | |
162 static_cast<SimpleCdmPromise*>(promise.get())); | |
163 simple_promise->resolve(); | |
164 } else { | |
165 // It is possible for the CDM to close a session independent of a | |
166 // Release() request. | |
167 session_closed_cb_.Run(web_session_id); | |
168 } | |
107 } | 169 } |
108 | 170 |
109 void ProxyMediaKeys::OnSessionError(uint32 session_id, | 171 void ProxyMediaKeys::OnSessionError(uint32 session_id, |
110 media::MediaKeys::KeyError error_code, | 172 media::MediaKeys::KeyError error_code, |
111 uint32 system_code) { | 173 uint32 system_code) { |
112 session_error_cb_.Run(session_id, error_code, system_code); | 174 const std::string web_session_id = LookupWebSessionId(session_id); |
175 media::MediaKeys::Exception exception_code; | |
176 switch (error_code) { | |
177 case media::MediaKeys::kClientError: | |
178 exception_code = media::MediaKeys::CLIENT_ERROR; | |
179 break; | |
180 case media::MediaKeys::kOutputError: | |
181 exception_code = media::MediaKeys::OUTPUT_ERROR; | |
182 break; | |
183 case media::MediaKeys::kUnknownError: | |
184 default: | |
185 exception_code = media::MediaKeys::UNKNOWN_ERROR; | |
186 break; | |
187 } | |
188 | |
189 scoped_ptr<media::CdmPromise> promise = TakePromise(session_id); | |
190 if (promise) { | |
191 promise->reject(exception_code, system_code, std::string()); | |
192 return; | |
193 } | |
194 | |
195 // Errors generally happen in response to a request, but it is possible | |
196 // for something bad to happen in the CDM and it needs to tell the client. | |
197 session_error_cb_.Run( | |
198 web_session_id, exception_code, system_code, std::string()); | |
113 } | 199 } |
114 | 200 |
115 int ProxyMediaKeys::GetCdmId() const { | 201 int ProxyMediaKeys::GetCdmId() const { |
116 return cdm_id_; | 202 return cdm_id_; |
117 } | 203 } |
118 | 204 |
119 ProxyMediaKeys::ProxyMediaKeys( | 205 ProxyMediaKeys::ProxyMediaKeys( |
120 RendererMediaPlayerManager* manager, | 206 RendererMediaPlayerManager* manager, |
121 const media::SessionCreatedCB& session_created_cb, | |
122 const media::SessionMessageCB& session_message_cb, | 207 const media::SessionMessageCB& session_message_cb, |
123 const media::SessionReadyCB& session_ready_cb, | 208 const media::SessionReadyCB& session_ready_cb, |
124 const media::SessionClosedCB& session_closed_cb, | 209 const media::SessionClosedCB& session_closed_cb, |
125 const media::SessionErrorCB& session_error_cb) | 210 const media::SessionErrorCB& session_error_cb) |
126 : manager_(manager), | 211 : manager_(manager), |
127 cdm_id_(next_cdm_id_++), | 212 cdm_id_(next_cdm_id_++), |
128 session_created_cb_(session_created_cb), | |
129 session_message_cb_(session_message_cb), | 213 session_message_cb_(session_message_cb), |
130 session_ready_cb_(session_ready_cb), | 214 session_ready_cb_(session_ready_cb), |
131 session_closed_cb_(session_closed_cb), | 215 session_closed_cb_(session_closed_cb), |
132 session_error_cb_(session_error_cb) { | 216 session_error_cb_(session_error_cb), |
217 next_session_id_(1) { | |
133 } | 218 } |
134 | 219 |
135 void ProxyMediaKeys::InitializeCdm(const std::string& key_system, | 220 void ProxyMediaKeys::InitializeCdm(const std::string& key_system, |
136 const GURL& security_origin) { | 221 const GURL& security_origin) { |
137 manager_->InitializeCdm(cdm_id_, this, key_system, security_origin); | 222 manager_->InitializeCdm(cdm_id_, this, key_system, security_origin); |
138 } | 223 } |
139 | 224 |
225 uint32_t ProxyMediaKeys::CreateSessionId() const { | |
226 return next_session_id_++; | |
xhwang
2014/05/29 23:44:38
With "next_session_id_++", this function can't be
jrummell
2014/05/30 18:04:25
Done.
| |
227 } | |
228 | |
229 void ProxyMediaKeys::AssignWebSessionId(const uint32_t session_id, | |
230 const std::string& web_session_id) { | |
231 DCHECK(!ContainsKey(web_session_to_session_id_map_, web_session_id)); | |
232 DCHECK(session_id); | |
233 web_session_to_session_id_map_.insert( | |
234 std::make_pair(web_session_id, session_id)); | |
235 } | |
236 | |
237 uint32_t ProxyMediaKeys::LookupSessionId( | |
238 const std::string& web_session_id) const { | |
239 SessionIdMap::iterator it = | |
240 web_session_to_session_id_map_.find(web_session_id); | |
241 return (it != web_session_to_session_id_map_.end()) ? it->second : 0; | |
242 } | |
243 | |
244 std::string ProxyMediaKeys::LookupWebSessionId( | |
245 const uint32_t session_id) const { | |
246 for (SessionIdMap::iterator it = web_session_to_session_id_map_.begin(); | |
247 it != web_session_to_session_id_map_.end(); | |
248 ++it) { | |
249 if (it->second == session_id) | |
250 return it->first; | |
251 } | |
252 // Possible to get an error creating a session, so no |web_session_id| | |
253 // available. | |
254 return std::string(); | |
255 } | |
256 | |
257 void ProxyMediaKeys::DropWebSessionId(const std::string& web_session_id) { | |
258 web_session_to_session_id_map_.erase(web_session_id); | |
259 } | |
260 | |
261 void ProxyMediaKeys::SavePromise(const uint32_t session_id, | |
262 scoped_ptr<media::CdmPromise> promise) { | |
263 // Should only be one promise outstanding for any |session_id|. | |
264 DCHECK(!ContainsKey(session_id_to_promise_map_, session_id)); | |
265 session_id_to_simple_map_.add(session_id, promise.Pass()); | |
266 } | |
267 | |
268 scoped_ptr<media::CdmPromise> ProxyMediaKeys::TakePromise( | |
269 const uint32_t session_id) { | |
270 PromiseMap::iterator it = session_id_to_promise_map_.find(session_id); | |
271 // May not be a promise associated with this session for asynchronous events. | |
272 if (it == session_id_to_promise_map_.end()) | |
273 return scoped_ptr<media::CdmPromise>(); | |
274 return session_id_to_promise_map_.take_and_erase(it).Pass(); | |
xhwang
2014/05/29 23:44:38
nit: .Pass() is not necessary (maybe :) try it!)
jrummell
2014/05/30 18:04:25
I tried it and it works. However, looks like I did
| |
275 } | |
276 | |
140 } // namespace content | 277 } // namespace content |
OLD | NEW |