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/crypto/key_systems.h"
6
7#include <map>
8
9#include "base/lazy_instance.h"
10#include "base/logging.h"
11#include "base/strings/string_util.h"
12#include "content/renderer/media/crypto/key_systems_info.h"
13#include "net/base/mime_util.h"
14#include "third_party/WebKit/public/platform/WebCString.h"
15#include "third_party/WebKit/public/platform/WebString.h"
16
17namespace content {
18
19// Convert a WebString to ASCII, falling back on an empty string in the case
20// of a non-ASCII string.
21static std::string ToASCIIOrEmpty(const WebKit::WebString& string) {
22  return IsStringASCII(string) ? UTF16ToASCII(string) : std::string();
23}
24
25class KeySystems {
26 public:
27  bool IsSupportedKeySystem(const std::string& key_system);
28
29  bool IsSupportedKeySystemWithMediaMimeType(
30      const std::string& mime_type,
31      const std::vector<std::string>& codecs,
32      const std::string& key_system);
33
34 private:
35  friend struct base::DefaultLazyInstanceTraits<KeySystems>;
36
37  typedef base::hash_set<std::string> CodecMappings;
38  typedef std::map<std::string, CodecMappings> MimeTypeMappings;
39  typedef std::map<std::string, MimeTypeMappings> KeySystemMappings;
40
41  KeySystems();
42
43  bool IsSupportedKeySystemWithContainerAndCodec(
44      const std::string& mime_type,
45      const std::string& codec,
46      const std::string& key_system);
47
48  KeySystemMappings key_system_map_;
49
50  DISALLOW_COPY_AND_ASSIGN(KeySystems);
51};
52
53static base::LazyInstance<KeySystems> g_key_systems = LAZY_INSTANCE_INITIALIZER;
54
55KeySystems::KeySystems() {
56  // Initialize the supported media type/key system combinations.
57  for (int i = 0; i < kNumSupportedFormatKeySystemCombinations; ++i) {
58    const MediaFormatAndKeySystem& combination =
59        kSupportedFormatKeySystemCombinations[i];
60    std::vector<std::string> mime_type_codecs;
61    net::ParseCodecString(combination.codecs_list,
62                          &mime_type_codecs,
63                          false);
64
65    CodecMappings codecs;
66    for (size_t j = 0; j < mime_type_codecs.size(); ++j)
67      codecs.insert(mime_type_codecs[j]);
68    // Support the MIME type string alone, without codec(s) specified.
69    codecs.insert(std::string());
70
71    // Key systems can be repeated, so there may already be an entry.
72    KeySystemMappings::iterator key_system_iter =
73        key_system_map_.find(combination.key_system);
74    if (key_system_iter == key_system_map_.end()) {
75      MimeTypeMappings mime_types_map;
76      mime_types_map[combination.mime_type] = codecs;
77      key_system_map_[combination.key_system] = mime_types_map;
78    } else {
79      MimeTypeMappings& mime_types_map = key_system_iter->second;
80      // mime_types_map may not be repeated for a given key system.
81      DCHECK(mime_types_map.find(combination.mime_type) ==
82             mime_types_map.end());
83      mime_types_map[combination.mime_type] = codecs;
84    }
85  }
86}
87
88bool KeySystems::IsSupportedKeySystem(const std::string& key_system) {
89  bool is_supported = key_system_map_.find(key_system) != key_system_map_.end();
90  return is_supported && IsSystemCompatible(key_system);
91}
92
93bool KeySystems::IsSupportedKeySystemWithContainerAndCodec(
94    const std::string& mime_type,
95    const std::string& codec,
96    const std::string& key_system) {
97  KeySystemMappings::const_iterator key_system_iter =
98      key_system_map_.find(key_system);
99  if (key_system_iter == key_system_map_.end())
100    return false;
101
102  const MimeTypeMappings& mime_types_map = key_system_iter->second;
103  MimeTypeMappings::const_iterator mime_iter = mime_types_map.find(mime_type);
104  if (mime_iter == mime_types_map.end())
105    return false;
106
107  const CodecMappings& codecs = mime_iter->second;
108  return (codecs.find(codec) != codecs.end()) && IsSystemCompatible(key_system);
109}
110
111bool KeySystems::IsSupportedKeySystemWithMediaMimeType(
112    const std::string& mime_type,
113    const std::vector<std::string>& codecs,
114    const std::string& key_system) {
115  // This method is only used by the canPlaytType() path (not the EME methods),
116  // so we check for suppressed key_systems here.
117  if(IsCanPlayTypeSuppressed(key_system))
118    return false;
119
120  if (codecs.empty())
121    return IsSupportedKeySystemWithContainerAndCodec(
122        mime_type, std::string(), key_system);
123
124  for (size_t i = 0; i < codecs.size(); ++i) {
125    if (!IsSupportedKeySystemWithContainerAndCodec(
126            mime_type, codecs[i], key_system))
127      return false;
128  }
129
130  return true;
131}
132
133bool IsSupportedKeySystem(const WebKit::WebString& key_system) {
134  return g_key_systems.Get().IsSupportedKeySystem(ToASCIIOrEmpty(key_system));
135}
136
137bool IsSupportedKeySystemWithMediaMimeType(
138    const std::string& mime_type,
139    const std::vector<std::string>& codecs,
140    const std::string& key_system) {
141  return g_key_systems.Get().IsSupportedKeySystemWithMediaMimeType(
142      mime_type, codecs, key_system);
143}
144
145std::string KeySystemNameForUMA(const WebKit::WebString& key_system) {
146  return KeySystemNameForUMAInternal(key_system);
147}
148
149bool CanUseAesDecryptor(const std::string& key_system) {
150  return CanUseBuiltInAesDecryptor(key_system);
151}
152
153#if defined(ENABLE_PEPPER_CDMS)
154std::string GetPepperType(const std::string& key_system) {
155  for (int i = 0; i < kNumKeySystemToPepperTypeMapping; ++i) {
156    if (kKeySystemToPepperTypeMapping[i].key_system == key_system)
157      return kKeySystemToPepperTypeMapping[i].type;
158  }
159
160  return std::string();
161}
162#endif  // defined(ENABLE_PEPPER_CDMS)
163
164#if defined(OS_ANDROID)
165std::vector<uint8> GetUUID(const std::string& key_system) {
166  for (int i = 0; i < kNumKeySystemToUUIDMapping; ++i) {
167    if (kKeySystemToUUIDMapping[i].key_system == key_system)
168      return std::vector<uint8>(kKeySystemToUUIDMapping[i].uuid,
169                                kKeySystemToUUIDMapping[i].uuid + 16);
170  }
171  return std::vector<uint8>();
172}
173#endif  // defined(OS_ANDROID)
174
175}  // namespace content
176