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 3 // found in the LICENSE file. 4 5 #include "content/renderer/media/webcontentdecryptionmodulesession_impl.h" 6 7 #include "base/bind.h" 8 #include "base/callback_helpers.h" 9 #include "base/logging.h" 10 #include "base/strings/string_util.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "content/renderer/media/cdm_result_promise.h" 13 #include "content/renderer/media/cdm_session_adapter.h" 14 #include "media/base/cdm_promise.h" 15 #include "third_party/WebKit/public/platform/WebURL.h" 16 17 namespace content { 18 19 const char kCreateSessionUMAName[] = "CreateSession"; 20 21 typedef base::Callback<blink::WebContentDecryptionModuleResult::SessionStatus( 22 const std::string& web_session_id)> SessionInitializedCB; 23 24 class NewSessionCdmResultPromise : public CdmResultPromise<std::string> { 25 public: 26 NewSessionCdmResultPromise(blink::WebContentDecryptionModuleResult result, 27 std::string uma_name, 28 const SessionInitializedCB& new_session_created_cb) 29 : CdmResultPromise<std::string>(result, uma_name), 30 new_session_created_cb_(new_session_created_cb) {} 31 32 protected: 33 virtual void OnResolve(const std::string& web_session_id) OVERRIDE { 34 blink::WebContentDecryptionModuleResult::SessionStatus status = 35 new_session_created_cb_.Run(web_session_id); 36 web_cdm_result_.completeWithSession(status); 37 } 38 39 private: 40 SessionInitializedCB new_session_created_cb_; 41 }; 42 43 WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl( 44 const scoped_refptr<CdmSessionAdapter>& adapter) 45 : adapter_(adapter), 46 is_closed_(false), 47 weak_ptr_factory_(this) { 48 } 49 50 WebContentDecryptionModuleSessionImpl:: 51 ~WebContentDecryptionModuleSessionImpl() { 52 if (!web_session_id_.empty()) 53 adapter_->UnregisterSession(web_session_id_); 54 } 55 56 void WebContentDecryptionModuleSessionImpl::setClientInterface(Client* client) { 57 client_ = client; 58 } 59 60 blink::WebString WebContentDecryptionModuleSessionImpl::sessionId() const { 61 return blink::WebString::fromUTF8(web_session_id_); 62 } 63 64 void WebContentDecryptionModuleSessionImpl::initializeNewSession( 65 const blink::WebString& init_data_type, 66 const uint8* init_data, 67 size_t init_data_length) { 68 // TODO(jrummell): Remove once blink updated. 69 NOTREACHED(); 70 } 71 72 void WebContentDecryptionModuleSessionImpl::update(const uint8* response, 73 size_t response_length) { 74 // TODO(jrummell): Remove once blink updated. 75 NOTREACHED(); 76 } 77 78 void WebContentDecryptionModuleSessionImpl::release() { 79 // TODO(jrummell): Remove once blink updated. 80 NOTREACHED(); 81 } 82 83 void WebContentDecryptionModuleSessionImpl::initializeNewSession( 84 const blink::WebString& init_data_type, 85 const uint8* init_data, 86 size_t init_data_length, 87 const blink::WebString& session_type, 88 blink::WebContentDecryptionModuleResult result) { 89 90 // TODO(ddorwin): Guard against this in supported types check and remove this. 91 // Chromium only supports ASCII MIME types. 92 if (!base::IsStringASCII(init_data_type)) { 93 NOTREACHED(); 94 std::string message = "The initialization data type " + 95 init_data_type.utf8() + 96 " is not supported by the key system."; 97 result.completeWithError( 98 blink::WebContentDecryptionModuleExceptionNotSupportedError, 99 0, 100 blink::WebString::fromUTF8(message)); 101 return; 102 } 103 104 std::string init_data_type_as_ascii = base::UTF16ToASCII(init_data_type); 105 DLOG_IF(WARNING, init_data_type_as_ascii.find('/') != std::string::npos) 106 << "init_data_type '" << init_data_type_as_ascii 107 << "' may be a MIME type"; 108 109 adapter_->InitializeNewSession( 110 init_data_type_as_ascii, 111 init_data, 112 init_data_length, 113 media::MediaKeys::TEMPORARY_SESSION, 114 scoped_ptr<media::NewSessionCdmPromise>(new NewSessionCdmResultPromise( 115 result, 116 adapter_->GetKeySystemUMAPrefix() + kCreateSessionUMAName, 117 base::Bind( 118 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized, 119 base::Unretained(this))))); 120 } 121 122 void WebContentDecryptionModuleSessionImpl::update( 123 const uint8* response, 124 size_t response_length, 125 blink::WebContentDecryptionModuleResult result) { 126 DCHECK(response); 127 DCHECK(!web_session_id_.empty()); 128 adapter_->UpdateSession( 129 web_session_id_, 130 response, 131 response_length, 132 scoped_ptr<media::SimpleCdmPromise>(new SimpleCdmResultPromise(result))); 133 } 134 135 void WebContentDecryptionModuleSessionImpl::close( 136 blink::WebContentDecryptionModuleResult result) { 137 DCHECK(!web_session_id_.empty()); 138 adapter_->CloseSession( 139 web_session_id_, 140 scoped_ptr<media::SimpleCdmPromise>(new SimpleCdmResultPromise(result))); 141 } 142 143 void WebContentDecryptionModuleSessionImpl::remove( 144 blink::WebContentDecryptionModuleResult result) { 145 DCHECK(!web_session_id_.empty()); 146 adapter_->RemoveSession( 147 web_session_id_, 148 scoped_ptr<media::SimpleCdmPromise>(new SimpleCdmResultPromise(result))); 149 } 150 151 void WebContentDecryptionModuleSessionImpl::getUsableKeyIds( 152 blink::WebContentDecryptionModuleResult result) { 153 DCHECK(!web_session_id_.empty()); 154 adapter_->GetUsableKeyIds( 155 web_session_id_, 156 scoped_ptr<media::KeyIdsPromise>( 157 new CdmResultPromise<media::KeyIdsVector>(result))); 158 } 159 160 void WebContentDecryptionModuleSessionImpl::release( 161 blink::WebContentDecryptionModuleResult result) { 162 close(result); 163 } 164 165 void WebContentDecryptionModuleSessionImpl::OnSessionMessage( 166 const std::vector<uint8>& message, 167 const GURL& destination_url) { 168 DCHECK(client_) << "Client not set before message event"; 169 client_->message( 170 message.empty() ? NULL : &message[0], message.size(), destination_url); 171 } 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::OnSessionExpirationUpdate( 179 const base::Time& new_expiry_time) { 180 // TODO(jrummell): Update this once Blink client supports this. 181 // The EME spec has expiration attribute as the time in milliseconds, so use 182 // InMillisecondsF() to convert. 183 } 184 185 void WebContentDecryptionModuleSessionImpl::OnSessionReady() { 186 client_->ready(); 187 } 188 189 void WebContentDecryptionModuleSessionImpl::OnSessionClosed() { 190 if (!is_closed_) { 191 is_closed_ = true; 192 client_->close(); 193 } 194 } 195 196 void WebContentDecryptionModuleSessionImpl::OnSessionError( 197 media::MediaKeys::Exception exception_code, 198 uint32 system_code, 199 const std::string& error_message) { 200 // Convert |exception_code| back to MediaKeyErrorCode if possible. 201 // TODO(jrummell): Update this conversion when promises flow 202 // back into blink:: (as blink:: will have its own error definition). 203 switch (exception_code) { 204 case media::MediaKeys::CLIENT_ERROR: 205 client_->error(Client::MediaKeyErrorCodeClient, system_code); 206 break; 207 default: 208 // This will include all other CDM4 errors and any error generated 209 // by CDM5 or later. 210 client_->error(Client::MediaKeyErrorCodeUnknown, system_code); 211 break; 212 } 213 } 214 215 blink::WebContentDecryptionModuleResult::SessionStatus 216 WebContentDecryptionModuleSessionImpl::OnSessionInitialized( 217 const std::string& web_session_id) { 218 // CDM will return NULL if the session to be loaded can't be found. 219 if (web_session_id.empty()) 220 return blink::WebContentDecryptionModuleResult::SessionNotFound; 221 222 DCHECK(web_session_id_.empty()) << "Session ID may not be changed once set."; 223 web_session_id_ = web_session_id; 224 return adapter_->RegisterSession(web_session_id_, 225 weak_ptr_factory_.GetWeakPtr()) 226 ? blink::WebContentDecryptionModuleResult::NewSession 227 : blink::WebContentDecryptionModuleResult::SessionAlreadyExists; 228 } 229 230 } // namespace content 231