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 (VoidPromiseMap::iterator it = session_id_to_promise_map_.begin(); |
| 44 it != session_id_to_promise_map_.end(); |
| 45 ++it) { |
| 46 it->second->reject(media::MediaKeys::MEDIA_KEYS_EXCEPTION_ABORT_ERROR, |
| 47 0, |
| 48 "The operation was aborted."); |
| 49 } |
| 50 for (SessionPromiseMap::iterator it = |
| 51 session_id_to_new_session_promise_map_.begin(); |
| 52 it != session_id_to_new_session_promise_map_.end(); |
| 53 ++it) { |
| 54 it->second->reject(media::MediaKeys::MEDIA_KEYS_EXCEPTION_ABORT_ERROR, |
| 55 0, |
| 56 "The operation was aborted."); |
| 57 } |
42 } | 58 } |
43 | 59 |
44 bool ProxyMediaKeys::CreateSession(uint32 session_id, | 60 void ProxyMediaKeys::CreateSession( |
45 const std::string& content_type, | 61 const std::string& init_data_type, |
46 const uint8* init_data, | 62 const uint8* init_data, |
47 int init_data_length) { | 63 int init_data_length, |
| 64 SessionType session_type, |
| 65 scoped_ptr<media::CdmNewSessionPromise> promise) { |
48 // TODO(xhwang): Move these checks up to blink and DCHECK here. | 66 // TODO(xhwang): Move these checks up to blink and DCHECK here. |
49 // See http://crbug.com/342510 | 67 // See http://crbug.com/342510 |
50 CdmHostMsg_CreateSession_ContentType session_type; | 68 CdmHostMsg_CreateSession_ContentType create_session_content_type; |
51 if (content_type == "audio/mp4" || content_type == "video/mp4") { | 69 if (init_data_type == "audio/mp4" || init_data_type == "video/mp4") { |
52 session_type = CREATE_SESSION_TYPE_MP4; | 70 create_session_content_type = CREATE_SESSION_TYPE_MP4; |
53 } else if (content_type == "audio/webm" || content_type == "video/webm") { | 71 } else if (init_data_type == "audio/webm" || init_data_type == "video/webm") { |
54 session_type = CREATE_SESSION_TYPE_WEBM; | 72 create_session_content_type = CREATE_SESSION_TYPE_WEBM; |
55 } else { | 73 } else { |
56 DLOG(ERROR) << "Unsupported EME CreateSession content type of " | 74 DLOG(ERROR) << "Unsupported EME CreateSession content type of " |
57 << content_type; | 75 << init_data_type; |
58 return false; | 76 promise->reject( |
| 77 MEDIA_KEYS_EXCEPTION_NOT_SUPPORTED_ERROR, |
| 78 0, |
| 79 "Unsupported EME CreateSession init data type of " + init_data_type); |
| 80 return; |
59 } | 81 } |
60 | 82 |
| 83 uint32 session_id = CreateSessionId(); |
| 84 RegisterSessionPromise(session_id, promise.Pass()); |
61 manager_->CreateSession( | 85 manager_->CreateSession( |
62 cdm_id_, | 86 cdm_id_, |
63 session_id, | 87 session_id, |
64 session_type, | 88 create_session_content_type, |
65 std::vector<uint8>(init_data, init_data + init_data_length)); | 89 std::vector<uint8>(init_data, init_data + init_data_length)); |
66 return true; | |
67 } | 90 } |
68 | 91 |
69 void ProxyMediaKeys::LoadSession(uint32 session_id, | 92 void ProxyMediaKeys::LoadSession( |
70 const std::string& web_session_id) { | 93 const std::string& web_session_id, |
| 94 scoped_ptr<media::CdmNewSessionPromise> promise) { |
71 // TODO(xhwang): Check key system and platform support for LoadSession in | 95 // TODO(xhwang): Check key system and platform support for LoadSession in |
72 // blink and add NOTREACHED() here. | 96 // blink and add NOTREACHED() here. |
73 DLOG(ERROR) << "ProxyMediaKeys doesn't support session loading."; | 97 DLOG(ERROR) << "ProxyMediaKeys doesn't support session loading."; |
74 OnSessionError(session_id, media::MediaKeys::kUnknownError, 0); | 98 promise->reject(MEDIA_KEYS_EXCEPTION_NOT_SUPPORTED_ERROR, |
| 99 0, |
| 100 "LoadSession() is not implemented."); |
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::CdmChangeSessionPromise> promise) { |
| 108 uint32 session_id = LookupSessionId(web_session_id); |
| 109 RegisterVoidPromise(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::CdmChangeSessionPromise> promise) { |
| 119 uint32 session_id = LookupSessionId(web_session_id); |
| 120 RegisterVoidPromise(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::CdmNewSessionPromise> promise = |
| 128 RetrieveSessionPromise(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::CdmChangeSessionPromise> promise = |
| 142 RetrieveVoidPromise(session_id); |
| 143 if (promise) { |
| 144 promise->resolve(); |
| 145 } else { |
| 146 // Still needed for keyadded. |
| 147 session_ready_cb_.Run(web_session_id); |
| 148 } |
103 } | 149 } |
104 | 150 |
105 void ProxyMediaKeys::OnSessionClosed(uint32 session_id) { | 151 void ProxyMediaKeys::OnSessionClosed(uint32 session_id) { |
106 session_closed_cb_.Run(session_id); | 152 std::string web_session_id = LookupWebSessionId(session_id); |
| 153 DropWebSessionId(web_session_id); |
| 154 scoped_ptr<media::CdmChangeSessionPromise> promise = |
| 155 RetrieveVoidPromise(session_id); |
| 156 if (promise) { |
| 157 promise->resolve(); |
| 158 } else { |
| 159 // It is possible for the CDM to close a session independent of a |
| 160 // Release() request. |
| 161 session_closed_cb_.Run(web_session_id); |
| 162 } |
107 } | 163 } |
108 | 164 |
109 void ProxyMediaKeys::OnSessionError(uint32 session_id, | 165 void ProxyMediaKeys::OnSessionError(uint32 session_id, |
110 media::MediaKeys::KeyError error_code, | 166 media::MediaKeys::KeyError error_code, |
111 uint32 system_code) { | 167 uint32 system_code) { |
112 session_error_cb_.Run(session_id, error_code, system_code); | 168 std::string web_session_id = LookupWebSessionId(session_id); |
| 169 media::MediaKeys::MediaKeysException exception_code; |
| 170 switch (error_code) { |
| 171 case media::MediaKeys::kClientError: |
| 172 exception_code = media::MediaKeys::MEDIA_KEYS_EXCEPTION_CLIENT_ERROR; |
| 173 break; |
| 174 case media::MediaKeys::kOutputError: |
| 175 exception_code = media::MediaKeys::MEDIA_KEYS_EXCEPTION_OUTPUT_ERROR; |
| 176 break; |
| 177 case media::MediaKeys::kUnknownError: |
| 178 default: |
| 179 exception_code = media::MediaKeys::MEDIA_KEYS_EXCEPTION_UNKNOWN_ERROR; |
| 180 break; |
| 181 } |
| 182 |
| 183 scoped_ptr<media::CdmNewSessionPromise> promise = |
| 184 RetrieveSessionPromise(session_id); |
| 185 if (promise) { |
| 186 promise->reject(exception_code, system_code, std::string()); |
| 187 } else { |
| 188 // Maybe an error for other set of promises. |
| 189 scoped_ptr<media::CdmChangeSessionPromise> promise2 = |
| 190 RetrieveVoidPromise(session_id); |
| 191 if (promise2) { |
| 192 promise2->reject(exception_code, system_code, std::string()); |
| 193 } else { |
| 194 // Errors generally happen in response to a request, but it is possible |
| 195 // for something bad to happen in the CDM and it needs to tell the client. |
| 196 session_error_cb_.Run( |
| 197 web_session_id, exception_code, system_code, std::string()); |
| 198 } |
| 199 } |
113 } | 200 } |
114 | 201 |
115 int ProxyMediaKeys::GetCdmId() const { | 202 int ProxyMediaKeys::GetCdmId() const { |
116 return cdm_id_; | 203 return cdm_id_; |
117 } | 204 } |
118 | 205 |
119 ProxyMediaKeys::ProxyMediaKeys( | 206 ProxyMediaKeys::ProxyMediaKeys( |
120 RendererMediaPlayerManager* manager, | 207 RendererMediaPlayerManager* manager, |
121 const media::SessionCreatedCB& session_created_cb, | |
122 const media::SessionMessageCB& session_message_cb, | 208 const media::SessionMessageCB& session_message_cb, |
123 const media::SessionReadyCB& session_ready_cb, | 209 const media::SessionReadyCB& session_ready_cb, |
124 const media::SessionClosedCB& session_closed_cb, | 210 const media::SessionClosedCB& session_closed_cb, |
125 const media::SessionErrorCB& session_error_cb) | 211 const media::SessionErrorCB& session_error_cb) |
126 : manager_(manager), | 212 : manager_(manager), |
127 cdm_id_(next_cdm_id_++), | 213 cdm_id_(next_cdm_id_++), |
128 session_created_cb_(session_created_cb), | |
129 session_message_cb_(session_message_cb), | 214 session_message_cb_(session_message_cb), |
130 session_ready_cb_(session_ready_cb), | 215 session_ready_cb_(session_ready_cb), |
131 session_closed_cb_(session_closed_cb), | 216 session_closed_cb_(session_closed_cb), |
132 session_error_cb_(session_error_cb) { | 217 session_error_cb_(session_error_cb), |
| 218 next_session_id_(1) { |
133 } | 219 } |
134 | 220 |
135 void ProxyMediaKeys::InitializeCdm(const std::string& key_system, | 221 void ProxyMediaKeys::InitializeCdm(const std::string& key_system, |
136 const GURL& security_origin) { | 222 const GURL& security_origin) { |
137 manager_->InitializeCdm(cdm_id_, this, key_system, security_origin); | 223 manager_->InitializeCdm(cdm_id_, this, key_system, security_origin); |
138 } | 224 } |
139 | 225 |
| 226 uint32_t ProxyMediaKeys::CreateSessionId() { |
| 227 return next_session_id_++; |
| 228 } |
| 229 |
| 230 void ProxyMediaKeys::AssignWebSessionId(uint32_t session_id, |
| 231 const std::string& web_session_id) { |
| 232 web_session_to_session_id_map_.insert( |
| 233 std::make_pair(web_session_id, session_id)); |
| 234 } |
| 235 |
| 236 uint32_t ProxyMediaKeys::LookupSessionId(const std::string& web_session_id) { |
| 237 return web_session_to_session_id_map_.find(web_session_id)->second; |
| 238 } |
| 239 |
| 240 std::string ProxyMediaKeys::LookupWebSessionId(uint32_t session_id) { |
| 241 for (SessionMap::iterator it = web_session_to_session_id_map_.begin(); |
| 242 it != web_session_to_session_id_map_.end(); |
| 243 ++it) { |
| 244 if (it->second == session_id) |
| 245 return it->first; |
| 246 } |
| 247 // Possible to get an error creating a session, so no |web_session_id| |
| 248 // available. |
| 249 return std::string(); |
| 250 } |
| 251 |
| 252 void ProxyMediaKeys::DropWebSessionId(std::string web_session_id) { |
| 253 web_session_to_session_id_map_.erase(web_session_id); |
| 254 } |
| 255 |
| 256 void ProxyMediaKeys::RegisterVoidPromise( |
| 257 uint32_t session_id, |
| 258 scoped_ptr<media::CdmChangeSessionPromise> promise) { |
| 259 // Should only be one promise outstanding for any |session_id|. |
| 260 DCHECK(session_id_to_promise_map_.find(session_id) == |
| 261 session_id_to_promise_map_.end()); |
| 262 session_id_to_promise_map_.insert( |
| 263 std::make_pair(session_id, promise.release())); |
| 264 } |
| 265 |
| 266 scoped_ptr<media::CdmChangeSessionPromise> ProxyMediaKeys::RetrieveVoidPromise( |
| 267 uint32_t session_id) { |
| 268 VoidPromiseMap::iterator it = session_id_to_promise_map_.find(session_id); |
| 269 // May not be a promise associated with this session for asynchronous events. |
| 270 if (it == session_id_to_promise_map_.end()) |
| 271 return scoped_ptr<media::CdmChangeSessionPromise>(); |
| 272 scoped_ptr<media::CdmChangeSessionPromise> result(it->second); |
| 273 session_id_to_promise_map_.erase(it); |
| 274 return result.Pass(); |
| 275 } |
| 276 |
| 277 void ProxyMediaKeys::RegisterSessionPromise( |
| 278 uint32_t session_id, |
| 279 scoped_ptr<media::CdmNewSessionPromise> promise) { |
| 280 // Should only be one promise outstanding for any |session_id|. |
| 281 DCHECK(session_id_to_new_session_promise_map_.find(session_id) == |
| 282 session_id_to_new_session_promise_map_.end()); |
| 283 session_id_to_new_session_promise_map_.insert( |
| 284 std::make_pair(session_id, promise.release())); |
| 285 } |
| 286 |
| 287 scoped_ptr<media::CdmNewSessionPromise> ProxyMediaKeys::RetrieveSessionPromise( |
| 288 uint32_t session_id) { |
| 289 SessionPromiseMap::iterator it = |
| 290 session_id_to_new_session_promise_map_.find(session_id); |
| 291 // May not be a promise associated with this session for asynchronous events. |
| 292 if (it == session_id_to_new_session_promise_map_.end()) |
| 293 return scoped_ptr<media::CdmNewSessionPromise>(); |
| 294 scoped_ptr<media::CdmNewSessionPromise> result(it->second); |
| 295 session_id_to_new_session_promise_map_.erase(it); |
| 296 return result.Pass(); |
| 297 } |
| 298 |
140 } // namespace content | 299 } // namespace content |
OLD | NEW |