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/webcontentdecryptionmodule_impl.h"
      6 
      7 #include <map>
      8 #include <vector>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/bind.h"
     12 #include "base/callback_helpers.h"
     13 #include "base/logging.h"
     14 #include "base/memory/weak_ptr.h"
     15 #include "base/strings/string_util.h"
     16 #include "content/renderer/media/crypto/content_decryption_module_factory.h"
     17 #include "content/renderer/media/webcontentdecryptionmodulesession_impl.h"
     18 #include "media/base/media_keys.h"
     19 #include "url/gurl.h"
     20 
     21 namespace content {
     22 
     23 // Forwards the session ID-based callbacks of the MediaKeys interface to the
     24 // appropriate session object.
     25 class SessionIdAdapter {
     26  public:
     27   SessionIdAdapter();
     28   ~SessionIdAdapter();
     29 
     30   // On success, creates a MediaKeys, returns it in |media_keys|, returns true.
     31   bool Initialize(const std::string& key_system,
     32                   scoped_ptr<media::MediaKeys>* media_keys);
     33 
     34   // Generates a unique internal session id.
     35   uint32 GenerateSessionId();
     36 
     37   // Adds a session to the internal map. Does not take ownership of the session.
     38   void AddSession(uint32 session_id,
     39                   WebContentDecryptionModuleSessionImpl* session);
     40 
     41   // Removes a session from the internal map.
     42   void RemoveSession(uint32 session_id);
     43 
     44  private:
     45   typedef std::map<uint32, WebContentDecryptionModuleSessionImpl*> SessionMap;
     46 
     47   // Callbacks for firing session events.
     48   void OnSessionCreated(uint32 session_id, const std::string& web_session_id);
     49   void OnSessionMessage(uint32 session_id,
     50                         const std::vector<uint8>& message,
     51                         const std::string& destination_url);
     52   void OnSessionReady(uint32 session_id);
     53   void OnSessionClosed(uint32 session_id);
     54   void OnSessionError(uint32 session_id,
     55                       media::MediaKeys::KeyError error_code,
     56                       int system_code);
     57 
     58   // Helper function of the callbacks.
     59   WebContentDecryptionModuleSessionImpl* GetSession(uint32 session_id);
     60 
     61   base::WeakPtrFactory<SessionIdAdapter> weak_ptr_factory_;
     62 
     63   SessionMap sessions_;
     64 
     65   // Session ID should be unique per renderer process for debugging purposes.
     66   static uint32 next_session_id_;
     67 
     68   DISALLOW_COPY_AND_ASSIGN(SessionIdAdapter);
     69 };
     70 
     71 const uint32 kStartingSessionId = 1;
     72 uint32 SessionIdAdapter::next_session_id_ = kStartingSessionId;
     73 COMPILE_ASSERT(kStartingSessionId > media::MediaKeys::kInvalidSessionId,
     74                invalid_starting_value);
     75 
     76 SessionIdAdapter::SessionIdAdapter()
     77     : weak_ptr_factory_(this) {
     78 }
     79 
     80 SessionIdAdapter::~SessionIdAdapter() {
     81 }
     82 
     83 bool SessionIdAdapter::Initialize(const std::string& key_system,
     84                                   scoped_ptr<media::MediaKeys>* media_keys) {
     85   DCHECK(media_keys);
     86   DCHECK(!*media_keys);
     87 
     88   base::WeakPtr<SessionIdAdapter> weak_this = weak_ptr_factory_.GetWeakPtr();
     89   scoped_ptr<media::MediaKeys> created_media_keys =
     90       ContentDecryptionModuleFactory::Create(
     91           // TODO(ddorwin): Address lower in the stack: http://crbug.com/252065
     92           "webkit-" + key_system,
     93 #if defined(ENABLE_PEPPER_CDMS)
     94           // TODO(ddorwin): Support Pepper-based CDMs: http://crbug.com/250049
     95           NULL,
     96           NULL,
     97           base::Closure(),
     98 #elif defined(OS_ANDROID)
     99           // TODO(xhwang): Support Android.
    100           NULL,
    101           0,
    102           // TODO(ddorwin): Get the URL for the frame containing the MediaKeys.
    103           GURL(),
    104 #endif  // defined(ENABLE_PEPPER_CDMS)
    105           base::Bind(&SessionIdAdapter::OnSessionCreated, weak_this),
    106           base::Bind(&SessionIdAdapter::OnSessionMessage, weak_this),
    107           base::Bind(&SessionIdAdapter::OnSessionReady, weak_this),
    108           base::Bind(&SessionIdAdapter::OnSessionClosed, weak_this),
    109           base::Bind(&SessionIdAdapter::OnSessionError, weak_this));
    110   if (!created_media_keys)
    111     return false;
    112 
    113   *media_keys = created_media_keys.Pass();
    114   return true;
    115 }
    116 
    117 uint32 SessionIdAdapter::GenerateSessionId() {
    118   return next_session_id_++;
    119 }
    120 
    121 void SessionIdAdapter::AddSession(
    122     uint32 session_id,
    123     WebContentDecryptionModuleSessionImpl* session) {
    124   DCHECK(sessions_.find(session_id) == sessions_.end());
    125   sessions_[session_id] = session;
    126 }
    127 
    128 void SessionIdAdapter::RemoveSession(uint32 session_id) {
    129   DCHECK(sessions_.find(session_id) != sessions_.end());
    130   sessions_.erase(session_id);
    131 }
    132 
    133 void SessionIdAdapter::OnSessionCreated(uint32 session_id,
    134                                         const std::string& web_session_id) {
    135   GetSession(session_id)->OnSessionCreated(web_session_id);
    136 }
    137 
    138 void SessionIdAdapter::OnSessionMessage(uint32 session_id,
    139                                         const std::vector<uint8>& message,
    140                                         const std::string& destination_url) {
    141   GetSession(session_id)->OnSessionMessage(message, destination_url);
    142 }
    143 
    144 void SessionIdAdapter::OnSessionReady(uint32 session_id) {
    145   GetSession(session_id)->OnSessionReady();
    146 }
    147 
    148 void SessionIdAdapter::OnSessionClosed(uint32 session_id) {
    149   GetSession(session_id)->OnSessionClosed();
    150 }
    151 
    152 void SessionIdAdapter::OnSessionError(uint32 session_id,
    153                                       media::MediaKeys::KeyError error_code,
    154                                       int system_code) {
    155   GetSession(session_id)->OnSessionError(error_code, system_code);
    156 }
    157 
    158 WebContentDecryptionModuleSessionImpl* SessionIdAdapter::GetSession(
    159     uint32 session_id) {
    160   DCHECK(sessions_.find(session_id) != sessions_.end());
    161   return sessions_[session_id];
    162 }
    163 
    164 //------------------------------------------------------------------------------
    165 
    166 WebContentDecryptionModuleImpl*
    167 WebContentDecryptionModuleImpl::Create(const base::string16& key_system) {
    168   // TODO(ddorwin): Guard against this in supported types check and remove this.
    169   // Chromium only supports ASCII key systems.
    170   if (!IsStringASCII(key_system)) {
    171     NOTREACHED();
    172     return NULL;
    173   }
    174 
    175   // SessionIdAdapter creates the MediaKeys so it can provide its callbacks to
    176   // during creation of the MediaKeys.
    177   scoped_ptr<media::MediaKeys> media_keys;
    178   scoped_ptr<SessionIdAdapter> adapter(new SessionIdAdapter());
    179   if (!adapter->Initialize(UTF16ToASCII(key_system), &media_keys))
    180     return NULL;
    181 
    182   return new WebContentDecryptionModuleImpl(media_keys.Pass(), adapter.Pass());
    183 }
    184 
    185 WebContentDecryptionModuleImpl::WebContentDecryptionModuleImpl(
    186     scoped_ptr<media::MediaKeys> media_keys,
    187     scoped_ptr<SessionIdAdapter> adapter)
    188     : media_keys_(media_keys.Pass()),
    189       adapter_(adapter.Pass()) {
    190 }
    191 
    192 WebContentDecryptionModuleImpl::~WebContentDecryptionModuleImpl() {
    193 }
    194 
    195 // The caller owns the created session.
    196 blink::WebContentDecryptionModuleSession*
    197 WebContentDecryptionModuleImpl::createSession(
    198     blink::WebContentDecryptionModuleSession::Client* client) {
    199   DCHECK(media_keys_);
    200   uint32 session_id = adapter_->GenerateSessionId();
    201   WebContentDecryptionModuleSessionImpl* session =
    202       new WebContentDecryptionModuleSessionImpl(
    203           session_id,
    204           media_keys_.get(),
    205           client,
    206           base::Bind(&WebContentDecryptionModuleImpl::OnSessionClosed,
    207                      base::Unretained(this)));
    208 
    209   adapter_->AddSession(session_id, session);
    210   return session;
    211 }
    212 
    213 void WebContentDecryptionModuleImpl::OnSessionClosed(uint32 session_id) {
    214   adapter_->RemoveSession(session_id);
    215 }
    216 
    217 }  // namespace content
    218