blob: ebbb42d9c6339d1926cb059e3842289ef5cf4470 [file] [log] [blame]
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/dom/navigator.h"
#include "base/optional.h"
#include "cobalt/dom/dom_exception.h"
#if defined(COBALT_MEDIA_SOURCE_2016)
#include "cobalt/dom/eme/media_key_system_access.h"
#endif // defined(COBALT_MEDIA_SOURCE_2016)
#include "cobalt/media_session/media_session_client.h"
#include "cobalt/script/script_value_factory.h"
#include "starboard/media.h"
using cobalt::media_session::MediaSession;
namespace cobalt {
namespace dom {
Navigator::Navigator(const std::string& user_agent, const std::string& language,
scoped_refptr<MediaSession> media_session,
script::ScriptValueFactory* script_value_factory)
: user_agent_(user_agent),
language_(language),
mime_types_(new MimeTypeArray()),
plugins_(new PluginArray()),
media_session_(media_session),
script_value_factory_(script_value_factory) {}
const std::string& Navigator::language() const { return language_; }
const std::string& Navigator::user_agent() const { return user_agent_; }
bool Navigator::java_enabled() const { return false; }
bool Navigator::cookie_enabled() const { return false; }
const scoped_refptr<MimeTypeArray>& Navigator::mime_types() const {
return mime_types_;
}
const scoped_refptr<PluginArray>& Navigator::plugins() const {
return plugins_;
}
const scoped_refptr<media_session::MediaSession>& Navigator::media_session()
const {
return media_session_;
}
#if defined(COBALT_MEDIA_SOURCE_2016)
namespace {
// See
// https://www.w3.org/TR/encrypted-media/#get-supported-capabilities-for-audio-video-type.
base::optional<script::Sequence<MediaKeySystemMediaCapability> >
TryGetSupportedCapabilities(
const std::string& key_system,
const script::Sequence<MediaKeySystemMediaCapability>&
requested_media_capabilities) {
// 2. Let supported media capabilities be an empty sequence of
// MediaKeySystemMediaCapability dictionaries.
script::Sequence<MediaKeySystemMediaCapability> supported_media_capabilities;
// 3. For each requested media capability in requested media capabilities:
for (std::size_t media_capability_index = 0;
media_capability_index < requested_media_capabilities.size();
++media_capability_index) {
const MediaKeySystemMediaCapability& requested_media_capability =
requested_media_capabilities.at(media_capability_index);
// 3.1. Let content type be requested media capability's contentType member.
const std::string& content_type = requested_media_capability.content_type();
// 3.3. If content type is the empty string, return null.
if (content_type.empty()) {
return base::nullopt;
}
// 3.13. If the user agent and [CDM] implementation definitely support
// playback of encrypted media data for the combination of container,
// media types [...]:
if (SbMediaCanPlayMimeAndKeySystem(content_type.c_str(),
key_system.c_str()) ==
kSbMediaSupportTypeProbably) {
// 3.13.1. Add requested media capability to supported media capabilities.
supported_media_capabilities.push_back(requested_media_capability);
}
}
// 4. If supported media capabilities is empty, return null.
if (supported_media_capabilities.empty()) {
return base::nullopt;
}
// 5. Return supported media capabilities.
return supported_media_capabilities;
}
// Technically, a user agent is supposed to implement "3.1.1.1 Get Supported
// Configuration" which requests the user consent until it's given. But since
// Cobalt never interacts with the user directly, we'll assume that the consent
// is always given and go straight to "3.1.1.2 Get Supported Configuration and
// Consent". See
// https://www.w3.org/TR/encrypted-media/#get-supported-configuration-and-consent.
base::optional<eme::MediaKeySystemConfiguration> TryGetSupportedConfiguration(
const std::string& key_system,
const eme::MediaKeySystemConfiguration& candidate_configuration) {
// 1. Let accumulated configuration be a new MediaKeySystemConfiguration
// dictionary.
eme::MediaKeySystemConfiguration accumulated_configuration;
// 2. Set the label member of accumulated configuration to equal the label
// member of candidate configuration.
accumulated_configuration.set_label(candidate_configuration.label());
// For now, copy initialization data types into accumulated configuration.
//
// TODO: Implement step 3 after introducing a Starboard API for detecting
// supported initialization data type.
// TODO: Checking has_init_data_types() won't be needed once Cobalt supports
// default values for IDL sequences.
accumulated_configuration.set_init_data_types(
candidate_configuration.has_init_data_types()
? candidate_configuration.init_data_types()
: script::Sequence<std::string>());
// TODO: Reject distinctive identifiers, persistent state, and persistent
// sessions.
// 15. If the videoCapabilities and audioCapabilities members in candidate
// configuration are both empty, return NotSupported.
//
// TODO: Checking has_video_capabilities() and has_audio_capabilities() won't
// be needed once Cobalt supports default values for IDL sequences.
if ((!candidate_configuration.has_video_capabilities() ||
candidate_configuration.video_capabilities().empty()) &&
(!candidate_configuration.has_audio_capabilities() ||
candidate_configuration.audio_capabilities().empty())) {
return base::nullopt;
}
// 16. If the videoCapabilities member in candidate configuration is
// non-empty:
if (candidate_configuration.has_video_capabilities() &&
!candidate_configuration.video_capabilities().empty()) {
// 16.1. Let video capabilities be the result of executing the "Get
// Supported Capabilities for Audio/Video Type" algorithm.
base::optional<script::Sequence<MediaKeySystemMediaCapability> >
maybe_video_capabilities = TryGetSupportedCapabilities(
key_system, candidate_configuration.video_capabilities());
// 16.2. If video capabilities is null, return NotSupported.
if (!maybe_video_capabilities) {
return base::nullopt;
}
// 16.3. Set the videoCapabilities member of accumulated configuration to
// video capabilities.
accumulated_configuration.set_video_capabilities(*maybe_video_capabilities);
} else {
// Otherwise: set the videoCapabilities member of accumulated configuration
// to an empty sequence.
accumulated_configuration.set_video_capabilities(
script::Sequence<MediaKeySystemMediaCapability>());
}
// 17. If the audioCapabilities member in candidate configuration is
// non-empty:
if (candidate_configuration.has_audio_capabilities() &&
!candidate_configuration.audio_capabilities().empty()) {
// 17.1. Let audio capabilities be the result of executing the "Get
// Supported Capabilities for Audio/Video Type" algorithm.
base::optional<script::Sequence<MediaKeySystemMediaCapability> >
maybe_audio_capabilities = TryGetSupportedCapabilities(
key_system, candidate_configuration.audio_capabilities());
// 17.2. If audio capabilities is null, return NotSupported.
if (!maybe_audio_capabilities) {
return base::nullopt;
}
// 17.3. Set the audioCapabilities member of accumulated configuration to
// audio capabilities.
accumulated_configuration.set_audio_capabilities(*maybe_audio_capabilities);
} else {
// Otherwise: set the audioCapabilities member of accumulated configuration
// to an empty sequence.
accumulated_configuration.set_audio_capabilities(
script::Sequence<MediaKeySystemMediaCapability>());
}
// 23. Return accumulated configuration.
return accumulated_configuration;
}
} // namespace
// See
// https://www.w3.org/TR/encrypted-media/#dom-navigator-requestmediakeysystemaccess.
scoped_ptr<Navigator::InterfacePromiseValue>
Navigator::RequestMediaKeySystemAccess(
const std::string& key_system,
const script::Sequence<eme::MediaKeySystemConfiguration>&
supported_configurations) {
scoped_ptr<InterfacePromiseValue> promise =
script_value_factory_
->CreateInterfacePromise<scoped_refptr<eme::MediaKeySystemAccess> >();
InterfacePromiseValue::StrongReference promise_reference(*promise);
// 1. If |keySystem| is the empty string, return a promise rejected
// with a newly created TypeError.
// 2. If |supportedConfigurations| is empty, return a promise rejected
// with a newly created TypeError.
if (key_system.empty() || supported_configurations.empty()) {
promise_reference.value().Reject(script::kTypeError);
return promise.Pass();
}
// 6.3. For each value in |supportedConfigurations|:
for (std::size_t configuration_index = 0;
configuration_index < supported_configurations.size();
++configuration_index) {
// 6.3.3. If supported configuration is not NotSupported:
base::optional<eme::MediaKeySystemConfiguration>
maybe_supported_configuration = TryGetSupportedConfiguration(
key_system, supported_configurations.at(configuration_index));
if (maybe_supported_configuration) {
// 6.3.3.1. Let access be a new MediaKeySystemAccess object.
scoped_refptr<eme::MediaKeySystemAccess> media_key_system_access(
new eme::MediaKeySystemAccess(key_system,
*maybe_supported_configuration,
script_value_factory_));
// 6.3.3.2. Resolve promise.
promise_reference.value().Resolve(media_key_system_access);
return promise.Pass();
}
}
// 6.4. Reject promise with a NotSupportedError.
promise_reference.value().Reject(
new DOMException(DOMException::kNotSupportedErr));
return promise.Pass();
}
#endif // defined(COBALT_MEDIA_SOURCE_2016)
} // namespace dom
} // namespace cobalt