Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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. | |
| 4 | |
| 5 #include "config.h" | |
| 6 #include "modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.h" | |
| 7 | |
| 8 #include "bindings/core/v8/ScriptPromiseResolver.h" | |
| 9 #include "bindings/core/v8/ScriptState.h" | |
| 10 #include "core/dom/DOMException.h" | |
| 11 #include "core/dom/ExceptionCode.h" | |
| 12 #include "modules/encryptedmedia/MediaKeySystemAccess.h" | |
| 13 #include "platform/ContentType.h" | |
| 14 #include "platform/Logging.h" | |
| 15 #include "platform/MIMETypeRegistry.h" | |
| 16 #include "wtf/text/WTFString.h" | |
| 17 | |
| 18 namespace blink { | |
| 19 | |
| 20 static bool isKeySystemSupportedWithContentType(const String& keySystem, const S tring& contentType) | |
| 21 { | |
| 22 ASSERT(!keySystem.isEmpty()); | |
| 23 | |
| 24 ContentType type(contentType); | |
| 25 String codecs = type.parameter("codecs"); | |
| 26 return MIMETypeRegistry::isSupportedEncryptedMediaMIMEType(keySystem, type.t ype(), codecs); | |
| 27 } | |
| 28 | |
| 29 const char* mediaKeysRequirementValidValues[] = { "required", "optional", "disal lowed" }; | |
| 30 | |
| 31 static bool IsValidMediaKeysRequirement(const String& itemValue) | |
| 32 { | |
| 33 for (size_t i = 0; i < WTF_ARRAY_LENGTH(mediaKeysRequirementValidValues); ++ i) { | |
| 34 if (mediaKeysRequirementValidValues[i] == itemValue) | |
| 35 return true; | |
| 36 } | |
| 37 return false; | |
| 38 } | |
| 39 | |
| 40 // This needs to change if MediaKeySystemOptions.idl changes. | |
| 41 MediaKeySystemOptions ConvertDictionaryIntoMediaKeySystemOptions(Dictionary& dic tionary, ExceptionState& exceptionState) | |
| 42 { | |
| 43 MediaKeySystemOptions result; | |
| 44 String itemValue; | |
| 45 | |
| 46 if (DictionaryHelper::get(dictionary, "initDataType", itemValue)) | |
| 47 result.setInitDataType(itemValue); | |
| 48 | |
| 49 if (DictionaryHelper::get(dictionary, "audioType", itemValue)) | |
| 50 result.setAudioType(itemValue); | |
| 51 | |
| 52 if (DictionaryHelper::get(dictionary, "audioCapability", itemValue)) | |
| 53 result.setAudioCapability(itemValue); | |
| 54 | |
| 55 if (DictionaryHelper::get(dictionary, "videoType", itemValue)) | |
| 56 result.setVideoType(itemValue); | |
| 57 | |
| 58 if (DictionaryHelper::get(dictionary, "videoCapability", itemValue)) | |
| 59 result.setVideoCapability(itemValue); | |
| 60 | |
| 61 if (DictionaryHelper::get(dictionary, "uniqueidentifier", itemValue)) { | |
| 62 if (!IsValidMediaKeysRequirement(itemValue)) | |
| 63 exceptionState.throwTypeError("Invalid MediaKeysRequirement value fo r 'uniqueidentifier'."); | |
| 64 result.setUniqueidentifier(itemValue); | |
| 65 } | |
| 66 | |
| 67 if (DictionaryHelper::get(dictionary, "stateful", itemValue)) { | |
| 68 if (!IsValidMediaKeysRequirement(itemValue)) | |
| 69 exceptionState.throwTypeError("Invalid MediaKeysRequirement value fo r 'stateful'."); | |
| 70 result.setStateful(itemValue); | |
| 71 } | |
| 72 | |
| 73 return result; | |
| 74 } | |
| 75 | |
| 76 // This class allows capabilities to be checked and a MediaKeySystemAccess | |
| 77 // object to be created asynchronously. | |
| 78 class MediaKeySystemAccessInitializer : public ScriptPromiseResolver { | |
|
haraken
2014/10/24 01:06:42
Add final.
yhirano
2014/10/24 09:22:32
Please place this class in an unnamed namespace.
jrummell
2014/10/24 22:43:22
Done.
jrummell
2014/10/24 22:43:22
Done.
| |
| 79 WTF_MAKE_NONCOPYABLE(MediaKeySystemAccessInitializer); | |
| 80 | |
| 81 public: | |
| 82 static ScriptPromise create(ScriptState*, const String& keySystem, const Vec tor<MediaKeySystemOptions>& supportedConfigurations); | |
| 83 virtual ~MediaKeySystemAccessInitializer(); | |
| 84 | |
| 85 private: | |
| 86 MediaKeySystemAccessInitializer(ScriptState*, const String& keySystem, const Vector<MediaKeySystemOptions>& supportedConfigurations); | |
| 87 void timerFired(Timer<MediaKeySystemAccessInitializer>*); | |
| 88 | |
| 89 const String m_keySystem; | |
| 90 const Vector<MediaKeySystemOptions> m_supportedConfigurations; | |
| 91 Timer<MediaKeySystemAccessInitializer> m_timer; | |
| 92 }; | |
| 93 | |
| 94 ScriptPromise MediaKeySystemAccessInitializer::create(ScriptState* scriptState, const String& keySystem, const Vector<MediaKeySystemOptions>& supportedConfigura tions) | |
| 95 { | |
| 96 RefPtr<MediaKeySystemAccessInitializer> initializer = adoptRef(new MediaKeyS ystemAccessInitializer(scriptState, keySystem, supportedConfigurations)); | |
| 97 initializer->suspendIfNeeded(); | |
| 98 initializer->keepAliveWhilePending(); | |
| 99 return initializer->promise(); | |
| 100 } | |
| 101 | |
| 102 MediaKeySystemAccessInitializer::MediaKeySystemAccessInitializer(ScriptState* sc riptState, const String& keySystem, const Vector<MediaKeySystemOptions>& support edConfigurations) | |
| 103 : ScriptPromiseResolver(scriptState) | |
| 104 , m_keySystem(keySystem) | |
| 105 , m_supportedConfigurations(supportedConfigurations) | |
| 106 , m_timer(this, &MediaKeySystemAccessInitializer::timerFired) | |
| 107 { | |
| 108 WTF_LOG(Media, "MediaKeySystemAccessInitializer::MediaKeySystemAccessInitial izer"); | |
| 109 // Start the timer so that MediaKeySystemAccess can be created asynchronousl y. | |
| 110 m_timer.startOneShot(0, FROM_HERE); | |
| 111 } | |
| 112 | |
| 113 MediaKeySystemAccessInitializer::~MediaKeySystemAccessInitializer() | |
| 114 { | |
| 115 WTF_LOG(Media, "MediaKeySystemAccessInitializer::~MediaKeySystemAccessInitia lizer"); | |
| 116 } | |
| 117 | |
| 118 void MediaKeySystemAccessInitializer::timerFired(Timer<MediaKeySystemAccessIniti alizer>*) | |
| 119 { | |
| 120 WTF_LOG(Media, "MediaKeySystemAccessInitializer::timerFired"); | |
| 121 | |
| 122 // Continued from requestMediaKeySystemAccess(). | |
| 123 // 5.1 If keySystem is not supported or not allowed in the origin of the | |
| 124 // calling context's Document, return a promise rejected with a new | |
| 125 // DOMException whose name is NotSupportedError. | |
| 126 // (Handled by Chromium.) | |
| 127 | |
| 128 // 5.2 If supportedConfigurations was not provided, resolve the promise | |
| 129 // with a new MediaKeySystemAccess object, execute the following steps: | |
| 130 if (!m_supportedConfigurations.size()) { | |
| 131 // 5.2.1 Let access be a new MediaKeySystemAccess object, and initialize | |
| 132 // it as follows: | |
| 133 // 5.2.1.1 Set the keySystem attribute to keySystem. | |
| 134 MediaKeySystemAccess* access = new MediaKeySystemAccess(m_keySystem); | |
| 135 | |
| 136 // 5.2.2 Resolve promise with access and abort these steps. | |
| 137 resolve(access); | |
| 138 return; | |
| 139 } | |
| 140 | |
| 141 // 5.3 For each element of supportedConfigurations: | |
| 142 // 5.3.1 Let combination be the element. | |
| 143 // 5.3.2 For each dictionary member in combination: | |
| 144 for (const auto& combination : m_supportedConfigurations) { | |
| 145 // 5.3.2.1 If the member's value cannot be satisfied together in | |
| 146 // combination with the previous members, continue to the next | |
| 147 // iteration of the loop. | |
| 148 // 5.3.3 If keySystem is supported and allowed in the origin of the | |
| 149 // calling context's Document in the configuration specified by | |
| 150 // the combination of the values in combination, execute the | |
| 151 // following steps: | |
| 152 // FIXME: This test needs to be enhanced to use more values from | |
| 153 // combination. | |
| 154 if (isKeySystemSupportedWithContentType(m_keySystem, combination.initDat aType())) { | |
| 155 // 5.3.3.1 Let access be a new MediaKeySystemAccess object, and | |
| 156 // initialize it as follows: | |
| 157 // 5.3.3.1.1 Set the keySystem attribute to keySystem. | |
| 158 MediaKeySystemAccess* access = new MediaKeySystemAccess(m_keySystem) ; | |
| 159 | |
| 160 // 5.3.3.2 Resolve promise with access and abort these steps. | |
| 161 resolve(access); | |
| 162 return; | |
| 163 } | |
| 164 } | |
| 165 | |
| 166 // 5.4 Reject promise with a new DOMException whose name is | |
| 167 // NotSupportedError. | |
| 168 reject(DOMException::create(NotSupportedError, "There were no supported comb inations in supportedConfigurations.")); | |
| 169 } | |
| 170 | |
| 171 NavigatorRequestMediaKeySystemAccess::NavigatorRequestMediaKeySystemAccess() | |
| 172 { | |
| 173 } | |
| 174 | |
| 175 NavigatorRequestMediaKeySystemAccess::~NavigatorRequestMediaKeySystemAccess() | |
| 176 { | |
| 177 } | |
| 178 | |
| 179 NavigatorRequestMediaKeySystemAccess& NavigatorRequestMediaKeySystemAccess::from (Navigator& navigator) | |
| 180 { | |
| 181 NavigatorRequestMediaKeySystemAccess* supplement = static_cast<NavigatorRequ estMediaKeySystemAccess*>(WillBeHeapSupplement<Navigator>::from(navigator, suppl ementName())); | |
| 182 if (!supplement) { | |
| 183 supplement = new NavigatorRequestMediaKeySystemAccess(); | |
| 184 provideTo(navigator, supplementName(), adoptPtrWillBeNoop(supplement)); | |
| 185 } | |
| 186 return *supplement; | |
| 187 } | |
| 188 | |
| 189 ScriptPromise NavigatorRequestMediaKeySystemAccess::requestMediaKeySystemAccess( | |
| 190 ScriptState* scriptState, | |
| 191 Navigator& navigator, | |
| 192 const String& keySystem) | |
| 193 { | |
| 194 // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/e ncrypted-media.html#requestmediakeysystemaccess | |
| 195 // When this method is invoked, the user agent must run the following steps: | |
| 196 // 1. If keySystem is an empty string, return a promise rejected with a | |
| 197 // new DOMException whose name is InvalidAccessError. | |
| 198 if (keySystem.isEmpty()) { | |
| 199 return ScriptPromise::rejectWithDOMException( | |
| 200 scriptState, DOMException::create(InvalidAccessError, "The keySystem parameter is empty.")); | |
| 201 } | |
| 202 | |
| 203 // 2. If supportedConfigurations was provided and is empty, return a | |
| 204 // promise rejected with a new DOMException whose name is | |
| 205 // InvalidAccessError. | |
| 206 // (no supportedConfigurations provided.) | |
| 207 | |
| 208 // Remainder of steps handled in common routine below. | |
| 209 return NavigatorRequestMediaKeySystemAccess::from(navigator).requestMediaKey SystemAccess(scriptState, keySystem, Vector<MediaKeySystemOptions>()); | |
| 210 } | |
| 211 | |
| 212 ScriptPromise NavigatorRequestMediaKeySystemAccess::requestMediaKeySystemAccess( | |
| 213 ScriptState* scriptState, | |
| 214 Navigator& navigator, | |
| 215 const String& keySystem, | |
| 216 const Vector<MediaKeySystemOptions>& supportedConfigurations) | |
| 217 { | |
| 218 // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/e ncrypted-media.html#requestmediakeysystemaccess | |
| 219 // When this method is invoked, the user agent must run the following steps: | |
| 220 // 1. If keySystem is an empty string, return a promise rejected with a | |
| 221 // new DOMException whose name is InvalidAccessError. | |
| 222 if (keySystem.isEmpty()) { | |
| 223 return ScriptPromise::rejectWithDOMException( | |
| 224 scriptState, DOMException::create(InvalidAccessError, "The keySystem parameter is empty.")); | |
| 225 } | |
| 226 | |
| 227 // 2. If supportedConfigurations was provided and is empty, return a | |
| 228 // promise rejected with a new DOMException whose name is | |
| 229 // InvalidAccessError. | |
| 230 if (!supportedConfigurations.size()) { | |
| 231 return ScriptPromise::rejectWithDOMException( | |
| 232 scriptState, DOMException::create(InvalidAccessError, "The supported Configurations parameter is empty.")); | |
| 233 } | |
| 234 | |
| 235 // Remainder of steps handled in common routine below. | |
| 236 return NavigatorRequestMediaKeySystemAccess::from(navigator).requestMediaKey SystemAccess( | |
| 237 scriptState, keySystem, supportedConfigurations); | |
| 238 } | |
| 239 | |
| 240 ScriptPromise NavigatorRequestMediaKeySystemAccess::requestMediaKeySystemAccess( | |
| 241 ScriptState* scriptState, | |
| 242 const String& keySystem, | |
| 243 const Vector<MediaKeySystemOptions>& supportedConfigurations) | |
| 244 { | |
| 245 // Continued from above. | |
| 246 // 3. If keySystem is not one of the Key Systems supported by the user | |
| 247 // agent, return a promise rejected with a new DOMException whose name | |
| 248 // is NotSupportedError. String comparison is case-sensitive. | |
| 249 if (!isKeySystemSupportedWithContentType(keySystem, "")) { | |
| 250 return ScriptPromise::rejectWithDOMException( | |
| 251 scriptState, DOMException::create(NotSupportedError, "The key system specified is not supported.")); | |
| 252 } | |
| 253 | |
| 254 // 4. Let promise be a new promise. | |
| 255 // 5. Asynchronously determine support, and if allowed, create and | |
| 256 // initialize the MediaKeySystemAccess object. | |
| 257 // 6. Return promise. | |
| 258 return MediaKeySystemAccessInitializer::create(scriptState, keySystem, suppo rtedConfigurations); | |
| 259 } | |
| 260 | |
| 261 const char* NavigatorRequestMediaKeySystemAccess::supplementName() | |
| 262 { | |
| 263 return "RequestMediaKeySystemAccess"; | |
| 264 } | |
| 265 | |
| 266 void NavigatorRequestMediaKeySystemAccess::trace(Visitor* visitor) | |
| 267 { | |
| 268 WillBeHeapSupplement<Navigator>::trace(visitor); | |
| 269 } | |
| 270 | |
| 271 } // namespace blink | |
| OLD | NEW |