Chromium Code Reviews| Index: Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp |
| diff --git a/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp b/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..5a2db08bcfe3d736fcca207b843d4b0b4b2b47ad |
| --- /dev/null |
| +++ b/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp |
| @@ -0,0 +1,270 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "config.h" |
| +#include "modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.h" |
| + |
| +#include "bindings/core/v8/ScriptPromiseResolver.h" |
| +#include "bindings/core/v8/ScriptState.h" |
| +#include "core/dom/DOMException.h" |
| +#include "core/dom/ExceptionCode.h" |
| +#include "modules/encryptedmedia/MediaKeySystemAccess.h" |
| +#include "platform/ContentType.h" |
| +#include "platform/Logging.h" |
| +#include "platform/MIMETypeRegistry.h" |
| +#include "wtf/text/WTFString.h" |
| + |
| +namespace blink { |
| + |
| +static bool isKeySystemSupportedWithContentType(const String& keySystem, const String& contentType) |
| +{ |
| + ASSERT(!keySystem.isEmpty()); |
| + |
| + ContentType type(contentType); |
| + String codecs = type.parameter("codecs"); |
| + return MIMETypeRegistry::isSupportedEncryptedMediaMIMEType(keySystem, type.type(), codecs); |
| +} |
| + |
| +const char* mediaKeysRequirementValidValues[] = { "required", "optional", "disallowed" }; |
|
ddorwin
2014/10/23 18:02:31
Okay for now, I guess. We'll probably need to conv
jrummell
2014/10/23 22:13:15
Acknowledged.
|
| + |
| +static bool ValidMediaKeysRequirement(const String& itemValue) |
|
ddorwin
2014/10/23 18:02:31
IsV...
jrummell
2014/10/23 22:13:16
Done.
|
| +{ |
| + for (size_t i = 0; i < WTF_ARRAY_LENGTH(mediaKeysRequirementValidValues); ++i) { |
| + if (mediaKeysRequirementValidValues[i] == itemValue) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +MediaKeySystemOptions ConvertDictionaryIntoMediaKeySystemOptions(Dictionary& dictionary, ExceptionState& exceptionState) |
| +{ |
| + MediaKeySystemOptions result; |
| + String itemValue; |
| + |
| + if (DictionaryHelper::get(dictionary, "initDataType", itemValue)) |
| + result.setInitDataType(itemValue); |
| + |
| + if (DictionaryHelper::get(dictionary, "audioType", itemValue)) |
| + result.setAudioType(itemValue); |
| + |
| + if (DictionaryHelper::get(dictionary, "audioCapability", itemValue)) |
| + result.setAudioCapability(itemValue); |
| + |
| + if (DictionaryHelper::get(dictionary, "videoType", itemValue)) |
| + result.setVideoType(itemValue); |
| + |
| + if (DictionaryHelper::get(dictionary, "videoCapability", itemValue)) |
| + result.setVideoCapability(itemValue); |
| + |
| + if (DictionaryHelper::get(dictionary, "uniqueidentifier", itemValue)) { |
| + if (!ValidMediaKeysRequirement(itemValue)) |
| + exceptionState.throwTypeError("Invalid MediaKeysRequirement value for 'uniqueidentifier'."); |
| + result.setUniqueidentifier(itemValue); |
| + } |
| + |
| + if (DictionaryHelper::get(dictionary, "stateful", itemValue)) { |
| + if (!ValidMediaKeysRequirement(itemValue)) |
| + exceptionState.throwTypeError("Invalid MediaKeysRequirement value for 'stateful'."); |
| + result.setStateful(itemValue); |
| + } |
| + |
| + return result; |
| +} |
| + |
| +// This class allows capabilities to be checked and a MediaKeySystemAccess |
| +// object to be created asynchronously. |
| +class MediaKeySystemAccessInitializer : public ScriptPromiseResolver { |
| + WTF_MAKE_NONCOPYABLE(MediaKeySystemAccessInitializer); |
| + |
| +public: |
| + static ScriptPromise create(ScriptState*, const String& keySystem, const Vector<MediaKeySystemOptions>& supportedConfigurations); |
| + virtual ~MediaKeySystemAccessInitializer(); |
| + |
| +private: |
| + MediaKeySystemAccessInitializer(ScriptState*, const String& keySystem, const Vector<MediaKeySystemOptions>& supportedConfigurations); |
| + void timerFired(Timer<MediaKeySystemAccessInitializer>*); |
| + |
| + const String m_keySystem; |
| + const Vector<MediaKeySystemOptions> m_supportedConfigurations; |
| + Timer<MediaKeySystemAccessInitializer> m_timer; |
| +}; |
| + |
| +ScriptPromise MediaKeySystemAccessInitializer::create(ScriptState* scriptState, const String& keySystem, const Vector<MediaKeySystemOptions>& supportedConfigurations) |
| +{ |
| + RefPtr<MediaKeySystemAccessInitializer> initializer = adoptRef(new MediaKeySystemAccessInitializer(scriptState, keySystem, supportedConfigurations)); |
| + initializer->suspendIfNeeded(); |
| + initializer->keepAliveWhilePending(); |
| + return initializer->promise(); |
| +} |
| + |
| +MediaKeySystemAccessInitializer::MediaKeySystemAccessInitializer(ScriptState* scriptState, const String& keySystem, const Vector<MediaKeySystemOptions>& supportedConfigurations) |
| + : ScriptPromiseResolver(scriptState) |
| + , m_keySystem(keySystem) |
| + , m_supportedConfigurations(supportedConfigurations) |
| + , m_timer(this, &MediaKeySystemAccessInitializer::timerFired) |
| +{ |
| + WTF_LOG(Media, "MediaKeySystemAccessInitializer::MediaKeySystemAccessInitializer"); |
| + // Start the timer so that MediaKeySystemAccess can be created asynchronously. |
| + m_timer.startOneShot(0, FROM_HERE); |
| +} |
| + |
| +MediaKeySystemAccessInitializer::~MediaKeySystemAccessInitializer() |
| +{ |
| + WTF_LOG(Media, "MediaKeySystemAccessInitializer::~MediaKeySystemAccessInitializer"); |
| +} |
| + |
| +void MediaKeySystemAccessInitializer::timerFired(Timer<MediaKeySystemAccessInitializer>*) |
| +{ |
| + WTF_LOG(Media, "MediaKeySystemAccessInitializer::timerFired"); |
| + |
| + // Continued from requestMediaKeySystemAccess(). |
| + // 5.1 If keySystem is not supported or not allowed in the origin of the |
| + // calling context's Document, return a promise rejected with a new |
| + // DOMException whose name is NotSupportedError. |
| + // (Handled by Chromium.) |
| + |
| + // 5.2 If supportedConfigurations was not provided, resolve the promise |
| + // with a new MediaKeySystemAccess object, execute the following steps: |
| + if (!m_supportedConfigurations.size()) { |
| + // 5.2.1 Let access be a new MediaKeySystemAccess object, and initialize |
| + // it as follows: |
| + // 5.2.1.1 Set the keySystem attribute to keySystem. |
| + MediaKeySystemAccess* access = new MediaKeySystemAccess(m_keySystem); |
| + |
| + // 5.2.2 Resolve promise with access and abort these steps. |
| + resolve(access); |
| + return; |
| + } |
| + |
| + // 5.3 For each element of supportedConfigurations: |
| + // 5.3.1 Let combination be the element. |
| + // 5.3.2 For each dictionary member in combination: |
| + for (const auto& combination : m_supportedConfigurations) { |
| + // 5.3.2.1 If the member's value cannot be satisfied together in |
| + // combination with the previous members, continue to the next |
| + // iteration of the loop. |
| + // 5.3.3 If keySystem is supported and allowed in the origin of the |
| + // calling context's Document in the configuration specified by |
| + // the combination of the values in combination, execute the |
| + // following steps: |
| + // FIXME: This test needs to be enhanced to use more values from |
| + // combination. |
| + if (isKeySystemSupportedWithContentType(m_keySystem, combination.initDataType())) { |
| + // 5.3.3.1 Let access be a new MediaKeySystemAccess object, and |
| + // initialize it as follows: |
| + // 5.3.3.1.1 Set the keySystem attribute to keySystem. |
| + MediaKeySystemAccess* access = new MediaKeySystemAccess(m_keySystem); |
| + |
| + // 5.3.3.2 Resolve promise with access and abort these steps. |
| + resolve(access); |
| + return; |
| + } |
| + } |
| + |
| + // 5.4 Reject promise with a new DOMException whose name is |
| + // NotSupportedError. |
| + reject(DOMException::create(NotSupportedError, "There were no supported combinations in supportedConfigurations.")); |
| +} |
| + |
| +NavigatorRequestMediaKeySystemAccess::NavigatorRequestMediaKeySystemAccess() |
| +{ |
| +} |
| + |
| +NavigatorRequestMediaKeySystemAccess::~NavigatorRequestMediaKeySystemAccess() |
| +{ |
| +} |
| + |
| +NavigatorRequestMediaKeySystemAccess& NavigatorRequestMediaKeySystemAccess::from(Navigator& navigator) |
| +{ |
| + NavigatorRequestMediaKeySystemAccess* supplement = static_cast<NavigatorRequestMediaKeySystemAccess*>(WillBeHeapSupplement<Navigator>::from(navigator, supplementName())); |
| + if (!supplement) { |
| + supplement = new NavigatorRequestMediaKeySystemAccess(); |
| + provideTo(navigator, supplementName(), adoptPtrWillBeNoop(supplement)); |
| + } |
| + return *supplement; |
| +} |
| + |
| +ScriptPromise NavigatorRequestMediaKeySystemAccess::requestMediaKeySystemAccess( |
| + ScriptState* scriptState, |
| + Navigator& navigator, |
| + const String& keySystem) |
| +{ |
| + // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#requestmediakeysystemaccess |
| + // When this method is invoked, the user agent must run the following steps: |
| + // 1. If keySystem is an empty string, return a promise rejected with a |
| + // new DOMException whose name is InvalidAccessError. |
| + if (keySystem.isEmpty()) { |
| + return ScriptPromise::rejectWithDOMException( |
| + scriptState, DOMException::create(InvalidAccessError, "The keySystem parameter is empty.")); |
| + } |
| + |
| + // 2. If supportedConfigurations was provided and is empty, return a |
| + // promise rejected with a new DOMException whose name is |
| + // InvalidAccessError. |
| + // (no supportedConfigurations provided.) |
| + |
| + // Remainder of steps handled in common routine below. |
| + return NavigatorRequestMediaKeySystemAccess::from(navigator).requestMediaKeySystemAccess(scriptState, keySystem, Vector<MediaKeySystemOptions>()); |
| +} |
| + |
| +ScriptPromise NavigatorRequestMediaKeySystemAccess::requestMediaKeySystemAccess( |
| + ScriptState* scriptState, |
| + Navigator& navigator, |
| + const String& keySystem, |
| + const Vector<MediaKeySystemOptions>& supportedConfigurations) |
| +{ |
| + // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#requestmediakeysystemaccess |
| + // When this method is invoked, the user agent must run the following steps: |
| + // 1. If keySystem is an empty string, return a promise rejected with a |
| + // new DOMException whose name is InvalidAccessError. |
| + if (keySystem.isEmpty()) { |
| + return ScriptPromise::rejectWithDOMException( |
| + scriptState, DOMException::create(InvalidAccessError, "The keySystem parameter is empty.")); |
| + } |
| + |
| + // 2. If supportedConfigurations was provided and is empty, return a |
| + // promise rejected with a new DOMException whose name is |
| + // InvalidAccessError. |
| + if (!supportedConfigurations.size()) { |
| + return ScriptPromise::rejectWithDOMException( |
| + scriptState, DOMException::create(InvalidAccessError, "The supportedConfigurations parameter is empty.")); |
| + } |
| + |
| + // Remainder of steps handled in common routine below. |
| + return NavigatorRequestMediaKeySystemAccess::from(navigator).requestMediaKeySystemAccess( |
| + scriptState, keySystem, supportedConfigurations); |
| +} |
| + |
| +ScriptPromise NavigatorRequestMediaKeySystemAccess::requestMediaKeySystemAccess( |
| + ScriptState* scriptState, |
| + const String& keySystem, |
| + const Vector<MediaKeySystemOptions>& supportedConfigurations) |
| +{ |
| + // Continued from above. |
| + // 3. If keySystem is not one of the Key Systems supported by the user |
| + // agent, return a promise rejected with a new DOMException whose name |
| + // is NotSupportedError. String comparison is case-sensitive. |
| + if (!isKeySystemSupportedWithContentType(keySystem, "")) { |
| + return ScriptPromise::rejectWithDOMException( |
| + scriptState, DOMException::create(NotSupportedError, "The key system specified is not supported.")); |
| + } |
| + |
| + // 4. Let promise be a new promise. |
| + // 5. Asynchronously determine support and if allowed create and |
|
ddorwin
2014/10/23 18:02:31
nit: missing commas
jrummell
2014/10/23 22:13:15
Done.
|
| + // initialize the MediaKeySystemAccess object. |
| + // 6. Return promise. |
| + return MediaKeySystemAccessInitializer::create(scriptState, keySystem, supportedConfigurations); |
| +} |
| + |
| +const char* NavigatorRequestMediaKeySystemAccess::supplementName() |
| +{ |
| + return "RequestMediaKeySystemAccess"; |
| +} |
| + |
| +void NavigatorRequestMediaKeySystemAccess::trace(Visitor* visitor) |
| +{ |
| + WillBeHeapSupplement<Navigator>::trace(visitor); |
| +} |
| + |
| +} // namespace blink |