1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "content/renderer/media/crypto/proxy_decryptor.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <cstring>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback_helpers.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/strings/string_util.h"
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "content/renderer/media/crypto/content_decryption_module_factory.h"
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "media/base/cdm_promise.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "media/cdm/json_web_key.h"
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "media/cdm/key_system_names.h"
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(ENABLE_PEPPER_CDMS)
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/renderer/media/crypto/pepper_cdm_wrapper.h"
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif  // defined(ENABLE_PEPPER_CDMS)
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if defined(ENABLE_BROWSER_CDMS)
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/renderer/media/crypto/renderer_cdm_manager.h"
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // defined(ENABLE_BROWSER_CDMS)
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace content {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Special system code to signal a closed persistent session in a SessionError()
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// call. This is needed because there is no SessionClosed() call in the prefixed
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// EME API.
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kSessionClosedSystemCode = 29127;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyDecryptor::ProxyDecryptor(
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(ENABLE_PEPPER_CDMS)
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const CreatePepperCdmCB& create_pepper_cdm_cb,
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#elif defined(ENABLE_BROWSER_CDMS)
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    RendererCdmManager* manager,
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif  // defined(ENABLE_PEPPER_CDMS)
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const KeyAddedCB& key_added_cb,
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const KeyErrorCB& key_error_cb,
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const KeyMessageCB& key_message_cb)
4223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    :
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(ENABLE_PEPPER_CDMS)
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      create_pepper_cdm_cb_(create_pepper_cdm_cb),
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#elif defined(ENABLE_BROWSER_CDMS)
461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      manager_(manager),
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      cdm_id_(RendererCdmManager::kInvalidCdmId),
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif  // defined(ENABLE_PEPPER_CDMS)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key_added_cb_(key_added_cb),
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key_error_cb_(key_error_cb),
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      key_message_cb_(key_message_cb),
5223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      is_clear_key_(false),
5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      weak_ptr_factory_(this) {
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(ENABLE_PEPPER_CDMS)
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!create_pepper_cdm_cb_.is_null());
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif  // defined(ENABLE_PEPPER_CDMS)
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!key_added_cb_.is_null());
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!key_error_cb_.is_null());
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!key_message_cb_.is_null());
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyDecryptor::~ProxyDecryptor() {
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Destroy the decryptor explicitly before destroying the plugin.
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  media_keys_.reset();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)media::Decryptor* ProxyDecryptor::GetDecryptor() {
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return media_keys_ ? media_keys_->GetDecryptor() : NULL;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if defined(ENABLE_BROWSER_CDMS)
72e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochint ProxyDecryptor::GetCdmId() {
73e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return cdm_id_;
74e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
75e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#endif
76e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
7768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool ProxyDecryptor::InitializeCDM(const std::string& key_system,
78e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                   const GURL& security_origin) {
797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DVLOG(1) << "InitializeCDM: key_system = " << key_system;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!media_keys_);
82e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  media_keys_ = CreateMediaKeys(key_system, security_origin);
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!media_keys_)
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  is_clear_key_ =
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      media::IsClearKey(key_system) || media::IsExternalClearKey(key_system);
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns true if |data| is prefixed with |header| and has data after the
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// |header|.
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HasHeader(const uint8* data, int data_length, const std::string& header) {
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return static_cast<size_t>(data_length) > header.size() &&
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         std::equal(data, data + header.size(), header.begin());
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ProxyDecryptor::GenerateKeyRequest(const std::string& content_type,
997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                        const uint8* init_data,
1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                        int init_data_length) {
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DVLOG(1) << "GenerateKeyRequest()";
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|";
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|";
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool loadSession =
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader);
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool persistent = HasHeader(
108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      init_data, init_data_length, kPrefixedApiPersistentSessionHeader);
109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<media::NewSessionCdmPromise> promise(
111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      new media::NewSessionCdmPromise(
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          base::Bind(&ProxyDecryptor::SetSessionId,
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     persistent || loadSession),
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          base::Bind(&ProxyDecryptor::OnSessionError,
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     std::string())));  // No session id until created.
118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (loadSession) {
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    media_keys_->LoadSession(
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        std::string(reinterpret_cast<const char*>(
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        init_data + strlen(kPrefixedApiLoadSessionHeader)),
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    init_data_length - strlen(kPrefixedApiLoadSessionHeader)),
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        promise.Pass());
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  media::MediaKeys::SessionType session_type =
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      persistent ? media::MediaKeys::PERSISTENT_SESSION
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                 : media::MediaKeys::TEMPORARY_SESSION;
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  media_keys_->CreateSession(
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      content_type, init_data, init_data_length, session_type, promise.Pass());
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void ProxyDecryptor::AddKey(const uint8* key,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            int key_length,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const uint8* init_data,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            int init_data_length,
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                            const std::string& web_session_id) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "AddKey()";
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // In the prefixed API, the session parameter provided to addKey() is
144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // optional, so use the single existing session if it exists.
145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // TODO(jrummell): remove when the prefixed API is removed.
146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::string session_id(web_session_id);
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (session_id.empty()) {
148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (active_sessions_.size() == 1) {
149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      base::hash_map<std::string, bool>::iterator it = active_sessions_.begin();
150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      session_id = it->first;
151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    } else {
152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      OnSessionError(std::string(),
153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     media::MediaKeys::NOT_SUPPORTED_ERROR,
154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     0,
155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     "SessionId not specified.");
156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return;
157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<media::SimpleCdmPromise> promise(
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      new media::SimpleCdmPromise(base::Bind(&ProxyDecryptor::OnSessionReady,
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             weak_ptr_factory_.GetWeakPtr(),
163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             web_session_id),
164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  base::Bind(&ProxyDecryptor::OnSessionError,
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             weak_ptr_factory_.GetWeakPtr(),
166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             web_session_id)));
167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // EME WD spec only supports a single array passed to the CDM. For
169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Clear Key using v0.1b, both arrays are used (|init_data| is key_id).
170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Since the EME WD spec supports the key as a JSON Web Key,
171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // convert the 2 arrays to a JWK and pass it as the single array.
172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (is_clear_key_) {
173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Decryptor doesn't support empty key ID (see http://crbug.com/123265).
174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // So ensure a non-empty value is passed.
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!init_data) {
176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      static const uint8 kDummyInitData[1] = {0};
177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      init_data = kDummyInitData;
178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      init_data_length = arraysize(kDummyInitData);
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::string jwk =
182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        media::GenerateJWKSet(key, key_length, init_data, init_data_length);
183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK(!jwk.empty());
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    media_keys_->UpdateSession(session_id,
185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               reinterpret_cast<const uint8*>(jwk.data()),
186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               jwk.size(),
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               promise.Pass());
188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  media_keys_->UpdateSession(session_id, key, key_length, promise.Pass());
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ProxyDecryptor::CancelKeyRequest(const std::string& web_session_id) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "CancelKeyRequest()";
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<media::SimpleCdmPromise> promise(
198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      new media::SimpleCdmPromise(base::Bind(&ProxyDecryptor::OnSessionClosed,
199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             weak_ptr_factory_.GetWeakPtr(),
200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             web_session_id),
201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  base::Bind(&ProxyDecryptor::OnSessionError,
202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             weak_ptr_factory_.GetWeakPtr(),
203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             web_session_id)));
204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  media_keys_->ReleaseSession(web_session_id, promise.Pass());
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochscoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys(
20868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& key_system,
209e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const GURL& security_origin) {
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return ContentDecryptionModuleFactory::Create(
2117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      key_system,
212e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      security_origin,
21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if defined(ENABLE_PEPPER_CDMS)
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      create_pepper_cdm_cb_,
215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#elif defined(ENABLE_BROWSER_CDMS)
2161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      manager_,
217e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      &cdm_id_,
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif  // defined(ENABLE_PEPPER_CDMS)
219a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&ProxyDecryptor::OnSessionMessage,
220a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()),
221a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&ProxyDecryptor::OnSessionReady,
222a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()),
223a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&ProxyDecryptor::OnSessionClosed,
224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()),
225a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&ProxyDecryptor::OnSessionError,
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()));
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ProxyDecryptor::OnSessionMessage(const std::string& web_session_id,
230a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                      const std::vector<uint8>& message,
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                      const GURL& destination_url) {
232a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Assumes that OnSessionCreated() has been called before this.
233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  key_message_cb_.Run(web_session_id, message, destination_url);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
236f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ProxyDecryptor::OnSessionReady(const std::string& web_session_id) {
237f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  key_added_cb_.Run(web_session_id);
238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ProxyDecryptor::OnSessionClosed(const std::string& web_session_id) {
241f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::hash_map<std::string, bool>::iterator it =
242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      active_sessions_.find(web_session_id);
243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Latest EME spec separates closing a session ("allows an application to
245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // indicate that it no longer needs the session") and actually closing the
246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // session (done by the CDM at any point "such as in response to a close()
247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // call, when the session is no longer needed, or when system resources are
248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // lost.") Thus the CDM may cause 2 close() events -- one to resolve the
249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // close() promise, and a second to actually close the session. Prefixed EME
250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // only expects 1 close event, so drop the second (and subsequent) events.
251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // However, this means we can't tell if the CDM is generating spurious close()
252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // events.
253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (it == active_sessions_.end())
254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return;
255a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (it->second) {
257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    OnSessionError(web_session_id,
258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   media::MediaKeys::NOT_SUPPORTED_ERROR,
259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   kSessionClosedSystemCode,
260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   "Do not close persistent sessions.");
261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  active_sessions_.erase(it);
263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ProxyDecryptor::OnSessionError(const std::string& web_session_id,
266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    media::MediaKeys::Exception exception_code,
267f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    uint32 system_code,
268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    const std::string& error_message) {
269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Convert |error_name| back to MediaKeys::KeyError if possible. Prefixed
270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // EME has different error message, so all the specific error events will
271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // get lost.
272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  media::MediaKeys::KeyError error_code;
273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  switch (exception_code) {
274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case media::MediaKeys::CLIENT_ERROR:
275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      error_code = media::MediaKeys::kClientError;
276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case media::MediaKeys::OUTPUT_ERROR:
278f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      error_code = media::MediaKeys::kOutputError;
279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    default:
281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // This will include all other CDM4 errors and any error generated
282f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // by CDM5 or later.
283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      error_code = media::MediaKeys::kUnknownError;
284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  key_error_cb_.Run(web_session_id, error_code, system_code);
287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ProxyDecryptor::SetSessionId(bool persistent,
290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  const std::string& web_session_id) {
291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  active_sessions_.insert(std::make_pair(web_session_id, persistent));
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}  // namespace content
295