1 // Copyright 2014 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.
5 #include "webencryptedmediaclient_impl.h"
7 #include "base/logging.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "media/base/key_systems.h"
11 #include "net/base/mime_util.h"
12 #include "third_party/WebKit/public/platform/WebEncryptedMediaRequest.h"
13 #include "third_party/WebKit/public/platform/WebMediaKeySystemConfiguration.h"
14 #include "third_party/WebKit/public/platform/WebString.h"
15 #include "third_party/WebKit/public/platform/WebVector.h"
16 #include "webcontentdecryptionmoduleaccess_impl.h"
20 static bool IsSupportedContentType(
21 const std::string
& key_system
,
22 const std::string
& mime_type
,
23 const std::string
& codecs
) {
24 // Per RFC 6838, "Both top-level type and subtype names are case-insensitive."
25 // TODO(sandersd): Check that |container| matches the capability:
26 // - audioCapabilitys: audio/mp4 or audio/webm.
27 // - videoCapabilitys: video/mp4 or video/webm.
28 // http://crbug.com/429781.
29 std::string container
= base::StringToLowerASCII(mime_type
);
31 // TODO(sandersd): Strict checking for codecs. http://crbug.com/374751.
32 bool strip_codec_suffixes
= !net::IsStrictMediaMimeType(container
);
33 std::vector
<std::string
> codec_vector
;
34 net::ParseCodecString(codecs
, &codec_vector
, strip_codec_suffixes
);
35 return IsSupportedKeySystemWithMediaMimeType(container
, codec_vector
,
39 static bool GetSupportedConfiguration(
40 const std::string
& key_system
,
41 const blink::WebMediaKeySystemConfiguration
& candidate
,
42 const blink::WebSecurityOrigin
& security_origin
,
43 blink::WebMediaKeySystemConfiguration
* accumulated_configuration
) {
44 if (!candidate
.initDataTypes
.isEmpty()) {
45 std::vector
<blink::WebString
> init_data_types
;
47 for (size_t i
= 0; i
< candidate
.initDataTypes
.size(); i
++) {
48 const blink::WebString
& init_data_type
= candidate
.initDataTypes
[i
];
49 if (init_data_type
.isEmpty())
51 if (base::IsStringASCII(init_data_type
) &&
52 IsSupportedKeySystemWithInitDataType(
53 key_system
, base::UTF16ToASCII(init_data_type
))) {
54 init_data_types
.push_back(init_data_type
);
58 if (init_data_types
.empty())
61 accumulated_configuration
->initDataTypes
= init_data_types
;
64 // TODO(sandersd): Implement distinctiveIdentifier and persistentState checks.
65 if (candidate
.distinctiveIdentifier
!=
66 blink::WebMediaKeySystemConfiguration::Requirement::Optional
||
67 candidate
.persistentState
!=
68 blink::WebMediaKeySystemConfiguration::Requirement::Optional
) {
72 if (!candidate
.audioCapabilities
.isEmpty()) {
73 std::vector
<blink::WebMediaKeySystemMediaCapability
> audio_capabilities
;
75 for (size_t i
= 0; i
< candidate
.audioCapabilities
.size(); i
++) {
76 const blink::WebMediaKeySystemMediaCapability
& capabilities
=
77 candidate
.audioCapabilities
[i
];
78 if (capabilities
.mimeType
.isEmpty())
80 if (!base::IsStringASCII(capabilities
.mimeType
) ||
81 !base::IsStringASCII(capabilities
.codecs
) ||
82 !IsSupportedContentType(
83 key_system
, base::UTF16ToASCII(capabilities
.mimeType
),
84 base::UTF16ToASCII(capabilities
.codecs
))) {
87 // TODO(sandersd): Support robustness.
88 if (!capabilities
.robustness
.isEmpty())
90 audio_capabilities
.push_back(capabilities
);
93 if (audio_capabilities
.empty())
96 accumulated_configuration
->audioCapabilities
= audio_capabilities
;
99 if (!candidate
.videoCapabilities
.isEmpty()) {
100 std::vector
<blink::WebMediaKeySystemMediaCapability
> video_capabilities
;
102 for (size_t i
= 0; i
< candidate
.videoCapabilities
.size(); i
++) {
103 const blink::WebMediaKeySystemMediaCapability
& capabilities
=
104 candidate
.videoCapabilities
[i
];
105 if (capabilities
.mimeType
.isEmpty())
107 if (!base::IsStringASCII(capabilities
.mimeType
) ||
108 !base::IsStringASCII(capabilities
.codecs
) ||
109 !IsSupportedContentType(
110 key_system
, base::UTF16ToASCII(capabilities
.mimeType
),
111 base::UTF16ToASCII(capabilities
.codecs
))) {
114 // TODO(sandersd): Support robustness.
115 if (!capabilities
.robustness
.isEmpty())
117 video_capabilities
.push_back(capabilities
);
120 if (video_capabilities
.empty())
123 accumulated_configuration
->videoCapabilities
= video_capabilities
;
126 // TODO(sandersd): Prompt for distinctive identifiers and/or persistent state
127 // if required. Make sure that future checks are silent.
128 // http://crbug.com/446263.
133 WebEncryptedMediaClientImpl::WebEncryptedMediaClientImpl(
134 scoped_ptr
<CdmFactory
> cdm_factory
)
135 : cdm_factory_(cdm_factory
.Pass()) {
138 WebEncryptedMediaClientImpl::~WebEncryptedMediaClientImpl() {
141 void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess(
142 blink::WebEncryptedMediaRequest request
) {
143 // TODO(jrummell): This should be asynchronous.
145 // Continued from requestMediaKeySystemAccess(), step 7, from
146 // https://w3c.github.io/encrypted-media/#requestmediakeysystemaccess
148 // 7.1 If keySystem is not one of the Key Systems supported by the user
149 // agent, reject promise with with a new DOMException whose name is
150 // NotSupportedError. String comparison is case-sensitive.
151 if (!base::IsStringASCII(request
.keySystem())) {
152 request
.requestNotSupported("Only ASCII keySystems are supported");
156 std::string key_system
= base::UTF16ToASCII(request
.keySystem());
157 if (!IsConcreteSupportedKeySystem(key_system
)) {
158 request
.requestNotSupported("Unsupported keySystem");
162 // 7.2 Let implementation be the implementation of keySystem.
163 // 7.3 Follow the steps for the first matching condition from the following
165 // - If supportedConfigurations was not provided, run the Is Key System
166 // Supported? algorithm and if successful, resolve promise with access
167 // and abort these steps.
168 // TODO(sandersd): Remove pending the resolution of
169 // https://github.com/w3c/encrypted-media/issues/1.
170 const blink::WebVector
<blink::WebMediaKeySystemConfiguration
>&
171 configurations
= request
.supportedConfigurations();
172 if (configurations
.isEmpty()) {
173 request
.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create(
174 request
.keySystem(), request
.securityOrigin(), cdm_factory_
.get()));
178 // - Otherwise, for each value in supportedConfigurations, run the
179 // GetSuppored Configuration algorithm and if successful, resolve
180 // promise with access and abort these steps.
181 for (size_t i
= 0; i
< configurations
.size(); i
++) {
182 const blink::WebMediaKeySystemConfiguration
& candidate
= configurations
[i
];
183 blink::WebMediaKeySystemConfiguration accumulated_configuration
;
184 if (GetSupportedConfiguration(key_system
, candidate
,
185 request
.securityOrigin(),
186 &accumulated_configuration
)) {
187 // TODO(sandersd): Pass the accumulated configuration along.
188 // http://crbug.com/447059.
189 request
.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create(
190 request
.keySystem(), request
.securityOrigin(), cdm_factory_
.get()));
195 // 7.4 Reject promise with a new DOMException whose name is NotSupportedError.
196 request
.requestNotSupported(
197 "None of the requested configurations were supported.");