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)
1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  SessionCreationType session_creation_type = TemporarySession;
1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader)) {
1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    session_creation_type = LoadSession;
1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else if (HasHeader(init_data,
1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                       init_data_length,
1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                       kPrefixedApiPersistentSessionHeader)) {
1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    session_creation_type = PersistentSession;
1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<media::NewSessionCdmPromise> promise(
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      new media::NewSessionCdmPromise(
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          base::Bind(&ProxyDecryptor::SetSessionId,
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                     session_creation_type),
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          base::Bind(&ProxyDecryptor::OnSessionError,
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     std::string())));  // No session id until created.
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (session_creation_type == LoadSession) {
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    media_keys_->LoadSession(
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        std::string(reinterpret_cast<const char*>(
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        init_data + strlen(kPrefixedApiLoadSessionHeader)),
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    init_data_length - strlen(kPrefixedApiLoadSessionHeader)),
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        promise.Pass());
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  media::MediaKeys::SessionType session_type =
1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      session_creation_type == PersistentSession
1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          ? media::MediaKeys::PERSISTENT_SESSION
1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          : media::MediaKeys::TEMPORARY_SESSION;
1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Convert MIME types used in the prefixed implementation.
1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string init_data_type;
1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (content_type == "audio/mp4" || content_type == "video/mp4") {
1406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    init_data_type = "cenc";
1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else if (content_type == "audio/webm" || content_type == "video/webm") {
1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    init_data_type = "webm";
1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else {
1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    NOTREACHED();
1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    init_data_type = content_type;
1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  media_keys_->CreateSession(init_data_type, init_data, init_data_length,
1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                             session_type, promise.Pass());
150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void ProxyDecryptor::AddKey(const uint8* key,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            int key_length,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const uint8* init_data,
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            int init_data_length,
157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                            const std::string& web_session_id) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "AddKey()";
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // In the prefixed API, the session parameter provided to addKey() is
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // optional, so use the single existing session if it exists.
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // TODO(jrummell): remove when the prefixed API is removed.
163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::string session_id(web_session_id);
164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (session_id.empty()) {
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (active_sessions_.size() == 1) {
166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      base::hash_map<std::string, bool>::iterator it = active_sessions_.begin();
167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      session_id = it->first;
168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    } else {
169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      OnSessionError(std::string(),
170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     media::MediaKeys::NOT_SUPPORTED_ERROR,
171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     0,
172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     "SessionId not specified.");
173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return;
174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<media::SimpleCdmPromise> promise(
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      new media::SimpleCdmPromise(base::Bind(&ProxyDecryptor::OnSessionReady,
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             weak_ptr_factory_.GetWeakPtr(),
180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             web_session_id),
181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  base::Bind(&ProxyDecryptor::OnSessionError,
182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             weak_ptr_factory_.GetWeakPtr(),
183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             web_session_id)));
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // EME WD spec only supports a single array passed to the CDM. For
186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Clear Key using v0.1b, both arrays are used (|init_data| is key_id).
187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Since the EME WD spec supports the key as a JSON Web Key,
188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // convert the 2 arrays to a JWK and pass it as the single array.
189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (is_clear_key_) {
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Decryptor doesn't support empty key ID (see http://crbug.com/123265).
191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // So ensure a non-empty value is passed.
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!init_data) {
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      static const uint8 kDummyInitData[1] = {0};
194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      init_data = kDummyInitData;
195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      init_data_length = arraysize(kDummyInitData);
196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::string jwk =
199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        media::GenerateJWKSet(key, key_length, init_data, init_data_length);
200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK(!jwk.empty());
201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    media_keys_->UpdateSession(session_id,
202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               reinterpret_cast<const uint8*>(jwk.data()),
203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               jwk.size(),
204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               promise.Pass());
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  media_keys_->UpdateSession(session_id, key, key_length, promise.Pass());
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ProxyDecryptor::CancelKeyRequest(const std::string& web_session_id) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "CancelKeyRequest()";
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<media::SimpleCdmPromise> promise(
215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      new media::SimpleCdmPromise(base::Bind(&ProxyDecryptor::OnSessionClosed,
216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             weak_ptr_factory_.GetWeakPtr(),
217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             web_session_id),
218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  base::Bind(&ProxyDecryptor::OnSessionError,
219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             weak_ptr_factory_.GetWeakPtr(),
220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             web_session_id)));
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  media_keys_->RemoveSession(web_session_id, promise.Pass());
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochscoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys(
22568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& key_system,
226e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const GURL& security_origin) {
227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return ContentDecryptionModuleFactory::Create(
2287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      key_system,
229e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      security_origin,
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if defined(ENABLE_PEPPER_CDMS)
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      create_pepper_cdm_cb_,
232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#elif defined(ENABLE_BROWSER_CDMS)
2331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      manager_,
234e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      &cdm_id_,
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif  // defined(ENABLE_PEPPER_CDMS)
236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&ProxyDecryptor::OnSessionMessage,
237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()),
238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&ProxyDecryptor::OnSessionReady,
239a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()),
240a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&ProxyDecryptor::OnSessionClosed,
241a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()),
242a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&ProxyDecryptor::OnSessionError,
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 weak_ptr_factory_.GetWeakPtr()),
2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&ProxyDecryptor::OnSessionKeysChange,
2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 weak_ptr_factory_.GetWeakPtr()),
2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&ProxyDecryptor::OnSessionExpirationUpdate,
247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()));
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ProxyDecryptor::OnSessionMessage(const std::string& web_session_id,
251a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                      const std::vector<uint8>& message,
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                      const GURL& destination_url) {
253a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Assumes that OnSessionCreated() has been called before this.
25403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
25503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // For ClearKey, convert the message from JSON into just passing the key
25603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // as the message. If unable to extract the key, return the message unchanged.
25703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (is_clear_key_) {
25803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    std::vector<uint8> key;
25903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (media::ExtractFirstKeyIdFromLicenseRequest(message, &key)) {
26003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      key_message_cb_.Run(web_session_id, key, destination_url);
26103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return;
26203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
26303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
26403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  key_message_cb_.Run(web_session_id, message, destination_url);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ProxyDecryptor::OnSessionKeysChange(const std::string& web_session_id,
2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                         bool has_additional_usable_key) {
2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // EME v0.1b doesn't support this event.
2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ProxyDecryptor::OnSessionExpirationUpdate(
2741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& web_session_id,
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::Time& new_expiry_time) {
2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // EME v0.1b doesn't support this event.
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ProxyDecryptor::OnSessionReady(const std::string& web_session_id) {
280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  key_added_cb_.Run(web_session_id);
281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ProxyDecryptor::OnSessionClosed(const std::string& web_session_id) {
284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::hash_map<std::string, bool>::iterator it =
285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      active_sessions_.find(web_session_id);
286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Latest EME spec separates closing a session ("allows an application to
288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // indicate that it no longer needs the session") and actually closing the
289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // session (done by the CDM at any point "such as in response to a close()
290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // call, when the session is no longer needed, or when system resources are
291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // lost.") Thus the CDM may cause 2 close() events -- one to resolve the
292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // close() promise, and a second to actually close the session. Prefixed EME
293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // only expects 1 close event, so drop the second (and subsequent) events.
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // However, this means we can't tell if the CDM is generating spurious close()
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // events.
296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (it == active_sessions_.end())
297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return;
298a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (it->second) {
300f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    OnSessionError(web_session_id,
301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   media::MediaKeys::NOT_SUPPORTED_ERROR,
302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   kSessionClosedSystemCode,
303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                   "Do not close persistent sessions.");
304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
305f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  active_sessions_.erase(it);
306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ProxyDecryptor::OnSessionError(const std::string& web_session_id,
309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    media::MediaKeys::Exception exception_code,
310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    uint32 system_code,
311f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    const std::string& error_message) {
312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Convert |error_name| back to MediaKeys::KeyError if possible. Prefixed
313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // EME has different error message, so all the specific error events will
314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // get lost.
315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  media::MediaKeys::KeyError error_code;
316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  switch (exception_code) {
317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case media::MediaKeys::CLIENT_ERROR:
318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      error_code = media::MediaKeys::kClientError;
319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case media::MediaKeys::OUTPUT_ERROR:
321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      error_code = media::MediaKeys::kOutputError;
322f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
323f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    default:
324f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // This will include all other CDM4 errors and any error generated
325f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // by CDM5 or later.
326f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      error_code = media::MediaKeys::kUnknownError;
327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  key_error_cb_.Run(web_session_id, error_code, system_code);
330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void ProxyDecryptor::SetSessionId(SessionCreationType session_type,
333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  const std::string& web_session_id) {
3346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Loaded sessions are considered persistent.
3356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  bool is_persistent =
3366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      session_type == PersistentSession || session_type == LoadSession;
3376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  active_sessions_.insert(std::make_pair(web_session_id, is_persistent));
3386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // For LoadSession(), generate the SessionReady event.
3406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (session_type == LoadSession)
3416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    OnSessionReady(web_session_id);
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}  // namespace content
345