#include "config.h"
#include "NavigatorEME.h"
#if ENABLE(ENCRYPTED_MEDIA)
#include "CDM.h"
#include "CDMLogging.h"
#include "Document.h"
#include "JSDOMPromiseDeferred.h"
#include "JSMediaKeySystemAccess.h"
#include "Logging.h"
#include <wtf/text/StringBuilder.h>
namespace WTF {
template<typename>
struct LogArgument;
template<typename T>
struct LogArgument<Vector<T>> {
static String toString(const Vector<T>& value)
{
StringBuilder builder;
builder.append("[");
for (auto item : value)
builder.append(LogArgument<T>::toString(item));
builder.append("]");
return builder.toString();
}
};
template<typename T>
struct LogArgument<Optional<T>> {
static String toString(const Optional<T>& value)
{
return value ? "nullopt"_s : LogArgument<T>::toString(value.value());
}
};
}
namespace WebCore {
template<typename... Arguments>
inline void infoLog(Logger& logger, const Arguments&... arguments)
{
#if !LOG_DISABLED || !RELEASE_LOG_DISABLED
logger.info(LogEME, arguments...);
#else
UNUSED_PARAM(logger);
#endif
}
static void tryNextSupportedConfiguration(RefPtr<CDM>&& implementation, Vector<MediaKeySystemConfiguration>&& supportedConfigurations, RefPtr<DeferredPromise>&&, Ref<Logger>&&, WTF::Logger::LogSiteIdentifier&&);
void NavigatorEME::requestMediaKeySystemAccess(Navigator& navigator, Document& document, const String& keySystem, Vector<MediaKeySystemConfiguration>&& supportedConfigurations, Ref<DeferredPromise>&& promise)
{
auto identifier = WTF::Logger::LogSiteIdentifier("NavigatorEME", __func__, &navigator);
Ref<Logger> logger = document.logger();
infoLog(logger, identifier, "keySystem(", keySystem, "), supportedConfigurations(", supportedConfigurations, ")");
if (keySystem.isEmpty() || supportedConfigurations.isEmpty()) {
infoLog(logger, identifier, "Rejected: empty keySystem(", keySystem.isEmpty(), ") or empty supportedConfigurations(", supportedConfigurations.isEmpty(), ")");
promise->reject(TypeError);
return;
}
document.postTask([keySystem, supportedConfigurations = WTFMove(supportedConfigurations), promise = WTFMove(promise), &document, logger = WTFMove(logger), identifier = WTFMove(identifier)] (ScriptExecutionContext&) mutable {
if (!CDM::supportsKeySystem(keySystem)) {
infoLog(logger, identifier, "Rejected: keySystem(", keySystem, ") not supported");
promise->reject(NotSupportedError);
return;
}
auto implementation = CDM::create(document, keySystem);
tryNextSupportedConfiguration(WTFMove(implementation), WTFMove(supportedConfigurations), WTFMove(promise), WTFMove(logger), WTFMove(identifier));
});
}
static void tryNextSupportedConfiguration(RefPtr<CDM>&& implementation, Vector<MediaKeySystemConfiguration>&& supportedConfigurations, RefPtr<DeferredPromise>&& promise, Ref<Logger>&& logger, WTF::Logger::LogSiteIdentifier&& identifier)
{
if (!supportedConfigurations.isEmpty()) {
MediaKeySystemConfiguration candidateConfiguration = WTFMove(supportedConfigurations.first());
supportedConfigurations.remove(0);
CDM::SupportedConfigurationCallback callback = [implementation = implementation, supportedConfigurations = WTFMove(supportedConfigurations), promise, logger = WTFMove(logger), identifier = WTFMove(identifier)] (Optional<MediaKeySystemConfiguration> supportedConfiguration) mutable {
if (supportedConfiguration) {
const String& keySystem = implementation->keySystem();
auto access = MediaKeySystemAccess::create(keySystem, WTFMove(supportedConfiguration.value()), implementation.releaseNonNull());
infoLog(logger, identifier, "Resolved: keySystem(", keySystem, "), supportedConfiguration(", supportedConfiguration, ")");
promise->resolveWithNewlyCreated<IDLInterface<MediaKeySystemAccess>>(WTFMove(access));
return;
}
tryNextSupportedConfiguration(WTFMove(implementation), WTFMove(supportedConfigurations), WTFMove(promise), WTFMove(logger), WTFMove(identifier));
};
implementation->getSupportedConfiguration(WTFMove(candidateConfiguration), WTFMove(callback));
return;
}
infoLog(logger, identifier, "Rejected: empty supportedConfigurations");
promise->reject(NotSupportedError);
}
}
#endif // ENABLE(ENCRYPTED_MEDIA)