blob: 225d47e994b1e97d3346d9dd2be00f7280a0a45f [file] [log] [blame]
// 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 "modules/encryptedmedia/MediaKeySystemAccess.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "bindings/core/v8/ScriptState.h"
#include "core/dom/DOMException.h"
#include "core/dom/Document.h"
#include "modules/encryptedmedia/ContentDecryptionModuleResultPromise.h"
#include "modules/encryptedmedia/EncryptedMediaUtils.h"
#include "modules/encryptedmedia/MediaKeySession.h"
#include "modules/encryptedmedia/MediaKeys.h"
#include "modules/encryptedmedia/MediaKeysController.h"
#include "platform/Timer.h"
#include "public/platform/WebContentDecryptionModule.h"
#include "public/platform/WebEncryptedMediaTypes.h"
#include "public/platform/WebMediaKeySystemConfiguration.h"
#include "wtf/PtrUtil.h"
#include <memory>
namespace blink {
namespace {
// This class wraps the promise resolver used when creating MediaKeys
// and is passed to Chromium to fullfill the promise. This implementation of
// completeWithCdm() will resolve the promise with a new MediaKeys object,
// while completeWithError() will reject the promise with an exception.
// All other complete methods are not expected to be called, and will
// reject the promise.
class NewCdmResultPromise : public ContentDecryptionModuleResultPromise {
WTF_MAKE_NONCOPYABLE(NewCdmResultPromise);
public:
NewCdmResultPromise(
ScriptState* scriptState,
const WebVector<WebEncryptedMediaSessionType>& supportedSessionTypes)
: ContentDecryptionModuleResultPromise(scriptState),
m_supportedSessionTypes(supportedSessionTypes) {}
~NewCdmResultPromise() override {}
// ContentDecryptionModuleResult implementation.
void completeWithContentDecryptionModule(
WebContentDecryptionModule* cdm) override {
// NOTE: Continued from step 2.8 of createMediaKeys().
if (!isValidToFulfillPromise())
return;
// 2.9. Let media keys be a new MediaKeys object.
MediaKeys* mediaKeys = MediaKeys::create(
getExecutionContext(), m_supportedSessionTypes, WTF::wrapUnique(cdm));
// 2.10. Resolve promise with media keys.
resolve(mediaKeys);
}
private:
WebVector<WebEncryptedMediaSessionType> m_supportedSessionTypes;
};
// These methods are the inverses of those with the same names in
// NavigatorRequestMediaKeySystemAccess.
static Vector<String> convertInitDataTypes(
const WebVector<WebEncryptedMediaInitDataType>& initDataTypes) {
Vector<String> result(initDataTypes.size());
for (size_t i = 0; i < initDataTypes.size(); i++)
result[i] = EncryptedMediaUtils::convertFromInitDataType(initDataTypes[i]);
return result;
}
static HeapVector<MediaKeySystemMediaCapability> convertCapabilities(
const WebVector<WebMediaKeySystemMediaCapability>& capabilities) {
HeapVector<MediaKeySystemMediaCapability> result(capabilities.size());
for (size_t i = 0; i < capabilities.size(); i++) {
MediaKeySystemMediaCapability capability;
capability.setContentType(capabilities[i].contentType);
capability.setRobustness(capabilities[i].robustness);
result[i] = capability;
}
return result;
}
static String convertMediaKeysRequirement(
WebMediaKeySystemConfiguration::Requirement requirement) {
switch (requirement) {
case WebMediaKeySystemConfiguration::Requirement::Required:
return "required";
case WebMediaKeySystemConfiguration::Requirement::Optional:
return "optional";
case WebMediaKeySystemConfiguration::Requirement::NotAllowed:
return "not-allowed";
}
NOTREACHED();
return "not-allowed";
}
static Vector<String> convertSessionTypes(
const WebVector<WebEncryptedMediaSessionType>& sessionTypes) {
Vector<String> result(sessionTypes.size());
for (size_t i = 0; i < sessionTypes.size(); i++)
result[i] = EncryptedMediaUtils::convertFromSessionType(sessionTypes[i]);
return result;
}
} // namespace
MediaKeySystemAccess::MediaKeySystemAccess(
const String& keySystem,
std::unique_ptr<WebContentDecryptionModuleAccess> access)
: m_keySystem(keySystem), m_access(std::move(access)) {}
MediaKeySystemAccess::~MediaKeySystemAccess() {}
void MediaKeySystemAccess::getConfiguration(
MediaKeySystemConfiguration& result) {
WebMediaKeySystemConfiguration configuration = m_access->getConfiguration();
// |initDataTypes|, |audioCapabilities|, and |videoCapabilities| can only be
// empty if they were not present in the requested configuration.
if (!configuration.initDataTypes.isEmpty())
result.setInitDataTypes(convertInitDataTypes(configuration.initDataTypes));
if (!configuration.audioCapabilities.isEmpty())
result.setAudioCapabilities(
convertCapabilities(configuration.audioCapabilities));
if (!configuration.videoCapabilities.isEmpty())
result.setVideoCapabilities(
convertCapabilities(configuration.videoCapabilities));
// |distinctiveIdentifier|, |persistentState|, and |sessionTypes| are always
// set by requestMediaKeySystemAccess().
result.setDistinctiveIdentifier(
convertMediaKeysRequirement(configuration.distinctiveIdentifier));
result.setPersistentState(
convertMediaKeysRequirement(configuration.persistentState));
result.setSessionTypes(convertSessionTypes(configuration.sessionTypes));
// |label| will (and should) be a null string if it was not set.
result.setLabel(configuration.label);
}
ScriptPromise MediaKeySystemAccess::createMediaKeys(ScriptState* scriptState) {
// From http://w3c.github.io/encrypted-media/#createMediaKeys
// (Reordered to be able to pass values into the promise constructor.)
// 2.4 Let configuration be the value of this object's configuration value.
// 2.5-2.8. [Set use distinctive identifier and persistent state allowed
// based on configuration.]
WebMediaKeySystemConfiguration configuration = m_access->getConfiguration();
// 1. Let promise be a new promise.
NewCdmResultPromise* helper =
new NewCdmResultPromise(scriptState, configuration.sessionTypes);
ScriptPromise promise = helper->promise();
// 2. Asynchronously create and initialize the MediaKeys object.
// 2.1 Let cdm be the CDM corresponding to this object.
// 2.2 Load and initialize the cdm if necessary.
// 2.3 If cdm fails to load or initialize, reject promise with a new
// DOMException whose name is the appropriate error name.
// (Done if completeWithException() called).
m_access->createContentDecryptionModule(helper->result());
// 3. Return promise.
return promise;
}
DEFINE_TRACE(MediaKeySystemAccess) {}
} // namespace blink