Home | History | Annotate | Download | only in media
      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