Chromium Code Reviews| 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 "content/renderer/media/android/renderer_media_player_manager.h" | 11 #include "content/renderer/media/android/renderer_media_player_manager.h" |
| 12 #include "content/renderer/media/crypto/key_systems.h" | 12 #include "content/renderer/media/crypto/key_systems.h" |
| 13 #include "media/base/cdm_promise.h" | |
| 13 | 14 |
| 14 namespace content { | 15 namespace content { |
| 15 | 16 |
| 16 int ProxyMediaKeys::next_cdm_id_ = | 17 int ProxyMediaKeys::next_cdm_id_ = |
| 17 RendererMediaPlayerManager::kInvalidCdmId + 1; | 18 RendererMediaPlayerManager::kInvalidCdmId + 1; |
| 18 | 19 |
| 19 scoped_ptr<ProxyMediaKeys> ProxyMediaKeys::Create( | 20 scoped_ptr<ProxyMediaKeys> ProxyMediaKeys::Create( |
| 20 const std::string& key_system, | 21 const std::string& key_system, |
| 21 const GURL& security_origin, | 22 const GURL& security_origin, |
| 22 RendererMediaPlayerManager* manager, | 23 RendererMediaPlayerManager* manager, |
| 23 const media::SessionCreatedCB& session_created_cb, | |
| 24 const media::SessionMessageCB& session_message_cb, | 24 const media::SessionMessageCB& session_message_cb, |
| 25 const media::SessionReadyCB& session_ready_cb, | 25 const media::SessionReadyCB& session_ready_cb, |
| 26 const media::SessionClosedCB& session_closed_cb, | 26 const media::SessionClosedCB& session_closed_cb, |
| 27 const media::SessionErrorCB& session_error_cb) { | 27 const media::SessionErrorCB& session_error_cb) { |
| 28 DCHECK(manager); | 28 DCHECK(manager); |
| 29 scoped_ptr<ProxyMediaKeys> proxy_media_keys( | 29 scoped_ptr<ProxyMediaKeys> proxy_media_keys( |
| 30 new ProxyMediaKeys(manager, | 30 new ProxyMediaKeys(manager, |
| 31 session_created_cb, | |
| 32 session_message_cb, | 31 session_message_cb, |
| 33 session_ready_cb, | 32 session_ready_cb, |
| 34 session_closed_cb, | 33 session_closed_cb, |
| 35 session_error_cb)); | 34 session_error_cb)); |
| 36 proxy_media_keys->InitializeCdm(key_system, security_origin); | 35 proxy_media_keys->InitializeCdm(key_system, security_origin); |
| 37 return proxy_media_keys.Pass(); | 36 return proxy_media_keys.Pass(); |
| 38 } | 37 } |
| 39 | 38 |
| 40 ProxyMediaKeys::~ProxyMediaKeys() { | 39 ProxyMediaKeys::~ProxyMediaKeys() { |
| 41 manager_->DestroyCdm(cdm_id_); | 40 manager_->DestroyCdm(cdm_id_); |
| 41 | |
| 42 // Reject any outstanding promises. | |
| 43 for (SimplePromiseMap::iterator it = | |
| 44 session_id_to_simple_promise_map_.begin(); | |
| 45 it != session_id_to_simple_promise_map_.end(); | |
| 46 ++it) { | |
| 47 it->second->reject(media::MediaKeys::EXCEPTION_ABORT_ERROR, | |
| 48 0, | |
| 49 "The operation was aborted."); | |
| 50 } | |
| 51 for (NewSessionPromiseMap::iterator it = | |
| 52 session_id_to_new_session_promise_map_.begin(); | |
| 53 it != session_id_to_new_session_promise_map_.end(); | |
| 54 ++it) { | |
| 55 it->second->reject(media::MediaKeys::EXCEPTION_ABORT_ERROR, | |
| 56 0, | |
| 57 "The operation was aborted."); | |
| 58 } | |
|
xhwang
2014/05/23 06:01:23
You need to delete it->second as well otherwise th
jrummell
2014/05/29 00:54:40
They are now ScopedPtrHashMaps which should clean
| |
| 42 } | 59 } |
| 43 | 60 |
| 44 bool ProxyMediaKeys::CreateSession(uint32 session_id, | 61 void ProxyMediaKeys::CreateSession( |
| 45 const std::string& content_type, | 62 const std::string& init_data_type, |
| 46 const uint8* init_data, | 63 const uint8* init_data, |
| 47 int init_data_length) { | 64 int init_data_length, |
| 65 SessionType session_type, | |
| 66 scoped_ptr<media::NewSessionCdmPromise> promise) { | |
| 48 // TODO(xhwang): Move these checks up to blink and DCHECK here. | 67 // TODO(xhwang): Move these checks up to blink and DCHECK here. |
| 49 // See http://crbug.com/342510 | 68 // See http://crbug.com/342510 |
| 50 CdmHostMsg_CreateSession_ContentType session_type; | 69 CdmHostMsg_CreateSession_ContentType create_session_content_type; |
| 51 if (content_type == "audio/mp4" || content_type == "video/mp4") { | 70 if (init_data_type == "audio/mp4" || init_data_type == "video/mp4") { |
| 52 session_type = CREATE_SESSION_TYPE_MP4; | 71 create_session_content_type = CREATE_SESSION_TYPE_MP4; |
| 53 } else if (content_type == "audio/webm" || content_type == "video/webm") { | 72 } else if (init_data_type == "audio/webm" || init_data_type == "video/webm") { |
| 54 session_type = CREATE_SESSION_TYPE_WEBM; | 73 create_session_content_type = CREATE_SESSION_TYPE_WEBM; |
| 55 } else { | 74 } else { |
| 56 DLOG(ERROR) << "Unsupported EME CreateSession content type of " | 75 DLOG(ERROR) << "Unsupported EME CreateSession content type of " |
| 57 << content_type; | 76 << init_data_type; |
| 58 return false; | 77 promise->reject( |
| 78 EXCEPTION_NOT_SUPPORTED_ERROR, | |
| 79 0, | |
| 80 "Unsupported EME CreateSession init data type of " + init_data_type); | |
| 81 return; | |
| 59 } | 82 } |
| 60 | 83 |
| 84 uint32 session_id = CreateSessionId(); | |
| 85 RegisterNewSessionPromise(session_id, promise.Pass()); | |
| 61 manager_->CreateSession( | 86 manager_->CreateSession( |
| 62 cdm_id_, | 87 cdm_id_, |
| 63 session_id, | 88 session_id, |
| 64 session_type, | 89 create_session_content_type, |
| 65 std::vector<uint8>(init_data, init_data + init_data_length)); | 90 std::vector<uint8>(init_data, init_data + init_data_length)); |
| 66 return true; | |
| 67 } | 91 } |
| 68 | 92 |
| 69 void ProxyMediaKeys::LoadSession(uint32 session_id, | 93 void ProxyMediaKeys::LoadSession( |
| 70 const std::string& web_session_id) { | 94 const std::string& web_session_id, |
| 95 scoped_ptr<media::NewSessionCdmPromise> promise) { | |
| 71 // TODO(xhwang): Check key system and platform support for LoadSession in | 96 // TODO(xhwang): Check key system and platform support for LoadSession in |
| 72 // blink and add NOTREACHED() here. | 97 // blink and add NOTREACHED() here. |
| 73 DLOG(ERROR) << "ProxyMediaKeys doesn't support session loading."; | 98 DLOG(ERROR) << "ProxyMediaKeys doesn't support session loading."; |
| 74 OnSessionError(session_id, media::MediaKeys::kUnknownError, 0); | 99 promise->reject( |
| 100 EXCEPTION_NOT_SUPPORTED_ERROR, 0, "LoadSession() is not implemented."); | |
|
xhwang
2014/05/23 06:01:23
s/implemented/supported/
jrummell
2014/05/29 00:54:40
Done.
| |
| 75 } | 101 } |
| 76 | 102 |
| 77 void ProxyMediaKeys::UpdateSession(uint32 session_id, | 103 void ProxyMediaKeys::UpdateSession( |
| 78 const uint8* response, | 104 const std::string& web_session_id, |
| 79 int response_length) { | 105 const uint8* response, |
| 106 int response_length, | |
| 107 scoped_ptr<media::SimpleCdmPromise> promise) { | |
| 108 uint32 session_id = LookupSessionId(web_session_id); | |
| 109 RegisterSimplePromise(session_id, promise.Pass()); | |
| 80 manager_->UpdateSession( | 110 manager_->UpdateSession( |
| 81 cdm_id_, | 111 cdm_id_, |
| 82 session_id, | 112 session_id, |
| 83 std::vector<uint8>(response, response + response_length)); | 113 std::vector<uint8>(response, response + response_length)); |
| 84 } | 114 } |
| 85 | 115 |
| 86 void ProxyMediaKeys::ReleaseSession(uint32 session_id) { | 116 void ProxyMediaKeys::ReleaseSession( |
| 117 const std::string& web_session_id, | |
| 118 scoped_ptr<media::SimpleCdmPromise> promise) { | |
| 119 uint32 session_id = LookupSessionId(web_session_id); | |
| 120 RegisterSimplePromise(session_id, promise.Pass()); | |
| 87 manager_->ReleaseSession(cdm_id_, session_id); | 121 manager_->ReleaseSession(cdm_id_, session_id); |
| 88 } | 122 } |
| 89 | 123 |
| 90 void ProxyMediaKeys::OnSessionCreated(uint32 session_id, | 124 void ProxyMediaKeys::OnSessionCreated(uint32 session_id, |
| 91 const std::string& web_session_id) { | 125 const std::string& web_session_id) { |
| 92 session_created_cb_.Run(session_id, web_session_id); | 126 AssignWebSessionId(session_id, web_session_id); |
| 127 scoped_ptr<media::NewSessionCdmPromise> promise = | |
| 128 TakeNewSessionPromise(session_id); | |
| 129 promise->resolve(web_session_id); | |
| 93 } | 130 } |
| 94 | 131 |
| 95 void ProxyMediaKeys::OnSessionMessage(uint32 session_id, | 132 void ProxyMediaKeys::OnSessionMessage(uint32 session_id, |
| 96 const std::vector<uint8>& message, | 133 const std::vector<uint8>& message, |
| 97 const std::string& destination_url) { | 134 const std::string& destination_url) { |
| 98 session_message_cb_.Run(session_id, message, destination_url); | 135 session_message_cb_.Run( |
| 136 LookupWebSessionId(session_id), message, destination_url); | |
| 99 } | 137 } |
| 100 | 138 |
| 101 void ProxyMediaKeys::OnSessionReady(uint32 session_id) { | 139 void ProxyMediaKeys::OnSessionReady(uint32 session_id) { |
| 102 session_ready_cb_.Run(session_id); | 140 std::string web_session_id = LookupWebSessionId(session_id); |
| 141 scoped_ptr<media::SimpleCdmPromise> promise = TakeSimplePromise(session_id); | |
| 142 if (promise) { | |
| 143 promise->resolve(); | |
| 144 } else { | |
| 145 // Still needed for keyadded. | |
| 146 session_ready_cb_.Run(web_session_id); | |
| 147 } | |
| 103 } | 148 } |
| 104 | 149 |
| 105 void ProxyMediaKeys::OnSessionClosed(uint32 session_id) { | 150 void ProxyMediaKeys::OnSessionClosed(uint32 session_id) { |
| 106 session_closed_cb_.Run(session_id); | 151 std::string web_session_id = LookupWebSessionId(session_id); |
| 152 DropWebSessionId(web_session_id); | |
| 153 scoped_ptr<media::SimpleCdmPromise> promise = TakeSimplePromise(session_id); | |
| 154 if (promise) { | |
| 155 promise->resolve(); | |
| 156 } else { | |
| 157 // It is possible for the CDM to close a session independent of a | |
| 158 // Release() request. | |
| 159 session_closed_cb_.Run(web_session_id); | |
|
xhwang
2014/05/23 06:01:23
This will be messy if we call ReleaseSession(), an
| |
| 160 } | |
| 107 } | 161 } |
| 108 | 162 |
| 109 void ProxyMediaKeys::OnSessionError(uint32 session_id, | 163 void ProxyMediaKeys::OnSessionError(uint32 session_id, |
| 110 media::MediaKeys::KeyError error_code, | 164 media::MediaKeys::KeyError error_code, |
| 111 uint32 system_code) { | 165 uint32 system_code) { |
| 112 session_error_cb_.Run(session_id, error_code, system_code); | 166 std::string web_session_id = LookupWebSessionId(session_id); |
| 167 media::MediaKeys::Exception exception_code; | |
| 168 switch (error_code) { | |
| 169 case media::MediaKeys::kClientError: | |
| 170 exception_code = media::MediaKeys::EXCEPTION_CLIENT_ERROR; | |
| 171 break; | |
| 172 case media::MediaKeys::kOutputError: | |
| 173 exception_code = media::MediaKeys::EXCEPTION_OUTPUT_ERROR; | |
| 174 break; | |
| 175 case media::MediaKeys::kUnknownError: | |
| 176 default: | |
| 177 exception_code = media::MediaKeys::EXCEPTION_UNKNOWN_ERROR; | |
| 178 break; | |
| 179 } | |
| 180 | |
| 181 scoped_ptr<media::NewSessionCdmPromise> promise = | |
| 182 TakeNewSessionPromise(session_id); | |
| 183 if (promise) { | |
| 184 promise->reject(exception_code, system_code, std::string()); | |
| 185 } else { | |
| 186 // Maybe an error for other set of promises. | |
| 187 scoped_ptr<media::SimpleCdmPromise> promise2 = | |
| 188 TakeSimplePromise(session_id); | |
| 189 if (promise2) { | |
| 190 promise2->reject(exception_code, system_code, std::string()); | |
| 191 } else { | |
| 192 // Errors generally happen in response to a request, but it is possible | |
| 193 // for something bad to happen in the CDM and it needs to tell the client. | |
| 194 session_error_cb_.Run( | |
| 195 web_session_id, exception_code, system_code, std::string()); | |
| 196 } | |
| 197 } | |
|
xhwang
2014/05/23 06:01:23
The nested if/else is hard to read, how about:
1
jrummell
2014/05/29 00:54:40
Done.
| |
| 113 } | 198 } |
| 114 | 199 |
| 115 int ProxyMediaKeys::GetCdmId() const { | 200 int ProxyMediaKeys::GetCdmId() const { |
| 116 return cdm_id_; | 201 return cdm_id_; |
| 117 } | 202 } |
| 118 | 203 |
| 119 ProxyMediaKeys::ProxyMediaKeys( | 204 ProxyMediaKeys::ProxyMediaKeys( |
| 120 RendererMediaPlayerManager* manager, | 205 RendererMediaPlayerManager* manager, |
| 121 const media::SessionCreatedCB& session_created_cb, | |
| 122 const media::SessionMessageCB& session_message_cb, | 206 const media::SessionMessageCB& session_message_cb, |
| 123 const media::SessionReadyCB& session_ready_cb, | 207 const media::SessionReadyCB& session_ready_cb, |
| 124 const media::SessionClosedCB& session_closed_cb, | 208 const media::SessionClosedCB& session_closed_cb, |
| 125 const media::SessionErrorCB& session_error_cb) | 209 const media::SessionErrorCB& session_error_cb) |
| 126 : manager_(manager), | 210 : manager_(manager), |
| 127 cdm_id_(next_cdm_id_++), | 211 cdm_id_(next_cdm_id_++), |
| 128 session_created_cb_(session_created_cb), | |
| 129 session_message_cb_(session_message_cb), | 212 session_message_cb_(session_message_cb), |
| 130 session_ready_cb_(session_ready_cb), | 213 session_ready_cb_(session_ready_cb), |
| 131 session_closed_cb_(session_closed_cb), | 214 session_closed_cb_(session_closed_cb), |
| 132 session_error_cb_(session_error_cb) { | 215 session_error_cb_(session_error_cb), |
| 216 next_session_id_(1) { | |
| 133 } | 217 } |
| 134 | 218 |
| 135 void ProxyMediaKeys::InitializeCdm(const std::string& key_system, | 219 void ProxyMediaKeys::InitializeCdm(const std::string& key_system, |
| 136 const GURL& security_origin) { | 220 const GURL& security_origin) { |
| 137 manager_->InitializeCdm(cdm_id_, this, key_system, security_origin); | 221 manager_->InitializeCdm(cdm_id_, this, key_system, security_origin); |
| 138 } | 222 } |
| 139 | 223 |
| 224 uint32_t ProxyMediaKeys::CreateSessionId() { | |
| 225 return next_session_id_++; | |
| 226 } | |
| 227 | |
| 228 void ProxyMediaKeys::AssignWebSessionId(uint32_t session_id, | |
| 229 const std::string& web_session_id) { | |
| 230 web_session_to_session_id_map_.insert( | |
| 231 std::make_pair(web_session_id, session_id)); | |
|
xhwang
2014/05/23 06:01:23
DCHECK that web_session_id isn't already in the ma
jrummell
2014/05/29 00:54:40
Done. AssignWebSession() is called when the CDM re
| |
| 232 } | |
| 233 | |
| 234 uint32_t ProxyMediaKeys::LookupSessionId(const std::string& web_session_id) { | |
| 235 return web_session_to_session_id_map_.find(web_session_id)->second; | |
| 236 } | |
| 237 | |
| 238 std::string ProxyMediaKeys::LookupWebSessionId(uint32_t session_id) { | |
| 239 for (SessionIdMap::iterator it = web_session_to_session_id_map_.begin(); | |
| 240 it != web_session_to_session_id_map_.end(); | |
| 241 ++it) { | |
| 242 if (it->second == session_id) | |
| 243 return it->first; | |
| 244 } | |
| 245 // Possible to get an error creating a session, so no |web_session_id| | |
| 246 // available. | |
| 247 return std::string(); | |
| 248 } | |
| 249 | |
| 250 void ProxyMediaKeys::DropWebSessionId(std::string web_session_id) { | |
| 251 web_session_to_session_id_map_.erase(web_session_id); | |
| 252 } | |
| 253 | |
| 254 void ProxyMediaKeys::RegisterSimplePromise( | |
| 255 uint32_t session_id, | |
| 256 scoped_ptr<media::SimpleCdmPromise> promise) { | |
| 257 // Should only be one promise outstanding for any |session_id|. | |
|
xhwang
2014/05/23 06:01:23
ditto, what if the app calls update() twice in a r
jrummell
2014/05/29 00:54:40
Bad things. Ideally the promise would get passed f
| |
| 258 DCHECK(session_id_to_simple_promise_map_.find(session_id) == | |
| 259 session_id_to_simple_promise_map_.end()); | |
| 260 session_id_to_simple_promise_map_.insert( | |
| 261 std::make_pair(session_id, promise.release())); | |
| 262 } | |
| 263 | |
| 264 scoped_ptr<media::SimpleCdmPromise> ProxyMediaKeys::TakeSimplePromise( | |
| 265 uint32_t session_id) { | |
| 266 SimplePromiseMap::iterator it = | |
| 267 session_id_to_simple_promise_map_.find(session_id); | |
| 268 // May not be a promise associated with this session for asynchronous events. | |
| 269 if (it == session_id_to_simple_promise_map_.end()) | |
| 270 return scoped_ptr<media::SimpleCdmPromise>(); | |
| 271 scoped_ptr<media::SimpleCdmPromise> result(it->second); | |
| 272 session_id_to_simple_promise_map_.erase(it); | |
| 273 return result.Pass(); | |
| 274 } | |
| 275 | |
| 276 void ProxyMediaKeys::RegisterNewSessionPromise( | |
| 277 uint32_t session_id, | |
| 278 scoped_ptr<media::NewSessionCdmPromise> promise) { | |
| 279 // Should only be one promise outstanding for any |session_id|. | |
| 280 DCHECK(session_id_to_new_session_promise_map_.find(session_id) == | |
| 281 session_id_to_new_session_promise_map_.end()); | |
| 282 session_id_to_new_session_promise_map_.insert( | |
| 283 std::make_pair(session_id, promise.release())); | |
| 284 } | |
| 285 | |
| 286 scoped_ptr<media::NewSessionCdmPromise> ProxyMediaKeys::TakeNewSessionPromise( | |
|
xhwang
2014/05/23 06:01:23
You could have
template <typename CdmPromiseType
jrummell
2014/05/29 00:54:40
Noe that there is a CdmPromise base class this get
| |
| 287 uint32_t session_id) { | |
| 288 NewSessionPromiseMap::iterator it = | |
| 289 session_id_to_new_session_promise_map_.find(session_id); | |
| 290 // May not be a promise associated with this session for asynchronous events. | |
| 291 if (it == session_id_to_new_session_promise_map_.end()) | |
| 292 return scoped_ptr<media::NewSessionCdmPromise>(); | |
| 293 scoped_ptr<media::NewSessionCdmPromise> result(it->second); | |
| 294 session_id_to_new_session_promise_map_.erase(it); | |
| 295 return result.Pass(); | |
| 296 } | |
| 297 | |
| 140 } // namespace content | 298 } // namespace content |
| OLD | NEW |