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