Import Cobalt 22.master.0.303689
diff --git a/src/.pre-commit-config.yaml b/src/.pre-commit-config.yaml
index 0150efe..6240f63 100644
--- a/src/.pre-commit-config.yaml
+++ b/src/.pre-commit-config.yaml
@@ -123,7 +123,7 @@
entry: python precommit_hooks/run_python2_unittests.py
language: python
language_version: python2
- additional_dependencies: ['mock', 'jsonschema']
+ additional_dependencies: ['mock']
types: [python]
- id: osslint
name: osslint
diff --git a/src/cobalt/bindings/IDLExtendedAttributes.txt b/src/cobalt/bindings/IDLExtendedAttributes.txt
index ed7490c..8f4ad98 100644
--- a/src/cobalt/bindings/IDLExtendedAttributes.txt
+++ b/src/cobalt/bindings/IDLExtendedAttributes.txt
@@ -47,7 +47,6 @@
# used by the Window interface, but is also used for TestWindow in unit tests.
# http://heycam.github.io/webidl/#Global
Global
-PrimaryGlobal
# This interface is exposed on the specified global interface, rather than
# the default of Window.
diff --git a/src/cobalt/bindings/testing/window.idl b/src/cobalt/bindings/testing/window.idl
index 3109cf5..3c15832 100644
--- a/src/cobalt/bindings/testing/window.idl
+++ b/src/cobalt/bindings/testing/window.idl
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-[PrimaryGlobal]
+[Global]
interface Window : GlobalInterfaceParent {
void windowOperation();
attribute DOMString windowProperty;
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index ba3c984..c0995fe 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -1093,14 +1093,20 @@
#endif // SB_API_VERSION >= 12 ||
// SB_HAS(ON_SCREEN_KEYBOARD)
case kSbEventTypeLink: {
- DispatchDeepLink(static_cast<const char*>(starboard_event->data));
+#if SB_API_VERSION >= 13
+ DispatchDeepLink(static_cast<const char*>(starboard_event->data),
+ starboard_event->timestamp);
+#else // SB_API_VERSION >= 13
+ DispatchDeepLink(static_cast<const char*>(starboard_event->data),
+ SbTimeGetMonotonicNow());
+#endif // SB_API_VERSION >= 13
break;
}
#if SB_API_VERSION >= 13
case kSbEventTypeAccessibilitySettingsChanged:
#else
case kSbEventTypeAccessiblitySettingsChanged:
-#endif // B_API_VERSION >= 13
+#endif // SB_API_VERSION >= 13
DispatchEventInternal(new base::AccessibilitySettingsChangedEvent());
#if SB_API_VERSION < 12
// Also dispatch the newer text-to-speech settings changed event since
@@ -1473,7 +1479,8 @@
}
}
-void Application::DispatchDeepLink(const char* link) {
+void Application::DispatchDeepLink(const char* link,
+ SbTimeMonotonic timestamp) {
if (!link || *link == 0) {
return;
}
@@ -1489,10 +1496,17 @@
deep_link = unconsumed_deep_link_;
}
+ deep_link_timestamp_ = timestamp;
+
LOG(INFO) << "Dispatching deep link: " << deep_link;
DispatchEventInternal(new base::DeepLinkEvent(
deep_link, base::Bind(&Application::OnDeepLinkConsumedCallback,
base::Unretained(this), deep_link)));
+#if SB_API_VERSION >= 13
+ if (browser_module_) {
+ browser_module_->SetDeepLinkTimestamp(timestamp);
+ }
+#endif // SB_API_VERSION >= 13
}
void Application::DispatchDeepLinkIfNotConsumed() {
@@ -1510,6 +1524,11 @@
deep_link, base::Bind(&Application::OnDeepLinkConsumedCallback,
base::Unretained(this), deep_link)));
}
+#if SB_API_VERSION >= 13
+ if (browser_module_) {
+ browser_module_->SetDeepLinkTimestamp(deep_link_timestamp_);
+ }
+#endif // SB_API_VERSION >= 13
}
} // namespace browser
diff --git a/src/cobalt/browser/application.h b/src/cobalt/browser/application.h
index 1fa07da..c08330c 100644
--- a/src/cobalt/browser/application.h
+++ b/src/cobalt/browser/application.h
@@ -224,11 +224,14 @@
// Lock for access to unconsumed_deep_link_ from different threads.
base::Lock unconsumed_deep_link_lock_;
+ SbTimeMonotonic deep_link_timestamp_ = 0;
+
// Called when deep links are consumed.
void OnDeepLinkConsumedCallback(const std::string& link);
// Dispatch events for deep links.
- void DispatchDeepLink(const char* link);
+ void DispatchDeepLink(const char* link,
+ SbTimeMonotonic timestamp);
void DispatchDeepLinkIfNotConsumed();
DISALLOW_COPY_AND_ASSIGN(Application);
diff --git a/src/cobalt/browser/browser_bindings_gen.gyp b/src/cobalt/browser/browser_bindings_gen.gyp
index 9941d47..bce6391 100644
--- a/src/cobalt/browser/browser_bindings_gen.gyp
+++ b/src/cobalt/browser/browser_bindings_gen.gyp
@@ -334,12 +334,12 @@
'../dom/buffer_source.idl',
'../dom/captions/navigator_system_caption_settings.idl',
- '../dom/document__web_animations_api.idl',
'../dom/document_cobalt.idl',
'../dom/document_cssom.idl',
'../dom/document_html5.idl',
'../dom/document_page_lifecycle.idl',
'../dom/document_page_visibility.idl',
+ '../dom/document_web_animations_api.idl',
'../dom/element_css_inline_style.idl',
'../dom/element_cssom_view.idl',
'../dom/element_dom_parsing_and_serialization.idl',
@@ -365,13 +365,13 @@
'../dom/speech_synthesis_getter.idl',
'../dom/url_mse.idl',
'../dom/url_utils.idl',
- '../dom/window__animation_timing.idl',
- '../dom/window__performance.idl',
+ '../dom/window_animation_timing.idl',
'../dom/window_cssom.idl',
'../dom/window_cssom_view.idl',
'../dom/window_event_handlers.idl',
'../dom/window_local_storage.idl',
'../dom/window_on_screen_keyboard.idl',
+ '../dom/window_performance.idl',
'../dom/window_session_storage.idl',
'../dom/window_timers.idl',
'../media_capture/navigator.idl',
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index d724d9e..bb922b0 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -2101,5 +2101,11 @@
is_preload, timestamp);
}
+void BrowserModule::SetDeepLinkTimestamp(
+ SbTimeMonotonic timestamp) {
+ DCHECK(web_module_);
+ web_module_->SetDeepLinkTimestamp(timestamp);
+}
+
} // namespace browser
} // namespace cobalt
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index ef8113f..cec410e 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -232,6 +232,8 @@
// Pass the application preload or start timestamps from Starboard.
void SetApplicationStartOrPreloadTimestamp(bool is_preload,
SbTimeMonotonic timestamp);
+ // Pass the deeplink timestamp from Starboard.
+ void SetDeepLinkTimestamp(SbTimeMonotonic timestamp);
private:
#if SB_HAS(CORE_DUMP_HANDLER_SUPPORT)
static void CoreDumpHandler(void* browser_module_as_void);
diff --git a/src/cobalt/browser/debug_console.h b/src/cobalt/browser/debug_console.h
index 798154d..ebb8d03 100644
--- a/src/cobalt/browser/debug_console.h
+++ b/src/cobalt/browser/debug_console.h
@@ -96,25 +96,25 @@
// LifecycleObserver implementation.
void Blur(SbTimeMonotonic timestamp) override {
- web_module_->Blur(timestamp);
+ web_module_->Blur(0);
}
void Conceal(render_tree::ResourceProvider* resource_provider,
SbTimeMonotonic timestamp) override {
- web_module_->Conceal(resource_provider, timestamp);
+ web_module_->Conceal(resource_provider, 0);
}
void Freeze(SbTimeMonotonic timestamp) override {
- web_module_->Freeze(timestamp);
+ web_module_->Freeze(0);
}
void Unfreeze(render_tree::ResourceProvider* resource_provider,
SbTimeMonotonic timestamp) override {
- web_module_->Unfreeze(resource_provider, timestamp);
+ web_module_->Unfreeze(resource_provider, 0);
}
void Reveal(render_tree::ResourceProvider* resource_provider,
SbTimeMonotonic timestamp) override {
- web_module_->Reveal(resource_provider, timestamp);
+ web_module_->Reveal(resource_provider, 0);
}
void Focus(SbTimeMonotonic timestamp) override {
- web_module_->Focus(timestamp);
+ web_module_->Focus(0);
}
void ReduceMemory() { web_module_->ReduceMemory(); }
diff --git a/src/cobalt/browser/main.cc b/src/cobalt/browser/main.cc
index 98ee605..371613c 100644
--- a/src/cobalt/browser/main.cc
+++ b/src/cobalt/browser/main.cc
@@ -63,9 +63,9 @@
}
LOG(INFO) << "Concealing application.";
DCHECK(!g_application);
- g_application =
- new cobalt::browser::Application(quit_closure, true /*should_preload*/,
- timestamp);
+ g_application = new cobalt::browser::Application(quit_closure,
+ true /*should_preload*/,
+ timestamp);
DCHECK(g_application);
}
@@ -79,9 +79,9 @@
LOG(INFO) << "Starting application.";
#if SB_API_VERSION >= 13
DCHECK(!g_application);
- g_application =
- new cobalt::browser::Application(quit_closure, false /*not_preload*/,
- timestamp);
+ g_application = new cobalt::browser::Application(quit_closure,
+ false /*not_preload*/,
+ timestamp);
DCHECK(g_application);
#else
if (!g_application) {
diff --git a/src/cobalt/browser/splash_screen.h b/src/cobalt/browser/splash_screen.h
index 3f0595d..1be5f33 100644
--- a/src/cobalt/browser/splash_screen.h
+++ b/src/cobalt/browser/splash_screen.h
@@ -53,26 +53,27 @@
}
// LifecycleObserver implementation.
+ // LifecycleObserver implementation.
void Blur(SbTimeMonotonic timestamp) override {
- web_module_->Blur(timestamp);
+ web_module_->Blur(0);
}
void Conceal(render_tree::ResourceProvider* resource_provider,
SbTimeMonotonic timestamp) override {
- web_module_->Conceal(resource_provider, timestamp);
+ web_module_->Conceal(resource_provider, 0);
}
void Freeze(SbTimeMonotonic timestamp) override {
- web_module_->Freeze(timestamp);
+ web_module_->Freeze(0);
}
void Unfreeze(render_tree::ResourceProvider* resource_provider,
SbTimeMonotonic timestamp) override {
- web_module_->Unfreeze(resource_provider, timestamp);
+ web_module_->Unfreeze(resource_provider, 0);
}
void Reveal(render_tree::ResourceProvider* resource_provider,
SbTimeMonotonic timestamp) override {
- web_module_->Reveal(resource_provider, timestamp);
+ web_module_->Reveal(resource_provider, 0);
}
void Focus(SbTimeMonotonic timestamp) override {
- web_module_->Focus(timestamp);
+ web_module_->Focus(0);
}
void ReduceMemory() { web_module_->ReduceMemory(); }
diff --git a/src/cobalt/browser/switches.cc b/src/cobalt/browser/switches.cc
index 1411c37..785e879 100644
--- a/src/cobalt/browser/switches.cc
+++ b/src/cobalt/browser/switches.cc
@@ -397,6 +397,11 @@
"the URL used to launch Cobalt, then the value of "
"'fallback_splash_screen_url' will be used.";
+const char kUseQAUpdateServer[] = "use_qa_update_server";
+const char kUseQAUpdateServerHelp[] =
+ "Uses the QA update server to test the changes to the configuration of the "
+ "PROD update server.";
+
const char kVersion[] = "version";
const char kVersionHelp[] = "Prints the current version of Cobalt";
@@ -480,7 +485,8 @@
{kSoftwareSurfaceCacheSizeInBytes,
kSoftwareSurfaceCacheSizeInBytesHelp},
{kFallbackSplashScreenURL, kFallbackSplashScreenURLHelp},
- {kVersion, kVersionHelp}, {kViewport, kViewportHelp},
+ {kUseQAUpdateServer, kUseQAUpdateServerHelp}, {kVersion, kVersionHelp},
+ {kViewport, kViewportHelp},
{kVideoPlaybackRateMultiplier, kVideoPlaybackRateMultiplierHelp},
};
diff --git a/src/cobalt/browser/switches.h b/src/cobalt/browser/switches.h
index 53fe622..9b3a0c2 100644
--- a/src/cobalt/browser/switches.h
+++ b/src/cobalt/browser/switches.h
@@ -151,6 +151,8 @@
extern const char kFallbackSplashScreenURLHelp[];
extern const char kFallbackSplashScreenTopics[];
extern const char kFallbackSplashScreenTopicsHelp[];
+extern const char kUseQAUpdateServer[];
+extern const char kUseQAUpdateServerHelp[];
extern const char kVersion[];
extern const char kVersionHelp[];
extern const char kViewport[];
diff --git a/src/cobalt/browser/user_agent_platform_info.cc b/src/cobalt/browser/user_agent_platform_info.cc
index 50a703f..8c47fee 100644
--- a/src/cobalt/browser/user_agent_platform_info.cc
+++ b/src/cobalt/browser/user_agent_platform_info.cc
@@ -20,10 +20,13 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "cobalt/browser/switches.h"
+#if SB_IS(EVERGREEN)
+#include "cobalt/extension/installation_manager.h"
+#endif // SB_IS(EVERGREEN)
#include "cobalt/renderer/get_default_rasterizer_for_platform.h"
#include "cobalt/script/javascript_engine.h"
#include "cobalt/version.h"
-#include "cobalt_build_id.h" // NOLINT(build/include)
+#include "cobalt_build_id.h" // NOLINT(build/include_subdir)
#include "starboard/common/log.h"
#include "starboard/common/string.h"
#include "starboard/system.h"
@@ -56,10 +59,12 @@
return "UNKNOWN";
default:
NOTREACHED();
- return "";
+ return "UNKNOWN";
}
}
+const char kUnspecifiedConnectionTypeName[] = "UnspecifiedConnectionType";
+
std::string CreateConnectionTypeString(
const base::Optional<SbSystemConnectionType>& connection_type) {
if (connection_type) {
@@ -68,23 +73,268 @@
return "Wired";
case kSbSystemConnectionTypeWireless:
return "Wireless";
- default:
- NOTREACHED();
+ case kSbSystemConnectionTypeUnknown:
+ return kUnspecifiedConnectionTypeName;
+ }
+ }
+ return kUnspecifiedConnectionTypeName;
+}
+
+static bool isAsciiAlphaDigit(int c) {
+ return base::IsAsciiAlpha(c) || base::IsAsciiDigit(c);
+}
+
+// https://datatracker.ietf.org/doc/html/rfc5234#appendix-B.1
+static bool isVCHARorSpace(int c) { return c >= 0x20 && c <= 0x7E; }
+
+// https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
+static bool isTCHAR(int c) {
+ if (isAsciiAlphaDigit(c)) return true;
+ switch (c) {
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '*':
+ case '+':
+ case '-':
+ case '.':
+ case '^':
+ case '_':
+ case '`':
+ case '|':
+ case '~':
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool isTCHARorForwardSlash(int c) { return isTCHAR(c) || c == '/'; }
+
+const char kStripParentheses[] = "()";
+const char kStripParenthesesAndComma[] = "(),";
+
+// Replace reserved characters with Unicode homoglyphs
+std::string Sanitize(const std::string& str, bool (*allowed)(int),
+ const char* strip = nullptr) {
+ std::string clean;
+ for (auto c : str) {
+ if (allowed(c) && (!strip || !strchr(strip, c))) {
+ clean.push_back(c);
+ }
+ }
+ return clean;
+}
+
+base::Optional<std::string> Sanitize(base::Optional<std::string> str,
+ bool (*allowed)(int),
+ const char* strip = nullptr) {
+ std::string clean;
+ if (str) {
+ clean = Sanitize(str.value(), allowed, strip);
+ }
+ if (clean.empty()) {
+ return base::Optional<std::string>();
+ }
+ return base::Optional<std::string>(clean);
+}
+
+
+// Function that will query Starboard and populate a UserAgentPlatformInfo
+// object based on those results. This is de-coupled from
+// CreateUserAgentString() so that the common logic in CreateUserAgentString()
+// can be easily unit tested.
+void InitializeUserAgentPlatformInfoFields(UserAgentPlatformInfo& info) {
+ info.set_starboard_version(
+ base::StringPrintf("Starboard/%d", SB_API_VERSION));
+
+ const size_t kSystemPropertyMaxLength = 1024;
+ char value[kSystemPropertyMaxLength];
+ bool result;
+
+ result = SbSystemGetProperty(kSbSystemPropertyPlatformName, value,
+ kSystemPropertyMaxLength);
+ SB_DCHECK(result);
+ info.set_os_name_and_version(value);
+
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
+ // Because we add Cobalt's user agent string to Crashpad before we actually
+ // start Cobalt, the command line won't be initialized when we first try to
+ // get the user agent string.
+ if (base::CommandLine::InitializedForCurrentProcess()) {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kUserAgentOsNameVersion)) {
+ info.set_os_name_and_version(
+ command_line->GetSwitchValueASCII(switches::kUserAgentOsNameVersion));
+ }
+ }
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
+
+#if SB_API_VERSION >= 12
+ // System Integrator
+ result = SbSystemGetProperty(kSbSystemPropertySystemIntegratorName, value,
+ kSystemPropertyMaxLength);
+#else
+ // Original Design Manufacturer (ODM)
+ result = SbSystemGetProperty(kSbSystemPropertyOriginalDesignManufacturerName,
+ value, kSystemPropertyMaxLength);
+#endif
+ if (result) {
+ info.set_original_design_manufacturer(value);
+ }
+
+ info.set_javascript_engine_version(
+ script::GetJavaScriptEngineNameAndVersion());
+ info.set_rasterizer_type(
+ renderer::GetDefaultRasterizerForPlatform().rasterizer_name);
+
+// Evergreen version
+#if SB_IS(EVERGREEN)
+ info.set_evergreen_version(updater::GetCurrentEvergreenVersion());
+ if (!SbSystemGetExtension(kCobaltExtensionInstallationManagerName)) {
+ // If the installation manager is not initialized, the "evergreen_lite"
+ // command line parameter is specified and the system image is loaded.
+ info.set_evergreen_type("Lite");
+ } else {
+ info.set_evergreen_type("Full");
+ }
+#endif
+
+ info.set_cobalt_version(COBALT_VERSION);
+ info.set_cobalt_build_version_number(COBALT_BUILD_VERSION_NUMBER);
+
+#if defined(COBALT_BUILD_TYPE_DEBUG)
+ info.set_build_configuration("debug");
+#elif defined(COBALT_BUILD_TYPE_DEVEL)
+ info.set_build_configuration("devel");
+#elif defined(COBALT_BUILD_TYPE_QA)
+ info.set_build_configuration("qa");
+#elif defined(COBALT_BUILD_TYPE_GOLD)
+ info.set_build_configuration("gold");
+#else
+#error Unknown build configuration.
+#endif
+
+ result = SbSystemGetProperty(kSbSystemPropertyUserAgentAuxField, value,
+ kSystemPropertyMaxLength);
+ if (result) {
+ info.set_aux_field(value);
+ }
+
+ // Fill platform info if it is a hardware TV device.
+ info.set_device_type(SbSystemGetDeviceType());
+
+ // Chipset model number
+ result = SbSystemGetProperty(kSbSystemPropertyChipsetModelNumber, value,
+ kSystemPropertyMaxLength);
+ if (result) {
+ info.set_chipset_model_number(value);
+ }
+
+ // Model year
+ result = SbSystemGetProperty(kSbSystemPropertyModelYear, value,
+ kSystemPropertyMaxLength);
+ if (result) {
+ info.set_model_year(value);
+ }
+
+ // Firmware version
+ result = SbSystemGetProperty(kSbSystemPropertyFirmwareVersion, value,
+ kSystemPropertyMaxLength);
+ if (result) {
+ info.set_firmware_version(value);
+ }
+
+ // Brand
+ result = SbSystemGetProperty(kSbSystemPropertyBrandName, value,
+ kSystemPropertyMaxLength);
+ if (result) {
+ info.set_brand(value);
+ // If we didn't get a value for the original design manufacturer, use the
+ // value for the brand if one is available.
+ if (!info.original_design_manufacturer() && info.brand()) {
+ info.set_original_design_manufacturer(info.brand());
}
}
- return "";
+ // Model name
+ result = SbSystemGetProperty(kSbSystemPropertyModelName, value,
+ kSystemPropertyMaxLength);
+ if (result) {
+ info.set_model(value);
+ }
+
+ // Connection type
+ info.set_connection_type(SbSystemGetConnectionType());
}
} // namespace
-UserAgentPlatformInfo::UserAgentPlatformInfo() { InitializeFields(); }
+UserAgentPlatformInfo::UserAgentPlatformInfo() {
+ InitializeUserAgentPlatformInfoFields(*this);
+}
+void UserAgentPlatformInfo::set_starboard_version(
+ const std::string& starboard_version) {
+ starboard_version_ = Sanitize(starboard_version, isTCHARorForwardSlash);
+}
+void UserAgentPlatformInfo::set_os_name_and_version(
+ const std::string& os_name_and_version) {
+ os_name_and_version_ =
+ Sanitize(os_name_and_version, isVCHARorSpace, kStripParentheses);
+}
+void UserAgentPlatformInfo::set_original_design_manufacturer(
+ base::Optional<std::string> original_design_manufacturer) {
+ if (original_design_manufacturer) {
+ original_design_manufacturer_ =
+ Sanitize(original_design_manufacturer, isAsciiAlphaDigit);
+ }
+}
void UserAgentPlatformInfo::set_device_type(SbSystemDeviceType device_type) {
device_type_ = device_type;
device_type_string_ = CreateDeviceTypeString(device_type_);
}
+void UserAgentPlatformInfo::set_chipset_model_number(
+ base::Optional<std::string> chipset_model_number) {
+ if (chipset_model_number) {
+ chipset_model_number_ = Sanitize(chipset_model_number, isAsciiAlphaDigit);
+ }
+}
+
+void UserAgentPlatformInfo::set_model_year(
+ base::Optional<std::string> model_year) {
+ if (model_year) {
+ model_year_ = Sanitize(model_year, base::IsAsciiDigit);
+ }
+}
+
+void UserAgentPlatformInfo::set_firmware_version(
+ base::Optional<std::string> firmware_version) {
+ if (firmware_version) {
+ firmware_version_ = Sanitize(firmware_version, isTCHAR);
+ }
+}
+
+void UserAgentPlatformInfo::set_brand(base::Optional<std::string> brand) {
+ if (brand) {
+ brand_ = Sanitize(brand, isVCHARorSpace, kStripParenthesesAndComma);
+ }
+}
+
+void UserAgentPlatformInfo::set_model(base::Optional<std::string> model) {
+ if (model) {
+ model_ = Sanitize(model, isVCHARorSpace, kStripParenthesesAndComma);
+ }
+}
+
+void UserAgentPlatformInfo::set_aux_field(const std::string& aux_field) {
+ aux_field_ = Sanitize(aux_field, isTCHARorForwardSlash);
+}
+
void UserAgentPlatformInfo::set_connection_type(
base::Optional<SbSystemConnectionType> connection_type) {
if (connection_type) {
@@ -95,110 +345,40 @@
}
}
-void UserAgentPlatformInfo::InitializeFields() {
- starboard_version_ = base::StringPrintf("Starboard/%d", SB_API_VERSION);
+void UserAgentPlatformInfo::set_javascript_engine_version(
+ const std::string& javascript_engine_version) {
+ javascript_engine_version_ =
+ Sanitize(javascript_engine_version, isTCHARorForwardSlash);
+}
- const size_t kSystemPropertyMaxLength = 1024;
- char value[kSystemPropertyMaxLength];
- bool result;
+void UserAgentPlatformInfo::set_rasterizer_type(
+ const std::string& rasterizer_type) {
+ rasterizer_type_ = Sanitize(rasterizer_type, isTCHARorForwardSlash);
+}
- result = SbSystemGetProperty(kSbSystemPropertyPlatformName, value,
- kSystemPropertyMaxLength);
- SB_DCHECK(result);
- os_name_and_version_ = value;
+void UserAgentPlatformInfo::set_evergreen_type(
+ const std::string& evergreen_type) {
+ evergreen_type_ = Sanitize(evergreen_type, isTCHARorForwardSlash);
+}
- // Fill platform info if it is a hardware TV device.
- SbSystemDeviceType device_type = SbSystemGetDeviceType();
+void UserAgentPlatformInfo::set_evergreen_version(
+ const std::string& evergreen_version) {
+ evergreen_version_ = Sanitize(evergreen_version, isTCHAR);
+}
-#if SB_API_VERSION >= 12
- // System Integrator
- result = SbSystemGetProperty(kSbSystemPropertySystemIntegratorName, value,
- kSystemPropertyMaxLength);
-#else
- // Original Design Manufacturer (ODM)
- result = SbSystemGetProperty(kSbSystemPropertyOriginalDesignManufacturerName,
- value, kSystemPropertyMaxLength);
-#endif
- if (result) {
- original_design_manufacturer_ = value;
- }
+void UserAgentPlatformInfo::set_cobalt_version(
+ const std::string& cobalt_version) {
+ cobalt_version_ = Sanitize(cobalt_version, isTCHAR);
+}
- javascript_engine_version_ = script::GetJavaScriptEngineNameAndVersion();
+void UserAgentPlatformInfo::set_cobalt_build_version_number(
+ const std::string& cobalt_build_version_number) {
+ cobalt_build_version_number_ = Sanitize(cobalt_build_version_number, isTCHAR);
+}
- rasterizer_type_ =
- renderer::GetDefaultRasterizerForPlatform().rasterizer_name;
-
-// Evergreen version
-#if SB_IS(EVERGREEN)
- evergreen_version_ = updater::GetCurrentEvergreenVersion();
-#endif
-
- cobalt_version_ = COBALT_VERSION;
- cobalt_build_version_number_ = COBALT_BUILD_VERSION_NUMBER;
-
-#if defined(COBALT_BUILD_TYPE_DEBUG)
- build_configuration_ = "debug";
-#elif defined(COBALT_BUILD_TYPE_DEVEL)
- build_configuration_ = "devel";
-#elif defined(COBALT_BUILD_TYPE_QA)
- build_configuration_ = "qa";
-#elif defined(COBALT_BUILD_TYPE_GOLD)
- build_configuration_ = "gold";
-#else
-#error Unknown build configuration.
-#endif
-
- result = SbSystemGetProperty(kSbSystemPropertyUserAgentAuxField, value,
- kSystemPropertyMaxLength);
- if (result) {
- aux_field_ = value;
- }
-
- // Device Type
- device_type_ = device_type;
- device_type_string_ = CreateDeviceTypeString(device_type_);
-
- // Chipset model number
- result = SbSystemGetProperty(kSbSystemPropertyChipsetModelNumber, value,
- kSystemPropertyMaxLength);
- if (result) {
- chipset_model_number_ = value;
- }
-
- // Model year
- result = SbSystemGetProperty(kSbSystemPropertyModelYear, value,
- kSystemPropertyMaxLength);
- if (result) {
- model_year_ = value;
- }
-
- // Firmware version
- result = SbSystemGetProperty(kSbSystemPropertyFirmwareVersion, value,
- kSystemPropertyMaxLength);
- if (result) {
- firmware_version_ = value;
- }
-
- // Brand
- result = SbSystemGetProperty(kSbSystemPropertyBrandName, value,
- kSystemPropertyMaxLength);
- if (result) {
- brand_ = value;
- }
-
- // Model name
- result = SbSystemGetProperty(kSbSystemPropertyModelName, value,
- kSystemPropertyMaxLength);
- if (result) {
- model_ = value;
- }
-
- // Connection type
- SbSystemConnectionType connection_type = SbSystemGetConnectionType();
- if (connection_type != kSbSystemConnectionTypeUnknown) {
- connection_type_ = connection_type;
- }
- connection_type_string_ = CreateConnectionTypeString(connection_type_);
+void UserAgentPlatformInfo::set_build_configuration(
+ const std::string& build_configuration) {
+ build_configuration_ = Sanitize(build_configuration, isTCHAR);
}
} // namespace browser
diff --git a/src/cobalt/browser/user_agent_platform_info.h b/src/cobalt/browser/user_agent_platform_info.h
index 80d9798..db6c94d 100644
--- a/src/cobalt/browser/user_agent_platform_info.h
+++ b/src/cobalt/browser/user_agent_platform_info.h
@@ -66,6 +66,7 @@
const std::string& rasterizer_type() const override {
return rasterizer_type_;
}
+ const std::string& evergreen_type() const override { return evergreen_type_; }
const std::string& evergreen_version() const override {
return evergreen_version_;
}
@@ -77,78 +78,33 @@
return build_configuration_;
}
- // Other: For unit testing cobalt::browser::CreateUserAgentString()
+ // Other: Setters that sanitize the strings where needed.
//
- void set_starboard_version(const std::string& starboard_version) {
- starboard_version_ = starboard_version;
- }
- void set_os_name_and_version(const std::string& os_name_and_version) {
- os_name_and_version_ = os_name_and_version;
- }
+ void set_starboard_version(const std::string& starboard_version);
+ void set_os_name_and_version(const std::string& os_name_and_version);
void set_original_design_manufacturer(
- base::Optional<std::string> original_design_manufacturer) {
- if (original_design_manufacturer) {
- original_design_manufacturer_ = original_design_manufacturer;
- }
- }
+ base::Optional<std::string> original_design_manufacturer);
void set_device_type(SbSystemDeviceType device_type);
void set_chipset_model_number(
- base::Optional<std::string> chipset_model_number) {
- if (chipset_model_number) {
- chipset_model_number_ = chipset_model_number;
- }
- }
- void set_model_year(base::Optional<std::string> model_year) {
- if (model_year) {
- model_year_ = model_year;
- }
- }
- void set_firmware_version(base::Optional<std::string> firmware_version) {
- if (firmware_version) {
- firmware_version_ = firmware_version;
- }
- }
- void set_brand(base::Optional<std::string> brand) {
- if (brand) {
- brand_ = brand;
- }
- }
- void set_model(base::Optional<std::string> model) {
- if (model) {
- model_ = model;
- }
- }
- void set_aux_field(const std::string& aux_field) { aux_field_ = aux_field; }
+ base::Optional<std::string> chipset_model_number);
+ void set_model_year(base::Optional<std::string> model_year);
+ void set_firmware_version(base::Optional<std::string> firmware_version);
+ void set_brand(base::Optional<std::string> brand);
+ void set_model(base::Optional<std::string> model);
+ void set_aux_field(const std::string& aux_field);
void set_connection_type(
base::Optional<SbSystemConnectionType> connection_type);
void set_javascript_engine_version(
- const std::string& javascript_engine_version) {
- javascript_engine_version_ = javascript_engine_version;
- }
- void set_rasterizer_type(const std::string& rasterizer_type) {
- rasterizer_type_ = rasterizer_type;
- }
- void set_evergreen_version(const std::string& evergreen_version) {
- evergreen_version_ = evergreen_version;
- }
- void set_cobalt_version(const std::string& cobalt_version) {
- cobalt_version_ = cobalt_version;
- }
+ const std::string& javascript_engine_version);
+ void set_rasterizer_type(const std::string& rasterizer_type);
+ void set_evergreen_type(const std::string& evergreen_type);
+ void set_evergreen_version(const std::string& evergreen_version);
+ void set_cobalt_version(const std::string& cobalt_version);
void set_cobalt_build_version_number(
- const std::string& cobalt_build_version_number) {
- cobalt_build_version_number_ = cobalt_build_version_number;
- }
- void set_build_configuration(const std::string& build_configuration) {
- build_configuration_ = build_configuration;
- }
+ const std::string& cobalt_build_version_number);
+ void set_build_configuration(const std::string& build_configuration);
private:
- // Function that will query Starboard and populate a UserAgentPlatformInfo
- // object based on those results. This is de-coupled from
- // CreateUserAgentString() so that the common logic in CreateUserAgentString()
- // can be easily unit tested.
- void InitializeFields();
-
std::string starboard_version_;
std::string os_name_and_version_;
base::Optional<std::string> original_design_manufacturer_;
@@ -164,6 +120,7 @@
std::string connection_type_string_;
std::string javascript_engine_version_;
std::string rasterizer_type_;
+ std::string evergreen_type_;
std::string evergreen_version_;
std::string cobalt_version_;
diff --git a/src/cobalt/browser/user_agent_string.cc b/src/cobalt/browser/user_agent_string.cc
index fde8edb..c048b18 100644
--- a/src/cobalt/browser/user_agent_string.cc
+++ b/src/cobalt/browser/user_agent_string.cc
@@ -17,42 +17,17 @@
#include <vector>
#include "base/command_line.h"
-#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "cobalt/browser/switches.h"
-#if SB_IS(EVERGREEN)
-#include "cobalt/extension/installation_manager.h"
-#endif // SB_IS(EVERGREEN)
#include "starboard/common/log.h"
#include "starboard/common/string.h"
#include "starboard/system.h"
namespace cobalt {
namespace browser {
-
namespace {
-struct SanitizeReplacements {
- const char* replace_chars;
- const char* replace_with;
-} kSanitizeReplacements[] = {
- {",", u8"\uFF0C"}, // fullwidth comma
- {"_", u8"\u2E0F"}, // paragraphos
- {"/", u8"\u2215"}, // division slash
- {"(", u8"\uFF08"}, // fullwidth left paren
- {")", u8"\uFF09"}, // fullwidth right paren
-};
-
-// Replace reserved characters with Unicode homoglyphs
-std::string Sanitize(const std::string& str) {
- std::string clean(str);
- for (size_t i = 0; i < arraysize(kSanitizeReplacements); i++) {
- const SanitizeReplacements* replacement = kSanitizeReplacements + i;
- base::ReplaceChars(clean, replacement->replace_chars,
- replacement->replace_with, &clean);
- }
- return clean;
-}
+const char kUnknownFieldName[] = "Unknown";
} // namespace
@@ -72,24 +47,9 @@
// Starboard/APIVersion,
// Device/FirmwareVersion (Brand, Model, ConnectionType)
- std::string os_name_and_version = platform_info.os_name_and_version();
-
-#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
- // Because we add Cobalt's user agent string to Crashpad before we actually
- // start Cobalt, the command line won't be initialized when we first try to
- // get the user agent string.
- if (base::CommandLine::InitializedForCurrentProcess()) {
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kUserAgentOsNameVersion)) {
- os_name_and_version =
- command_line->GetSwitchValueASCII(switches::kUserAgentOsNameVersion);
- }
- }
-#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
-
// Mozilla/5.0 (ChromiumStylePlatform)
- std::string user_agent =
- base::StringPrintf("Mozilla/5.0 (%s)", os_name_and_version.c_str());
+ std::string user_agent = base::StringPrintf(
+ "Mozilla/5.0 (%s)", platform_info.os_name_and_version().c_str());
// Cobalt/Version.BuildNumber-BuildConfiguration (unlike Gecko)
base::StringAppendF(&user_agent, " Cobalt/%s.%s-%s (unlike Gecko)",
@@ -113,15 +73,11 @@
if (!platform_info.evergreen_version().empty()) {
base::StringAppendF(&user_agent, " Evergreen/%s",
platform_info.evergreen_version().c_str());
-#if SB_IS(EVERGREEN)
- if (!SbSystemGetExtension(kCobaltExtensionInstallationManagerName)) {
- // If the installation manager is not initialized, the "evergreen_lite"
- // command line parameter is specified and the system image is loaded.
- base::StringAppendF(&user_agent, " Evergreen-Lite");
- } else {
- base::StringAppendF(&user_agent, " Evergreen-Full");
- }
-#endif // SB_IS(EVERGREEN)
+ }
+ // Evergreen type
+ if (!platform_info.evergreen_type().empty()) {
+ base::StringAppendF(&user_agent, " Evergreen-%s",
+ platform_info.evergreen_type().c_str());
}
// Starboard/APIVersion,
@@ -133,19 +89,19 @@
// Device/FirmwareVersion (Brand, Model, ConnectionType)
base::StringAppendF(
&user_agent, ", %s_%s_%s_%s/%s (%s, %s, %s)",
- Sanitize(platform_info.original_design_manufacturer().value_or(""))
+ platform_info.original_design_manufacturer()
+ .value_or(kUnknownFieldName)
.c_str(),
platform_info.device_type_string().c_str(),
- Sanitize(platform_info.chipset_model_number().value_or("")).c_str(),
- Sanitize(platform_info.model_year().value_or("")).c_str(),
- Sanitize(platform_info.firmware_version().value_or("")).c_str(),
- Sanitize(platform_info.brand().value_or("")).c_str(),
- Sanitize(platform_info.model().value_or("")).c_str(),
+ platform_info.chipset_model_number().value_or(kUnknownFieldName).c_str(),
+ platform_info.model_year().value_or("0").c_str(),
+ platform_info.firmware_version().value_or(kUnknownFieldName).c_str(),
+ platform_info.brand().value_or(kUnknownFieldName).c_str(),
+ platform_info.model().value_or(kUnknownFieldName).c_str(),
platform_info.connection_type_string().c_str());
if (!platform_info.aux_field().empty()) {
- user_agent.append(" ");
- user_agent.append(platform_info.aux_field());
+ base::StringAppendF(&user_agent, " %s", platform_info.aux_field().c_str());
}
return user_agent;
}
diff --git a/src/cobalt/browser/user_agent_string_test.cc b/src/cobalt/browser/user_agent_string_test.cc
index 042d180..d2537e7 100644
--- a/src/cobalt/browser/user_agent_string_test.cc
+++ b/src/cobalt/browser/user_agent_string_test.cc
@@ -79,13 +79,204 @@
EXPECT_NE(std::string::npos, user_agent_string.find(tv_info_str));
}
-// Look-alike replacements expected from sanitizing fields
+// Look-alike replacements previously used for sanitizing fields
#define COMMA u8"\uFF0C" // fullwidth comma
#define UNDER u8"\u2E0F" // paragraphos
#define SLASH u8"\u2215" // division slash
#define LPAREN u8"\uFF08" // fullwidth left paren
#define RPAREN u8"\uFF09" // fullwidth right paren
+#define ALPHALOWER "abcdefghijklmnopqrstuvwxyz"
+#define ALPHAUPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define ALPHA ALPHAUPPER ALPHALOWER
+#define DIGIT "0123456789"
+#define DIGITREVERSED "9876543210"
+#define ALPHADIGIT ALPHA DIGIT
+#define TCHAR ALPHADIGIT "!#$%&\'*+-.^_`|~"
+#define TCHARORSLASH TCHAR "/"
+#define VCHAR_EXCEPTALPHADIGIT "!\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~"
+#define VCHAR_EXCEPTPARENTHESES "!\"#$%&\'*+,-./:;<=>?@[\\]^_`{|}~" ALPHADIGIT
+#define VCHAR_EXCEPTPARENTHESESANDCOMMA \
+ "!\"#$%&\'*+-./:;<=>?@[\\]^_`{|}~" ALPHADIGIT
+#define VCHAR VCHAR_EXCEPTALPHADIGIT ALPHADIGIT
+#define VCHARORSPACE " " VCHAR
+#define VCHARORSPACE_EXCEPTPARENTHESES " " VCHAR_EXCEPTPARENTHESES
+#define VCHARORSPACE_EXCEPTPARENTHESESANDCOMMA \
+ " " VCHAR_EXCEPTPARENTHESESANDCOMMA
+
+#define CONTROL \
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" \
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
+#define DEL "\x7F"
+#define HIGH_ASCII \
+ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F" \
+ "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F" \
+ "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF" \
+ "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF" \
+ "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF" \
+ "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF" \
+ "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF" \
+ "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"
+
+#define NOT_DIGIT CONTROL VCHAR_EXCEPTALPHADIGIT ALPHA DEL HIGH_ASCII
+#define NOT_ALPHADIGIT CONTROL VCHAR_EXCEPTALPHADIGIT DEL HIGH_ASCII
+#define NOT_TCHAR CONTROL "\"(),/:;<=>?@[\\]{}" DEL HIGH_ASCII
+#define NOT_TCHARORSLASH CONTROL "\"(),:;<=>?@[\\]{}" DEL HIGH_ASCII
+
+#define NOT_VCHARORSPACE CONTROL DEL HIGH_ASCII
+
+TEST(UserAgentStringFactoryTest, SanitizedStarboardVersion) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_starboard_version("Foo" NOT_TCHARORSLASH "Bar" TCHARORSLASH
+ "Baz" NOT_TCHARORSLASH "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos,
+ user_agent_string.find("FooBar" TCHARORSLASH "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedOsNameAndVersion) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_os_name_and_version("Foo()" NOT_VCHARORSPACE
+ "Bar" VCHARORSPACE_EXCEPTPARENTHESES
+ "Baz()" NOT_VCHARORSPACE "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(
+ std::string::npos,
+ user_agent_string.find("FooBar" VCHARORSPACE_EXCEPTPARENTHESES "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedOriginalDesignManufacturer) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_original_design_manufacturer(
+ "Foo" NOT_ALPHADIGIT "Bar" ALPHADIGIT "Baz" NOT_ALPHADIGIT "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos,
+ user_agent_string.find("FooBar" ALPHADIGIT "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedChipsetModelNumber) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_chipset_model_number("Foo" NOT_ALPHADIGIT "Bar" ALPHADIGIT
+ "Baz" NOT_ALPHADIGIT "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos,
+ user_agent_string.find("FooBar" ALPHADIGIT "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedModelYear) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_chipset_model_number("FooBar");
+ platform_info.set_model_year(NOT_DIGIT DIGIT NOT_DIGIT DIGITREVERSED);
+ platform_info.set_firmware_version("BazQux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos,
+ user_agent_string.find("FooBar_" DIGIT DIGITREVERSED "/BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedFirmwareVersion) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_firmware_version("Foo" NOT_TCHAR "Bar" TCHAR "Baz" NOT_TCHAR
+ "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos, user_agent_string.find("FooBar" TCHAR "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedBrand) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_brand("Foo()," NOT_VCHARORSPACE
+ "Bar" VCHARORSPACE_EXCEPTPARENTHESESANDCOMMA
+ "Baz()," NOT_VCHARORSPACE "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos,
+ user_agent_string.find(
+ "FooBar" VCHARORSPACE_EXCEPTPARENTHESESANDCOMMA "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedModel) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_model("Foo()," NOT_VCHARORSPACE
+ "Bar" VCHARORSPACE_EXCEPTPARENTHESESANDCOMMA
+ "Baz()," NOT_VCHARORSPACE "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos,
+ user_agent_string.find(
+ "FooBar" VCHARORSPACE_EXCEPTPARENTHESESANDCOMMA "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedAuxField) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_aux_field("Foo" NOT_TCHARORSLASH "Bar" TCHARORSLASH
+ "Baz" NOT_TCHARORSLASH "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos,
+ user_agent_string.find("FooBar" TCHARORSLASH "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedJavascriptEngineVersion) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_javascript_engine_version(
+ "Foo" NOT_TCHARORSLASH "Bar" TCHARORSLASH "Baz" NOT_TCHARORSLASH "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos,
+ user_agent_string.find("FooBar" TCHARORSLASH "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedRasterizerType) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_rasterizer_type("Foo" NOT_TCHARORSLASH "Bar" TCHARORSLASH
+ "Baz" NOT_TCHARORSLASH "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos,
+ user_agent_string.find("FooBar" TCHARORSLASH "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedEvergreenType) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_evergreen_version("Foo" NOT_TCHAR "Bar" TCHAR
+ "Baz" NOT_TCHAR "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos, user_agent_string.find("FooBar" TCHAR "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedCobaltVersion) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_cobalt_version("Foo" NOT_TCHAR "Bar" TCHAR "Baz" NOT_TCHAR
+ "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos, user_agent_string.find("FooBar" TCHAR "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedCobaltBuildVersionNumber) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_cobalt_build_version_number("Foo" NOT_TCHAR "Bar" TCHAR
+ "Baz" NOT_TCHAR "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos, user_agent_string.find("FooBar" TCHAR "BazQux"));
+}
+
+TEST(UserAgentStringFactoryTest, SanitizedCobaltBuildConfiguration) {
+ UserAgentPlatformInfo platform_info =
+ CreateOnlyOSNameAndVersionPlatformInfo();
+ platform_info.set_build_configuration("Foo" NOT_TCHAR "Bar" TCHAR
+ "Baz" NOT_TCHAR "Qux");
+ std::string user_agent_string = CreateUserAgentString(platform_info);
+ EXPECT_NE(std::string::npos, user_agent_string.find("FooBar" TCHAR "BazQux"));
+}
+
TEST(UserAgentStringFactoryTest, WithPlatformInfo) {
// There are deliberately a variety of underscores, commas, slashes, and
// parentheses in the strings below to ensure they get sanitized.
@@ -101,13 +292,8 @@
std::string user_agent_string = CreateUserAgentString(platform_info);
const char* tv_info_str =
- "Aperture" UNDER "Science" UNDER
- "Innovators"
- "_OTT_"
- "P-body" SLASH "Orange" UNDER "Atlas" SLASH
- "Blue"
- "_2013"
- "/0" COMMA "01 (Aperture Science " LPAREN "Labs" RPAREN ", GLaDOS, )";
+ "ApertureScienceInnovators_OTT_PbodyOrangeAtlasBlue_2013/001 "
+ "(Aperture Science Labs, GLaDOS, )";
EXPECT_NE(std::string::npos, user_agent_string.find(tv_info_str));
}
@@ -118,7 +304,7 @@
platform_info.set_device_type(kSbSystemDeviceTypeOverTheTopBox);
std::string user_agent_string = CreateUserAgentString(platform_info);
- EXPECT_NE(std::string::npos, user_agent_string.find("Wired"));
+ EXPECT_NE(std::string::npos, user_agent_string.find(", Wired)"));
}
TEST(UserAgentStringFactoryTest, WithWirelessConnection) {
@@ -128,7 +314,7 @@
platform_info.set_device_type(kSbSystemDeviceTypeOverTheTopBox);
std::string user_agent_string = CreateUserAgentString(platform_info);
- EXPECT_NE(std::string::npos, user_agent_string.find("Wireless"));
+ EXPECT_NE(std::string::npos, user_agent_string.find(", Wireless)"));
}
TEST(UserAgentStringFactoryTest, WithOnlyBrandModelAndDeviceType) {
@@ -139,7 +325,8 @@
platform_info.set_model("GLaDOS");
std::string user_agent_string = CreateUserAgentString(platform_info);
- const char* tv_info_str = ", _OTT__/ (Aperture Science, GLaDOS, )";
+ const char* tv_info_str =
+ ", Unknown_OTT_Unknown_0/Unknown (Aperture Science, GLaDOS, )";
EXPECT_NE(std::string::npos, user_agent_string.find(tv_info_str));
}
@@ -149,7 +336,8 @@
platform_info.set_device_type(kSbSystemDeviceTypeOverTheTopBox);
std::string user_agent_string = CreateUserAgentString(platform_info);
- const char* tv_info_str = "Starboard/6, _OTT__/ (, , )";
+ const char* tv_info_str =
+ "Starboard/6, Unknown_OTT_Unknown_0/Unknown (Unknown, Unknown, )";
EXPECT_NE(std::string::npos, user_agent_string.find(tv_info_str));
}
@@ -158,7 +346,7 @@
platform_info.set_javascript_engine_version("V8/6.5.254.28");
std::string user_agent_string = CreateUserAgentString(platform_info);
- EXPECT_NE(std::string::npos, user_agent_string.find("V8/6.5.254.28"));
+ EXPECT_NE(std::string::npos, user_agent_string.find(" V8/6.5.254.28"));
}
} // namespace
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index f4c2294..606938d 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -263,6 +263,7 @@
void SetApplicationStartOrPreloadTimestamp(
bool is_preload, SbTimeMonotonic timestamp);
+ void SetDeepLinkTimestamp(SbTimeMonotonic timestamp);
private:
class DocumentLoadedObserver;
@@ -1034,6 +1035,11 @@
is_preload, timestamp);
}
+void WebModule::Impl::SetDeepLinkTimestamp(SbTimeMonotonic timestamp) {
+ DCHECK(window_);
+ window_->performance()->SetDeepLinkTimestamp(timestamp);
+}
+
void WebModule::Impl::OnCspPolicyChanged() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(is_running_);
@@ -1836,5 +1842,20 @@
}
}
+void WebModule::SetDeepLinkTimestamp(SbTimeMonotonic timestamp) {
+ TRACE_EVENT0("cobalt::browser",
+ "WebModule::SetDeepLinkTimestamp()");
+ DCHECK(message_loop());
+ DCHECK(impl_);
+ if (base::MessageLoop::current() != message_loop()) {
+ message_loop()->task_runner()->PostBlockingTask(
+ FROM_HERE,
+ base::Bind(&WebModule::Impl::SetDeepLinkTimestamp,
+ base::Unretained(impl_.get()), timestamp));
+ } else {
+ impl_->SetDeepLinkTimestamp(timestamp);
+ }
+}
+
} // namespace browser
} // namespace cobalt
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h
index d3350b3..16c830d 100644
--- a/src/cobalt/browser/web_module.h
+++ b/src/cobalt/browser/web_module.h
@@ -411,6 +411,7 @@
void SetApplicationStartOrPreloadTimestamp(bool is_preload,
SbTimeMonotonic timestamp);
+ void SetDeepLinkTimestamp(SbTimeMonotonic timestamp);
private:
// Data required to construct a WebModule, initialized in the constructor and
// passed to |Initialize|.
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 912bb2b..0c55a1f 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-303120
\ No newline at end of file
+303689
\ No newline at end of file
diff --git a/src/cobalt/content/fonts/BUILD.gn b/src/cobalt/content/fonts/BUILD.gn
new file mode 100644
index 0000000..87b11ff
--- /dev/null
+++ b/src/cobalt/content/fonts/BUILD.gn
@@ -0,0 +1,64 @@
+# Copyright 2021 The Cobalt Authors. 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.
+
+import("//cobalt/content/fonts/variables.gni")
+
+if (cobalt_font_package == "empty") {
+ copy("copy_font_data") {
+ sources = [ "$source_font_config_dir/fonts.xml" ]
+ outputs =
+ [ "$sb_static_contents_output_data_dir/fonts/{{source_file_part}}" ]
+ }
+} else {
+ action("fonts_xml") {
+ script = "scripts/filter_fonts.py"
+ font_xml = "$source_font_config_dir/fonts.xml"
+ sources = [ font_xml ]
+ outputs = [ "$sb_static_contents_output_data_dir/fonts/fonts.xml" ]
+ args = [
+ "-i",
+ rebase_path(font_xml, root_build_dir),
+ "-o",
+ outputs[0],
+ ] + package_categories
+ }
+
+ copy("copy_fonts") {
+ if (copy_font_files) {
+ fonts = exec_script("scripts/filter_fonts.py",
+ [
+ "-i",
+ rebase_path("$source_font_config_dir/fonts.xml",
+ root_build_dir),
+ "-f",
+ source_font_files_dir,
+ ] + package_categories,
+ "trim list lines",
+ [ "$source_font_config_dir/fonts.xml" ])
+ } else {
+ # Copy at least the fallback Roboto Subsetted font.
+ fonts = [ "$source_font_files_dir/Roboto-Regular-Subsetted.woff2" ]
+ }
+ sources = fonts
+ outputs =
+ [ "$sb_static_contents_output_data_dir/fonts/{{source_file_part}}" ]
+ }
+
+ group("copy_font_data") {
+ data_deps = [
+ ":copy_fonts",
+ ":fonts_xml",
+ ]
+ }
+}
diff --git a/src/cobalt/content/fonts/scripts/filter_fonts.py b/src/cobalt/content/fonts/scripts/filter_fonts.py
index bf332da..74486da 100755
--- a/src/cobalt/content/fonts/scripts/filter_fonts.py
+++ b/src/cobalt/content/fonts/scripts/filter_fonts.py
@@ -12,7 +12,6 @@
# 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.
-
"""Filters fonts.xml to include only desired font packages.
This is meant to be used in a GYP file to generate the list of fonts as the
@@ -26,7 +25,6 @@
from xml.dom import Node
from xml.dom.minidom import parse as parse_xml
-
NORMAL_WEIGHT = 400
BOLD_WEIGHT = 700
@@ -77,8 +75,8 @@
elif category == '2':
return weight in (NORMAL_WEIGHT, BOLD_WEIGHT) and style == NORMAL_STYLE
elif category == '3':
- return (weight in (NORMAL_WEIGHT, BOLD_WEIGHT)
- and style in (NORMAL_STYLE, ITALIC_STYLE))
+ return (weight in (NORMAL_WEIGHT, BOLD_WEIGHT) and
+ style in (NORMAL_STYLE, ITALIC_STYLE))
elif category == '4':
return True
else:
@@ -161,13 +159,18 @@
If --fonts_dir is specified, a newline-separated list of font files.
"""
parser = argparse.ArgumentParser()
- parser.add_argument('-i', '--input_xml', required=True,
- help='path to fonts.xml to be filtered')
- parser.add_argument('-o', '--output_xml',
- help='path to write a filtered XML file')
- parser.add_argument('-f', '--fonts_dir',
- help='prints a list of font files prefixed by the '
- 'specified FONTS_DIR (for GYP inputs)')
+ parser.add_argument(
+ '-i',
+ '--input_xml',
+ required=True,
+ help='path to fonts.xml to be filtered')
+ parser.add_argument(
+ '-o', '--output_xml', help='path to write a filtered XML file')
+ parser.add_argument(
+ '-f',
+ '--fonts_dir',
+ help='prints a list of font files prefixed by the '
+ 'specified FONTS_DIR (for GYP inputs)')
parser.add_argument('package_categories', nargs=argparse.REMAINDER)
options = parser.parse_args(argv)
@@ -176,8 +179,8 @@
# Make a dictionary mapping package name to category.
# E.g. ['sans-serif=1', 'serif=2'] becomes {'sans-serif':'1', 'serif':'2'}
- package_categories = dict(pkg.split('=')
- for pkg in options.package_categories)
+ package_categories = dict(
+ pkg.split('=') for pkg in options.package_categories)
fonts_doc = parse_xml(options.input_xml)
@@ -194,15 +197,16 @@
# Join with '/' rather than os.path.join() because this is for GYP, which
# even on Windows wants slashes rather than backslashes.
# Make a set for unique fonts since .ttc files may be listed more than once.
- result = ['/'.join((options.fonts_dir, font))
- for font in sorted(set(kept_fonts))]
+ result = [
+ '/'.join((options.fonts_dir, font)) for font in sorted(set(kept_fonts))
+ ]
return '\n'.join(result)
def main(argv):
result = DoMain(argv[1:])
if result:
- print result
+ print(result)
return 0
diff --git a/src/cobalt/content/fonts/variables.gni b/src/cobalt/content/fonts/variables.gni
new file mode 100644
index 0000000..8e16bd8
--- /dev/null
+++ b/src/cobalt/content/fonts/variables.gni
@@ -0,0 +1,158 @@
+# Copyright 2021 The Cobalt Authors. 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.
+
+declare_args() {
+ # See content/fonts/README.md for details on the specific values used for the
+ # variables below.
+ cobalt_font_package = "standard"
+ cobalt_font_package_override_named_sans_serif = -1
+ cobalt_font_package_override_named_serif = -1
+ cobalt_font_package_override_named_fcc_fonts = -1
+ cobalt_font_package_override_fallback_lang_non_cjk = -1
+ cobalt_font_package_override_fallback_lang_cjk = -1
+ cobalt_font_package_override_fallback_lang_cjk_low_quality = -1
+ cobalt_font_package_override_fallback_historic = -1
+ cobalt_font_package_override_fallback_color_emoji = -1
+ cobalt_font_package_override_fallback_emoji = -1
+ cobalt_font_package_override_fallback_symbols = -1
+
+ source_font_files_dir = "font_files"
+ copy_font_files = true
+}
+
+if (cobalt_font_package == "standard") {
+ declare_args() {
+ source_font_config_dir = "config/common"
+ package_named_sans_serif = 4
+ package_named_serif = 3
+ package_named_fcc_fonts = 2
+ package_fallback_lang_non_cjk = 2
+ package_fallback_lang_cjk = 1
+ package_fallback_lang_cjk_low_quality = 0
+ package_fallback_historic = 1
+ package_fallback_color_emoji = 1
+ package_fallback_emoji = 0
+ package_fallback_symbols = 1
+ }
+} else if (cobalt_font_package == "limited") {
+ declare_args() {
+ source_font_config_dir = "config/common"
+ package_named_sans_serif = 2
+ package_named_serif = 0
+ package_named_fcc_fonts = 0
+ package_fallback_lang_non_cjk = 1
+ package_fallback_lang_cjk = 0
+ package_fallback_lang_cjk_low_quality = 1
+ package_fallback_historic = 0
+ package_fallback_color_emoji = 0
+ package_fallback_emoji = 1
+ package_fallback_symbols = 1
+ }
+} else if (cobalt_font_package == "minimal") {
+ declare_args() {
+ source_font_config_dir = "config/common"
+ package_named_sans_serif = 0
+ package_named_serif = 0
+ package_named_fcc_fonts = 0
+ package_fallback_lang_non_cjk = 0
+ package_fallback_lang_cjk = 0
+ package_fallback_lang_cjk_low_quality = 0
+ package_fallback_historic = 0
+ package_fallback_color_emoji = 0
+ package_fallback_emoji = 0
+ package_fallback_symbols = 0
+ }
+} else if (cobalt_font_package == "empty") {
+ declare_args() {
+ source_font_config_dir = "config/empty"
+ package_named_sans_serif = 0
+ package_named_serif = 0
+ package_named_fcc_fonts = 0
+ package_fallback_lang_non_cjk = 0
+ package_fallback_lang_cjk = 0
+ package_fallback_lang_cjk_low_quality = 0
+ package_fallback_historic = 0
+ package_fallback_color_emoji = 0
+ package_fallback_emoji = 0
+ package_fallback_symbols = 0
+ }
+} else if (cobalt_font_package == "android_system") {
+ # fonts.xml contains a superset of what we expect to find on Android
+ # devices. The Android SbFile implementation falls back to system font
+ # files for those not in cobalt content.
+ declare_args() {
+ source_font_config_dir = "config/android"
+ package_named_sans_serif = 0
+ package_named_serif = 0
+ package_named_fcc_fonts = 0
+ package_fallback_lang_non_cjk = 0
+ package_fallback_lang_cjk = 0
+ package_fallback_lang_cjk_low_quality = 0
+ package_fallback_historic = 0
+ package_fallback_color_emoji = 0
+ package_fallback_emoji = 0
+ package_fallback_symbols = 0
+ }
+
+ # Don't copy font files for Android since it falls back to system
+ # font files for everything listed in fonts.xml.
+ copy_font_files = false
+}
+
+if (cobalt_font_package_override_named_sans_serif >= 0) {
+ package_named_sans_serif = cobalt_font_package_override_named_sans_serif
+}
+if (cobalt_font_package_override_named_serif >= 0) {
+ package_named_serif = cobalt_font_package_override_named_serif
+}
+if (cobalt_font_package_override_named_fcc_fonts >= 0) {
+ package_named_fcc_fonts = cobalt_font_package_override_named_fcc_fonts
+}
+if (cobalt_font_package_override_fallback_lang_non_cjk >= 0) {
+ package_fallback_lang_non_cjk =
+ cobalt_font_package_override_fallback_lang_non_cjk
+}
+if (cobalt_font_package_override_fallback_lang_cjk >= 0) {
+ package_fallback_lang_cjk = cobalt_font_package_override_fallback_lang_cjk
+}
+if (cobalt_font_package_override_fallback_lang_cjk_low_quality >= 0) {
+ package_fallback_lang_cjk_low_quality =
+ cobalt_font_package_override_fallback_lang_cjk_low_quality
+}
+if (cobalt_font_package_override_fallback_historic >= 0) {
+ package_fallback_historic = cobalt_font_package_override_fallback_historic
+}
+if (cobalt_font_package_override_fallback_color_emoji >= 0) {
+ package_fallback_color_emoji =
+ cobalt_font_package_override_fallback_color_emoji
+}
+if (cobalt_font_package_override_fallback_emoji >= 0) {
+ package_fallback_emoji = cobalt_font_package_override_fallback_emoji
+}
+if (cobalt_font_package_override_fallback_symbols >= 0) {
+ package_fallback_symbols = cobalt_font_package_override_fallback_symbols
+}
+
+package_categories = [
+ "sans-serif=${package_named_sans_serif}",
+ "serif=${package_named_serif}",
+ "fcc-captions=${package_named_fcc_fonts}",
+ "fallback-lang-non-cjk=${package_fallback_lang_non_cjk}",
+ "fallback-lang-cjk=${package_fallback_lang_cjk}",
+ "fallback-lang-cjk-low-quality=${package_fallback_lang_cjk_low_quality}",
+ "fallback-historic=${package_fallback_historic}",
+ "fallback-color-emoji=${package_fallback_color_emoji}",
+ "fallback-emoji=${package_fallback_emoji}",
+ "fallback-symbols=${package_fallback_symbols}",
+]
diff --git a/src/cobalt/debug/remote/devtools/copy_devtools_modules.rsp b/src/cobalt/debug/remote/devtools/copy_devtools_modules.rsp
new file mode 100644
index 0000000..39ad8b2
--- /dev/null
+++ b/src/cobalt/debug/remote/devtools/copy_devtools_modules.rsp
@@ -0,0 +1,476 @@
+front_end/network/network.js
+front_end/network/SignedExchangeInfoView.js
+front_end/network/ResourceWebSocketFrameView.js
+front_end/network/RequestTimingView.js
+front_end/network/RequestResponseView.js
+front_end/network/RequestPreviewView.js
+front_end/network/RequestInitiatorView.js
+front_end/network/RequestHeadersView.js
+front_end/network/RequestHTMLView.js
+front_end/network/RequestCookiesView.js
+front_end/network/NetworkWaterfallColumn.js
+front_end/network/NetworkTimeCalculator.js
+front_end/network/NetworkSearchScope.js
+front_end/network/NetworkPanel.js
+front_end/network/NetworkOverview.js
+front_end/network/NetworkManageCustomHeadersView.js
+front_end/network/NetworkLogViewColumns.js
+front_end/network/NetworkLogView.js
+front_end/network/NetworkItemView.js
+front_end/network/NetworkFrameGrouper.js
+front_end/network/NetworkDataGridNode.js
+front_end/network/NetworkConfigView.js
+front_end/network/HARWriter.js
+front_end/network/EventSourceMessagesView.js
+front_end/network/BlockedURLsPane.js
+front_end/network/BinaryResourceView.js
+front_end/test_runner/test_runner.js
+front_end/test_runner/TestRunner.js
+front_end/emulation/emulation.js
+front_end/emulation/SensorsView.js
+front_end/emulation/MediaQueryInspector.js
+front_end/emulation/InspectedPagePlaceholder.js
+front_end/emulation/GeolocationsSettingsTab.js
+front_end/emulation/EmulatedDevices.js
+front_end/emulation/DevicesSettingsTab.js
+front_end/emulation/DeviceModeWrapper.js
+front_end/emulation/DeviceModeView.js
+front_end/emulation/DeviceModeToolbar.js
+front_end/emulation/DeviceModeModel.js
+front_end/emulation/AdvancedApp.js
+front_end/inspector_main/inspector_main.js
+front_end/inspector_main/RenderingOptions.js
+front_end/inspector_main/InspectorMain.js
+front_end/js_main/js_main.js
+front_end/js_main/JsMain.js
+front_end/search/search.js
+front_end/search/SearchView.js
+front_end/search/SearchResultsPane.js
+front_end/search/SearchConfig.js
+front_end/screencast/screencast.js
+front_end/screencast/ScreencastView.js
+front_end/screencast/ScreencastApp.js
+front_end/screencast/InputModel.js
+front_end/performance_monitor/performance_monitor.js
+front_end/performance_monitor/PerformanceMonitor.js
+front_end/main/main.js
+front_end/main/SimpleApp.js
+front_end/main/MainImpl.js
+front_end/main/ExecutionContextSelector.js
+front_end/snippets/snippets.js
+front_end/snippets/SnippetsQuickOpen.js
+front_end/snippets/ScriptSnippetFileSystem.js
+front_end/settings/settings.js
+front_end/settings/SettingsScreen.js
+front_end/settings/FrameworkBlackboxSettingsTab.js
+front_end/security/security.js
+front_end/security/SecurityPanel.js
+front_end/security/SecurityModel.js
+front_end/javascript_metadata/javascript_metadata.js
+front_end/javascript_metadata/NativeFunctions.js
+front_end/javascript_metadata/JavaScriptMetadata.js
+front_end/har_importer/har_importer.js
+front_end/har_importer/HARImporter.js
+front_end/har_importer/HARFormat.js
+front_end/browser_debugger/browser_debugger.js
+front_end/browser_debugger/XHRBreakpointsSidebarPane.js
+front_end/browser_debugger/ObjectEventListenersSidebarPane.js
+front_end/browser_debugger/EventListenerBreakpointsSidebarPane.js
+front_end/browser_debugger/DOMBreakpointsSidebarPane.js
+front_end/layer_viewer/layer_viewer.js
+front_end/layer_viewer/TransformController.js
+front_end/layer_viewer/PaintProfilerView.js
+front_end/layer_viewer/Layers3DView.js
+front_end/layer_viewer/LayerViewHost.js
+front_end/layer_viewer/LayerTreeOutline.js
+front_end/layer_viewer/LayerDetailsView.js
+front_end/cm_web_modes/cm_web_modes.js
+front_end/cm_web_modes/cm_web_modes_cm.js
+front_end/cm_web_modes/cm_web_modes_headless.js
+front_end/cm_web_modes/css.js
+front_end/cm_web_modes/javascript.js
+front_end/cm_web_modes/xml.js
+front_end/cm_web_modes/htmlmixed.js
+front_end/cm_web_modes/htmlembedded.js
+front_end/text_editor/text_editor.js
+front_end/text_editor/TextEditorAutocompleteController.js
+front_end/text_editor/CodeMirrorUtils.js
+front_end/text_editor/CodeMirrorTextEditor.js
+front_end/quick_open/quick_open.js
+front_end/quick_open/QuickOpen.js
+front_end/quick_open/HelpQuickOpen.js
+front_end/quick_open/FilteredListWidget.js
+front_end/quick_open/CommandMenu.js
+front_end/elements/elements.js
+front_end/elements/elements-legacy.js
+front_end/elements/StylesSidebarPane.js
+front_end/elements/StylePropertyTreeElement.js
+front_end/elements/StylePropertyHighlighter.js
+front_end/elements/PropertiesWidget.js
+front_end/elements/PlatformFontsWidget.js
+front_end/elements/NodeStackTraceWidget.js
+front_end/elements/MetricsSidebarPane.js
+front_end/elements/MarkerDecorator.js
+front_end/elements/InspectElementModeController.js
+front_end/elements/EventListenersWidget.js
+front_end/elements/ElementsTreeOutline.js
+front_end/elements/ElementsTreeElement.js
+front_end/elements/ElementsTreeElementHighlighter.js
+front_end/elements/ElementStatePaneWidget.js
+front_end/elements/ElementsSidebarPane.js
+front_end/elements/ElementsPanel.js
+front_end/elements/ElementsBreadcrumbs.js
+front_end/elements/DOMPath.js
+front_end/elements/DOMLinkifier.js
+front_end/elements/ComputedStyleWidget.js
+front_end/elements/ComputedStyleModel.js
+front_end/elements/ColorSwatchPopoverIcon.js
+front_end/elements/ClassesPaneWidget.js
+front_end/timeline_model/timeline_model.js
+front_end/timeline_model/TracingLayerTree.js
+front_end/timeline_model/TimelineProfileTree.js
+front_end/timeline_model/TimelineModel.js
+front_end/timeline_model/TimelineModelFilter.js
+front_end/timeline_model/TimelineJSProfile.js
+front_end/timeline_model/TimelineIRModel.js
+front_end/timeline_model/TimelineFrameModel.js
+front_end/help/help.js
+front_end/help/ReleaseNoteView.js
+front_end/help/ReleaseNoteText.js
+front_end/help/HelpImpl.js
+front_end/workspace_diff/workspace_diff.js
+front_end/workspace_diff/WorkspaceDiff.js
+front_end/mobile_throttling/mobile_throttling.js
+front_end/mobile_throttling/ThrottlingSettingsTab.js
+front_end/mobile_throttling/ThrottlingPresets.js
+front_end/mobile_throttling/ThrottlingManager.js
+front_end/mobile_throttling/NetworkThrottlingSelector.js
+front_end/mobile_throttling/NetworkPanelIndicator.js
+front_end/mobile_throttling/MobileThrottlingSelector.js
+front_end/event_listeners/event_listeners.js
+front_end/event_listeners/EventListenersView.js
+front_end/event_listeners/EventListenersUtils.js
+front_end/object_ui/object_ui.js
+front_end/object_ui/RemoteObjectPreviewFormatter.js
+front_end/object_ui/ObjectPropertiesSection.js
+front_end/object_ui/ObjectPopoverHelper.js
+front_end/object_ui/JavaScriptREPL.js
+front_end/object_ui/JavaScriptAutocomplete.js
+front_end/object_ui/CustomPreviewComponent.js
+front_end/cookie_table/cookie_table.js
+front_end/cookie_table/CookiesTable.js
+front_end/cm_modes/cm_modes.js
+front_end/cm_modes/DefaultCodeMirrorMimeMode.js
+front_end/cm_modes/clike.js
+front_end/cm_modes/coffeescript.js
+front_end/cm_modes/php.js
+front_end/cm_modes/python.js
+front_end/cm_modes/shell.js
+front_end/cm_modes/livescript.js
+front_end/cm_modes/markdown.js
+front_end/cm_modes/clojure.js
+front_end/cm_modes/jsx.js
+front_end/css_overview/css_overview.js
+front_end/css_overview/CSSOverviewUnusedDeclarations.js
+front_end/css_overview/CSSOverviewStartView.js
+front_end/css_overview/CSSOverviewSidebarPanel.js
+front_end/css_overview/CSSOverviewProcessingView.js
+front_end/css_overview/CSSOverviewPanel.js
+front_end/css_overview/CSSOverviewModel.js
+front_end/css_overview/CSSOverviewController.js
+front_end/css_overview/CSSOverviewCompletedView.js
+front_end/console/console.js
+front_end/console/ConsoleContextSelector.js
+front_end/console/ConsoleFilter.js
+front_end/console/ConsoleSidebar.js
+front_end/console/ConsolePanel.js
+front_end/console/ConsolePinPane.js
+front_end/console/ConsolePrompt.js
+front_end/console/ConsoleView.js
+front_end/console/ConsoleViewMessage.js
+front_end/console/ConsoleViewport.js
+front_end/source_frame/source_frame.js
+front_end/source_frame/XMLView.js
+front_end/source_frame/SourcesTextEditor.js
+front_end/source_frame/SourceFrame.js
+front_end/source_frame/source_frame.js
+front_end/source_frame/SourceCodeDiff.js
+front_end/source_frame/ResourceSourceFrame.js
+front_end/source_frame/PreviewFactory.js
+front_end/source_frame/JSONView.js
+front_end/source_frame/ImageView.js
+front_end/source_frame/FontView.js
+front_end/source_frame/BinaryResourceViewFactory.js
+front_end/inline_editor/inline_editor.js
+front_end/inline_editor/SwatchPopoverHelper.js
+front_end/inline_editor/CSSShadowModel.js
+front_end/inline_editor/CSSShadowEditor.js
+front_end/inline_editor/ColorSwatch.js
+front_end/inline_editor/BezierUI.js
+front_end/inline_editor/BezierEditor.js
+front_end/diff/diff.js
+front_end/diff/diff_match_patch.js
+front_end/diff/DiffWrapper.js
+front_end/formatter/formatter.js
+front_end/formatter/ScriptFormatter.js
+front_end/formatter/FormatterWorkerPool.js
+front_end/color_picker/color_picker.js
+front_end/color_picker/Spectrum.js
+front_end/color_picker/ContrastOverlay.js
+front_end/color_picker/ContrastInfo.js
+front_end/color_picker/ContrastDetails.js
+front_end/cm/cm.js
+front_end/cm/active-line.js
+front_end/cm/brace-fold.js
+front_end/cm/closebrackets.js
+front_end/cm/codemirror.js
+front_end/cm/comment.js
+front_end/cm/foldcode.js
+front_end/cm/foldgutter.js
+front_end/cm/mark-selection.js
+front_end/cm/matchbrackets.js
+front_end/cm/multiplex.js
+front_end/cm/overlay.js
+front_end/formatter_worker.unbundled.js
+front_end/heap_snapshot_worker.unbundled.js
+front_end/heap_snapshot_model/heap_snapshot_model.js
+front_end/heap_snapshot_model/HeapSnapshotModel.js
+front_end/heap_snapshot_worker/heap_snapshot_worker.js
+front_end/heap_snapshot_worker/AllocationProfile.js
+front_end/heap_snapshot_worker/HeapSnapshot.js
+front_end/heap_snapshot_worker/HeapSnapshotLoader.js
+front_end/heap_snapshot_worker/HeapSnapshotWorker.js
+front_end/heap_snapshot_worker/HeapSnapshotWorkerDispatcher.js
+front_end/text_utils/text_utils.js
+front_end/text_utils/TextUtils.js
+front_end/text_utils/TextRange.js
+front_end/text_utils/Text.js
+front_end/formatter_worker/formatter_worker.js
+front_end/formatter_worker/RelaxedJSONParser.js
+front_end/formatter_worker/JavaScriptOutline.js
+front_end/formatter_worker/JavaScriptFormatter.js
+front_end/formatter_worker/IdentityFormatter.js
+front_end/formatter_worker/HTMLFormatter.js
+front_end/formatter_worker/FormatterWorker.js
+front_end/formatter_worker/FormattedContentBuilder.js
+front_end/formatter_worker/ESTreeWalker.js
+front_end/formatter_worker/CSSRuleParser.js
+front_end/formatter_worker/CSSFormatter.js
+front_end/formatter_worker/AcornTokenizer.js
+front_end/cm_headless/cm_headless.js
+front_end/cm_headless/headlesscodemirror.js
+front_end/data_grid/data_grid.js
+front_end/data_grid/ViewportDataGrid.js
+front_end/data_grid/SortableDataGrid.js
+front_end/data_grid/ShowMoreDataGridNode.js
+front_end/data_grid/DataGrid.js
+front_end/protocol_monitor/protocol_monitor.js
+front_end/protocol_monitor/ProtocolMonitor.js
+front_end/console_counters/console_counters.js
+front_end/console_counters/WarningErrorCounter.js
+front_end/extensions/extensions.js
+front_end/extensions/ExtensionAPI.js
+front_end/extensions/ExtensionPanel.js
+front_end/extensions/ExtensionServer.js
+front_end/extensions/ExtensionTraceProvider.js
+front_end/extensions/ExtensionView.js
+front_end/browser_sdk/browser_sdk.js
+front_end/browser_sdk/LogManager.js
+front_end/persistence/persistence.js
+front_end/persistence/WorkspaceSettingsTab.js
+front_end/persistence/PlatformFileSystem.js
+front_end/persistence/PersistenceUtils.js
+front_end/persistence/PersistenceImpl.js
+front_end/persistence/PersistenceActions.js
+front_end/persistence/NetworkPersistenceManager.js
+front_end/persistence/IsolatedFileSystemManager.js
+front_end/persistence/IsolatedFileSystem.js
+front_end/persistence/FileSystemWorkspaceBinding.js
+front_end/persistence/EditFileSystemView.js
+front_end/persistence/Automapping.js
+front_end/components/components.js
+front_end/components/TargetDetachedDialog.js
+front_end/components/Reload.js
+front_end/components/Linkifier.js
+front_end/components/JSPresentationUtils.js
+front_end/components/ImagePreview.js
+front_end/components/DockController.js
+front_end/bindings/bindings.js
+front_end/bindings/TempFile.js
+front_end/bindings/StylesSourceMapping.js
+front_end/bindings/SASSSourceMapping.js
+front_end/bindings/ResourceUtils.js
+front_end/bindings/ResourceScriptMapping.js
+front_end/bindings/ResourceMapping.js
+front_end/bindings/PresentationConsoleMessageHelper.js
+front_end/bindings/NetworkProject.js
+front_end/bindings/LiveLocation.js
+front_end/bindings/FileUtils.js
+front_end/bindings/DefaultScriptMapping.js
+front_end/bindings/DebuggerWorkspaceBinding.js
+front_end/bindings/CSSWorkspaceBinding.js
+front_end/bindings/ContentProviderBasedProject.js
+front_end/bindings/CompilerScriptMapping.js
+front_end/bindings/BreakpointManager.js
+front_end/bindings/BlackboxManager.js
+front_end/workspace/workspace.js
+front_end/workspace/WorkspaceImpl.js
+front_end/workspace/UISourceCode.js
+front_end/workspace/FileManager.js
+front_end/services/services.js
+front_end/services/ServiceManager.js
+front_end/sdk/sdk.js
+front_end/sdk/TracingModel.js
+front_end/sdk/TracingManager.js
+front_end/sdk/TargetManager.js
+front_end/sdk/Target.js
+front_end/sdk/SourceMapManager.js
+front_end/sdk/SourceMap.js
+front_end/sdk/ServiceWorkerManager.js
+front_end/sdk/ServiceWorkerCacheModel.js
+front_end/sdk/ServerTiming.js
+front_end/sdk/SecurityOriginManager.js
+front_end/sdk/SDKModel.js
+front_end/sdk/Script.js
+front_end/sdk/ScreenCaptureModel.js
+front_end/sdk/RuntimeModel.js
+front_end/sdk/ResourceTreeModel.js
+front_end/sdk/Resource.js
+front_end/sdk/RemoteObject.js
+front_end/sdk/ProfileTreeModel.js
+front_end/sdk/IssuesModel.js
+front_end/sdk/PerformanceMetricsModel.js
+front_end/sdk/PaintProfiler.js
+front_end/sdk/OverlayModel.js
+front_end/sdk/NetworkRequest.js
+front_end/sdk/NetworkManager.js
+front_end/sdk/NetworkLog.js
+front_end/sdk/LogModel.js
+front_end/sdk/LayerTreeBase.js
+front_end/sdk/IsolateManager.js
+front_end/sdk/HeapProfilerModel.js
+front_end/sdk/HARLog.js
+front_end/sdk/FilmStripModel.js
+front_end/sdk/EmulationModel.js
+front_end/sdk/DOMModel.js
+front_end/sdk/DOMDebuggerModel.js
+front_end/sdk/DebuggerModel.js
+front_end/sdk/CSSStyleSheetHeader.js
+front_end/sdk/CSSStyleDeclaration.js
+front_end/sdk/CSSRule.js
+front_end/sdk/CSSProperty.js
+front_end/sdk/CSSModel.js
+front_end/sdk/CSSMetadata.js
+front_end/sdk/CSSMedia.js
+front_end/sdk/CSSMatchedStyles.js
+front_end/sdk/CPUProfilerModel.js
+front_end/sdk/CPUProfileDataModel.js
+front_end/sdk/CookieParser.js
+front_end/sdk/CookieModel.js
+front_end/sdk/CompilerSourceMappingContentProvider.js
+front_end/sdk/ConsoleModel.js
+front_end/sdk/Connections.js
+front_end/sdk/ChildTargetManager.js
+front_end/protocol/protocol.js
+front_end/protocol/NodeURL.js
+front_end/protocol/InspectorBackend.js
+front_end/host/host.js
+front_end/host/UserMetrics.js
+front_end/host/ResourceLoader.js
+front_end/host/Platform.js
+front_end/host/InspectorFrontendHost.js
+front_end/host/InspectorFrontendHostAPI.js
+front_end/dom_extension/DOMExtension.js
+front_end/dom_extension/dom_extension.js
+front_end/root.js
+front_end/Runtime.js
+front_end/platform/utilities.js
+front_end/platform/platform.js
+front_end/ui/ARIAUtils.js
+front_end/ui/ZoomManager.js
+front_end/ui/XWidget.js
+front_end/ui/XLink.js
+front_end/ui/XElement.js
+front_end/ui/Widget.js
+front_end/ui/View.js
+front_end/ui/ViewManager.js
+front_end/ui/UIUtils.js
+front_end/ui/ui.js
+front_end/ui/Treeoutline.js
+front_end/ui/Tooltip.js
+front_end/ui/Toolbar.js
+front_end/ui/ThrottledWidget.js
+front_end/ui/TextPrompt.js
+front_end/ui/TextEditor.js
+front_end/ui/TargetCrashedScreen.js
+front_end/ui/TabbedPane.js
+front_end/ui/SyntaxHighlighter.js
+front_end/ui/SuggestBox.js
+front_end/ui/SplitWidget.js
+front_end/ui/SoftDropDown.js
+front_end/ui/SoftContextMenu.js
+front_end/ui/ShortcutsScreen.js
+front_end/ui/ShortcutRegistry.js
+front_end/ui/SettingsUI.js
+front_end/ui/SegmentedButton.js
+front_end/ui/SearchableView.js
+front_end/ui/RootView.js
+front_end/ui/ResizerWidget.js
+front_end/ui/ReportView.js
+front_end/ui/RemoteDebuggingTerminatedScreen.js
+front_end/ui/ProgressIndicator.js
+front_end/ui/PopoverHelper.js
+front_end/ui/Panel.js
+front_end/ui/ListWidget.js
+front_end/ui/ListModel.js
+front_end/ui/ListControl.js
+front_end/ui/KeyboardShortcut.js
+front_end/ui/InspectorView.js
+front_end/ui/InplaceEditor.js
+front_end/ui/Infobar.js
+front_end/ui/Icon.js
+front_end/ui/HistoryInput.js
+front_end/ui/GlassPane.js
+front_end/ui/Geometry.js
+front_end/ui/Fragment.js
+front_end/ui/ForwardedInputEventHandler.js
+front_end/ui/FilterSuggestionBuilder.js
+front_end/ui/FilterBar.js
+front_end/ui/EmptyWidget.js
+front_end/ui/DropTarget.js
+front_end/ui/Dialog.js
+front_end/ui/ContextMenu.js
+front_end/ui/Context.js
+front_end/ui/ARIAUtils.js
+front_end/ui/ActionRegistry.js
+front_end/ui/Action.js
+front_end/ui/ActionDelegate.js
+front_end/ui/ContextFlavorListener.js
+front_end/root.js
+front_end/common/common.js
+front_end/common/common-legacy.js
+front_end/common/App.js
+front_end/common/AppProvider.js
+front_end/common/CharacterIdMap.js
+front_end/common/Color.js
+front_end/common/ContentProvider.js
+front_end/common/EventTarget.js
+front_end/common/JavaScriptMetaData.js
+front_end/common/Linkifier.js
+front_end/common/Object.js
+front_end/common/Console.js
+front_end/common/ParsedURL.js
+front_end/common/Progress.js
+front_end/common/QueryParamHandler.js
+front_end/common/ResourceType.js
+front_end/common/Revealer.js
+front_end/common/Runnable.js
+front_end/common/SegmentedRange.js
+front_end/common/Settings.js
+front_end/common/StaticContentProvider.js
+front_end/common/StringOutputStream.js
+front_end/common/TextDictionary.js
+front_end/common/Throttler.js
+front_end/common/Trie.js
+front_end/common/UIString.js
+front_end/common/Worker.js
diff --git a/src/cobalt/dom/cobalt_ua_data_values.idl b/src/cobalt/dom/cobalt_ua_data_values.idl
index 000b238..2dea119 100644
--- a/src/cobalt/dom/cobalt_ua_data_values.idl
+++ b/src/cobalt/dom/cobalt_ua_data_values.idl
@@ -19,6 +19,7 @@
DOMString cobaltBuildConfiguration;
DOMString jsEngineVersion;
DOMString rasterizer;
+ DOMString evergreenType;
DOMString evergreenVersion;
DOMString starboardVersion;
DOMString originalDesignManufacturer;
diff --git a/src/cobalt/dom/cobalt_ua_data_values_interface.cc b/src/cobalt/dom/cobalt_ua_data_values_interface.cc
index a688cf8..586e086 100644
--- a/src/cobalt/dom/cobalt_ua_data_values_interface.cc
+++ b/src/cobalt/dom/cobalt_ua_data_values_interface.cc
@@ -58,6 +58,9 @@
if (init_dict.has_rasterizer()) {
rasterizer_ = init_dict.rasterizer();
}
+ if (init_dict.has_evergreen_type()) {
+ evergreen_type_ = init_dict.evergreen_type();
+ }
if (init_dict.has_evergreen_version()) {
evergreen_version_ = init_dict.evergreen_version();
}
diff --git a/src/cobalt/dom/cobalt_ua_data_values_interface.h b/src/cobalt/dom/cobalt_ua_data_values_interface.h
index e3ef570..cf0093b 100644
--- a/src/cobalt/dom/cobalt_ua_data_values_interface.h
+++ b/src/cobalt/dom/cobalt_ua_data_values_interface.h
@@ -43,6 +43,7 @@
}
const std::string& js_engine_version() const { return js_engine_version_; }
const std::string& rasterizer() const { return rasterizer_; }
+ const std::string& evergreen_type() const { return evergreen_type_; }
const std::string& evergreen_version() const { return evergreen_version_; }
const std::string& starboard_version() const { return starboard_version_; }
const std::string& original_design_manufacturer() const {
@@ -72,6 +73,7 @@
std::string cobalt_build_configuration_;
std::string js_engine_version_;
std::string rasterizer_;
+ std::string evergreen_type_;
std::string evergreen_version_;
std::string starboard_version_;
std::string original_design_manufacturer_;
diff --git a/src/cobalt/dom/cobalt_ua_data_values_interface.idl b/src/cobalt/dom/cobalt_ua_data_values_interface.idl
index 179ac91..ff1b119 100644
--- a/src/cobalt/dom/cobalt_ua_data_values_interface.idl
+++ b/src/cobalt/dom/cobalt_ua_data_values_interface.idl
@@ -29,6 +29,7 @@
readonly attribute DOMString cobaltBuildConfiguration;
readonly attribute DOMString jsEngineVersion;
readonly attribute DOMString rasterizer;
+ readonly attribute DOMString evergreenType;
readonly attribute DOMString evergreenVersion;
readonly attribute DOMString starboardVersion;
readonly attribute DOMString originalDesignManufacturer;
diff --git a/src/cobalt/dom/document__web_animations_api.idl b/src/cobalt/dom/document_web_animations_api.idl
similarity index 100%
rename from src/cobalt/dom/document__web_animations_api.idl
rename to src/cobalt/dom/document_web_animations_api.idl
diff --git a/src/cobalt/dom/html_link_element.cc b/src/cobalt/dom/html_link_element.cc
index 3e398c7..8e94b1b 100644
--- a/src/cobalt/dom/html_link_element.cc
+++ b/src/cobalt/dom/html_link_element.cc
@@ -254,6 +254,9 @@
void HTMLLinkElement::OnLoadingComplete(
const base::Optional<std::string>& error) {
+ // GetLoadTimingInfo and create resource timing before loader released.
+ GetLoadTimingInfoAndCreateResourceTiming();
+
base::MessageLoop::current()->task_runner()->PostTask(
FROM_HERE, base::Bind(&HTMLLinkElement::ReleaseLoader, this));
@@ -279,9 +282,6 @@
// complete.
node_document()->DecreaseLoadingCounterAndMaybeDispatchLoadEvent();
}
-
- // GetLoadTimingInfo and create resource timing before loader released.
- GetLoadTimingInfoAndCreateResourceTiming();
}
void HTMLLinkElement::OnSplashscreenLoaded(Document* document,
diff --git a/src/cobalt/dom/html_script_element.cc b/src/cobalt/dom/html_script_element.cc
index ad9386e..fe37061 100644
--- a/src/cobalt/dom/html_script_element.cc
+++ b/src/cobalt/dom/html_script_element.cc
@@ -555,6 +555,9 @@
// https://www.w3.org/TR/html50/scripting-1.html#prepare-a-script
void HTMLScriptElement::OnLoadingComplete(
const base::Optional<std::string>& error) {
+ // GetLoadTimingInfo and create resource timing before loader released.
+ GetLoadTimingInfoAndCreateResourceTiming();
+
if (!error) return;
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -596,9 +599,6 @@
// once the resource has been fetched (defined above) has been run.
document_->DecreaseLoadingCounterAndMaybeDispatchLoadEvent();
- // GetLoadTimingInfo and create resource timing before loader released.
- GetLoadTimingInfoAndCreateResourceTiming();
-
// Post a task to release the loader.
base::MessageLoop::current()->task_runner()->PostTask(
FROM_HERE, base::Bind(&HTMLScriptElement::ReleaseLoader, this));
diff --git a/src/cobalt/dom/navigator_ua_data.cc b/src/cobalt/dom/navigator_ua_data.cc
index 2d19869..73d9aed 100644
--- a/src/cobalt/dom/navigator_ua_data.cc
+++ b/src/cobalt/dom/navigator_ua_data.cc
@@ -57,6 +57,7 @@
all_high_entropy_values_.set_js_engine_version(
platform_info->javascript_engine_version());
all_high_entropy_values_.set_rasterizer(platform_info->rasterizer_type());
+ all_high_entropy_values_.set_evergreen_type(platform_info->evergreen_type());
all_high_entropy_values_.set_evergreen_version(
platform_info->evergreen_version());
all_high_entropy_values_.set_starboard_version(
@@ -118,6 +119,9 @@
} else if ((*it).compare("rasterizer") == 0) {
select_high_entropy_values_.set_rasterizer(
all_high_entropy_values_.rasterizer());
+ } else if ((*it).compare("evergreenType") == 0) {
+ select_high_entropy_values_.set_evergreen_type(
+ all_high_entropy_values_.evergreen_type());
} else if ((*it).compare("evergreenVersion") == 0) {
select_high_entropy_values_.set_evergreen_version(
all_high_entropy_values_.evergreen_version());
diff --git a/src/cobalt/dom/performance.cc b/src/cobalt/dom/performance.cc
index a90c2e8..7554005 100644
--- a/src/cobalt/dom/performance.cc
+++ b/src/cobalt/dom/performance.cc
@@ -31,7 +31,7 @@
namespace {
base::TimeDelta GetUnixAtZeroMonotonic(const base::Clock* clock,
- const base::TickClock* tick_clock) {
+ const base::TickClock* tick_clock) {
base::TimeDelta unix_time_now = clock->Now() - base::Time::UnixEpoch();
base::TimeDelta time_since_origin = tick_clock->NowTicks().since_origin();
return unix_time_now - time_since_origin;
@@ -622,5 +622,9 @@
is_preload, timestamp);
}
+void Performance::SetDeepLinkTimestamp(SbTimeMonotonic timestamp) {
+ lifecycle_timing_->SetDeepLinkTimestamp(timestamp);
+}
+
} // namespace dom
} // namespace cobalt
diff --git a/src/cobalt/dom/performance.h b/src/cobalt/dom/performance.h
index 753123d..d48c7ea 100644
--- a/src/cobalt/dom/performance.h
+++ b/src/cobalt/dom/performance.h
@@ -138,6 +138,8 @@
void SetApplicationStartOrPreloadTimestamp(
bool is_preload, SbTimeMonotonic timestamp);
+ void SetDeepLinkTimestamp(SbTimeMonotonic timestamp);
+
void TraceMembers(script::Tracer* tracer) override;
DEFINE_WRAPPABLE_TYPE(Performance);
diff --git a/src/cobalt/dom/performance_lifecycle_timing.cc b/src/cobalt/dom/performance_lifecycle_timing.cc
index bb2e21b..08f47d4 100644
--- a/src/cobalt/dom/performance_lifecycle_timing.cc
+++ b/src/cobalt/dom/performance_lifecycle_timing.cc
@@ -40,11 +40,13 @@
return "INVALID_APPLICATION_STATE";
}
- DOMHighResTimeStamp ConvertSbTimeMonotonicToDOMHiResTimeStamp(
+ DOMHighResTimeStamp ConvertSbTimeMonotonicToDOMHiResTimeStamp(
base::TimeTicks time_origin, SbTimeMonotonic monotonic_time) {
SbTimeMonotonic time_delta = SbTimeGetNow() - SbTimeGetMonotonicNow();
+ base::Time base_time = base::Time::FromSbTime(time_delta + monotonic_time);
base::TimeTicks time_ticks =
- base::TimeTicks::FromInternalValue(time_delta + monotonic_time);
+ base::TimeTicks::FromInternalValue(static_cast<int64_t>(
+ base_time.ToJsTime()));
return Performance::MonotonicTimeToDOMHighResTimeStamp(
time_origin, time_ticks);
}
@@ -88,6 +90,10 @@
return ReportDOMHighResTimeStamp(lifecycle_timing_info_.app_unfreeze);
}
+DOMHighResTimeStamp PerformanceLifecycleTiming::app_deeplink() const {
+ return ReportDOMHighResTimeStamp(lifecycle_timing_info_.app_deeplink);
+}
+
std::string PerformanceLifecycleTiming::current_state() const {
return TranslateApplicationStateToString(
lifecycle_timing_info_.current_state);
@@ -102,24 +108,40 @@
base::ApplicationState state, SbTimeMonotonic timestamp) {
switch (state) {
case base::kApplicationStateBlurred:
- if (GetLastState() == base::kApplicationStateStarted) {
+ if (GetCurrentState() == base::kApplicationStateStarted ||
+ // TODO: Figure out why the current state is not set
+ // by SetApplicationStartOrPreloadTimestamp.
+ GetCurrentState() == base::kApplicationStateStopped) {
lifecycle_timing_info_.app_blur = timestamp;
- } else if (GetLastState() == base::kApplicationStateConcealed) {
+ } else if (GetCurrentState() == base::kApplicationStateConcealed) {
lifecycle_timing_info_.app_reveal = timestamp;
+ } else {
+ DLOG(INFO) << "Current State: " <<
+ TranslateApplicationStateToString(GetCurrentState());
+ DLOG(INFO) << "Next State: " <<
+ TranslateApplicationStateToString(state);
+ NOTREACHED() << "Invalid application state transition.";
}
break;
case base::kApplicationStateConcealed:
- if (GetLastState() == base::kApplicationStateBlurred) {
+ if (GetCurrentState() == base::kApplicationStateBlurred ||
+ GetCurrentState() == base::kApplicationStateStopped) {
lifecycle_timing_info_.app_conceal = timestamp;
- } else if (GetLastState() == base::kApplicationStateFrozen) {
+ } else if (GetCurrentState() == base::kApplicationStateFrozen) {
lifecycle_timing_info_.app_unfreeze = timestamp;
+ } else {
+ DLOG(INFO) << "Current State: " <<
+ TranslateApplicationStateToString(GetCurrentState());
+ DLOG(INFO) << "Next State: " <<
+ TranslateApplicationStateToString(state);
+ NOTREACHED() << "Invalid application state transition.";
}
break;
case base::kApplicationStateFrozen:
lifecycle_timing_info_.app_freeze = timestamp;
break;
case base::kApplicationStateStarted:
- if (GetLastState() == base::kApplicationStateBlurred) {
+ if (GetCurrentState() == base::kApplicationStateBlurred) {
if (lifecycle_timing_info_.app_preload != 0) {
lifecycle_timing_info_.app_start = timestamp;
}
@@ -137,7 +159,7 @@
}
void PerformanceLifecycleTiming::SetApplicationStartOrPreloadTimestamp(
- bool is_preload, SbTimeMonotonic timestamp) {
+ bool is_preload, SbTimeMonotonic timestamp) {
if (is_preload) {
lifecycle_timing_info_.app_preload = timestamp;
SetLifecycleTimingInfoState(base::kApplicationStateConcealed);
@@ -147,8 +169,13 @@
}
}
-base::ApplicationState PerformanceLifecycleTiming::GetLastState() const {
- return lifecycle_timing_info_.last_state;
+void PerformanceLifecycleTiming::SetDeepLinkTimestamp(
+ SbTimeMonotonic timestamp) {
+ lifecycle_timing_info_.app_deeplink = timestamp;
+}
+
+base::ApplicationState PerformanceLifecycleTiming::GetCurrentState() const {
+ return lifecycle_timing_info_.current_state;
}
void PerformanceLifecycleTiming::SetLifecycleTimingInfoState(
@@ -158,12 +185,11 @@
lifecycle_timing_info_.current_state = state;
}
-DOMHighResTimeStamp
- PerformanceLifecycleTiming::ReportDOMHighResTimeStamp(
- SbTimeMonotonic timestamp) const {
+DOMHighResTimeStamp PerformanceLifecycleTiming::ReportDOMHighResTimeStamp(
+ SbTimeMonotonic timestamp) const {
if (timestamp != 0) {
- return ConvertSbTimeMonotonicToDOMHiResTimeStamp(
- time_origin_, timestamp);
+ return ConvertSbTimeMonotonicToDOMHiResTimeStamp(time_origin_,
+ timestamp);
}
return PerformanceEntry::start_time();
}
diff --git a/src/cobalt/dom/performance_lifecycle_timing.h b/src/cobalt/dom/performance_lifecycle_timing.h
index 42fc320..9baa10c 100644
--- a/src/cobalt/dom/performance_lifecycle_timing.h
+++ b/src/cobalt/dom/performance_lifecycle_timing.h
@@ -42,6 +42,7 @@
DOMHighResTimeStamp app_reveal() const;
DOMHighResTimeStamp app_freeze() const;
DOMHighResTimeStamp app_unfreeze() const;
+ DOMHighResTimeStamp app_deeplink() const;
std::string current_state() const;
std::string last_state() const;
@@ -54,6 +55,7 @@
SbTimeMonotonic timestamp);
void SetApplicationStartOrPreloadTimestamp(
bool is_preload, SbTimeMonotonic timestamp);
+ void SetDeepLinkTimestamp(SbTimeMonotonic timestamp);
DEFINE_WRAPPABLE_TYPE(PerformanceLifecycleTiming);
@@ -61,7 +63,7 @@
void SetLifecycleTimingInfoState(base::ApplicationState state);
DOMHighResTimeStamp ReportDOMHighResTimeStamp(
SbTimeMonotonic timestamp) const;
- base::ApplicationState GetLastState() const;
+ base::ApplicationState GetCurrentState() const;
struct LifecycleTimingInfo {
SbTimeMonotonic app_preload = 0;
SbTimeMonotonic app_start = 0;
@@ -71,6 +73,7 @@
SbTimeMonotonic app_reveal = 0;
SbTimeMonotonic app_freeze = 0;
SbTimeMonotonic app_unfreeze = 0;
+ SbTimeMonotonic app_deeplink = 0;
base::ApplicationState current_state =
base::kApplicationStateStopped;
diff --git a/src/cobalt/dom/performance_lifecycle_timing.idl b/src/cobalt/dom/performance_lifecycle_timing.idl
index 7d14eb8..8dd56fb 100644
--- a/src/cobalt/dom/performance_lifecycle_timing.idl
+++ b/src/cobalt/dom/performance_lifecycle_timing.idl
@@ -22,6 +22,7 @@
readonly attribute DOMHighResTimeStamp appReveal;
readonly attribute DOMHighResTimeStamp appFreeze;
readonly attribute DOMHighResTimeStamp appUnfreeze;
+ readonly attribute DOMHighResTimeStamp appDeeplink;
readonly attribute DOMString currentState;
readonly attribute DOMString lastState;
};
diff --git a/src/cobalt/dom/user_agent_platform_info.h b/src/cobalt/dom/user_agent_platform_info.h
index a63c8a5..2b288b5 100644
--- a/src/cobalt/dom/user_agent_platform_info.h
+++ b/src/cobalt/dom/user_agent_platform_info.h
@@ -44,6 +44,7 @@
virtual const std::string& connection_type_string() const = 0;
virtual const std::string& javascript_engine_version() const = 0;
virtual const std::string& rasterizer_type() const = 0;
+ virtual const std::string& evergreen_type() const = 0;
virtual const std::string& evergreen_version() const = 0;
virtual const std::string& cobalt_version() const = 0;
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index a3bee80..52fe0bb 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -538,6 +538,7 @@
SbTimeMonotonic timestamp) {
html_element_context_->application_lifecycle_state()->SetApplicationState(
state);
+ if (timestamp == 0) return;
performance_->SetApplicationState(state, timestamp);
}
diff --git a/src/cobalt/dom/window.idl b/src/cobalt/dom/window.idl
index 2173dd9..711559d 100644
--- a/src/cobalt/dom/window.idl
+++ b/src/cobalt/dom/window.idl
@@ -15,7 +15,7 @@
// https://www.w3.org/TR/html50/browsers.html#the-window-object
// Note: Cobalt only supports one browsing context and one Window object.
-[PrimaryGlobal]
+[Global]
/*sealed*/ interface Window : EventTarget {
// the current browsing context
[Unforgeable] readonly attribute Window window;
@@ -52,4 +52,3 @@
};
Window implements GlobalEventHandlers;
Window implements WindowEventHandlers;
-
diff --git a/src/cobalt/dom/window__animation_timing.idl b/src/cobalt/dom/window_animation_timing.idl
similarity index 100%
rename from src/cobalt/dom/window__animation_timing.idl
rename to src/cobalt/dom/window_animation_timing.idl
diff --git a/src/cobalt/dom/window__performance.idl b/src/cobalt/dom/window_performance.idl
similarity index 90%
rename from src/cobalt/dom/window__performance.idl
rename to src/cobalt/dom/window_performance.idl
index 0e6b71e..0eda289 100644
--- a/src/cobalt/dom/window__performance.idl
+++ b/src/cobalt/dom/window_performance.idl
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// https://www.w3.org/TR/navigation-timing/#performance
+// https://www.w3.org/TR/2012/REC-navigation-timing-20121217/#performance
partial interface Window {
readonly attribute Performance performance;
diff --git a/src/cobalt/loader/image/image_decoder.cc b/src/cobalt/loader/image/image_decoder.cc
index a499c63..68782a3 100644
--- a/src/cobalt/loader/image/image_decoder.cc
+++ b/src/cobalt/loader/image/image_decoder.cc
@@ -54,25 +54,6 @@
result->append(message);
}
-// Determine the ImageType of an image from its signature.
-ImageDecoder::ImageType DetermineImageType(const uint8* header) {
- if (!memcmp(header, "\xFF\xD8\xFF", 3)) {
- return ImageDecoder::kImageTypeJPEG;
- } else if (!memcmp(header, "GIF87a", 6) || !memcmp(header, "GIF89a", 6)) {
- return ImageDecoder::kImageTypeGIF;
- } else if (!memcmp(header, "{", 1)) {
- // TODO: Improve heuristics for determining whether the file contains valid
- // Lottie JSON.
- return ImageDecoder::kImageTypeJSON;
- } else if (!memcmp(header, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8)) {
- return ImageDecoder::kImageTypePNG;
- } else if (!memcmp(header, "RIFF", 4) && !memcmp(header + 8, "WEBPVP", 6)) {
- return ImageDecoder::kImageTypeWebP;
- } else {
- return ImageDecoder::kImageTypeInvalid;
- }
-}
-
// Returns true if the ResourceProvider is ResourceProviderStub.
bool IsResourceProviderStub(render_tree::ResourceProvider* resource_provider) {
return resource_provider->GetTypeId() ==
@@ -81,6 +62,39 @@
} // namespace
+// Determine the ImageType of an image from its signature.
+ImageDecoder::ImageType DetermineImageType(const uint8* header) {
+ if (!memcmp(header, "\xFF\xD8\xFF", 3)) {
+ return ImageDecoder::kImageTypeJPEG;
+ } else if (!memcmp(header, "GIF87a", 6) || !memcmp(header, "GIF89a", 6)) {
+ return ImageDecoder::kImageTypeGIF;
+ } else if (!memcmp(header, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8)) {
+ return ImageDecoder::kImageTypePNG;
+ } else if (!memcmp(header, "RIFF", 4) && !memcmp(header + 8, "WEBPVP", 6)) {
+ return ImageDecoder::kImageTypeWebP;
+ } else {
+ const std::string header_str = reinterpret_cast<const char*>(header);
+ std::string::size_type first_non_white_space_pos =
+ header_str.find_first_not_of(" \t\r\n");
+ if (first_non_white_space_pos + 1 < header_str.size()) {
+ if (header_str[first_non_white_space_pos] == '{' ||
+ header_str[first_non_white_space_pos] ==
+ '[') { // json can start with either object hash or an array
+ std::string::size_type second_non_white_space_pos =
+ header_str.find_first_not_of(" \t\r\n",
+ first_non_white_space_pos + 1);
+ if (second_non_white_space_pos + 1 < header_str.size()) {
+ if (header_str[second_non_white_space_pos] == '"' &&
+ isalnum(header_str[second_non_white_space_pos + 1])) {
+ return ImageDecoder::kImageTypeJSON;
+ }
+ }
+ }
+ }
+ return ImageDecoder::kImageTypeInvalid;
+ }
+}
+
ImageDecoder::ImageDecoder(
render_tree::ResourceProvider* resource_provider,
const base::DebuggerHooks& debugger_hooks,
diff --git a/src/cobalt/loader/image/image_decoder.h b/src/cobalt/loader/image/image_decoder.h
index cb80ce6..89b4d6b 100644
--- a/src/cobalt/loader/image/image_decoder.h
+++ b/src/cobalt/loader/image/image_decoder.h
@@ -122,6 +122,8 @@
bool use_failure_image_decoder_ = false;
};
+ImageDecoder::ImageType DetermineImageType(const uint8* header);
+
} // namespace image
} // namespace loader
} // namespace cobalt
diff --git a/src/cobalt/loader/image/image_decoder_unit_test.cc b/src/cobalt/loader/image/image_decoder_unit_test.cc
new file mode 100644
index 0000000..a6dfc5d
--- /dev/null
+++ b/src/cobalt/loader/image/image_decoder_unit_test.cc
@@ -0,0 +1,68 @@
+// Copyright 2021 The Cobalt Authors. 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/loader/image/image_decoder.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cobalt {
+namespace loader {
+namespace image {
+
+TEST(ImageDecoderUnitTest, ValidImageType) {
+ EXPECT_EQ(DetermineImageType(reinterpret_cast<const uint8*>("\xFF\xD8\xFF")),
+ ImageDecoder::kImageTypeJPEG);
+ EXPECT_EQ(DetermineImageType(reinterpret_cast<const uint8*>("GIF87a")),
+ ImageDecoder::kImageTypeGIF);
+ EXPECT_EQ(DetermineImageType(reinterpret_cast<const uint8*>("GIF89a")),
+ ImageDecoder::kImageTypeGIF);
+ EXPECT_EQ(DetermineImageType(reinterpret_cast<const uint8*>(
+ "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")),
+ ImageDecoder::kImageTypePNG);
+ EXPECT_EQ(
+ DetermineImageType(reinterpret_cast<const uint8*>("RIFF WEBPVP")),
+ ImageDecoder::kImageTypeWebP);
+ EXPECT_EQ(
+ DetermineImageType(reinterpret_cast<const uint8*>("{\"v\":\"4.6.8\"")),
+ ImageDecoder::kImageTypeJSON);
+ EXPECT_EQ(DetermineImageType(
+ reinterpret_cast<const uint8*>(" {\t\"v\":\"4.6.8\"")),
+ ImageDecoder::kImageTypeJSON);
+ EXPECT_EQ(DetermineImageType(
+ reinterpret_cast<const uint8*>("\r [ \"v\":\"4.6.8\"")),
+ ImageDecoder::kImageTypeJSON);
+}
+
+TEST(ImageDecoderUnitTest, InvalidImageType) {
+ EXPECT_EQ(DetermineImageType(reinterpret_cast<const uint8*>(
+ "\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01"
+ "\x00")),
+ ImageDecoder::kImageTypeInvalid);
+ EXPECT_EQ(
+ DetermineImageType(reinterpret_cast<const uint8*>("{}\0\0\0\0\0\0")),
+ ImageDecoder::kImageTypeInvalid);
+ EXPECT_EQ(
+ DetermineImageType(reinterpret_cast<const uint8*>("{a\0\0\0\0\0\0")),
+ ImageDecoder::kImageTypeInvalid);
+ EXPECT_EQ(
+ DetermineImageType(reinterpret_cast<const uint8*>("{\"\"\0\0\0\0\0")),
+ ImageDecoder::kImageTypeInvalid);
+ EXPECT_EQ(
+ DetermineImageType(reinterpret_cast<const uint8*>("{\"{\0\0\0\0\0")),
+ ImageDecoder::kImageTypeInvalid);
+}
+
+} // namespace image
+} // namespace loader
+} // namespace cobalt
diff --git a/src/cobalt/loader/loader.gyp b/src/cobalt/loader/loader.gyp
index 3a213f3..b4f2551 100644
--- a/src/cobalt/loader/loader.gyp
+++ b/src/cobalt/loader/loader.gyp
@@ -114,7 +114,7 @@
'<(DEPTH)/third_party/libjpeg/libjpeg.gyp:libjpeg',
'<(DEPTH)/third_party/libpng/libpng.gyp:libpng',
'<(DEPTH)/third_party/libwebp/libwebp.gyp:libwebp',
- 'embed_resources_as_header_files',
+ 'embed_resources_as_header_files_loader',
],
'conditions': [
['cobalt_config != "gold"', {
@@ -142,6 +142,7 @@
'file_fetcher_test.cc',
'font/typeface_decoder_test.cc',
'image/image_decoder_test.cc',
+ 'image/image_decoder_unit_test.cc',
'mesh/mesh_decoder_test.cc',
'loader_test.cc',
'text_decoder_test.cc',
@@ -187,7 +188,7 @@
# This target takes all files in the embedded_resources directory (e.g.
# the splash screen) and embeds them as header files for
# inclusion into the binary.
- 'target_name': 'embed_resources_as_header_files',
+ 'target_name': 'embed_resources_as_header_files_loader',
'type': 'none',
# Because we generate a header, we must set the hard_dependency flag.
'hard_dependency': 1,
@@ -211,7 +212,7 @@
],
'actions': [
{
- 'action_name': 'embed_resources_as_header_files',
+ 'action_name': 'embed_resources_as_header_files_loader',
'inputs': [
'<(script_path)',
'<@(_sources)',
diff --git a/src/cobalt/media/base/playback_statistics.cc b/src/cobalt/media/base/playback_statistics.cc
index 2c797c8..2aca335 100644
--- a/src/cobalt/media/base/playback_statistics.cc
+++ b/src/cobalt/media/base/playback_statistics.cc
@@ -14,6 +14,9 @@
#include "cobalt/media/base/playback_statistics.h"
+#include <math.h>
+#include <stdint.h>
+
#include "base/strings/stringprintf.h"
#include "starboard/atomic.h"
#include "starboard/common/string.h"
@@ -34,14 +37,12 @@
volatile SbAtomic32 s_max_video_height = 0;
volatile SbAtomic32 s_last_working_codec = kUnknownVideoCodec;
-int RoundValues(SbAtomic32 value) {
+int64_t RoundValues(int64_t value) {
if (value < 10) {
return value;
}
- if (value < 100) {
- return value / 10 * 10;
- }
- return value / 100 * 100;
+ int64_t closest_power = pow(10, floor(log10(value)));
+ return floor(value / closest_power) * closest_power;
}
void UpdateMaxValue(SbAtomic32 new_value, volatile SbAtomic32* max) {
@@ -210,15 +211,13 @@
std::string PlaybackStatistics::GetStatistics(
const VideoDecoderConfig& current_video_config) const {
return starboard::FormatString(
- "current_codec: %s, drm: %s, width: %d, height: %d,"
- " active_players (max): %d (%d), av1: ~%d, h264: ~%d, hevc: ~%d,"
- " vp9: ~%d, min_width: %d, min_height: %d, max_width: %d, max_height: %d,"
- " last_working_codec: %s,"
- " seek_time: %s,"
- " first_audio_time: %s,"
- " first_video_time: %s,"
- " last_audio_time: %s,"
- " last_video_time: %s",
+ "current_codec: %s, drm: %s, width: %d, height: %d"
+ ", active_players (max): %d (%d), av1: ~%" PRId64 ", h264: ~%" PRId64
+ ", hevc: ~%" PRId64 ", vp9: ~%" PRId64
+ ", min_width: %d, min_height: %d, max_width: %d, max_height: %d"
+ ", last_working_codec: %s, seek_time: %s"
+ ", first_audio_time: ~%" PRId64 ", first_video_time: ~%" PRId64
+ ", last_audio_time: ~%" PRId64 ", last_video_time: ~%" PRId64,
GetCodecName(current_video_config.codec()).c_str(),
(current_video_config.is_encrypted() ? "Y" : "N"), video_width_.value(),
video_height_.value(), SbAtomicNoBarrier_Load(&s_active_instances),
@@ -236,17 +235,17 @@
.c_str(),
ValToString(seek_time_).c_str(),
is_first_audio_buffer_written_
- ? ValToString(last_written_audio_timestamp_).c_str()
- : "n/a",
+ ? RoundValues(first_written_audio_timestamp_.value().InSeconds())
+ : -1,
is_first_video_buffer_written_
- ? ValToString(first_written_audio_timestamp_).c_str()
- : "n/a",
+ ? RoundValues(first_written_video_timestamp_.value().InSeconds())
+ : -1,
is_first_audio_buffer_written_
- ? ValToString(last_written_audio_timestamp_).c_str()
- : "n/a",
+ ? RoundValues(last_written_audio_timestamp_.value().InSeconds())
+ : -1,
is_first_video_buffer_written_
- ? ValToString(last_written_video_timestamp_).c_str()
- : "n/a");
+ ? RoundValues(last_written_video_timestamp_.value().InSeconds())
+ : -1);
}
} // namespace media
diff --git a/src/cobalt/media/base/sbplayer_pipeline.cc b/src/cobalt/media/base/sbplayer_pipeline.cc
index aefa84b..baebdee 100644
--- a/src/cobalt/media/base/sbplayer_pipeline.cc
+++ b/src/cobalt/media/base/sbplayer_pipeline.cc
@@ -57,6 +57,8 @@
static const int kRetryDelayAtSuspendInMilliseconds = 100;
+unsigned int g_pipeline_identifier_counter = 0;
+
// Used to post parameters to SbPlayerPipeline::StartTask() as the number of
// parameters exceed what base::Bind() can support.
struct StartTaskParameters {
@@ -325,7 +327,8 @@
get_decode_target_graphics_context_provider_func,
bool allow_resume_after_suspend, MediaLog* media_log,
VideoFrameProvider* video_frame_provider)
- : pipeline_identifier_(base::StringPrintf("%p", this)),
+ : pipeline_identifier_(base::StringPrintf("%X",
+ g_pipeline_identifier_counter++)),
task_runner_(task_runner),
allow_resume_after_suspend_(allow_resume_after_suspend),
window_(window),
@@ -909,11 +912,15 @@
task_runner_, source_url, window_, this, set_bounds_helper_.get(),
allow_resume_after_suspend_, *decode_to_texture_output_mode_,
on_encrypted_media_init_data_encountered_cb_, video_frame_provider_));
- SetPlaybackRateTask(playback_rate_);
- SetVolumeTask(volume_);
+ if (player_->IsValid()) {
+ SetPlaybackRateTask(playback_rate_);
+ SetVolumeTask(volume_);
+ } else {
+ player_.reset();
+ }
}
- if (player_->IsValid()) {
+ if (player_ && player_->IsValid()) {
base::Closure output_mode_change_cb;
{
base::AutoLock auto_lock(lock_);
@@ -924,7 +931,6 @@
return;
}
- player_.reset();
CallSeekCB(DECODER_ERROR_NOT_SUPPORTED,
"SbPlayerPipeline::CreateUrlPlayer failed: "
"player_->IsValid() is false.");
@@ -997,33 +1003,35 @@
set_bounds_helper_.get(), allow_resume_after_suspend_,
*decode_to_texture_output_mode_, video_frame_provider_,
max_video_capabilities_));
-
- if (!player_->IsValid()) {
+ if (player_->IsValid()) {
+ SetPlaybackRateTask(playback_rate_);
+ SetVolumeTask(volume_);
+ } else {
player_.reset();
- CallErrorCB(DECODER_ERROR_NOT_SUPPORTED,
- "SbPlayerPipeline::CreatePlayer failed: "
- "player_->IsValid() is false.");
- return;
}
-
- SetPlaybackRateTask(playback_rate_);
- SetVolumeTask(volume_);
}
- base::Closure output_mode_change_cb;
- {
- base::AutoLock auto_lock(lock_);
- DCHECK(!output_mode_change_cb_.is_null());
- output_mode_change_cb = std::move(output_mode_change_cb_);
- }
- output_mode_change_cb.Run();
+ if (player_ && player_->IsValid()) {
+ base::Closure output_mode_change_cb;
+ {
+ base::AutoLock auto_lock(lock_);
+ DCHECK(!output_mode_change_cb_.is_null());
+ output_mode_change_cb = std::move(output_mode_change_cb_);
+ }
+ output_mode_change_cb.Run();
- if (audio_stream_) {
- UpdateDecoderConfig(audio_stream_);
+ if (audio_stream_) {
+ UpdateDecoderConfig(audio_stream_);
+ }
+ if (video_stream_) {
+ UpdateDecoderConfig(video_stream_);
+ }
+ return;
}
- if (video_stream_) {
- UpdateDecoderConfig(video_stream_);
- }
+
+ CallSeekCB(DECODER_ERROR_NOT_SUPPORTED,
+ "SbPlayerPipeline::CreatePlayer failed: "
+ "player_->IsValid() is false.");
}
void SbPlayerPipeline::OnDemuxerInitialized(PipelineStatus status) {
@@ -1426,7 +1434,12 @@
if (player_) {
player_->Resume(window);
if (!player_->IsValid()) {
- player_.reset();
+ {
+ base::AutoLock auto_lock(lock_);
+ player_.reset();
+ }
+ // TODO: Determine if CallSeekCB() may be used here, as |seek_cb_| may be
+ // available if the app is suspended before a seek is completed.
CallErrorCB(DECODER_ERROR_NOT_SUPPORTED,
"SbPlayerPipeline::ResumeTask failed: "
"player_->IsValid() is false.");
diff --git a/src/cobalt/media/player/web_media_player_impl.cc b/src/cobalt/media/player/web_media_player_impl.cc
index 480d7e8..050af74 100644
--- a/src/cobalt/media/player/web_media_player_impl.cc
+++ b/src/cobalt/media/player/web_media_player_impl.cc
@@ -231,7 +231,7 @@
UMA_HISTOGRAM_ENUMERATION("Media.URLScheme", URLScheme(url), kMaxURLScheme);
DLOG(INFO) << "Start URL playback";
- // Handle any volume changes that occured before load().
+ // Handle any volume changes that occurred before load().
SetVolume(GetClient()->Volume());
// TODO: Set networkState to WebMediaPlayer::kNetworkStateIdle on stop.
@@ -251,7 +251,7 @@
DLOG(INFO) << "Start MEDIASOURCE playback";
- // Handle any volume changes that occured before load().
+ // Handle any volume changes that occurred before load().
SetVolume(GetClient()->Volume());
SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
@@ -278,7 +278,7 @@
UMA_HISTOGRAM_ENUMERATION("Media.URLScheme", URLScheme(url), kMaxURLScheme);
DLOG(INFO) << "Start PROGRESSIVE playback";
- // Handle any volume changes that occured before load().
+ // Handle any volume changes that occurred before load().
SetVolume(GetClient()->Volume());
SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
@@ -307,9 +307,6 @@
TRACE_EVENT0("cobalt::media", "WebMediaPlayerImpl::Play");
DCHECK_EQ(main_loop_, base::MessageLoop::current());
-#if defined(__LB_ANDROID__)
- audio_focus_bridge_.RequestAudioFocus();
-#endif // defined(__LB_ANDROID__)
state_.paused = false;
pipeline_->SetPlaybackRate(state_.playback_rate);
@@ -319,9 +316,6 @@
void WebMediaPlayerImpl::Pause() {
DCHECK_EQ(main_loop_, base::MessageLoop::current());
-#if defined(__LB_ANDROID__)
- audio_focus_bridge_.AbandonAudioFocus();
-#endif // defined(__LB_ANDROID__)
state_.paused = true;
pipeline_->SetPlaybackRate(0.0f);
diff --git a/src/cobalt/media/player/web_media_player_impl.h b/src/cobalt/media/player/web_media_player_impl.h
index 9056524..8707d64 100644
--- a/src/cobalt/media/player/web_media_player_impl.h
+++ b/src/cobalt/media/player/web_media_player_impl.h
@@ -316,10 +316,6 @@
std::unique_ptr<Demuxer> progressive_demuxer_;
std::unique_ptr<ChunkDemuxer> chunk_demuxer_;
-#if defined(__LB_ANDROID__)
- AudioFocusBridge audio_focus_bridge_;
-#endif // defined(__LB_ANDROID__)
-
// Suppresses calls to OnPipelineError() after destruction / shutdown has been
// started; prevents us from spuriously logging errors that are transient or
// unimportant.
diff --git a/src/cobalt/media_integration_tests/endurance/endurance_test.py b/src/cobalt/media_integration_tests/endurance/endurance_test.py
new file mode 100644
index 0000000..302519d
--- /dev/null
+++ b/src/cobalt/media_integration_tests/endurance/endurance_test.py
@@ -0,0 +1,264 @@
+# Copyright 2021 The Cobalt Authors. 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.
+""" Endurance test of playbacks."""
+
+import argparse
+import logging
+import random
+import time
+
+import _env # pylint: disable=unused-import
+from cobalt.media_integration_tests.test_app import Features, MediaSessionPlaybackState
+from cobalt.media_integration_tests.test_case import TestCase
+from cobalt.media_integration_tests.test_util import PlaybackUrls
+
+# The variables below are all in seconds.
+STATUS_CHECK_INTERVAL = 0.5
+SINGLE_PLAYBACK_WATCH_TIME_MAXIMUM = 2.0 * 60 * 60
+PLAYER_INITIALIZATION_WAITING_TIMEOUT = 5.0 * 60
+MEDIA_TIME_UPDATE_WAITING_TIMEOUT = 10.0
+WRITTEN_INPUT_WAITING_TIMEOUT = 30.0
+PLAYBACK_END_WAITING_TIMEOUT = 30.0
+# Needs to interact with the app regularly to keep it active. Otherwise, the
+# playback may be paused.
+IDLE_TIME_MAXIMUM = 60 * 60
+
+
+class EnduranceTest(TestCase):
+ """
+ Test case for playback endurance test.
+ """
+
+ def __init__(self, *args, **kwargs):
+ super(EnduranceTest, self).__init__(*args, **kwargs)
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--startup_url', default=PlaybackUrls.PLAYLIST, type=str)
+ # Stop the test after |max_running_time| (in hours). If |max_running_time|
+ # is 0 or negative, the test will not stop until it gets an error.
+ parser.add_argument('--max_running_time', default=20, type=float)
+ # Insert random actions if |random_action_interval| is greater than 0.
+ parser.add_argument('--random_action_interval', default=0.0, type=float)
+ args, _ = parser.parse_known_args()
+
+ self.startup_url = args.startup_url
+ # Convert |max_running_time| to seconds.
+ self.max_running_time = args.max_running_time * 60 * 60
+ self.needs_random_action = args.random_action_interval > 0
+ self.random_action_interval = args.random_action_interval
+
+ def ResetTimestamps(self):
+ self.last_media_time = -1
+ self.last_media_time_update_time = -1
+ self.last_written_audio_timestamp = -1
+ self.last_written_audio_update_time = -1
+ self.last_written_video_timestamp = -1
+ self.last_written_video_update_time = -1
+ self.audio_eos_written_time = -1
+ self.video_eos_written_time = -1
+ self.playback_end_time = -1
+
+ def OnPlayerStateChanged(self, player_state_handler, player_state):
+ current_running_time = time.time() - self.start_time
+ element_state = player_state.video_element_state
+ pipeline_state = player_state.pipeline_state
+ media_session_state = player_state.media_session_state
+
+ if not player_state_handler.IsPlayerPlaying():
+ return
+
+ # Reset timestamps after player identifier is changed.
+ if self.player_identifier != pipeline_state.identifier:
+ self.player_identifier = pipeline_state.identifier
+ self.playback_start_time = current_running_time
+ self.ResetTimestamps()
+
+ # Reset timestamps after resume. It could happen after pause, fastforward,
+ # rewind and playback switch.
+ if media_session_state.playback_state != MediaSessionPlaybackState.PLAYING:
+ self.playback_is_playing = False
+ elif not self.playback_is_playing:
+ self.playback_is_playing = True
+ self.ResetTimestamps()
+
+ # Update media time.
+ if self.last_media_time != element_state.current_time:
+ self.last_media_time = element_state.current_time
+ self.last_media_time_update_time = current_running_time
+
+ # Update written audio timestamp.
+ if (self.last_written_audio_timestamp !=
+ pipeline_state.last_written_audio_timestamp):
+ self.last_written_audio_timestamp = (
+ pipeline_state.last_written_audio_timestamp)
+ self.last_written_audio_update_time = current_running_time
+
+ # Update written video timestamp.
+ if (self.last_written_video_timestamp !=
+ pipeline_state.last_written_video_timestamp):
+ self.last_written_video_timestamp = (
+ pipeline_state.last_written_video_timestamp)
+ self.last_written_video_update_time = current_running_time
+
+ # Update audio eos timestamp.
+ if (self.audio_eos_written_time == -1 and
+ pipeline_state.is_audio_eos_written):
+ self.audio_eos_written_time = current_running_time
+
+ # Update video eos timestamp.
+ if (self.video_eos_written_time == -1 and
+ pipeline_state.is_video_eos_written):
+ self.video_eos_written_time = current_running_time
+
+ # Update playback end time.
+ if (self.audio_eos_written_time != -1 and
+ self.video_eos_written_time != -1 and self.playback_end_time == -1 and
+ element_state.current_time >= element_state.duration):
+ self.playback_end_time = current_running_time
+
+ def GenerateErrorString(self, err_msg):
+ return (
+ '%s (running time: %f, player identifier: "%s", is playing: %r, '
+ 'playback start time: %f, last media time: %f (updated at %f), '
+ 'last written audio timestamp: %d (updated at %f), '
+ 'last written video timestamp: %d (updated at %f), '
+ 'audio eos written at %f, video eos written at %f, '
+ 'playback ended at %f).' %
+ (err_msg, time.time() - self.start_time, self.player_identifier,
+ self.playback_is_playing, self.playback_start_time,
+ self.last_media_time, self.last_media_time_update_time,
+ self.last_written_audio_timestamp, self.last_written_audio_update_time,
+ self.last_written_video_timestamp, self.last_written_video_update_time,
+ self.audio_eos_written_time, self.video_eos_written_time,
+ self.playback_end_time))
+
+ def SendRandomAction(self, app):
+
+ def SuspendAndResume(app):
+ app.Suspend()
+ app.WaitUntilReachState(
+ lambda _app: not _app.ApplicationState().is_visible)
+ # Wait for 1 second before resume.
+ time.sleep(1)
+ app.Resume()
+
+ actions = {
+ 'PlayPause': lambda _app: _app.PlayOrPause(),
+ 'Fastforward': lambda _app: _app.Fastforward(),
+ 'Rewind': lambda _app: _app.Rewind(),
+ 'PlayPrevious': lambda _app: _app.PlayPrevious(),
+ 'PlayNext': lambda _app: _app.PlayNext(),
+ }
+ if TestCase.IsFeatureSupported(Features.SUSPEND_AND_RESUME):
+ actions['SuspendAndResume'] = SuspendAndResume
+
+ action_name = random.choice(list(actions.keys()))
+ logging.info('Send random action (%s).', action_name)
+ actions[action_name](app)
+
+ def test_playback_endurance(self):
+ self.start_time = time.time()
+ self.player_identifier = ''
+ self.playback_is_playing = False
+ self.playback_start_time = -1
+ self.last_state_check_time = 0
+ self.last_action_time = 0
+ self.ResetTimestamps()
+
+ app = self.CreateCobaltApp(self.startup_url)
+ app.AddPlayerStateChangeHandler(self.OnPlayerStateChanged)
+ with app:
+ while True:
+ # Put the sleep at the top of the loop.
+ time.sleep(STATUS_CHECK_INTERVAL)
+
+ current_running_time = time.time() - self.start_time
+ # Stop the test after reaching max running time.
+ if (self.max_running_time > 0 and
+ current_running_time > self.max_running_time):
+ break
+ # Skip if there's no running player.
+ if not app.player_state_handler.IsPlayerPlaying():
+ # TODO: identify network problem
+ self.assertTrue(
+ current_running_time - self.last_state_check_time <
+ PLAYER_INITIALIZATION_WAITING_TIMEOUT,
+ self.GenerateErrorString(
+ 'Timed out waiting for player initialization (waited: %f).' %
+ (current_running_time - self.last_state_check_time)))
+ continue
+ self.last_state_check_time = current_running_time
+ # Skip to next playback if it has been played for long time.
+ if (self.playback_start_time != -1 and
+ current_running_time - self.playback_start_time >
+ SINGLE_PLAYBACK_WATCH_TIME_MAXIMUM):
+ app.PlayNext()
+ # Set start time to -1 here to avoid send same command in next loop.
+ self.playback_start_time = -1
+ continue
+ if self.playback_is_playing:
+ # Check media time.
+ if self.last_media_time_update_time > 0:
+ # TODO: identify network problem
+ self.assertTrue(
+ current_running_time - self.last_media_time_update_time <
+ MEDIA_TIME_UPDATE_WAITING_TIMEOUT,
+ self.GenerateErrorString(
+ 'Timed out waiting for media time update (waited: %f).' %
+ (current_running_time - self.last_media_time_update_time)))
+ # Check written audio timestamp.
+ if (self.last_written_audio_update_time > 0 and
+ self.audio_eos_written_time == -1):
+ self.assertTrue(
+ current_running_time - self.last_written_audio_update_time <
+ WRITTEN_INPUT_WAITING_TIMEOUT,
+ self.GenerateErrorString(
+ 'Timed out waiting for new audio input (waited: %f).' %
+ (current_running_time -
+ self.last_written_audio_update_time)))
+ # Check written video timestamp.
+ if (self.last_written_video_update_time > 0 and
+ self.video_eos_written_time == -1):
+ self.assertTrue(
+ current_running_time - self.last_written_video_update_time <
+ WRITTEN_INPUT_WAITING_TIMEOUT,
+ self.GenerateErrorString(
+ 'Timed out waiting for new video input (waited: %f).' %
+ (current_running_time -
+ self.last_written_video_update_time)))
+ # Check if the playback ends properly.
+ if (self.audio_eos_written_time > 0 and
+ self.video_eos_written_time > 0 and self.playback_end_time > 0):
+ self.assertTrue(
+ current_running_time - self.playback_end_time <
+ PLAYBACK_END_WAITING_TIMEOUT,
+ self.GenerateErrorString(
+ 'Timed out waiting for playback to end (waited: %f).' %
+ (current_running_time - self.playback_end_time,)))
+
+ # Send random actions.
+ if (self.needs_random_action and
+ current_running_time - self.last_action_time >
+ self.random_action_interval):
+ self.SendRandomAction(app)
+ self.last_action_time = current_running_time
+
+ # Interact with the app to keep it active.
+ if current_running_time - self.last_action_time > IDLE_TIME_MAXIMUM:
+ # Play the previous playback again.
+ app.PlayPrevious()
+ self.playback_start_time = -1
+
+ app.RemovePlayerStateChangeHandler(self.OnPlayerStateChanged)
diff --git a/src/cobalt/media_integration_tests/functionality/general_playback.py b/src/cobalt/media_integration_tests/functionality/general_playback.py
new file mode 100644
index 0000000..d90eca4
--- /dev/null
+++ b/src/cobalt/media_integration_tests/functionality/general_playback.py
@@ -0,0 +1,58 @@
+# Copyright 2021 The Cobalt Authors. 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.
+""" Tests for general playbacks with different formats."""
+
+import logging
+
+import _env # pylint: disable=unused-import
+from cobalt.media_integration_tests.test_case import TestCase
+from cobalt.media_integration_tests.test_util import MimeStrings, PlaybackUrls
+
+
+class GeneralPlaybackTest(TestCase):
+ """
+ Test cases for general playbacks.
+ """
+
+ def run_test(self, url, mime=None):
+ app = self.CreateCobaltApp(url)
+ with app:
+ # Skip the test if the mime is not supported.
+ if mime and not app.IsMediaTypeSupported(mime):
+ logging.info('Mime type (%s) is not supported. Skip the test.', mime)
+ return
+ # Wait until the playback starts.
+ app.WaitUntilPlayerStart()
+ app.WaitUntilAdsEnd()
+ # Let the playback play for 10 seconds.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 10)
+
+TEST_PARAMETERS = [
+ ('H264', PlaybackUrls.H264_ONLY, None),
+ ('ENCRYPTED', PlaybackUrls.ENCRYPTED, None),
+ ('VR', PlaybackUrls.VR, None),
+ ('VP9', PlaybackUrls.VP9, MimeStrings.VP9),
+ ('VP9_HFR', PlaybackUrls.VP9_HFR, MimeStrings.VP9_HFR),
+ ('AV1', PlaybackUrls.AV1, MimeStrings.AV1),
+ ('AV1_HFR', PlaybackUrls.AV1_HFR, MimeStrings.AV1_HFR),
+ ('VERTICAL', PlaybackUrls.VERTICAL, None),
+ ('SHORT', PlaybackUrls.SHORT, None),
+ ('VP9_HDR_HLG', PlaybackUrls.VP9_HDR_HLG, MimeStrings.VP9_HDR_HLG),
+ ('VP9_HDR_PQ', PlaybackUrls.VP9_HDR_PQ, MimeStrings.VP9_HDR_PQ),
+ ('HDR_PQ_HFR', PlaybackUrls.HDR_PQ_HFR, MimeStrings.VP9_HDR_PQ_HFR),
+]
+
+for name, playback_url, mime_str in TEST_PARAMETERS:
+ TestCase.CreateTest(GeneralPlaybackTest, name, GeneralPlaybackTest.run_test,
+ playback_url, mime_str)
diff --git a/src/cobalt/media_integration_tests/functionality/live_playback.py b/src/cobalt/media_integration_tests/functionality/live_playback.py
new file mode 100644
index 0000000..7390116
--- /dev/null
+++ b/src/cobalt/media_integration_tests/functionality/live_playback.py
@@ -0,0 +1,57 @@
+# Copyright 2021 The Cobalt Authors. 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.
+""" Tests for live playbacks."""
+
+import time
+
+import _env # pylint: disable=unused-import
+from cobalt.media_integration_tests.test_case import TestCase
+from cobalt.media_integration_tests.test_util import PlaybackUrls
+
+
+class LivePlaybackTest(TestCase):
+ """
+ Test cases for live playbacks.
+ """
+
+ def run_test(self, url):
+ app = self.CreateCobaltApp(url)
+ with app:
+ # Wait until the playback starts.
+ app.WaitUntilPlayerStart()
+ app.WaitUntilAdsEnd()
+ # Let the playback play for 5 seconds.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 5)
+ # Pause the playback and wait for some time.
+ app.PlayOrPause()
+ app.WaitUntilReachState(
+ lambda _app: _app.PlayerState().video_element_state.paused)
+ time.sleep(2)
+ # Resume the playback.
+ app.PlayOrPause()
+ app.WaitUntilReachState(
+ lambda _app: not _app.PlayerState().video_element_state.paused)
+ # Let the playback play for another 5 seconds.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 5)
+
+
+TEST_PARAMETERS = [
+ ('LIVE', PlaybackUrls.LIVE),
+ ('LIVE_ULL', PlaybackUrls.LIVE_ULL),
+ ('LIVE_VR', PlaybackUrls.LIVE_VR),
+]
+
+for name, playback_url in TEST_PARAMETERS:
+ TestCase.CreateTest(LivePlaybackTest, name, LivePlaybackTest.run_test,
+ playback_url)
diff --git a/src/cobalt/media_integration_tests/functionality/playback_controls.py b/src/cobalt/media_integration_tests/functionality/playback_controls.py
new file mode 100644
index 0000000..13b1ec8
--- /dev/null
+++ b/src/cobalt/media_integration_tests/functionality/playback_controls.py
@@ -0,0 +1,101 @@
+# Copyright 2021 The Cobalt Authors. 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.
+""" Tests for playback control shortcuts."""
+
+import logging
+
+import _env # pylint: disable=unused-import
+from cobalt.media_integration_tests.test_case import TestCase
+from cobalt.media_integration_tests.test_util import PlaybackUrls
+
+
+class PlaybackControlsTest(TestCase):
+ """
+ Test cases for playback control shortcuts.
+ """
+
+ def test_play_pause(self):
+ app = self.CreateCobaltApp(PlaybackUrls.H264_ONLY)
+ with app:
+ # Wait until the playback starts.
+ app.WaitUntilPlayerStart()
+ app.WaitUntilAdsEnd()
+ # Let the playback play for 2 seconds.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 2)
+ # Pause the playback.
+ app.PlayOrPause()
+ app.WaitUntilReachState(
+ lambda _app: _app.PlayerState().video_element_state.paused)
+ # Resume the playback.
+ app.PlayOrPause()
+ app.WaitUntilReachState(
+ lambda _app: not _app.PlayerState().video_element_state.paused)
+ # Let the playback play for another 2 seconds.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 2)
+
+ def test_rewind_fastforward(self):
+ app = self.CreateCobaltApp(PlaybackUrls.H264_ONLY)
+ with app:
+ # Wait until the playback starts.
+ app.WaitUntilPlayerStart()
+ app.WaitUntilAdsEnd()
+ # Let the playback play for 2 seconds.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 2)
+
+ logging.info('Fast forward the playback.')
+ old_media_time = app.CurrentMediaTime()
+ # Fastforward the playback by 10 seconds.
+ app.Fastforward()
+ app.WaitUntilReachState(
+ lambda _app: _app.CurrentMediaTime() > old_media_time + 10)
+ # Let the playback play for another 2 seconds.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 2)
+
+ logging.info('Rewind the playback.')
+ old_media_time = app.CurrentMediaTime()
+ # Rewind the playback by 10 seconds.
+ app.Rewind()
+ app.WaitUntilReachState(
+ lambda _app: _app.CurrentMediaTime() < old_media_time)
+ # Let the playback play for another 2 seconds.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 2)
+
+ def test_play_next_and_previous(self):
+ app = self.CreateCobaltApp(PlaybackUrls.PLAYLIST)
+ with app:
+ # Wait until the playback starts.
+ app.WaitUntilPlayerStart()
+ app.WaitUntilAdsEnd()
+ # Let the playback play for 2 seconds.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 2)
+ # Play next track.
+ logging.info('Play next playback.')
+ app.PlayNext()
+ # Wait until the player is destroyed.
+ app.WaitUntilPlayerDestroyed()
+ # Wait until the playback starts.
+ app.WaitUntilPlayerStart()
+ app.WaitUntilAdsEnd()
+ # Let the playback play for another 2 seconds.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 2)
+ # Play previous track.
+ logging.info('Play previous playback.')
+ app.PlayPrevious()
+ # Wait until the player is destroyed.
+ app.WaitUntilPlayerDestroyed()
+ # Wait until the playback starts.
+ app.WaitUntilPlayerStart()
+ app.WaitUntilAdsEnd()
+ # Let the playback play for another 2 seconds.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 2)
diff --git a/src/cobalt/media_integration_tests/functionality/suspend_resume.py b/src/cobalt/media_integration_tests/functionality/suspend_resume.py
index e51215b..cc26c33 100644
--- a/src/cobalt/media_integration_tests/functionality/suspend_resume.py
+++ b/src/cobalt/media_integration_tests/functionality/suspend_resume.py
@@ -11,14 +11,15 @@
# 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.
-""" Tests of suspend and resume during playing."""
+""" Tests for suspend and resume during playing."""
+import logging
import time
-import unittest
import _env # pylint: disable=unused-import
from cobalt.media_integration_tests.test_app import Features
from cobalt.media_integration_tests.test_case import TestCase
+from cobalt.media_integration_tests.test_util import MimeStrings, PlaybackUrls
class SuspendResumeTest(TestCase):
@@ -26,56 +27,46 @@
Test cases for suspend and resume.
"""
- def run_test_with_url(self, url):
+ def run_test(self, url, mime=None):
app = self.CreateCobaltApp(url)
with app:
+ # Skip the test if the mime is not supported.
+ if mime and not app.IsMediaTypeSupported(mime):
+ logging.info('Mime type (%s) is not supported. Skip the test.', mime)
+ return
# Wait until the playback starts.
app.WaitUntilPlayerStart()
app.WaitUntilAdsEnd()
# Let the playback play for 2 seconds.
app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 2)
# Suspend the app and wait the app enters background.
+ logging.info('Suspend the application.')
app.Suspend()
app.WaitUntilReachState(
lambda _app: not _app.ApplicationState().is_visible)
# Wait for 1 second before resume.
time.sleep(1)
# Resume the app and let it play for a few time.
+ logging.info('Resume the application.')
app.Resume()
app.WaitUntilPlayerStart()
app.WaitUntilAdsEnd()
# Let the playback play for 2 seconds.
app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 2)
- @unittest.skipIf(not TestCase.IsFeatureSupported(Features.SUSPEND_AND_RESUME),
- 'Suspend and resume is not supported on this platform.')
- def test_playback_h264(self):
- self.run_test_with_url('https://www.youtube.com/tv#/watch?v=RACW52qnJMI')
+TEST_PARAMETERS = [
+ ('H264', PlaybackUrls.H264_ONLY, None),
+ ('ENCRYPTED', PlaybackUrls.ENCRYPTED, None),
+ ('LIVE', PlaybackUrls.LIVE, None),
+ ('VP9', PlaybackUrls.VP9, MimeStrings.VP9),
+ ('AV1', PlaybackUrls.AV1, MimeStrings.AV1),
+ ('VERTICAL', PlaybackUrls.VERTICAL, None),
+ ('VR', PlaybackUrls.VR, None),
+]
- @unittest.skipIf(not TestCase.IsFeatureSupported(Features.SUSPEND_AND_RESUME),
- 'Suspend and resume is not supported on this platform.')
- def test_encrypted_playback(self):
- self.run_test_with_url('https://www.youtube.com/tv#/watch?v=Vx5lkGS4w30')
-
- @unittest.skipIf(not TestCase.IsFeatureSupported(Features.SUSPEND_AND_RESUME),
- 'Suspend and resume is not supported on this platform.')
- def test_live_stream(self):
- self.run_test_with_url('https://www.youtube.com/tv#/watch?v=KI1XlTQrsa0')
-
- # Test for vp9 playback if supported.
- @unittest.skipIf(not TestCase.IsFeatureSupported(Features.SUSPEND_AND_RESUME),
- 'Suspend and resume is not supported on this platform.')
- def test_playback_vp9(self):
- self.run_test_with_url('https://www.youtube.com/tv#/watch?v=1La4QzGeaaQ')
-
- # Test for av1 playback if supported.
- @unittest.skipIf(not TestCase.IsFeatureSupported(Features.SUSPEND_AND_RESUME),
- 'Suspend and resume is not supported on this platform.')
- def test_playback_av1(self):
- self.run_test_with_url('https://www.youtube.com/tv#/watch?v=iXvy8ZeCs5M')
-
- # Test for vertical playback
- @unittest.skipIf(not TestCase.IsFeatureSupported(Features.SUSPEND_AND_RESUME),
- 'Suspend and resume is not supported on this platform.')
- def test_vertical_playback(self):
- self.run_test_with_url('https://www.youtube.com/tv#/watch?v=jNQXAC9IVRw')
+if not TestCase.IsFeatureSupported(Features.SUSPEND_AND_RESUME):
+ logging.info('Suspend and resume is not supported on this platform.')
+else:
+ for name, playback_url, mime_str in TEST_PARAMETERS:
+ TestCase.CreateTest(SuspendResumeTest, name, SuspendResumeTest.run_test,
+ playback_url, mime_str)
diff --git a/src/cobalt/media_integration_tests/performance/codec_capability.py b/src/cobalt/media_integration_tests/performance/codec_capability.py
new file mode 100644
index 0000000..c117fd2
--- /dev/null
+++ b/src/cobalt/media_integration_tests/performance/codec_capability.py
@@ -0,0 +1,78 @@
+# Copyright 2021 The Cobalt Authors. 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.
+""" Tests of platform codec capabilities."""
+
+import logging
+
+import _env # pylint: disable=unused-import
+from cobalt.media_integration_tests.test_case import TestCase
+from cobalt.media_integration_tests.test_util import MimeStrings, PlaybackUrls
+
+
+class CodecCapabilityTest(TestCase):
+ """
+ Test cases for platform codec capabilities.
+ """
+
+ # Returns a string which shows the max supported resolution, or "n/a" if the
+ # codec is not supported.
+ @staticmethod
+ def run_video_codec_test(app, codec_name, codec_mime):
+ if app.IsMediaTypeSupported(codec_mime):
+ for res_name, _ in reversed(MimeStrings.RESOLUTIONS.items()):
+ if app.IsMediaTypeSupported(
+ MimeStrings.create_video_mime_string(codec_mime, res_name)):
+ return '[%s, %s]' % (codec_name, res_name)
+ return '[%s, n/a]' % (codec_name)
+
+ # Returns a string which shows the max supported channels, or "n/a" if the
+ # codec is not supported.
+ @staticmethod
+ def run_audio_codec_test(app, codec_name, codec_mime):
+ if app.IsMediaTypeSupported(codec_mime):
+ for channels in [6, 4, 2]:
+ if app.IsMediaTypeSupported(
+ MimeStrings.create_audio_mime_string(codec_mime, channels)):
+ return '[%s, %s]' % (codec_name, channels)
+ return '[%s, n/a]' % (codec_name)
+
+ def test_video_codec_capability(self):
+ app = self.CreateCobaltApp(PlaybackUrls.DEFAULT)
+ mimes = [
+ ('H264', MimeStrings.H264),
+ ('VP9', MimeStrings.VP9),
+ ('VP9_HFR', MimeStrings.VP9_HFR),
+ ('AV1', MimeStrings.AV1),
+ ('AV1_HFR', MimeStrings.AV1_HFR),
+ ('VP9_HDR_HLG', MimeStrings.VP9_HDR_HLG),
+ ('VP9_HDR_PQ', MimeStrings.VP9_HDR_PQ),
+ ('VP9_HDR_PQ_HFR', MimeStrings.VP9_HDR_PQ_HFR),
+ ]
+ result = [' ***** Video codec capability test results: ']
+ with app:
+ for mime_name, mime_str in mimes:
+ result.append(self.run_video_codec_test(app, mime_name, mime_str))
+ logging.info(', '.join(result))
+
+ def test_audio_codec_capability(self):
+ app = self.CreateCobaltApp(PlaybackUrls.DEFAULT)
+ mimes = [
+ ('AAC', MimeStrings.AAC),
+ ('OPUS', MimeStrings.OPUS),
+ ]
+ result = [' ***** Audio codec capability test results: ']
+ with app:
+ for mime_name, mime_str in mimes:
+ result.append(self.run_audio_codec_test(app, mime_name, mime_str))
+ logging.info(', '.join(result))
diff --git a/src/cobalt/media_integration_tests/performance/dropped_frames.py b/src/cobalt/media_integration_tests/performance/dropped_frames.py
new file mode 100644
index 0000000..89f426c
--- /dev/null
+++ b/src/cobalt/media_integration_tests/performance/dropped_frames.py
@@ -0,0 +1,75 @@
+# Copyright 2021 The Cobalt Authors. 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.
+""" Performance tests of dropped frames."""
+
+import argparse
+import logging
+
+import _env # pylint: disable=unused-import
+from cobalt.media_integration_tests.test_case import TestCase
+from cobalt.media_integration_tests.test_util import MimeStrings, PlaybackUrls
+
+
+class DroppedFrameTest(TestCase):
+ """
+ Test cases for playback dropped frames.
+ """
+
+ def __init__(self, *args, **kwargs):
+ super(DroppedFrameTest, self).__init__(*args, **kwargs)
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--test_times', default=5, type=int)
+ args, _ = parser.parse_known_args()
+ self.test_times = args.test_times
+
+ def run_test_with_url(self, test_name, url, mime=None):
+ test_results = []
+ for _ in range(self.test_times):
+ app = self.CreateCobaltApp(url)
+ with app:
+ # Skip the test if the mime is not supported.
+ if mime and not app.IsMediaTypeSupported(mime):
+ logging.info(' ***** Dropped frame test result: [%s, n/a]', test_name)
+ return
+ # Wait until the playback starts.
+ app.WaitUntilPlayerStart()
+ app.WaitUntilAdsEnd()
+ # Let the playback play for 10 seconds.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 10)
+
+ total_frames = app.PlayerState().video_element_state.total_video_frames
+ dropped_frames = app.PlayerState(
+ ).video_element_state.dropped_video_frames
+ dropped_ratio = dropped_frames * 1.0 / total_frames
+ test_results.append([dropped_ratio, dropped_frames, total_frames])
+ logging.info(' ***** Dropped frame test result of %s : %r.', test_name,
+ test_results)
+
+
+TEST_PARAMETERS = [
+ ('H264', PlaybackUrls.H264_ONLY, MimeStrings.H264),
+ ('VP9', PlaybackUrls.VP9, MimeStrings.VP9),
+ ('VP9_HFR', PlaybackUrls.VP9_HFR, MimeStrings.VP9_HFR),
+ ('AV1', PlaybackUrls.AV1, MimeStrings.AV1),
+ ('AV1_HFR', PlaybackUrls.AV1_HFR, MimeStrings.AV1_HFR),
+ ('VP9_HDR_HLG', PlaybackUrls.VP9_HDR_HLG, MimeStrings.VP9_HDR_HLG),
+ ('VP9_HDR_PQ', PlaybackUrls.VP9_HDR_PQ, MimeStrings.VP9_HDR_PQ),
+ ('VP9_HDR_PQ_HFR', PlaybackUrls.HDR_PQ_HFR, MimeStrings.VP9_HDR_PQ_HFR),
+]
+
+for name, playback_url, mime_str in TEST_PARAMETERS:
+ TestCase.CreateTest(DroppedFrameTest, name,
+ DroppedFrameTest.run_test_with_url, name, playback_url,
+ mime_str)
diff --git a/src/cobalt/media_integration_tests/performance/start_latency.py b/src/cobalt/media_integration_tests/performance/start_latency.py
new file mode 100644
index 0000000..62b32f1
--- /dev/null
+++ b/src/cobalt/media_integration_tests/performance/start_latency.py
@@ -0,0 +1,157 @@
+# Copyright 2021 The Cobalt Authors. 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.
+""" Performance tests of playback operation latency."""
+
+import argparse
+import logging
+import time
+
+import _env # pylint: disable=unused-import
+from cobalt.media_integration_tests.test_app import AdsState
+from cobalt.media_integration_tests.test_case import TestCase
+from cobalt.media_integration_tests.test_util import MimeStrings, PlaybackUrls
+
+
+class StartLatencyTest(TestCase):
+ """
+ Test cases for playback operation latency.
+ """
+
+ def __init__(self, *args, **kwargs):
+ super(StartLatencyTest, self).__init__(*args, **kwargs)
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--test_times', default=5, type=int)
+ args, _ = parser.parse_known_args()
+ self.test_times = args.test_times
+
+ def run_first_start_latency_test(self, test_name, url, mime=None):
+ test_results = []
+ while len(test_results) < self.test_times:
+ app = self.CreateCobaltApp(url)
+ with app:
+ # Skip the test if the mime is not supported.
+ if mime and not app.IsMediaTypeSupported(mime):
+ logging.info(' ***** First start latency test result of %s : [n/a].',
+ test_name)
+ return
+ app.WaitUntilPlayerStart()
+ start_time = time.time()
+ start_media_time = app.CurrentMediaTime()
+ app.WaitUntilReachState(lambda _app: _app.PlayerState(
+ ).pipeline_state.first_written_video_timestamp != _app.PlayerState().
+ pipeline_state.last_written_video_timestamp)
+ # Record inputs received time to know the preliminary impact of network.
+ inputs_received_time = time.time()
+ inputs_received_latency = inputs_received_time - start_time
+ # Let the playback play for 1 second.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 1)
+
+ # If it's playing ads, wait until ads end and run the test again.
+ if app.GetAdsState() != AdsState.NONE:
+ app.WaitUntilAdsEnd()
+ continue
+ media_time = app.CurrentMediaTime() - start_media_time
+ end_time = time.time()
+ start_latency = end_time - start_time - media_time
+ test_results.append([
+ start_latency, inputs_received_latency, start_time,
+ inputs_received_time, media_time, end_time
+ ])
+ logging.info(' ***** First start latency test result of %s : %r.',
+ test_name, test_results)
+
+ def run_play_pause_latency_test(self, test_name, url, mime=None):
+ app = self.CreateCobaltApp(url)
+ with app:
+ # Skip the test if the mime is not supported.
+ if mime and not app.IsMediaTypeSupported(mime):
+ logging.info(' ***** Play/pause latency test result of %s : [n/a].',
+ test_name)
+ return
+ test_results = []
+ # Wait until the playback starts.
+ app.WaitUntilPlayerStart()
+ app.WaitUntilAdsEnd()
+ while len(test_results) < self.test_times:
+ # Let the playback play for 1 second.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 1)
+ start_time = time.time()
+ # Pause the playback.
+ app.PlayOrPause()
+ app.WaitUntilReachState(
+ lambda _app: _app.PlayerState().video_element_state.paused)
+ pause_latency = time.time() - start_time
+
+ start_time = time.time()
+ # Resume the playback.
+ app.PlayOrPause()
+ app.WaitUntilReachState(
+ lambda _app: not _app.PlayerState().video_element_state.paused)
+
+ play_latency = time.time() - start_time
+ test_results.append([play_latency, pause_latency])
+ logging.info(' ***** Play/pause latency test result of %s : %r.',
+ test_name, test_results)
+
+ def run_fastforward_latency_test(self, test_name, url, mime=None):
+ app = self.CreateCobaltApp(url)
+ with app:
+ # Skip the test if the mime is not supported.
+ if mime and not app.IsMediaTypeSupported(mime):
+ logging.info(' ***** Fastforward latency test result of %s : [n/a].',
+ test_name)
+ return
+ test_results = []
+ # Wait until the playback starts.
+ app.WaitUntilPlayerStart()
+ app.WaitUntilAdsEnd()
+ # Let the playback play for 1 second.
+ app.WaitUntilMediaTimeReached(app.CurrentMediaTime() + 1)
+ while len(test_results) < self.test_times:
+ old_media_time = app.CurrentMediaTime()
+ start_time = time.time()
+ app.Fastforward()
+ app.WaitUntilReachState(lambda _app: _app.PlayerState(
+ ).pipeline_state.first_written_video_timestamp != _app.PlayerState().
+ pipeline_state.last_written_video_timestamp)
+ # Record inputs received time to know the preliminary impact of network.
+ inputs_received_latency = time.time() - start_time
+ app.WaitUntilReachState(
+ lambda _app: _app.CurrentMediaTime() > old_media_time + 10)
+ fastforward_latency = time.time() - start_time
+ test_results.append([fastforward_latency, inputs_received_latency])
+
+ logging.info(' ***** Fastforward latency test result of %s : %r.',
+ test_name, test_results)
+
+
+TEST_PARAMETERS = [
+ ('H264', PlaybackUrls.H264_ONLY, MimeStrings.H264),
+ ('VP9', PlaybackUrls.VP9, MimeStrings.VP9),
+ ('AV1', PlaybackUrls.AV1, MimeStrings.AV1),
+ ('VP9_HDR_HLG', PlaybackUrls.VP9_HDR_HLG, MimeStrings.VP9_HDR_HLG),
+ ('VP9_HDR_PQ', PlaybackUrls.VP9_HDR_PQ, MimeStrings.VP9_HDR_PQ),
+]
+
+for name, playback_url, mime_str in TEST_PARAMETERS:
+ TestCase.CreateTest(StartLatencyTest, 'first_start_latency_%s' % (name),
+ StartLatencyTest.run_first_start_latency_test, name,
+ playback_url, mime_str)
+ TestCase.CreateTest(StartLatencyTest, 'play_pause_latency_%s' % (name),
+ StartLatencyTest.run_play_pause_latency_test, name,
+ playback_url, mime_str)
+ TestCase.CreateTest(StartLatencyTest, 'fastforward_latency_%s' % (name),
+ StartLatencyTest.run_fastforward_latency_test, name,
+ playback_url, mime_str)
diff --git a/src/cobalt/media_integration_tests/test_app.py b/src/cobalt/media_integration_tests/test_app.py
index d0f62dd..cea1406 100644
--- a/src/cobalt/media_integration_tests/test_app.py
+++ b/src/cobalt/media_integration_tests/test_app.py
@@ -32,6 +32,8 @@
WAIT_UNTIL_ADS_END_DEFAULT_TIMEOUT_SECONDS = 120
WAIT_UNTIL_MEDIA_TIME_REACHED_DEFAULT_TIMEOUT_SECONDS = 30
+ACCOUNT_SELECTOR_ADD_ACCOUNT_TEXT = u'Add account'
+
def GetValueFromQueryResult(query_result, key, default):
if query_result is None:
@@ -83,7 +85,9 @@
MEDIA_NEXT_TRACK = u'\uf000'
MEDIA_PREV_TRACK = u'\uf001'
MEDIA_STOP = u'\uf002'
- MEDIA_PLAYPAUSE = u'\uf003'
+ MEDIA_PLAY_PAUSE = u'\uf003'
+ MEDIA_REWIND = u'\uf004'
+ MEDIA_FAST_FORWARD = u'\uf005'
class Features(enum.Enum):
@@ -250,11 +254,12 @@
const primary_pipeline_keys = h5vcc.cVal.keys().filter(key =>
key.startsWith("Media.Pipeline.") &&
key.endsWith("MaxVideoCapabilities") &&
- h5vcc.cVal.getValue(key).length === 0)
+ h5vcc.cVal.getValue(key).length === 0);
if (primary_pipeline_keys.length == 0) {
- return "null"
+ return "null";
}
- const key_prefix = primary_pipeline_keys[0].slice(0, -".MaxVideoCapabilities".length)
+ const key_prefix = primary_pipeline_keys[0].slice(0,
+ -".MaxVideoCapabilities".length);
return {
identifier: key_prefix.slice("Media.Pipeline.".length),
is_started: h5vcc.cVal.getValue(key_prefix + '.Started'),
@@ -266,7 +271,8 @@
playback_rate: h5vcc.cVal.getValue(key_prefix + '.PlaybackRate'),
duration: h5vcc.cVal.getValue(key_prefix + '.Duration'),
last_media_time: h5vcc.cVal.getValue(key_prefix + '.LastMediaTime'),
- max_video_capabilities: h5vcc.cVal.getValue(key_prefix + '.MaxVideoCapabilities'),
+ max_video_capabilities: h5vcc.cVal.getValue(
+ key_prefix + '.MaxVideoCapabilities'),
seek_time: h5vcc.cVal.getValue(key_prefix + '.SeekTime'),
first_written_audio_timestamp:
h5vcc.cVal.getValue(key_prefix + '.FirstWrittenAudioTimestamp'),
@@ -278,11 +284,13 @@
h5vcc.cVal.getValue(key_prefix + '.LastWrittenVideoTimestamp'),
video_width: h5vcc.cVal.getValue(key_prefix + '.VideoWidth'),
video_height: h5vcc.cVal.getValue(key_prefix + '.VideoHeight'),
- is_audio_eos_written: h5vcc.cVal.getValue(key_prefix + '.IsAudioEOSWritten'),
- is_video_eos_written: h5vcc.cVal.getValue(key_prefix + '.IsVideoEOSWritten'),
+ is_audio_eos_written: h5vcc.cVal.getValue(key_prefix +
+ '.IsAudioEOSWritten'),
+ is_video_eos_written: h5vcc.cVal.getValue(key_prefix +
+ '.IsVideoEOSWritten'),
pipeline_status: h5vcc.cVal.getValue(key_prefix + '.PipelineStatus'),
error_message: h5vcc.cVal.getValue(key_prefix + '.ErrorMessage'),
- }
+ };
"""
def IsPlaying(self):
@@ -340,7 +348,7 @@
return {
metadata: navigator.mediaSession.metadata,
playbackState: navigator.mediaSession.playbackState,
- }
+ };
"""
@@ -391,8 +399,8 @@
const players = document.querySelectorAll("video");
if (players && players.length > 0) {
for (let i = 0; i < players.length; i++) {
- const player = players[i]
- const rect = player.getBoundingClientRect()
+ const player = players[i];
+ const rect = player.getBoundingClientRect();
if (rect.width === window.innerWidth ||
rect.height === window.innerHeight) {
const quality = player.getVideoPlaybackQuality();
@@ -404,11 +412,11 @@
volume: player.volume,
dropped_video_frames: quality.droppedVideoFrames,
total_video_frames: quality.totalVideoFrames,
- }
+ };
}
}
}
- return "null"
+ return "null";
"""
@@ -522,9 +530,17 @@
def __exit__(self, *args):
self.should_exit.set()
- self.periodic_query_thread.join(THREAD_EXIT_TIMEOUT_SECONDS)
+ if self.periodic_query_thread.is_alive():
+ self.periodic_query_thread.join(THREAD_EXIT_TIMEOUT_SECONDS)
return self.runner.__exit__(*args)
+ def ExecuteScript(self, script):
+ try:
+ result = self.runner.webdriver.execute_script(script)
+ except Exception as e:
+ raise RuntimeError('Fail to excute script with error (%s).' % (str(e)))
+ return result
+
def _OnNewLogLine(self, line):
# Note that the function is called on cobalt runner reader thread.
# pass
@@ -584,7 +600,7 @@
self.player_state_handler.AddPlayerStateChangeHandler(handler)
def RemovePlayerStateChangeHandler(self, handler):
- self.player_state_handler.RemoveAppStateChangeHandler(handler)
+ self.player_state_handler.RemovePlayerStateChangeHandler(handler)
# The handler will receive parameters (TestApp, String, Dictionary).
def RegisterPeriodicQuery(self, query_name, query_js_code, result_handler):
@@ -620,12 +636,7 @@
# Generate javascript code and execute it.
js_code = self._GeneratePeriodicQueryJsCode(local_is_queries_changed,
local_periodic_queries)
- try:
- result = self.runner.webdriver.execute_script(js_code)
- except Exception as e:
- raise RuntimeError('Periodic queries failed with error (%s)' %
- (str(e)))
-
+ result = self.ExecuteScript(js_code)
for query_name in local_periodic_queries.keys():
if not result.get(query_name):
raise RuntimeError(
@@ -636,11 +647,11 @@
time.sleep(PERIODIC_QUERIES_INTERVAL_SECONDS)
_PERIODIC_QUERIES_JS_CODE = """
- var ret = {}
- for(var key in _media_integration_testing_queries) {
- ret[key] = _media_integration_testing_queries[key]()
+ let ret = {};
+ for(let key in _media_integration_testing_queries) {
+ ret[key] = _media_integration_testing_queries[key]();
}
- return ret
+ return ret;
"""
def _GeneratePeriodicQueryJsCode(self, is_queries_changed, periodic_queries):
@@ -658,7 +669,10 @@
return js_code
# The first input of |state_lambda| is an instance of TestApp.
- def WaitUntilReachState(self, state_lambda, timeout=WAIT_UNTIL_REACH_STATE_DEFAULT_TIMEOUT_SECONDS):
+ def WaitUntilReachState(
+ self,
+ state_lambda,
+ timeout=WAIT_UNTIL_REACH_STATE_DEFAULT_TIMEOUT_SECONDS):
start_time = time.time()
while not state_lambda(self) and time.time() - start_time < timeout:
time.sleep(WAIT_INTERVAL_SECONDS)
@@ -667,36 +681,94 @@
raise RuntimeError('WaitUntilReachState timed out after (%f) seconds.' %
(execute_interval))
- def WaitUntilPlayerStart(self,
- timeout=WAIT_UNTIL_REACH_STATE_DEFAULT_TIMEOUT_SECONDS
- ):
- self.WaitUntilReachState(
- lambda _app: _app.player_state_handler.IsPlayerPlaying(), timeout)
+ # The result is an array of overlay header text contents.
+ _OVERLAY_QUERY_JS_CODE = """
+ let result = [];
+ if (document.getElementsByTagName(
+ "YTLR-OVERLAY-PANEL-HEADER-RENDERER").length > 0) {
+ let childNodes = document.getElementsByTagName(
+ "YTLR-OVERLAY-PANEL-HEADER-RENDERER")[0].childNodes;
+ for (let i = 0; i < childNodes.length; i++) {
+ result.push(childNodes[i].textContent);
+ }
+ }
+ return result;
+ """
- # TODO: Need to verify if it works without corp network.
- # TODO: Needs to recognize and skip survery.
+ def WaitUntilPlayerStart(
+ self, timeout=WAIT_UNTIL_REACH_STATE_DEFAULT_TIMEOUT_SECONDS):
+
+ def PlayerStateCheckCallback(app):
+ # Check if it's showing account selector page.
+ is_showing_account_selector = self.ExecuteScript(
+ 'return document.getElementsByTagName("YTLR-ACCOUNT-SELECTOR")'
+ '.length > 0;')
+ if is_showing_account_selector:
+ active_element_label_attr = self.ExecuteScript(
+ 'return document.activeElement.getAttribute("aria-label");')
+ if active_element_label_attr != ACCOUNT_SELECTOR_ADD_ACCOUNT_TEXT:
+ logging.info('Select an account (%s) to continue the test.',
+ active_element_label_attr)
+ self.SendKeys(webdriver_keys.Keys.ENTER)
+ else:
+ logging.info('Current selected item is "Add acount", move to next'
+ ' item.')
+ self.SendKeys(webdriver_keys.Keys.ARROW_RIGHT)
+ return False
+ # Check if it's showing a playback survey.
+ is_showing_skip_button = self.ExecuteScript(
+ 'return document.getElementsByTagName("YTLR-SKIP-BUTTON-RENDERER")'
+ '.length > 0;')
+ # When there's a skip button and no running player, it's showing a
+ # survey.
+ if (is_showing_skip_button and
+ not app.player_state_handler.IsPlayerPlaying()):
+ self.SendKeys(webdriver_keys.Keys.ENTER)
+ logging.info('Send enter key event to skip the survey.')
+ return False
+ # Check if it's showing an overlay.
+ overlay_query_result = self.ExecuteScript(self._OVERLAY_QUERY_JS_CODE)
+ if len(overlay_query_result) > 0:
+ # Note that if there're playback errors, after close the overlay,
+ # the test will end with timeout error.
+ self.SendKeys(webdriver_keys.Keys.ENTER)
+ logging.info(
+ 'Send enter key event to close the overlay. Overlay '
+ 'headers : %r', overlay_query_result)
+ return False
+
+ return app.player_state_handler.IsPlayerPlaying()
+
+ self.WaitUntilReachState(PlayerStateCheckCallback, timeout)
+
+ def WaitUntilPlayerDestroyed(
+ self, timeout=WAIT_UNTIL_REACH_STATE_DEFAULT_TIMEOUT_SECONDS):
+ current_identifier = self.PlayerState().pipeline_state.identifier
+ if not current_identifier or len(current_identifier) == 0:
+ raise RuntimeError('No existing player when calling'
+ 'WaitUntilPlayerDestroyed.')
+ self.WaitUntilReachState(
+ lambda _app: _app.PlayerState().pipeline_state.identifier !=
+ current_identifier, timeout)
+
"""
The return values of the query, exact mapping of AdsState defined earlier
in this file.
"""
_GET_ADS_STATE_QUERY_JS_CODE = """
- if( document.getElementsByTagName("YTLR-AD-PREVIEW-RENDERER").length > 0 ) {
- return 1
+ if (document.getElementsByTagName("YTLR-AD-PREVIEW-RENDERER").length > 0) {
+ return 1;
}
- else if( document.getElementsByTagName("YTLR-SKIP-BUTTON-RENDERER").length > 0 ) {
- return 2
+ if (document.getElementsByTagName("YTLR-SKIP-BUTTON-RENDERER").length > 0) {
+ return 2;
}
- return 0
+ return 0;
"""
def GetAdsState(self):
if not self.runner.test_script_started.is_set():
raise RuntimeError('Webdriver is not ready yet')
- try:
- result = self.runner.webdriver.execute_script(
- self._GET_ADS_STATE_QUERY_JS_CODE)
- except Exception as e:
- raise RuntimeError('Ads query failed with error (%s)' % (str(e)))
+ result = self.ExecuteScript(self._GET_ADS_STATE_QUERY_JS_CODE)
return AdsState(result)
def WaitUntilAdsEnd(self, timeout=WAIT_UNTIL_ADS_END_DEFAULT_TIMEOUT_SECONDS):
@@ -730,15 +802,49 @@
if start_media_time > media_time:
return
- # Wait until playback starts, otherwise playback rate could be 0.
+ # Wait until playback starts.
self.WaitUntilReachState(
- lambda _app: _app.CurrentMediaTime() > start_media_time, timeout)
+ lambda _app: _app.PlayerState().pipeline_state.playback_rate > 0,
+ timeout)
+ duration = self.PlayerState().video_element_state.duration
+ if media_time > duration:
+ logging.info(
+ 'Requested media time (%f) is greater than the duration (%f)',
+ media_time, duration)
+ media_time = duration
+
+ time_to_play = max(media_time - self.CurrentMediaTime(), 0)
playback_rate = self.PlayerState().pipeline_state.playback_rate
- if playback_rate == 0:
- raise NotImplementedError
-
- adjusted_timeout = (media_time -
- self.CurrentMediaTime()) / playback_rate + timeout
+ adjusted_timeout = time_to_play / playback_rate + timeout
self.WaitUntilReachState(lambda _app: _app.CurrentMediaTime() > media_time,
adjusted_timeout)
+
+ def IsMediaTypeSupported(self, mime):
+ return self.ExecuteScript('return MediaSource.isTypeSupported("%s");' %
+ (mime))
+
+ def PlayOrPause(self):
+ self.SendKeys(AdditionalKeys.MEDIA_PLAY_PAUSE)
+
+ def Fastforward(self):
+ # The first fastforward will only bring up the progress bar.
+ self.SendKeys(AdditionalKeys.MEDIA_FAST_FORWARD)
+ # The second fastforward will forward the playback by 10 seconds.
+ self.SendKeys(AdditionalKeys.MEDIA_FAST_FORWARD)
+ # Press play button to start the playback.
+ self.SendKeys(AdditionalKeys.MEDIA_PLAY_PAUSE)
+
+ def Rewind(self):
+ # The first rewind will only bring up the progress bar.
+ self.SendKeys(AdditionalKeys.MEDIA_REWIND)
+ # The second rewind will rewind the playback by 10 seconds.
+ self.SendKeys(AdditionalKeys.MEDIA_REWIND)
+ # It needs to press play button to start the playback.
+ self.SendKeys(AdditionalKeys.MEDIA_PLAY_PAUSE)
+
+ def PlayPrevious(self):
+ self.SendKeys(AdditionalKeys.MEDIA_PREV_TRACK)
+
+ def PlayNext(self):
+ self.SendKeys(AdditionalKeys.MEDIA_NEXT_TRACK)
diff --git a/src/cobalt/media_integration_tests/test_case.py b/src/cobalt/media_integration_tests/test_case.py
index 09e2ec2..04b942a 100644
--- a/src/cobalt/media_integration_tests/test_case.py
+++ b/src/cobalt/media_integration_tests/test_case.py
@@ -59,3 +59,9 @@
def IsFeatureSupported(feature):
global _supported_features
return _supported_features[feature]
+
+ @staticmethod
+ def CreateTest(test_class, test_name, test_function, *args):
+ test_method = lambda self: test_function(self, *args)
+ test_method.__name__ = 'test_%s' % test_name
+ setattr(test_class, test_method.__name__, test_method)
diff --git a/src/cobalt/media_integration_tests/test_util.py b/src/cobalt/media_integration_tests/test_util.py
new file mode 100644
index 0000000..c2153327
--- /dev/null
+++ b/src/cobalt/media_integration_tests/test_util.py
@@ -0,0 +1,87 @@
+# Copyright 2021 The Cobalt Authors. 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.
+"""The module of base media integration test case."""
+
+from collections import OrderedDict
+
+import _env # pylint: disable=unused-import
+
+
+class MimeStrings():
+ """
+ Set of playback mime strings.
+ """
+
+ H264 = 'video/mp4; codecs=\\"avc1.4d4015\\"'
+ VP9 = 'video/webm; codecs=\\"vp9\\"'
+ VP9_HFR = 'video/webm; codecs=\\"vp9\\"; framerate=60'
+ AV1 = 'video/mp4; codecs=\\"av01.0.08M.08\\"'
+ AV1_HFR = 'video/mp4; codecs=\\"av01.0.08M.08\\"; framerate=60'
+ VP9_HDR_HLG = 'video/webm; codecs=\\"vp09.02.51.10.01.09.18.09.00\\"'
+ VP9_HDR_PQ = 'video/webm; codecs=\\"vp09.02.51.10.01.09.16.09.00\\"'
+ VP9_HDR_PQ_HFR = ('video/webm; codecs=\\"vp09.02.51.10.01.09.16.09.00\\";'
+ 'framerate=60')
+
+ AAC = 'audio/mp4; codecs=\\"mp4a.40.2\\"'
+ OPUS = 'audio/webm; codecs=\\"opus\\"'
+
+ RESOLUTIONS = OrderedDict([('140P', 'width=256; height=144'),
+ ('240P', 'width=352; height=240'),
+ ('360P', 'width=480; height=360'),
+ ('480P', 'width=640; height=480'),
+ ('720P', 'width=1280; height=720'),
+ ('1080P', 'width=1920; height=1080'),
+ ('2K', 'width=2560; height=1440'),
+ ('4K', 'width=3840; height=2160'),
+ ('8K', 'width=7680; height=4320')])
+
+ @staticmethod
+ def create_video_mime_string(codec, resolution):
+ return '%s; %s' % (codec, MimeStrings.RESOLUTIONS[resolution])
+
+ @staticmethod
+ def create_audio_mime_string(codec, channels):
+ return '%s; channels=%d' % (codec, channels)
+
+
+class PlaybackUrls():
+ """
+ Set of testing video urls.
+ """
+
+ DEFAULT = 'https://www.youtube.com/tv'
+ H264_ONLY = 'https://www.youtube.com/tv#/watch?v=RACW52qnJMI'
+ ENCRYPTED = 'https://www.youtube.com/tv#/watch?v=iNvUS1dnwfw'
+
+ VP9 = 'https://www.youtube.com/tv#/watch?v=x7GkebUe6XQ'
+ VP9_HFR = 'https://www.youtube.com/tv#/watch?v=Jsjtt5dWDYU'
+ AV1 = 'https://www.youtube.com/tv#/watch?v=iXvy8ZeCs5M'
+ AV1_HFR = 'https://www.youtube.com/tv#/watch?v=9jZ01i92JI8'
+ VERTICAL = 'https://www.youtube.com/tv#/watch?v=jNQXAC9IVRw'
+ SHORT = 'https://www.youtube.com/tv#/watch?v=NEf8Ug49FEw'
+ VP9_HDR_HLG = 'https://www.youtube.com/tv#/watch?v=ebhEiRWGvZM'
+ VP9_HDR_PQ = 'https://www.youtube.com/tv#/watch?v=Rw-qEKR5uv8'
+ HDR_PQ_HFR = 'https://www.youtube.com/tv#/watch?v=LXb3EKWsInQ'
+ VR = 'https://www.youtube.com/tv#/watch?v=Ei0fgLfJ6Tk'
+
+ LIVE = 'https://www.youtube.com/tv#/watch?v=o7UP6i4PAbk'
+ LIVE_ULL = 'https://www.youtube.com/tv#/watch?v=KI1XlTQrsa0'
+ LIVE_VR = 'https://www.youtube.com/tv#/watch?v=soeo5OPv7CA'
+
+ PLAYLIST = ('https://www.youtube.com/tv#/watch?list='
+ 'PLynQTqo4blSSCMPUGcH2YnbSrV84AnsRD')
+ # The link refers to a video in the middle of the playlist, so that
+ # it can be used to test both play previous and next.
+ PLAYLIST_MID = ('https://www.youtube.com/tv#/watch?'
+ 'v=9WrgRpOJr0I&list=PLynQTqo4blSSCMPUGcH2YnbSrV84AnsRD')
diff --git a/src/cobalt/renderer/egl_and_gles.h b/src/cobalt/renderer/egl_and_gles.h
index 59d0dc8..fdf1839 100644
--- a/src/cobalt/renderer/egl_and_gles.h
+++ b/src/cobalt/renderer/egl_and_gles.h
@@ -18,40 +18,29 @@
#include "base/logging.h"
#include "starboard/common/log.h"
#include "starboard/configuration.h"
-
-// Defining COBALT_EGL_AND_GLES_LOGGING enables a greater amount of logging and
-// error reporting with EGL and GLES calls throughout Cobalt. Each invoked
-// function will be logged, and when checks are failed the EGL or GLES error
-// code will be outputted.
-#undef COBALT_EGL_AND_GLES_LOGGING
-
#include "starboard/egl.h"
#include "starboard/gles.h"
+
#define EGL_CALL_PREFIX ::cobalt::renderer::CobaltGetEglInterface().
#define GL_CALL_PREFIX ::cobalt::renderer::CobaltGetGlesInterface().
-#if defined(COBALT_EGL_AND_GLES_LOGGING)
-#define EGL_DCHECK_MAYBE_LOG(x) SB_LOG(INFO) << #x;
-#define GL_DCHECK_MAYBE_LOG(x) SB_LOG(INFO) << #x;
-#else // !defined(COBALT_EGL_AND_GLES_LOGGING)
-#define EGL_DCHECK_MAYBE_LOG(x)
-#define GL_DCHECK_MAYBE_LOG(x)
-#endif // defined(COBALT_EGL_AND_GLES_LOGGING)
-
+#if SB_DCHECK_ENABLED
#define EGL_DCHECK(x) \
do { \
- EGL_DCHECK_MAYBE_LOG(x); \
const int32_t COBALT_EGL_ERRNO = (EGL_CALL_PREFIX eglGetError()); \
SB_DCHECK(COBALT_EGL_ERRNO == EGL_SUCCESS) \
<< #x << " exited with code: " << COBALT_EGL_ERRNO; \
} while (false)
#define GL_DCHECK(x) \
do { \
- GL_DCHECK_MAYBE_LOG(x); \
const int32_t COBALT_GL_ERRNO = (GL_CALL_PREFIX glGetError()); \
SB_DCHECK(COBALT_GL_ERRNO == GL_NO_ERROR) \
<< #x << " exited with code: " << COBALT_GL_ERRNO; \
} while (false)
+#else
+#define EGL_DCHECK(x)
+#define GL_DCHECK(x)
+#endif // SB_DCHECK_ENABLED
namespace cobalt {
namespace renderer {
@@ -92,21 +81,8 @@
GL_DCHECK(x); \
} while (false)
-#if defined(COBALT_EGL_AND_GLES_LOGGING)
-#define EGL_CALL_SIMPLE(x) \
- ([&]() { \
- SB_LOG(INFO) << #x; \
- return EGL_CALL_PREFIX x; \
- }())
-#define GL_CALL_SIMPLE(x) \
- ([&]() { \
- SB_LOG(INFO) << #x; \
- return GL_CALL_PREFIX x; \
- }())
-#else // !defined(COBALT_EGL_AND_GLES_LOGGING)
#define EGL_CALL_SIMPLE(x) (EGL_CALL_PREFIX x)
#define GL_CALL_SIMPLE(x) (GL_CALL_PREFIX x)
-#endif // defined(COBALT_EGL_AND_GLES_LOGGING)
// EGL TYPES
#define EGLint SbEglInt32
diff --git a/src/cobalt/updater/configurator.cc b/src/cobalt/updater/configurator.cc
index b14e2d1..ec7b09d 100644
--- a/src/cobalt/updater/configurator.cc
+++ b/src/cobalt/updater/configurator.cc
@@ -7,7 +7,9 @@
#include <set>
#include <utility>
+#include "base/command_line.h"
#include "base/version.h"
+#include "cobalt/browser/switches.h"
#include "cobalt/script/javascript_engine.h"
#include "cobalt/updater/network_fetcher.h"
#include "cobalt/updater/patcher.h"
@@ -86,7 +88,12 @@
int Configurator::UpdateDelay() const { return 0; }
std::vector<GURL> Configurator::UpdateUrl() const {
- return std::vector<GURL>{GURL(kUpdaterJSONDefaultUrl)};
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ browser::switches::kUseQAUpdateServer)) {
+ return std::vector<GURL>{GURL(kUpdaterJSONDefaultUrlQA)};
+ } else {
+ return std::vector<GURL>{GURL(kUpdaterJSONDefaultUrl)};
+ }
}
std::vector<GURL> Configurator::PingUrl() const { return UpdateUrl(); }
diff --git a/src/cobalt/updater/network_fetcher.cc b/src/cobalt/updater/network_fetcher.cc
index fb7ea98..1dfbc7c 100644
--- a/src/cobalt/updater/network_fetcher.cc
+++ b/src/cobalt/updater/network_fetcher.cc
@@ -129,6 +129,13 @@
url_fetcher_->Start();
}
+void NetworkFetcher::CancelDownloadToFile() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ SB_LOG(INFO) << "Canceling DownloadToFile";
+ url_fetcher_.reset();
+}
+
void NetworkFetcher::OnURLFetchResponseStarted(const net::URLFetcher* source) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
std::move(response_started_callback_)
diff --git a/src/cobalt/updater/network_fetcher.h b/src/cobalt/updater/network_fetcher.h
index 1ff2675..17b8909 100644
--- a/src/cobalt/updater/network_fetcher.h
+++ b/src/cobalt/updater/network_fetcher.h
@@ -69,6 +69,7 @@
ProgressCallback progress_callback,
DownloadToFileCompleteCallback
download_to_file_complete_callback) override;
+ void CancelDownloadToFile() override;
// net::URLFetcherDelegate interface.
void OnURLFetchResponseStarted(const net::URLFetcher* source) override;
diff --git a/src/cobalt/updater/updater_constants.h b/src/cobalt/updater/updater_constants.h
index aaaf48c..99f5759 100644
--- a/src/cobalt/updater/updater_constants.h
+++ b/src/cobalt/updater/updater_constants.h
@@ -47,8 +47,10 @@
// URLs.
//
-// Omaha server end point.
+// Update server end point (prod).
extern const char kUpdaterJSONDefaultUrl[];
+// Update server end point (qa).
+extern const char kUpdaterJSONDefaultUrlQA[];
// The URL where crash reports are uploaded.
extern const char kCrashUploadURL[];
diff --git a/src/cobalt/updater/updater_module.cc b/src/cobalt/updater/updater_module.cc
index 8f5663f..3941cb6 100644
--- a/src/cobalt/updater/updater_module.cc
+++ b/src/cobalt/updater/updater_module.cc
@@ -174,6 +174,7 @@
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
update_client_->RemoveObserver(updater_observer_.get());
updater_observer_.reset();
+ update_client_->Stop();
update_client_ = nullptr;
if (updater_configurator_ != nullptr) {
diff --git a/src/cobalt/webdriver/keyboard.cc b/src/cobalt/webdriver/keyboard.cc
index b65672a..59331ac 100644
--- a/src/cobalt/webdriver/keyboard.cc
+++ b/src/cobalt/webdriver/keyboard.cc
@@ -171,17 +171,21 @@
kSpecialKey_MediaPrevTrack,
kSpecialKey_MediaStop,
kSpecialKey_MediaPlayPause,
- kLastAdditionalSpecialKey = kSpecialKey_MediaPlayPause,
+ kSpecialKey_MediaRewind,
+ kSpecialKey_MediaFastForward,
+ kLastAdditionalSpecialKey = kSpecialKey_MediaFastForward,
};
// Mapping from an additional special keycode to virtual keycode. Subtract
// kFirstAdditionalSpecialKey from the integer value of the WebDriver keycode
// and index into this table.
const int32 additional_special_keycode_mapping[] = {
- dom::keycode::kMediaNextTrack, // kSpecialKey_MediaNextTrack,
- dom::keycode::kMediaPrevTrack, // kSpecialKey_MediaPrevTrack,
- dom::keycode::kMediaStop, // kSpecialKey_MediaStop,
- dom::keycode::kMediaPlayPause, // kSpecialKey_MediaPlayPause,
+ dom::keycode::kMediaNextTrack, // kMediaNextTrack,
+ dom::keycode::kMediaPrevTrack, // kMediaPrevTrack,
+ dom::keycode::kMediaStop, // kMediaStop,
+ dom::keycode::kMediaPlayPause, // kMediaPlayPause,
+ dom::keycode::kMediaRewind, // kMediaRewind,
+ dom::keycode::kMediaFastForward, // kMediaFastForward,
};
// Check that the mapping is the expected size.
diff --git a/src/components/update_client/component.cc b/src/components/update_client/component.cc
index 787ec2e..421dc40 100644
--- a/src/components/update_client/component.cc
+++ b/src/components/update_client/component.cc
@@ -300,6 +300,13 @@
base::BindOnce(&Component::ChangeState, base::Unretained(this)));
}
+#if defined(STARBOARD)
+void Component::Cancel() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ state_->Cancel();
+}
+#endif
+
void Component::ChangeState(std::unique_ptr<State> next_state) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -532,6 +539,14 @@
DoHandle();
}
+#if defined(STARBOARD)
+void Component::State::Cancel() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // Further work may be needed to ensure cancelation during any state results
+ // in a clear result and no memory leaks.
+}
+#endif
+
void Component::State::TransitionState(std::unique_ptr<State> next_state) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(next_state);
@@ -726,6 +741,13 @@
DCHECK(thread_checker_.CalledOnValidThread());
}
+#if defined(STARBOARD)
+void Component::StateDownloadingDiff::Cancel() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ crx_downloader_->CancelDownload();
+}
+#endif
+
void Component::StateDownloadingDiff::DoHandle() {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -800,6 +822,13 @@
DCHECK(thread_checker_.CalledOnValidThread());
}
+#if defined(STARBOARD)
+void Component::StateDownloading::Cancel() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ crx_downloader_->CancelDownload();
+}
+#endif
+
void Component::StateDownloading::DoHandle() {
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/src/components/update_client/component.h b/src/components/update_client/component.h
index 4058985..f6cc035 100644
--- a/src/components/update_client/component.h
+++ b/src/components/update_client/component.h
@@ -55,6 +55,12 @@
// to the next component state before |callback_handle_complete_| is invoked.
void Handle(CallbackHandleComplete callback_handle_complete);
+#if defined(STARBOARD)
+ // Stops update progress for the component and may clean resources used in its
+ // current state.
+ void Cancel();
+#endif
+
CrxUpdateItem GetCrxUpdateItem() const;
// Sets the uninstall state for this component.
@@ -156,6 +162,11 @@
// by the outer component, after the current state is fully handled.
void Handle(CallbackNextState callback);
+#if defined(STARBOARD)
+ // Stops update progress and may clean resources used in the current state.
+ virtual void Cancel();
+#endif
+
ComponentState state() const { return state_; }
protected:
@@ -247,6 +258,9 @@
public:
explicit StateDownloadingDiff(Component* component);
~StateDownloadingDiff() override;
+#if defined(STARBOARD)
+ void Cancel() override;
+#endif
private:
// State overrides.
@@ -270,6 +284,9 @@
public:
explicit StateDownloading(Component* component);
~StateDownloading() override;
+#if defined(STARBOARD)
+ void Cancel() override;
+#endif
private:
// State overrides.
diff --git a/src/components/update_client/crx_downloader.cc b/src/components/update_client/crx_downloader.cc
index fe83b57..8f2bffa 100644
--- a/src/components/update_client/crx_downloader.cc
+++ b/src/components/update_client/crx_downloader.cc
@@ -120,6 +120,12 @@
DoStartDownload(*current_url_);
}
+#if defined(STARBOARD)
+void CrxDownloader::CancelDownload() {
+ DoCancelDownload();
+}
+#endif
+
void CrxDownloader::OnDownloadComplete(
bool is_handled,
const Result& result,
diff --git a/src/components/update_client/crx_downloader.h b/src/components/update_client/crx_downloader.h
index 6378d03..ae19a4a 100644
--- a/src/components/update_client/crx_downloader.h
+++ b/src/components/update_client/crx_downloader.h
@@ -122,6 +122,10 @@
const std::string& expected_hash,
DownloadCallback download_callback);
+#if defined(STARBOARD)
+ void CancelDownload();
+#endif
+
const std::vector<DownloadMetrics> download_metrics() const;
protected:
@@ -151,6 +155,9 @@
private:
virtual void DoStartDownload(const GURL& url) = 0;
+#if defined(STARBOARD)
+ virtual void DoCancelDownload() = 0;
+#endif
void VerifyResponse(bool is_handled,
Result result,
diff --git a/src/components/update_client/network.h b/src/components/update_client/network.h
index daed162..dec108f 100644
--- a/src/components/update_client/network.h
+++ b/src/components/update_client/network.h
@@ -63,6 +63,9 @@
ResponseStartedCallback response_started_callback,
ProgressCallback progress_callback,
DownloadToFileCompleteCallback download_to_file_complete_callback) = 0;
+#if defined(STARBOARD)
+ virtual void CancelDownloadToFile() = 0;
+#endif
protected:
NetworkFetcher() = default;
diff --git a/src/components/update_client/task_update.cc b/src/components/update_client/task_update.cc
index ab445b5..0129e4c 100644
--- a/src/components/update_client/task_update.cc
+++ b/src/components/update_client/task_update.cc
@@ -36,13 +36,25 @@
return;
}
+#if defined(STARBOARD)
+ update_engine_->Update(is_foreground_, ids_, std::move(crx_data_callback_),
+ base::BindOnce(&TaskUpdate::TaskComplete, this),
+ cancelation_closure_);
+#else
update_engine_->Update(is_foreground_, ids_, std::move(crx_data_callback_),
base::BindOnce(&TaskUpdate::TaskComplete, this));
+#endif
}
void TaskUpdate::Cancel() {
DCHECK(thread_checker_.CalledOnValidThread());
+#if defined(STARBOARD)
+ if (cancelation_closure_) { // The engine's picked up the task.
+ std::move(cancelation_closure_).Run();
+ }
+#endif
+
TaskComplete(Error::UPDATE_CANCELED);
}
diff --git a/src/components/update_client/task_update.h b/src/components/update_client/task_update.h
index 4df796b..74c0a6a 100644
--- a/src/components/update_client/task_update.h
+++ b/src/components/update_client/task_update.h
@@ -57,6 +57,9 @@
const std::vector<std::string> ids_;
UpdateClient::CrxDataCallback crx_data_callback_;
Callback callback_;
+#if defined(STARBOARD)
+ base::OnceClosure cancelation_closure_;
+#endif
DISALLOW_COPY_AND_ASSIGN(TaskUpdate);
};
diff --git a/src/components/update_client/update_client.cc b/src/components/update_client/update_client.cc
index 369c6d3..6ce65bf 100644
--- a/src/components/update_client/update_client.cc
+++ b/src/components/update_client/update_client.cc
@@ -201,6 +201,16 @@
is_stopped_ = true;
+ // Cancel the pending tasks. These tasks are safe to cancel and delete since
+ // they have not picked up by the update engine, and not shared with any
+ // task runner yet.
+ while (!task_queue_.empty()) {
+ auto task = task_queue_.front();
+ task_queue_.pop_front();
+ task->Cancel();
+ }
+
+#if !defined(STARBOARD)
// In the current implementation it is sufficient to cancel the pending
// tasks only. The tasks that are run by the update engine will stop
// making progress naturally, as the main task runner stops running task
@@ -210,15 +220,15 @@
// area, to cancel the running tasks by canceling the current action update.
// This behavior would be expected, correct, and result in no resource leaks
// in all cases, in shutdown or not.
- //
- // Cancel the pending tasks. These tasks are safe to cancel and delete since
- // they have not picked up by the update engine, and not shared with any
- // task runner yet.
- while (!task_queue_.empty()) {
- auto task = task_queue_.front();
- task_queue_.pop_front();
+#else
+ // For Cobalt it's not sufficient to just let the tasks already picked up by
+ // the update engine stop naturally, as this can result in resource leaks and
+ // crashes. These tasks are also canceled so that any necessary cleanup can be
+ // done.
+ for (auto task : tasks_) {
task->Cancel();
}
+#endif
}
void UpdateClientImpl::SendUninstallPing(const std::string& id,
diff --git a/src/components/update_client/update_engine.cc b/src/components/update_client/update_engine.cc
index a6d6920..29c260b 100644
--- a/src/components/update_client/update_engine.cc
+++ b/src/components/update_client/update_engine.cc
@@ -72,10 +72,19 @@
DCHECK(thread_checker_.CalledOnValidThread());
}
+#if !defined(STARBOARD)
void UpdateEngine::Update(bool is_foreground,
const std::vector<std::string>& ids,
UpdateClient::CrxDataCallback crx_data_callback,
Callback callback) {
+#else
+void UpdateEngine::Update(bool is_foreground,
+ const std::vector<std::string>& ids,
+ UpdateClient::CrxDataCallback crx_data_callback,
+ Callback callback,
+ base::OnceClosure& cancelation_closure) {
+
+#endif
DCHECK(thread_checker_.CalledOnValidThread());
if (ids.empty()) {
@@ -100,6 +109,10 @@
config_, is_foreground, ids, std::move(crx_data_callback),
notify_observers_callback_, std::move(callback), crx_downloader_factory_);
DCHECK(!update_context->session_id.empty());
+#if defined(STARBOARD)
+ cancelation_closure = base::BindOnce(&UpdateEngine::Cancel, this,
+ update_context->session_id, ids);
+#endif
const auto result = update_contexts_.insert(
std::make_pair(update_context->session_id, update_context));
@@ -405,6 +418,17 @@
now < throttle_updates_until_;
}
+#if defined(STARBOARD)
+void UpdateEngine::Cancel(const std::string& update_context_session_id,
+ const std::vector<std::string>& crx_component_ids) {
+ const auto& context = update_contexts_.at(update_context_session_id);
+ for (const auto& crx_component_id : crx_component_ids) {
+ auto& component = context->components.at(crx_component_id);
+ component->Cancel();
+ }
+}
+#endif
+
void UpdateEngine::SendUninstallPing(const std::string& id,
const base::Version& version,
int reason,
diff --git a/src/components/update_client/update_engine.h b/src/components/update_client/update_engine.h
index 9601873..4384fa8 100644
--- a/src/components/update_client/update_engine.h
+++ b/src/components/update_client/update_engine.h
@@ -56,10 +56,20 @@
// is not found.
bool GetUpdateState(const std::string& id, CrxUpdateItem* update_state);
+#if !defined(STARBOARD)
void Update(bool is_foreground,
const std::vector<std::string>& ids,
UpdateClient::CrxDataCallback crx_data_callback,
Callback update_callback);
+#else
+ // |cancelation_closure| is populated with a closure that can be run to cancel
+ // the update requested by the caller.
+ void Update(bool is_foreground,
+ const std::vector<std::string>& ids,
+ UpdateClient::CrxDataCallback crx_data_callback,
+ Callback update_callback,
+ base::OnceClosure& cancelation_closure);
+#endif
void SendUninstallPing(const std::string& id,
const base::Version& version,
@@ -96,6 +106,14 @@
// occurs too soon.
bool IsThrottled(bool is_foreground) const;
+#if defined(STARBOARD)
+ // Cancels updates currently handled by the engine for each component
+ // identified by one of |crx_component_ids| for the update context identified
+ // by the |update_context_session_id|.
+ void Cancel(const std::string& update_context_session_id,
+ const std::vector<std::string>& crx_component_ids);
+#endif
+
base::ThreadChecker thread_checker_;
scoped_refptr<Configurator> config_;
UpdateChecker::Factory update_checker_factory_;
diff --git a/src/components/update_client/url_fetcher_downloader.cc b/src/components/update_client/url_fetcher_downloader.cc
index 83c5727..078c275 100644
--- a/src/components/update_client/url_fetcher_downloader.cc
+++ b/src/components/update_client/url_fetcher_downloader.cc
@@ -144,6 +144,13 @@
#endif
}
+#if defined(STARBOARD)
+void UrlFetcherDownloader::DoCancelDownload() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ network_fetcher_->CancelDownloadToFile();
+}
+#endif
+
void UrlFetcherDownloader::CreateDownloadDir() {
base::CreateNewTempDirectory(FILE_PATH_LITERAL("chrome_url_fetcher_"),
&download_dir_);
diff --git a/src/components/update_client/url_fetcher_downloader.h b/src/components/update_client/url_fetcher_downloader.h
index e5c240d..3880efc 100644
--- a/src/components/update_client/url_fetcher_downloader.h
+++ b/src/components/update_client/url_fetcher_downloader.h
@@ -42,6 +42,9 @@
private:
// Overrides for CrxDownloader.
void DoStartDownload(const GURL& url) override;
+#if defined(STARBOARD)
+ void DoCancelDownload() override;
+#endif
void CreateDownloadDir();
void StartURLFetch(const GURL& url);
diff --git a/src/docker-compose.yml b/src/docker-compose.yml
index 743a169..19374ed 100644
--- a/src/docker-compose.yml
+++ b/src/docker-compose.yml
@@ -167,19 +167,6 @@
USE_CCACHE: ${USE_CCACHE:-1}
NINJA_STATUS: ${NINJA_STATUS}
- linux-x64x11-sbversion12-evergreen:
- <<: *build-common-definitions
- build:
- context: ./docker/linux
- dockerfile: linux-x64x11/Dockerfile
- args:
- - FROM_IMAGE=cobalt-build-evergreen
- image: cobalt-build-linux-x64x11-evergreen
- environment:
- <<: *shared-build-env
- PLATFORM: linux-x64x11-sbversion-12
- CONFIG: ${CONFIG:-debug}
-
# Define common build container for Android
build-android:
<<: *build-common-definitions
@@ -362,6 +349,20 @@
<<: *shared-build-env
PLATFORM: evergreen-arm-softfp-sbversion-12
+ linux-x64x11-sbversion12-evergreen:
+ <<: *build-common-definitions
+ build:
+ context: ./docker/linux
+ dockerfile: linux-x64x11/Dockerfile
+ args:
+ - FROM_IMAGE=cobalt-build-evergreen
+ image: cobalt-build-linux-x64x11-evergreen
+ depends_on: [ build-evergreen ]
+ environment:
+ <<: *shared-build-env
+ PLATFORM: linux-x64x11-sbversion-12
+ CONFIG: ${CONFIG:-debug}
+
unittest:
<<: *common-definitions
build:
diff --git a/src/docker/linux/base/build/Dockerfile b/src/docker/linux/base/build/Dockerfile
index 7b39d75..0de107d 100644
--- a/src/docker/linux/base/build/Dockerfile
+++ b/src/docker/linux/base/build/Dockerfile
@@ -33,10 +33,15 @@
&& echo "Done"
# === Get Nodejs pinned LTS version via NVM
+ARG NVM_SHA256SUM="f068e17dacb88f73302790cc076956c7a0d459ce9b01df842ff3e75744f9e2fe /tmp/install.sh"
+ARG NVM_URL="https://cobalt.googlesource.com/third_party/nvm/+/refs/tags/v0.35.3/install.sh?format=TEXT"
ENV NVM_DIR /root/.nvm
ENV NODE_VERSION 12.17.0
-RUN curl --silent -o- https://raw.githubusercontent.com/creationix/nvm/v0.35.3/install.sh | bash
+RUN curl --silent -o- ${NVM_URL} \
+ | base64 -d > /tmp/install.sh \
+ && echo ${NVM_SHA256SUM} | sha256sum --check \
+ && . /tmp/install.sh
RUN . $NVM_DIR/nvm.sh \
&& nvm install --lts \
diff --git a/src/nb/nb_test.gyp b/src/nb/nb_test.gyp
index 5520709..2d5b937 100644
--- a/src/nb/nb_test.gyp
+++ b/src/nb/nb_test.gyp
@@ -80,6 +80,7 @@
'variables': {
'executable_name': 'reuse_allocator_benchmark',
},
+ 'includes': [ '<(DEPTH)/starboard/build/deploy.gypi' ],
},
{
diff --git a/src/starboard/android/apk/app/CMakeLists.txt b/src/starboard/android/apk/app/CMakeLists.txt
index 2ac5b87..b3f36b7 100644
--- a/src/starboard/android/apk/app/CMakeLists.txt
+++ b/src/starboard/android/apk/app/CMakeLists.txt
@@ -47,9 +47,9 @@
endif()
# If COBALT_LIBRARY_DIR isn't set for a particular deploy target use the
-# base product directory.
+# toplevel lib/ subdirectory.
if(NOT COBALT_LIBRARY_DIR)
- set(COBALT_LIBRARY_DIR COBALT_PRODUCT_DIR)
+ set(COBALT_LIBRARY_DIR ${COBALT_PRODUCT_DIR}/lib)
endif()
# For platform deploy builds, use the -n parameter to skip Cobalt ninja and
diff --git a/src/starboard/android/apk/app/build.gradle b/src/starboard/android/apk/app/build.gradle
index 7cdb4f1..944dcbd 100644
--- a/src/starboard/android/apk/app/build.gradle
+++ b/src/starboard/android/apk/app/build.gradle
@@ -30,7 +30,8 @@
project.hasProperty('cobaltProductDir') ? new File(cobaltProductDir).canonicalPath : ''
cobaltContentDir =
project.hasProperty('cobaltContentDir') ? new File(cobaltContentDir).canonicalPath : ''
- cobaltLibraryDir = project.hasProperty('cobaltLibraryDir') ? cobaltLibraryDir : cobaltProductDir
+ cobaltLibraryDir =
+ project.hasProperty('cobaltLibraryDir') ? new File(cobaltLibraryDir).canonicalPath : ''
enableVulkan =
project.hasProperty('enableVulkan') ? enableVulkan : 0
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java
index 22f7e05..d9082da 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java
@@ -33,6 +33,7 @@
import dev.cobalt.util.DisplayUtil;
import dev.cobalt.util.Log;
import dev.cobalt.util.UsedByNative;
+import java.security.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -65,10 +66,15 @@
private boolean forceCreateNewVideoSurfaceView = false;
+ private long timeInNanoseconds;
+
private static native void nativeLowMemoryEvent();
@Override
protected void onCreate(Bundle savedInstanceState) {
+ // Record the application start timestamp.
+ timeInNanoseconds = System.nanoTime();
+
// To ensure that volume controls adjust the correct stream, make this call
// early in the app's lifecycle. This connects the volume controls to
// STREAM_MUSIC whenever the target activity or fragment is visible.
@@ -341,4 +347,8 @@
super.onLowMemory();
nativeLowMemoryEvent();
}
+
+ public long getAppStartTimestamp() {
+ return timeInNanoseconds;
+ }
}
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/MediaPlaybackService.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/MediaPlaybackService.java
index 43227de..16518da 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/MediaPlaybackService.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/MediaPlaybackService.java
@@ -32,10 +32,9 @@
public class MediaPlaybackService extends Service {
- private static final int NOTIFICATION_ID = 1234;
- private static final String NOTIFICATION_CHANNEL_ID = "default";
- private static final String NOTIFICATION_CHANNEL_NAME = "Default channel";
- private Context context;
+ private static final int NOTIFICATION_ID = 193266736; // CL number for uniqueness.
+ private static final String NOTIFICATION_CHANNEL_ID = "dev.cobalt.coat media playback service";
+ private static final String NOTIFICATION_CHANNEL_NAME = "Media playback service";
@Override
public void onCreate() {
@@ -46,7 +45,6 @@
return;
}
getStarboardBridge().onServiceStart(this);
- context = getApplicationContext();
}
@Override
@@ -70,7 +68,6 @@
return;
}
getStarboardBridge().onServiceDestroy(this);
- context = null;
super.onDestroy();
Log.i(TAG, "Destroying the Media playback service.");
}
@@ -81,16 +78,18 @@
}
public void stopService() {
+ // Do not remove notification here.
+ stopForeground(false);
+ stopSelf();
+ // Delete notification after foreground stopped.
deleteChannel();
hideNotification();
- stopForeground(true);
- stopSelf();
}
private void hideNotification() {
Log.i(TAG, "Hiding notification after stopped the service");
NotificationManager notificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFICATION_ID);
}
@@ -103,7 +102,7 @@
@RequiresApi(26)
private void createChannelInternalV26() {
NotificationManager notificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel =
new NotificationChannel(
NOTIFICATION_CHANNEL_ID,
@@ -113,7 +112,7 @@
try {
notificationManager.createNotificationChannel(channel);
} catch (IllegalArgumentException e) {
-
+ // intentional empty.
}
}
@@ -126,13 +125,13 @@
@RequiresApi(26)
private void deleteChannelInternalV26() {
NotificationManager notificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
}
Notification buildNotification() {
NotificationCompat.Builder builder =
- new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
+ new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setShowWhen(false)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setSmallIcon(android.R.drawable.stat_sys_warning)
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
index 495b761..455f47b 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
@@ -94,6 +94,8 @@
private final HashMap<String, CobaltService.Factory> cobaltServiceFactories = new HashMap<>();
private final HashMap<String, CobaltService> cobaltServices = new HashMap<>();
+ private final long timeNanosecondsPerMicrosecond = 1000;
+
public StarboardBridge(
Context appContext,
Holder<Activity> activityHolder,
@@ -123,6 +125,8 @@
private native boolean nativeInitialize();
+ private native long nativeSbTimeGetMonotonicNow();
+
protected void onActivityStart(Activity activity, KeyboardEditor keyboardEditor) {
activityHolder.set(activity);
this.keyboardEditor = keyboardEditor;
@@ -167,6 +171,10 @@
protected void startMediaPlaybackService() {
Service service = serviceHolder.get();
if (service == null) {
+ if (appContext == null) {
+ Log.w(TAG, "Activiy already destoryed.");
+ return;
+ }
Log.i(TAG, "Cold start - Instantiating a MediaPlaybackService.");
Intent intent = new Intent(appContext, MediaPlaybackService.class);
appContext.startService(intent);
@@ -673,4 +681,21 @@
void closeCobaltService(String serviceName) {
cobaltServices.remove(serviceName);
}
+
+ /**
+ * Returns the application start timestamp.
+ */
+ @SuppressWarnings("unused")
+ @UsedByNative
+ protected long getAppStartTimestamp() {
+ Activity activity = activityHolder.get();
+ if (activity instanceof CobaltActivity) {
+ long javaStartTimestamp = ((CobaltActivity) activity).getAppStartTimestamp();
+ long cppTimestamp = nativeSbTimeGetMonotonicNow();
+ long javaStopTimestamp = System.nanoTime();
+ return cppTimestamp -
+ (javaStartTimestamp - javaStopTimestamp) / timeNanosecondsPerMicrosecond;
+ }
+ return 0;
+ }
}
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioOutputManager.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioOutputManager.java
index 71009ed..0e1d66b 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioOutputManager.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioOutputManager.java
@@ -17,6 +17,7 @@
import static dev.cobalt.media.Log.TAG;
import android.content.Context;
+import android.media.AudioAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioManager;
@@ -122,7 +123,7 @@
/** Convert AudioDeviceInfo.TYPE_* to name in String */
@RequiresApi(23)
- private static String getDeviceTypeName(int device_type) {
+ private static String getDeviceTypeNameV23(int device_type) {
switch (device_type) {
case AudioDeviceInfo.TYPE_AUX_LINE:
return "TYPE_AUX_LINE";
@@ -240,7 +241,7 @@
TAG,
String.format(
" Audio Device: %s, channels: %s, sample rates: %s, encodings: %s",
- getDeviceTypeName(info.getType()),
+ getDeviceTypeNameV23(info.getType()),
Arrays.toString(info.getChannelCounts()),
Arrays.toString(info.getSampleRates()),
getEncodingNames(info.getEncodings())));
@@ -292,4 +293,140 @@
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
return audioManager.generateAudioSessionId();
}
+
+ /** Returns whether passthrough on `encoding` is supported. */
+ @SuppressWarnings("unused")
+ @UsedByNative
+ boolean hasPassthroughSupportFor(int encoding) {
+ if (Build.VERSION.SDK_INT < 23) {
+ Log.i(
+ TAG,
+ String.format(
+ "Passthrough on encoding %d is rejected on api %d, as passthrough is only"
+ + " supported on api 23 or later.",
+ encoding, Build.VERSION.SDK_INT));
+ return false;
+ }
+ if (hasPassthroughSupportForV23(encoding)) {
+ Log.i(
+ TAG,
+ String.format(
+ "Passthrough on encoding %d is supported, as hasPassthroughSupportForV23() returns"
+ + " true.",
+ encoding));
+ return true;
+ }
+ if (Build.VERSION.SDK_INT < 29) {
+ Log.i(
+ TAG,
+ String.format(
+ "Passthrough on encoding %d is rejected, as"
+ + " hasDirectSurroundingPlaybackSupportForV29() is not called for api %d.",
+ encoding, Build.VERSION.SDK_INT));
+ return false;
+ }
+ if (hasDirectSurroundingPlaybackSupportForV29(encoding)) {
+ Log.i(
+ TAG,
+ String.format(
+ "Passthrough on encoding %d is supported, as"
+ + " hasDirectSurroundingPlaybackSupportForV29() returns true.",
+ encoding));
+ return true;
+ }
+
+ Log.i(
+ TAG,
+ String.format(
+ "Passthrough on encoding %d is not supported, as"
+ + " hasDirectSurroundingPlaybackSupportForV29() returns false.",
+ encoding));
+ return false;
+ }
+
+ /** Returns whether passthrough on `encoding` is supported for API 23 and above. */
+ @RequiresApi(23)
+ private boolean hasPassthroughSupportForV23(int encoding) {
+ AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ AudioDeviceInfo[] deviceInfos = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+
+ // TODO: Verify the follow code returns false if non-surrounding BT device is routed.
+ for (AudioDeviceInfo info : deviceInfos) {
+ final int type = info.getType();
+ if (type != AudioDeviceInfo.TYPE_HDMI && type != AudioDeviceInfo.TYPE_HDMI_ARC) {
+ continue;
+ }
+ // TODO: ExoPlayer uses ACTION_HDMI_AUDIO_PLUG to detect the encodings supported via
+ // passthrough, we should consider using it, and maybe other actions like
+ // ACTION_HEADSET_PLUG for general audio device switch/encoding detection.
+ final int[] encodings = info.getEncodings();
+ if (encodings.length == 0) {
+ // Per https://developer.android.com/reference/android/media/AudioDeviceInfo#getEncodings()
+ // an empty array indicates that the device supports arbitrary encodings.
+ Log.i(
+ TAG,
+ String.format(
+ "Passthrough on encoding %d is supported on %s, because getEncodings() returns"
+ + " an empty array.",
+ encoding, getDeviceTypeNameV23(type)));
+ return true;
+ }
+ for (int i = 0; i < encodings.length; ++i) {
+ if (encodings[i] == encoding) {
+ Log.i(
+ TAG,
+ String.format(
+ "Passthrough on encoding %d is supported on %s.",
+ encoding, getDeviceTypeNameV23(type)));
+ return true;
+ }
+ }
+ Log.i(
+ TAG,
+ String.format(
+ "Passthrough on encoding %d is not supported on %s.",
+ encoding, getDeviceTypeNameV23(type)));
+ }
+ Log.i(
+ TAG,
+ String.format("Passthrough on encoding %d is not supported on any devices.", encoding));
+ return false;
+ }
+
+ @RequiresApi(29)
+ /**
+ * Returns whether direct playback on surrounding `encoding` is supported for API 29 and above.
+ */
+ private boolean hasDirectSurroundingPlaybackSupportForV29(int encoding) {
+ if (encoding != AudioFormat.ENCODING_AC3
+ && encoding != AudioFormat.ENCODING_E_AC3
+ && encoding != AudioFormat.ENCODING_E_AC3_JOC) {
+ Log.w(
+ TAG,
+ String.format(
+ "hasDirectSurroundingPlaybackSupportForV29() encountered unsupported encoding %d.",
+ encoding));
+ return false;
+ }
+
+ // Sample rate is not provided when the function is called, assume it is 48000.
+ final int DEFAULT_SURROUNDING_SAMPLE_RATE = 48000;
+ AudioFormat format =
+ new AudioFormat.Builder()
+ .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1)
+ .setEncoding(encoding)
+ .setSampleRate(DEFAULT_SURROUNDING_SAMPLE_RATE)
+ .build();
+ AudioAttributes attributes =
+ new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_MEDIA)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MOVIE)
+ .build();
+ final boolean supported = AudioTrack.isDirectPlaybackSupported(format, attributes);
+ Log.i(
+ TAG,
+ String.format(
+ "isDirectPlaybackSupported() for encoding %d returned %b.", encoding, supported));
+ return supported;
+ }
}
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java
index ac387f5..7441984 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java
@@ -63,10 +63,11 @@
return 4;
case AudioFormat.ENCODING_INVALID:
default:
- throw new RuntimeException("Unsupport audio format " + audioFormat);
+ throw new RuntimeException("Unsupported audio format " + audioFormat);
}
}
+ // TODO: Pass error details to caller.
public AudioTrackBridge(
int sampleType,
int sampleRate,
@@ -119,11 +120,18 @@
.setUsage(AudioAttributes.USAGE_MEDIA)
.build();
} else {
- // TODO: Investigate if we can use |CONTENT_TYPE_MOVIE| for AudioTrack
- // used by video playback.
+ // TODO: Support ENCODING_E_AC3_JOC for api level 28 or later.
+ final boolean is_surrounding =
+ sampleType == AudioFormat.ENCODING_AC3 || sampleType == AudioFormat.ENCODING_E_AC3;
+ // TODO: We start to enforce |CONTENT_TYPE_MOVIE| for surrounding playback, investigate if we
+ // can use |CONTENT_TYPE_MOVIE| for all non-surrounding AudioTrack used by video
+ // playback.
attributes =
new AudioAttributes.Builder()
- .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
+ .setContentType(
+ is_surrounding
+ ? AudioAttributes.CONTENT_TYPE_MOVIE
+ : AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build();
}
@@ -243,14 +251,29 @@
@SuppressWarnings("unused")
@UsedByNative
+ private void stop() {
+ if (audioTrack == null) {
+ Log.e(TAG, "Unable to stop with NULL audio track.");
+ return;
+ }
+ audioTrack.stop();
+ }
+
+ @SuppressWarnings("unused")
+ @UsedByNative
private void flush() {
if (audioTrack == null) {
Log.e(TAG, "Unable to flush with NULL audio track.");
return;
}
audioTrack.flush();
+ // Reset the states to allow reuse of |audioTrack| after flush() is called. This can reduce
+ // switch latency for passthrough playbacks.
avSyncHeader = null;
avSyncPacketBytesRemaining = 0;
+ synchronized (this) {
+ maxFramePositionSoFar = 0;
+ }
}
@SuppressWarnings("unused")
@@ -355,25 +378,30 @@
Log.e(TAG, "Unable to getAudioTimestamp with NULL audio track.");
return audioTimestamp;
}
- if (audioTrack.getTimestamp(audioTimestamp)) {
- // This conversion is safe, as only the lower bits will be set, since we
- // called |getTimestamp| without a timebase.
- // https://developer.android.com/reference/android/media/AudioTimestamp.html#framePosition
- audioTimestamp.framePosition &= 0x7FFFFFFF;
- } else {
- // Time stamps haven't been updated yet, assume playback hasn't started.
- audioTimestamp.framePosition = 0;
- audioTimestamp.nanoTime = System.nanoTime();
- }
+ // The `synchronized` is required as `maxFramePositionSoFar` can also be modified in flush().
+ // TODO: Consider refactor the code to remove the dependency on `synchronized`.
+ synchronized (this) {
+ if (audioTrack.getTimestamp(audioTimestamp)) {
+ // This conversion is safe, as only the lower bits will be set, since we
+ // called |getTimestamp| without a timebase.
+ // https://developer.android.com/reference/android/media/AudioTimestamp.html#framePosition
+ audioTimestamp.framePosition &= 0x7FFFFFFF;
+ } else {
+ // Time stamps haven't been updated yet, assume playback hasn't started.
+ audioTimestamp.framePosition = 0;
+ audioTimestamp.nanoTime = System.nanoTime();
+ }
- // TODO: This is required for correctness of the audio sink, because
- // otherwise we would be going back in time. Investigate the impact it has
- // on playback. All empirical measurements so far suggest that it should
- // be negligible.
- if (audioTimestamp.framePosition < maxFramePositionSoFar) {
- audioTimestamp.framePosition = maxFramePositionSoFar;
+ if (audioTimestamp.framePosition > maxFramePositionSoFar) {
+ maxFramePositionSoFar = audioTimestamp.framePosition;
+ } else {
+ // The returned |audioTimestamp.framePosition| is not monotonically
+ // increasing, and a monotonically increastion frame position is
+ // required to calculate the playback time correctly, because otherwise
+ // we would be going back in time.
+ audioTimestamp.framePosition = maxFramePositionSoFar;
+ }
}
- maxFramePositionSoFar = audioTimestamp.framePosition;
return audioTimestamp;
}
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
index 4bf638b..0ca198c 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
@@ -33,6 +33,7 @@
import dev.cobalt.util.Log;
import dev.cobalt.util.UsedByNative;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
/** A wrapper of the MediaCodec class. */
@SuppressWarnings("unused")
@@ -364,9 +365,7 @@
// This logic is inspired by
// https://github.com/google/ExoPlayer/blob/deb9b301b2c7ef66fdd7d8a3e58298a79ba9c619/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java#L1803.
- byte[] hdrStaticInfoData = new byte[25];
- ByteBuffer hdrStaticInfo = ByteBuffer.wrap(hdrStaticInfoData);
-
+ ByteBuffer hdrStaticInfo = ByteBuffer.allocateDirect(25).order(ByteOrder.LITTLE_ENDIAN);
hdrStaticInfo.put((byte) 0);
hdrStaticInfo.putShort((short) ((primaryRChromaticityX * MAX_CHROMATICITY) + 0.5f));
hdrStaticInfo.putShort((short) ((primaryRChromaticityY * MAX_CHROMATICITY) + 0.5f));
diff --git a/src/starboard/android/shared/BUILD.gn b/src/starboard/android/shared/BUILD.gn
index 76af15f..66628a2 100644
--- a/src/starboard/android/shared/BUILD.gn
+++ b/src/starboard/android/shared/BUILD.gn
@@ -14,12 +14,6 @@
import("//starboard/shared/starboard/player/buildfiles.gni")
-declare_args() {
- has_input_events_filter = false
-
- has_drm_system_extension = false
-}
-
config("starboard_platform_config") {
include_dirs = [ "bionic" ]
}
@@ -431,16 +425,6 @@
"//starboard/shared/starboard/player/player_set_playback_rate.cc",
]
- if (has_drm_system_extension) {
- # TODO(andrewsavage)
- } else {
- sources += [
- "drm_create_system.cc",
- "media_is_supported.cc",
- "player_components_factory.cc",
- ]
- }
-
configs += [
":starboard_platform_config",
"//starboard/build/config:starboard_implementation",
@@ -458,6 +442,21 @@
"//third_party/libevent",
"//third_party/opus",
]
+
+ if (is_internal_build) {
+ sources += [
+ "input_events_filter.cc",
+ "input_events_filter.h",
+ ]
+ defines = [ "STARBOARD_INPUT_EVENTS_FILTER" ]
+ deps += [ "//starboard/android/shared/drm_system_extension" ]
+ } else {
+ sources += [
+ "drm_create_system.cc",
+ "media_is_supported.cc",
+ "player_components_factory.cc",
+ ]
+ }
}
static_library("starboard_base_symbolize") {
diff --git a/src/starboard/android/shared/application_android.cc b/src/starboard/android/shared/application_android.cc
index 2c4cda0..598bed7 100644
--- a/src/starboard/android/shared/application_android.cc
+++ b/src/starboard/android/shared/application_android.cc
@@ -259,9 +259,18 @@
// This is the initial launch, so we have to start Cobalt now that we
// have a window.
env->CallStarboardVoidMethodOrAbort("beforeStartOrResume", "()V");
+#if SB_API_VERSION >= 13
+ DispatchStart(GetAppStartTimestamp());
+#else // SB_API_VERSION >= 13
DispatchStart();
+#endif // SB_API_VERSION >= 13
} else if (state() == kStateConcealed || state() == kStateFrozen) {
+#if SB_API_VERSION >= 13
+ DispatchAndDelete(new Event(kSbEventTypeReveal, SbTimeGetMonotonicNow(),
+ NULL, NULL));
+#else // SB_API_VERSION >= 13
DispatchAndDelete(new Event(kSbEventTypeReveal, NULL, NULL));
+#endif // SB_API_VERSION >= 13
} else {
// Now that we got a window back, change the command for the switch
// below to sync up with the current activity lifecycle.
@@ -280,7 +289,12 @@
// Cobalt can't keep running without a window, even if the Activity
// hasn't stopped yet. DispatchAndDelete() will inject events as needed
// if we're not already paused.
+#if SB_API_VERSION >= 13
+ DispatchAndDelete(new Event(kSbEventTypeConceal, SbTimeGetMonotonicNow(),
+ NULL, NULL));
+#else // SB_API_VERSION >= 13
DispatchAndDelete(new Event(kSbEventTypeConceal, NULL, NULL));
+#endif // SB_API_VERSION >= 13
if (window_) {
window_->native_window = NULL;
}
@@ -334,7 +348,12 @@
SbMemoryDeallocate(static_cast<void*>(deep_link));
} else {
SB_LOG(INFO) << "ApplicationAndroid Inject: kSbEventTypeLink";
+#if SB_API_VERSION >= 13
+ Inject(new Event(kSbEventTypeLink, SbTimeGetMonotonicNow(),
+ deep_link, SbMemoryDeallocate));
+#else // SB_API_VERSION >= 13
Inject(new Event(kSbEventTypeLink, deep_link, SbMemoryDeallocate));
+#endif // SB_API_VERSION >= 13
}
}
break;
@@ -342,6 +361,35 @@
// If there's a window, sync the app state to the Activity lifecycle, letting
// DispatchAndDelete() inject events as needed if we missed a state.
+#if SB_API_VERSION >= 13
+if (native_window_) {
+ switch (sync_state) {
+ case AndroidCommand::kStart:
+ DispatchAndDelete(new Event(kSbEventTypeReveal, SbTimeGetMonotonicNow(),
+ NULL, NULL));
+ break;
+ case AndroidCommand::kResume:
+ DispatchAndDelete(new Event(kSbEventTypeFocus, SbTimeGetMonotonicNow(),
+ NULL, NULL));
+ break;
+ case AndroidCommand::kPause:
+ DispatchAndDelete(new Event(kSbEventTypeBlur, SbTimeGetMonotonicNow(),
+ NULL, NULL));
+ break;
+ case AndroidCommand::kStop:
+ if (state() != kStateConcealed && state() != kStateFrozen) {
+ // We usually conceal when losing the window above, but if the window
+ // wasn't destroyed (e.g. when Daydream starts) then we still have to
+ // conceal when the Activity is stopped.
+ DispatchAndDelete(new Event(kSbEventTypeConceal, SbTimeGetMonotonicNow(),
+ NULL, NULL));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+#else // SB_API_VERSION >= 13
if (native_window_) {
switch (sync_state) {
case AndroidCommand::kStart:
@@ -365,6 +413,7 @@
break;
}
}
+#endif // SB_API_VERSION >= 13
}
void ApplicationAndroid::SendAndroidCommand(AndroidCommand::CommandType type,
@@ -619,6 +668,22 @@
}
}
+SbTimeMonotonic ApplicationAndroid::GetAppStartTimestamp() {
+ JniEnvExt* env = JniEnvExt::Get();
+ jlong app_start_timestamp =
+ env->CallStarboardLongMethodOrAbort("getAppStartTimestamp",
+ "()J");
+ return app_start_timestamp;
+}
+
+extern "C" SB_EXPORT_PLATFORM jlong
+Java_dev_cobalt_coat_StarboardBridge_nativeSbTimeGetMonotonicNow(
+ JNIEnv* env,
+ jobject jcaller,
+ jboolean online) {
+ return SbTimeGetMonotonicNow();
+}
+
} // namespace shared
} // namespace android
} // namespace starboard
diff --git a/src/starboard/android/shared/application_android.h b/src/starboard/android/shared/application_android.h
index 90ffecd..1c8dde4 100644
--- a/src/starboard/android/shared/application_android.h
+++ b/src/starboard/android/shared/application_android.h
@@ -92,6 +92,7 @@
void SbWindowSendInputEvent(const char* input_text, bool is_composing);
void SendLowMemoryEvent();
void OsNetworkStatusChange(bool became_online);
+ SbTimeMonotonic GetAppStartTimestamp();
protected:
// --- Application overrides ---
diff --git a/src/starboard/android/shared/audio_decoder.h b/src/starboard/android/shared/audio_decoder.h
index 45460f5..8a909fe 100644
--- a/src/starboard/android/shared/audio_decoder.h
+++ b/src/starboard/android/shared/audio_decoder.h
@@ -57,8 +57,8 @@
bool is_valid() const { return media_decoder_ != NULL; }
private:
- // The maximum amount of work that can exist in the union of |EventQueue|,
- // |pending_work| and |decoded_audios_|.
+ // The maximum amount of work that can exist in the union of |decoded_audios_|
+ // and |media_decoder_->GetNumberOfPendingTasks()|.
static const int kMaxPendingWorkSize = 64;
bool InitializeCodec();
diff --git a/src/starboard/android/shared/audio_decoder_passthrough.h b/src/starboard/android/shared/audio_decoder_passthrough.h
new file mode 100644
index 0000000..59b2473
--- /dev/null
+++ b/src/starboard/android/shared/audio_decoder_passthrough.h
@@ -0,0 +1,118 @@
+// Copyright 2021 The Cobalt Authors. 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.
+
+#ifndef STARBOARD_ANDROID_SHARED_AUDIO_DECODER_PASSTHROUGH_H_
+#define STARBOARD_ANDROID_SHARED_AUDIO_DECODER_PASSTHROUGH_H_
+
+#include <queue>
+
+#include "starboard/common/log.h"
+#include "starboard/common/ref_counted.h"
+#include "starboard/media.h"
+#include "starboard/shared/internal_only.h"
+#include "starboard/shared/starboard/player/decoded_audio_internal.h"
+#include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
+#include "starboard/shared/starboard/player/filter/common.h"
+#include "starboard/shared/starboard/player/input_buffer_internal.h"
+#include "starboard/shared/starboard/thread_checker.h"
+#include "starboard/types.h"
+
+namespace starboard {
+namespace android {
+namespace shared {
+
+// This class simply creates a DecodedAudio object from the InputBuffer passed
+// in, without actually decoding the input audio. It can be used in situations
+// (like passthrough playbacks) where an AudioDecoder has to be used, but is
+// expected to not alter the input and pass it to the renderer as is.
+class AudioDecoderPassthrough
+ : public ::starboard::shared::starboard::player::filter::AudioDecoder {
+ public:
+ explicit AudioDecoderPassthrough(int samples_per_second)
+ : samples_per_second_(samples_per_second) {}
+
+ // AudioDecoder methods.
+ void Initialize(const OutputCB& output_cb, const ErrorCB& error_cb) override {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+ SB_DCHECK(!output_cb_);
+ SB_DCHECK(output_cb);
+
+ output_cb_ = output_cb;
+ }
+
+ void Decode(const scoped_refptr<InputBuffer>& input_buffer,
+ const ConsumedCB& consumed_cb) override {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+ SB_DCHECK(input_buffer);
+ SB_DCHECK(consumed_cb);
+ SB_DCHECK(output_cb_);
+
+ // TODO: |decoded_audio| is used as a buffer to store raw, encoded audio
+ // here, which isn't aligned to its intended usage. The code won't
+ // break as its channel is explicitly set to 1, and the ctor of
+ // DecodedAudio doesn't check whether the buffer size is a multiple of
+ // the sample size.
+ // We should revisit this once |DecodedAudio| is used by passthrough
+ // mode on more platforms.
+ const int kChannels = 1;
+ scoped_refptr<DecodedAudio> decoded_audio =
+ new DecodedAudio(kChannels, kSbMediaAudioSampleTypeInt16Deprecated,
+ kSbMediaAudioFrameStorageTypePlanar,
+ input_buffer->timestamp(), input_buffer->size());
+ memcpy(decoded_audio->buffer(), input_buffer->data(), input_buffer->size());
+ decoded_audios_.push(decoded_audio);
+
+ consumed_cb();
+ output_cb_();
+ }
+
+ void WriteEndOfStream() override {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+ SB_DCHECK(output_cb_);
+
+ decoded_audios_.push(new DecodedAudio);
+ output_cb_();
+ }
+
+ scoped_refptr<DecodedAudio> Read(int* samples_per_second) override {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+ SB_DCHECK(samples_per_second);
+ SB_DCHECK(!decoded_audios_.empty());
+
+ *samples_per_second = samples_per_second_;
+
+ auto decoded_audio = decoded_audios_.front();
+ decoded_audios_.pop();
+ return decoded_audio;
+ }
+
+ void Reset() override {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+
+ decoded_audios_ = std::queue<scoped_refptr<DecodedAudio>>(); // Clear
+ }
+
+ private:
+ ::starboard::shared::starboard::ThreadChecker thread_checker_;
+
+ const int samples_per_second_;
+ OutputCB output_cb_;
+ std::queue<scoped_refptr<DecodedAudio>> decoded_audios_;
+};
+
+} // namespace shared
+} // namespace android
+} // namespace starboard
+
+#endif // STARBOARD_ANDROID_SHARED_AUDIO_DECODER_PASSTHROUGH_H_
diff --git a/src/starboard/android/shared/audio_renderer_passthrough.cc b/src/starboard/android/shared/audio_renderer_passthrough.cc
new file mode 100644
index 0000000..4f2820d
--- /dev/null
+++ b/src/starboard/android/shared/audio_renderer_passthrough.cc
@@ -0,0 +1,568 @@
+// Copyright 2021 The Cobalt Authors. 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 "starboard/android/shared/audio_renderer_passthrough.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "starboard/android/shared/audio_decoder_passthrough.h"
+#include "starboard/android/shared/jni_env_ext.h"
+#include "starboard/android/shared/jni_utils.h"
+#include "starboard/memory.h"
+
+namespace starboard {
+namespace android {
+namespace shared {
+namespace {
+
+// Soft limit to ensure that the user of AudioRendererPassthrough won't keep
+// pushing data when there are enough decoded audio buffers.
+constexpr int kMaxDecodedAudios = 64;
+
+constexpr SbTime kAudioTrackUpdateInternal = kSbTimeMillisecond * 5;
+
+constexpr int kPreferredBufferSizeInBytes = 16 * 1024;
+// TODO: Enable audio routing and link it to client side experiment.
+constexpr bool kEnableAudioRouting = false;
+// TODO: Enable passthrough with tunnel mode.
+constexpr int kTunnelModeAudioSessionId = -1;
+
+// C++ rewrite of ExoPlayer function parseAc3SyncframeAudioSampleCount(), it
+// works for AC-3, E-AC-3, and E-AC-3-JOC.
+// The ExoPlayer implementation is based on
+// https://www.etsi.org/deliver/etsi_ts/102300_102399/102366/01.04.01_60/ts_102366v010401p.pdf.
+int ParseAc3SyncframeAudioSampleCount(const uint8_t* buffer, int size) {
+ SB_DCHECK(buffer);
+
+ constexpr int kAudioSamplesPerAudioBlock = 256;
+ // Each syncframe has 6 blocks that provide 256 new audio samples. See
+ // subsection 4.1.
+ constexpr int kAc3SyncFrameAudioSampleCount = 6 * kAudioSamplesPerAudioBlock;
+ // Number of audio blocks per E-AC-3 syncframe, indexed by numblkscod.
+ constexpr int kBlocksPerSyncFrameByNumblkscod[] = {1, 2, 3, 6};
+
+ if (size < 6) {
+ SB_LOG(WARNING) << "Invalid e/ac3 input buffer size " << size;
+ return kAc3SyncFrameAudioSampleCount;
+ }
+
+ // Parse the bitstream ID for AC-3 and E-AC-3 (see subsections 4.3, E.1.2 and
+ // E.1.3.1.6).
+ const bool is_eac3 = ((buffer[5] & 0xF8) >> 3) > 10;
+ if (is_eac3) {
+ int fscod = (buffer[4] & 0xC0) >> 6;
+ int numblkscod = fscod == 0x03 ? 3 : (buffer[4] & 0x30) >> 4;
+ return kBlocksPerSyncFrameByNumblkscod[numblkscod] *
+ kAudioSamplesPerAudioBlock;
+ } else {
+ return kAc3SyncFrameAudioSampleCount;
+ }
+}
+
+} // namespace
+
+AudioRendererPassthrough::AudioRendererPassthrough(
+ const SbMediaAudioSampleInfo& audio_sample_info,
+ SbDrmSystem drm_system)
+ : audio_sample_info_(audio_sample_info) {
+ SB_DCHECK(audio_sample_info_.codec == kSbMediaAudioCodecAc3 ||
+ audio_sample_info_.codec == kSbMediaAudioCodecEac3);
+ if (SbDrmSystemIsValid(drm_system)) {
+ SB_LOG(INFO) << "Creating AudioDecoder as decryptor.";
+ scoped_ptr<AudioDecoder> audio_decoder(new AudioDecoder(
+ audio_sample_info_.codec, audio_sample_info, drm_system));
+ if (audio_decoder->is_valid()) {
+ decoder_.reset(audio_decoder.release());
+ }
+ } else {
+ SB_LOG(INFO) << "Creating AudioDecoderPassthrough.";
+ decoder_.reset(
+ new AudioDecoderPassthrough(audio_sample_info_.samples_per_second));
+ }
+}
+
+AudioRendererPassthrough::~AudioRendererPassthrough() {
+ SB_DCHECK(BelongsToCurrentThread());
+
+ if (is_valid()) {
+ SB_LOG(INFO) << "Force a seek to 0 to reset all states before destructing.";
+ Seek(0);
+ }
+}
+
+void AudioRendererPassthrough::Initialize(const ErrorCB& error_cb,
+ const PrerolledCB& prerolled_cb,
+ const EndedCB& ended_cb) {
+ SB_DCHECK(BelongsToCurrentThread());
+ SB_DCHECK(error_cb);
+ SB_DCHECK(prerolled_cb);
+ SB_DCHECK(ended_cb);
+ SB_DCHECK(!error_cb_);
+ SB_DCHECK(!prerolled_cb_);
+ SB_DCHECK(!ended_cb_);
+ SB_DCHECK(decoder_);
+
+ error_cb_ = error_cb;
+ prerolled_cb_ = prerolled_cb;
+ ended_cb_ = ended_cb;
+
+ decoder_->Initialize(
+ std::bind(&AudioRendererPassthrough::OnDecoderOutput, this), error_cb);
+}
+
+void AudioRendererPassthrough::WriteSample(
+ const scoped_refptr<InputBuffer>& input_buffer) {
+ SB_DCHECK(BelongsToCurrentThread());
+ SB_DCHECK(input_buffer);
+ SB_DCHECK(can_accept_more_data_.load());
+
+ if (!audio_track_thread_) {
+ audio_track_thread_.reset(
+ new JobThread("AudioPassthrough", 0, kSbThreadPriorityHigh));
+ audio_track_thread_->Schedule(std::bind(
+ &AudioRendererPassthrough::CreateAudioTrackAndStartProcessing, this));
+ }
+
+ if (frames_per_input_buffer_ == 0) {
+ frames_per_input_buffer_ = ParseAc3SyncframeAudioSampleCount(
+ input_buffer->data(), input_buffer->size());
+ SB_LOG(INFO) << "Got frames per input buffer " << frames_per_input_buffer_;
+ }
+
+ can_accept_more_data_.store(false);
+
+ decoder_->Decode(
+ input_buffer,
+ std::bind(&AudioRendererPassthrough::OnDecoderConsumed, this));
+}
+
+void AudioRendererPassthrough::WriteEndOfStream() {
+ SB_DCHECK(BelongsToCurrentThread());
+
+ if (end_of_stream_written_) {
+ SB_LOG(INFO) << "WriteEndOfStream() ignored as |end_of_stream_written_| is"
+ << " true.";
+ return;
+ }
+
+ SB_LOG(INFO) << "WriteEndOfStream() called.";
+
+ end_of_stream_written_ = true;
+
+ if (audio_track_thread_) {
+ decoder_->WriteEndOfStream();
+ return;
+ }
+
+ SB_LOG(INFO) << "Audio eos reached without any samples written.";
+ end_of_stream_played_.store(true);
+ ended_cb_();
+}
+
+void AudioRendererPassthrough::SetVolume(double volume) {
+ SB_DCHECK(BelongsToCurrentThread());
+
+ if (volume_ == volume) {
+ SB_LOG(INFO) << "Volume already at " << volume;
+ return;
+ }
+
+ SB_LOG(INFO) << "Set volume to " << volume;
+
+ ScopedLock scoped_lock(mutex_);
+ volume_ = volume;
+}
+
+bool AudioRendererPassthrough::IsEndOfStreamWritten() const {
+ SB_DCHECK(BelongsToCurrentThread());
+
+ return end_of_stream_written_;
+}
+
+bool AudioRendererPassthrough::IsEndOfStreamPlayed() const {
+ SB_DCHECK(BelongsToCurrentThread());
+
+ return end_of_stream_played_.load();
+}
+
+bool AudioRendererPassthrough::CanAcceptMoreData() const {
+ SB_DCHECK(BelongsToCurrentThread());
+
+ ScopedLock scoped_lock(mutex_);
+ return can_accept_more_data_.load() &&
+ decoded_audios_.size() < kMaxDecodedAudios;
+}
+
+void AudioRendererPassthrough::Play() {
+ SB_DCHECK(BelongsToCurrentThread());
+
+ if (!paused_) {
+ SB_LOG(INFO) << "Already playing.";
+ return;
+ }
+
+ SB_LOG(INFO) << "Play.";
+
+ ScopedLock scoped_lock(mutex_);
+ paused_ = false;
+}
+
+void AudioRendererPassthrough::Pause() {
+ SB_DCHECK(BelongsToCurrentThread());
+
+ if (paused_) {
+ SB_LOG(INFO) << "Already paused.";
+ return;
+ }
+
+ SB_LOG(INFO) << "Pause.";
+
+ ScopedLock scoped_lock(mutex_);
+ paused_ = true;
+}
+
+void AudioRendererPassthrough::SetPlaybackRate(double playback_rate) {
+ SB_DCHECK(BelongsToCurrentThread());
+
+ if (playback_rate > 0.0 && playback_rate != 1.0) {
+ // TODO: Report unsupported playback rate as an error.
+ SB_LOG(WARNING) << "Playback rate " << playback_rate << " is not supported"
+ << " and is set to 1.0.";
+ playback_rate = 1.0;
+ }
+
+ if (playback_rate_ == playback_rate) {
+ SB_LOG(INFO) << "Playback rate already at " << playback_rate;
+ return;
+ }
+
+ SB_LOG(INFO) << "Change playback rate from " << playback_rate_ << " to "
+ << playback_rate << ".";
+
+ ScopedLock scoped_lock(mutex_);
+ playback_rate_ = playback_rate;
+}
+
+void AudioRendererPassthrough::Seek(SbTime seek_to_time) {
+ SB_DCHECK(BelongsToCurrentThread());
+
+ SB_LOG(INFO) << "Seek to " << seek_to_time;
+
+ decoder_->Reset();
+
+ bool seek_to_time_set = false;
+ if (audio_track_thread_) {
+ audio_track_thread_->ScheduleAndWait(
+ std::bind(&AudioRendererPassthrough::FlushAudioTrackAndStopProcessing,
+ this, seek_to_time));
+ // |seek_to_time_| is updated inside FlushAudioTrackAndStopProcessing(),
+ // update the flag so we needn't set it again below.
+ seek_to_time_set = true;
+ // Destroy the audio track thread, it will be re-created during preroll.
+ audio_track_thread_.reset();
+ }
+
+ CancelPendingJobs();
+
+ ScopedLock scoped_lock(mutex_);
+
+ can_accept_more_data_.store(true);
+ prerolled_.store(false);
+ end_of_stream_played_.store(false);
+ total_frames_written_ = 0;
+
+ end_of_stream_written_ = false;
+
+ stop_called_ = false;
+ playback_head_position_when_stopped_ = 0;
+ stopped_at_ = 0;
+ if (!seek_to_time_set) {
+ seek_to_time_ = seek_to_time;
+ }
+ paused_ = true;
+ decoded_audios_ = std::queue<scoped_refptr<DecodedAudio>>(); // clear it
+ decoded_audio_writing_in_progress_ = nullptr;
+ decoded_audio_writing_offset_ = 0;
+ total_frames_written_on_audio_track_thread_ = 0;
+}
+
+// This function can be called from *any* threads.
+SbTime AudioRendererPassthrough::GetCurrentMediaTime(bool* is_playing,
+ bool* is_eos_played,
+ bool* is_underflow,
+ double* playback_rate) {
+ SB_DCHECK(is_playing);
+ SB_DCHECK(is_eos_played);
+ SB_DCHECK(is_underflow);
+ SB_DCHECK(playback_rate);
+
+ ScopedLock scoped_lock(mutex_);
+ *is_playing = !paused_;
+ *is_eos_played = end_of_stream_played_.load();
+ *is_underflow = false; // TODO: Support underflow
+ *playback_rate = playback_rate_;
+
+ if (!audio_track_bridge_) {
+ return seek_to_time_;
+ }
+
+ if (stop_called_) {
+ // When AudioTrackBridge::Stop() is called, the playback will continue until
+ // all the frames written are played, as the AudioTrack in created in
+ // MODE_STREAM.
+ auto now = SbTimeGetMonotonicNow();
+ SB_DCHECK(now >= stopped_at_);
+ auto time_elapsed = now - stopped_at_;
+ int64_t frames_played =
+ time_elapsed * audio_sample_info_.samples_per_second / kSbTimeSecond;
+ int64_t total_frames_played =
+ frames_played + playback_head_position_when_stopped_;
+ total_frames_played = std::min(total_frames_played, total_frames_written_);
+ return seek_to_time_ + total_frames_played * kSbTimeSecond /
+ audio_sample_info_.samples_per_second;
+ }
+
+ SbTime updated_at;
+ auto playback_head_position =
+ audio_track_bridge_->GetPlaybackHeadPosition(&updated_at);
+ if (playback_head_position <= 0) {
+ // The playback is warming up, don't adjust the media time by the monotonic
+ // system time.
+ return seek_to_time_;
+ }
+
+ // TODO: This may cause time regression, because the unadjusted time will be
+ // returned on pause, after an adjusted time has been returned.
+ SbTime playback_time =
+ seek_to_time_ + playback_head_position * kSbTimeSecond /
+ audio_sample_info_.samples_per_second;
+ if (paused_ || playback_rate_ == 0.0) {
+ return playback_time;
+ }
+
+ // TODO: Cap this to the maximum frames written to the AudioTrack.
+ auto now = SbTimeGetMonotonicNow();
+ SB_LOG_IF(WARNING, now < updated_at)
+ << "now (" << now << ") is not greater than updated_at (" << updated_at
+ << ").";
+ playback_time += std::max<SbTime>(now - updated_at, 0);
+
+ return playback_time;
+}
+
+void AudioRendererPassthrough::CreateAudioTrackAndStartProcessing() {
+ SB_DCHECK(audio_track_thread_);
+ SB_DCHECK(audio_track_thread_->BelongsToCurrentThread());
+ SB_DCHECK(error_cb_);
+
+ if (audio_track_bridge_) {
+ SB_DCHECK(!update_status_and_write_data_token_.is_valid());
+ AudioTrackState initial_state;
+ update_status_and_write_data_token_ = audio_track_thread_->Schedule(
+ std::bind(&AudioRendererPassthrough::UpdateStatusAndWriteData, this,
+ initial_state));
+ SB_LOG(INFO) << "|audio_track_bridge_| already created, start processing.";
+ return;
+ }
+
+ std::unique_ptr<AudioTrackBridge> audio_track_bridge(new AudioTrackBridge(
+ audio_sample_info_.codec == kSbMediaAudioCodecAc3
+ ? kSbMediaAudioCodingTypeAc3
+ : kSbMediaAudioCodingTypeDolbyDigitalPlus,
+ optional<SbMediaAudioSampleType>(), // Not required in passthrough mode
+ audio_sample_info_.number_of_channels,
+ audio_sample_info_.samples_per_second, kPreferredBufferSizeInBytes,
+ kEnableAudioRouting, kTunnelModeAudioSessionId));
+
+ if (!audio_track_bridge->is_valid()) {
+ error_cb_(kSbPlayerErrorDecode, "Error creating AudioTrackBridge");
+ return;
+ }
+
+ {
+ ScopedLock scoped_lock(mutex_);
+ audio_track_bridge_ = std::move(audio_track_bridge);
+ }
+
+ AudioTrackState initial_state;
+ update_status_and_write_data_token_ = audio_track_thread_->Schedule(
+ std::bind(&AudioRendererPassthrough::UpdateStatusAndWriteData, this,
+ initial_state));
+ SB_LOG(INFO) << "|audio_track_bridge_| created, start processing.";
+}
+
+void AudioRendererPassthrough::FlushAudioTrackAndStopProcessing(
+ SbTime seek_to_time) {
+ SB_DCHECK(audio_track_thread_);
+ SB_DCHECK(audio_track_thread_->BelongsToCurrentThread());
+
+ SB_LOG(INFO) << "Pause audio track and stop processing.";
+
+ // Flushing of |audio_track_bridge_| and updating of |seek_to_time_| have to
+ // be done together under lock to avoid |seek_to_time_| being added to a stale
+ // playback head or vice versa in GetCurrentMediaTime().
+ ScopedLock scoped_lock(mutex_);
+
+ // We have to reuse |audio_track_bridge_| instead of creating a new one, to
+ // reduce output mode switching between PCM and e/ac3. Otherwise a noticeable
+ // silence can be observed after seeking on some audio receivers.
+ // TODO: Consider reusing audio sink for non-passthrough playbacks, to see if
+ // it reduces latency after seeking.
+ audio_track_bridge_->PauseAndFlush();
+ seek_to_time_ = seek_to_time;
+ paused_ = true;
+ if (update_status_and_write_data_token_.is_valid()) {
+ audio_track_thread_->RemoveJobByToken(update_status_and_write_data_token_);
+ update_status_and_write_data_token_.ResetToInvalid();
+ }
+}
+
+void AudioRendererPassthrough::UpdateStatusAndWriteData(
+ const AudioTrackState previous_state) {
+ SB_DCHECK(audio_track_thread_);
+ SB_DCHECK(audio_track_thread_->BelongsToCurrentThread());
+ SB_DCHECK(error_cb_);
+ SB_DCHECK(audio_track_bridge_);
+
+ AudioTrackState current_state;
+
+ {
+ ScopedLock scoped_lock(mutex_);
+ current_state.volume = volume_;
+ current_state.paused = paused_;
+ current_state.playback_rate = playback_rate_;
+
+ if (!decoded_audio_writing_in_progress_ && !decoded_audios_.empty()) {
+ decoded_audio_writing_in_progress_ = decoded_audios_.front();
+ decoded_audios_.pop();
+ decoded_audio_writing_offset_ = 0;
+ }
+ }
+
+ if (previous_state.volume != current_state.volume) {
+ audio_track_bridge_->SetVolume(current_state.volume);
+ }
+ if (previous_state.playing() != current_state.playing()) {
+ if (current_state.playing()) {
+ audio_track_bridge_->Play();
+ SB_LOG(INFO) << "Played on AudioTrack thread.";
+ ScopedLock scoped_lock(mutex_);
+ stop_called_ = false;
+ } else {
+ audio_track_bridge_->Pause();
+ SB_LOG(INFO) << "Paused on AudioTrack thread.";
+ }
+ }
+
+ bool fully_written = false;
+ if (decoded_audio_writing_in_progress_) {
+ if (decoded_audio_writing_in_progress_->is_end_of_stream()) {
+ if (!prerolled_.exchange(true)) {
+ SB_LOG(INFO) << "Prerolled due to end of stream.";
+ prerolled_cb_();
+ }
+ ScopedLock scoped_lock(mutex_);
+ if (current_state.playing() && !stop_called_) {
+ // TODO: Check if we can apply the same stop logic to non-passthrough.
+ audio_track_bridge_->Stop();
+ stop_called_ = true;
+ playback_head_position_when_stopped_ =
+ audio_track_bridge_->GetPlaybackHeadPosition(&stopped_at_);
+ total_frames_written_ = total_frames_written_on_audio_track_thread_;
+ decoded_audio_writing_in_progress_ = nullptr;
+ SB_LOG(INFO) << "Audio track stopped at " << stopped_at_
+ << ", playback head: "
+ << playback_head_position_when_stopped_;
+ }
+ } else {
+ auto sample_buffer = decoded_audio_writing_in_progress_->buffer() +
+ decoded_audio_writing_offset_;
+ auto samples_to_write = (decoded_audio_writing_in_progress_->size() -
+ decoded_audio_writing_offset_);
+ // TODO: |sync_time| currently doesn't take partial writes into account.
+ // It is not used in non-tunneled mode so it doesn't matter, but we
+ // should revisit this.
+ auto sync_time = decoded_audio_writing_in_progress_->timestamp();
+ int samples_written = audio_track_bridge_->WriteSample(
+ sample_buffer, samples_to_write, sync_time);
+ // Error code returned as negative value, like kAudioTrackErrorDeadObject.
+ if (samples_written < 0) {
+ // `kSbPlayerErrorDecode` is used for general SbPlayer error, there is
+ // no error code corresponding to audio sink.
+ auto error = kSbPlayerErrorDecode;
+ if (samples_written == AudioTrackBridge::kAudioTrackErrorDeadObject) {
+ // Inform the audio end point change.
+ error = kSbPlayerErrorCapabilityChanged;
+ }
+ error_cb_(error, FormatString("Error while writing frames: %d",
+ samples_written));
+ }
+ decoded_audio_writing_offset_ += samples_written;
+
+ if (decoded_audio_writing_offset_ ==
+ decoded_audio_writing_in_progress_->size()) {
+ total_frames_written_on_audio_track_thread_ += frames_per_input_buffer_;
+ decoded_audio_writing_in_progress_ = nullptr;
+ decoded_audio_writing_offset_ = 0;
+ fully_written = true;
+ } else if (!prerolled_.exchange(true)) {
+ // The audio sink no longer takes all the samples written to it. Assume
+ // that it has enough samples and preroll is finished.
+ SB_LOG(INFO) << "Prerolled.";
+ prerolled_cb_();
+ }
+ }
+ }
+
+ // EOS is handled on this thread instead of in GetCurrentMediaTime(), because
+ // GetCurrentMediaTime() is not guaranteed to be called.
+ if (stop_called_ && !end_of_stream_played_.load()) {
+ auto time_elapsed = SbTimeGetMonotonicNow() - stopped_at_;
+ auto frames_played =
+ time_elapsed * audio_sample_info_.samples_per_second / kSbTimeSecond;
+ if (frames_played + playback_head_position_when_stopped_ >=
+ total_frames_written_on_audio_track_thread_) {
+ end_of_stream_played_.store(true);
+ ended_cb_();
+ SB_LOG(INFO) << "Audio playback ended, UpdateStatusAndWriteData stopped.";
+ return;
+ }
+ }
+
+ update_status_and_write_data_token_ = audio_track_thread_->Schedule(
+ std::bind(&AudioRendererPassthrough::UpdateStatusAndWriteData, this,
+ current_state),
+ fully_written ? 0 : kAudioTrackUpdateInternal);
+}
+
+// This function can be called from *any* threads.
+void AudioRendererPassthrough::OnDecoderConsumed() {
+ auto old_value = can_accept_more_data_.exchange(true);
+ SB_DCHECK(!old_value);
+}
+
+// This function can be called from *any* threads.
+void AudioRendererPassthrough::OnDecoderOutput() {
+ int decoded_audio_sample_rate;
+ auto decoded_audio = decoder_->Read(&decoded_audio_sample_rate);
+ SB_DCHECK(decoded_audio);
+
+ ScopedLock scoped_lock(mutex_);
+ decoded_audios_.push(decoded_audio);
+}
+
+} // namespace shared
+} // namespace android
+} // namespace starboard
diff --git a/src/starboard/android/shared/audio_renderer_passthrough.h b/src/starboard/android/shared/audio_renderer_passthrough.h
new file mode 100644
index 0000000..6d9a050
--- /dev/null
+++ b/src/starboard/android/shared/audio_renderer_passthrough.h
@@ -0,0 +1,146 @@
+// Copyright 2021 The Cobalt Authors. 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.
+
+#ifndef STARBOARD_ANDROID_SHARED_AUDIO_RENDERER_PASSTHROUGH_H_
+#define STARBOARD_ANDROID_SHARED_AUDIO_RENDERER_PASSTHROUGH_H_
+
+#include <memory>
+#include <queue>
+
+#include "starboard/android/shared/audio_decoder.h"
+#include "starboard/android/shared/audio_track_bridge.h"
+#include "starboard/android/shared/drm_system.h"
+#include "starboard/atomic.h"
+#include "starboard/common/mutex.h"
+#include "starboard/common/ref_counted.h"
+#include "starboard/drm.h"
+#include "starboard/media.h"
+#include "starboard/shared/internal_only.h"
+#include "starboard/shared/starboard/player/decoded_audio_internal.h"
+#include "starboard/shared/starboard/player/filter/audio_renderer_internal.h"
+#include "starboard/shared/starboard/player/filter/common.h"
+#include "starboard/shared/starboard/player/filter/media_time_provider.h"
+#include "starboard/shared/starboard/player/input_buffer_internal.h"
+#include "starboard/shared/starboard/player/job_queue.h"
+#include "starboard/shared/starboard/player/job_thread.h"
+#include "starboard/time.h"
+
+namespace starboard {
+namespace android {
+namespace shared {
+
+// TODO: The audio receiver often requires some warm up time to switch the
+// output to eac3. Consider pushing some silence at the very beginning so
+// the sound at the very beginning won't get lost during the switching.
+class AudioRendererPassthrough
+ : public ::starboard::shared::starboard::player::filter::AudioRenderer,
+ public ::starboard::shared::starboard::player::filter::MediaTimeProvider,
+ private ::starboard::shared::starboard::player::JobQueue::JobOwner {
+ public:
+ AudioRendererPassthrough(const SbMediaAudioSampleInfo& audio_sample_info,
+ SbDrmSystem drm_system);
+ ~AudioRendererPassthrough() override;
+
+ bool is_valid() const { return decoder_ != nullptr; }
+
+ // AudioRenderer methods
+ void Initialize(const ErrorCB& error_cb,
+ const PrerolledCB& prerolled_cb,
+ const EndedCB& ended_cb) override;
+ void WriteSample(const scoped_refptr<InputBuffer>& input_buffer) override;
+ void WriteEndOfStream() override;
+
+ void SetVolume(double volume) override;
+
+ bool IsEndOfStreamWritten() const override;
+ bool IsEndOfStreamPlayed() const override;
+ bool CanAcceptMoreData() const override;
+
+ // MediaTimeProvider methods
+ void Play() override;
+ void Pause() override;
+ void SetPlaybackRate(double playback_rate) override;
+ void Seek(SbTime seek_to_time) override;
+ SbTime GetCurrentMediaTime(bool* is_playing,
+ bool* is_eos_played,
+ bool* is_underflow,
+ double* playback_rate) override;
+
+ private:
+ typedef ::starboard::shared::starboard::player::DecodedAudio DecodedAudio;
+ typedef ::starboard::shared::starboard::player::JobThread JobThread;
+ typedef ::starboard::shared::starboard::player::JobQueue::JobToken JobToken;
+
+ struct AudioTrackState {
+ double volume = 1.0;
+ bool paused = true;
+ double playback_rate = 1.0;
+
+ bool playing() const { return !paused && playback_rate > 0.0; }
+ };
+
+ void CreateAudioTrackAndStartProcessing();
+ void FlushAudioTrackAndStopProcessing(SbTime seek_to_time);
+ void UpdateStatusAndWriteData(const AudioTrackState previous_state);
+ void OnDecoderConsumed();
+ void OnDecoderOutput();
+
+ // The following two variables are set in the ctor.
+ const SbMediaAudioSampleInfo audio_sample_info_;
+ // The AudioDecoder is used as a decryptor when the stream is encrypted.
+ // TODO: Revisit to encapsulate the AudioDecoder as a SbDrmSystemPrivate
+ // instead. This would need to turn SbDrmSystemPrivate::Decrypt() into
+ // asynchronous, which comes with extra risks.
+ std::unique_ptr<::starboard::shared::starboard::player::filter::AudioDecoder>
+ decoder_;
+
+ // The following three variables are set in Initialize().
+ ErrorCB error_cb_;
+ PrerolledCB prerolled_cb_;
+ EndedCB ended_cb_;
+
+ int frames_per_input_buffer_ = 0; // Set once before all uses.
+ atomic_bool can_accept_more_data_{true};
+ atomic_bool prerolled_;
+ atomic_bool end_of_stream_played_;
+
+ bool end_of_stream_written_ = false; // Only accessed on PlayerWorker thread.
+
+ Mutex mutex_;
+ bool stop_called_ = false;
+ int64_t total_frames_written_ = 0;
+ int64_t playback_head_position_when_stopped_ = 0;
+ SbTimeMonotonic stopped_at_ = 0;
+ SbTime seek_to_time_ = 0;
+ double volume_ = 1.0;
+ bool paused_ = true;
+ double playback_rate_ = 1.0;
+ std::queue<scoped_refptr<DecodedAudio>> decoded_audios_;
+
+ // The following variable group is only accessed on |audio_track_thread_|, or
+ // after |audio_track_thread_| is destroyed (in Seek()).
+ scoped_refptr<DecodedAudio> decoded_audio_writing_in_progress_;
+ int decoded_audio_writing_offset_ = 0;
+ JobToken update_status_and_write_data_token_;
+ int64_t total_frames_written_on_audio_track_thread_ = 0;
+
+ std::unique_ptr<JobThread> audio_track_thread_;
+ std::unique_ptr<AudioTrackBridge> audio_track_bridge_;
+};
+
+} // namespace shared
+} // namespace android
+} // namespace starboard
+
+#endif // STARBOARD_ANDROID_SHARED_AUDIO_RENDERER_PASSTHROUGH_H_
diff --git a/src/starboard/android/shared/audio_track_audio_sink_type.cc b/src/starboard/android/shared/audio_track_audio_sink_type.cc
index 189cea7..4c46710 100644
--- a/src/starboard/android/shared/audio_track_audio_sink_type.cc
+++ b/src/starboard/android/shared/audio_track_audio_sink_type.cc
@@ -19,6 +19,7 @@
#include <vector>
#include "starboard/common/string.h"
+#include "starboard/shared/starboard/media/media_util.h"
#include "starboard/shared/starboard/player/filter/common.h"
namespace {
@@ -31,8 +32,7 @@
namespace shared {
namespace {
-// The same as AudioTrack.ERROR_DEAD_OBJECT.
-const int kAudioTrackErrorDeadObject = -6;
+using ::starboard::shared::starboard::media::GetBytesPerSample;
// The maximum number of frames that can be written to android audio track per
// write request. If we don't set this cap for writing frames to audio track,
@@ -48,7 +48,6 @@
// large (non zero) and results in dropped video frames.
const SbTime kMaxDurationPerRequestInTunnelMode = 16 * kSbTimeMillisecond;
-const jint kNoOffset = 0;
const size_t kSilenceFramesPerAppend = 1024;
const int kMaxRequiredFrames = 16 * 1024;
@@ -58,32 +57,6 @@
const int kSampleFrequency22050 = 22050;
const int kSampleFrequency48000 = 48000;
-// Helper function to compute the size of the two valid starboard audio sample
-// types.
-size_t GetSampleSize(SbMediaAudioSampleType sample_type) {
- switch (sample_type) {
- case kSbMediaAudioSampleTypeFloat32:
- return sizeof(float);
- case kSbMediaAudioSampleTypeInt16Deprecated:
- return sizeof(int16_t);
- }
- SB_NOTREACHED();
- return 0u;
-}
-
-int GetAudioFormatSampleType(SbMediaAudioSampleType sample_type) {
- switch (sample_type) {
- case kSbMediaAudioSampleTypeFloat32:
- // Android AudioFormat.ENCODING_PCM_FLOAT.
- return 4;
- case kSbMediaAudioSampleTypeInt16Deprecated:
- // Android AudioFormat.ENCODING_PCM_16BIT.
- return 2;
- }
- SB_NOTREACHED();
- return 0u;
-}
-
void* IncrementPointerByBytes(void* pointer, size_t offset) {
return static_cast<uint8_t*>(pointer) + offset;
}
@@ -126,30 +99,21 @@
tunnel_mode_audio_session_id_ == -1
? kMaxFramesPerRequest
: GetMaxFramesPerRequestForTunnelMode(sampling_frequency_hz_)),
- context_(context) {
+ context_(context),
+ bridge_(kSbMediaAudioCodingTypePcm,
+ sample_type,
+ channels,
+ sampling_frequency_hz,
+ preferred_buffer_size_in_bytes,
+ enable_audio_routing,
+ tunnel_mode_audio_session_id) {
SB_DCHECK(update_source_status_func_);
SB_DCHECK(consume_frames_func_);
SB_DCHECK(frame_buffer_);
- SB_DCHECK(SbAudioSinkIsAudioSampleTypeSupported(sample_type));
-
- // TODO: Support query if platform supports float type for tunnel mode.
- if (tunnel_mode_audio_session_id_ != -1) {
- SB_DCHECK(sample_type_ == kSbMediaAudioSampleTypeInt16Deprecated);
- }
SB_LOG(INFO) << "Creating audio sink starts at " << start_time_;
- JniEnvExt* env = JniEnvExt::Get();
- ScopedLocalJavaRef<jobject> j_audio_output_manager(
- env->CallStarboardObjectMethodOrAbort(
- "getAudioOutputManager", "()Ldev/cobalt/media/AudioOutputManager;"));
- jobject j_audio_track_bridge = env->CallObjectMethodOrAbort(
- j_audio_output_manager.Get(), "createAudioTrackBridge",
- "(IIIIZI)Ldev/cobalt/media/AudioTrackBridge;",
- GetAudioFormatSampleType(sample_type_), sampling_frequency_hz_, channels_,
- preferred_buffer_size_in_bytes, enable_audio_routing,
- tunnel_mode_audio_session_id_);
- if (!j_audio_track_bridge) {
+ if (!bridge_.is_valid()) {
// One of the cases that this may hit is when output happened to be switched
// to a device that doesn't support tunnel mode.
// TODO: Find a way to exclude the device from tunnel mode playback, to
@@ -159,18 +123,6 @@
// investigate if this can be reported as a capability changed error.
return;
}
- j_audio_track_bridge_ = env->ConvertLocalRefToGlobalRef(j_audio_track_bridge);
- if (sample_type_ == kSbMediaAudioSampleTypeFloat32) {
- j_audio_data_ = env->NewFloatArray(channels_ * max_frames_per_request_);
- } else if (sample_type_ == kSbMediaAudioSampleTypeInt16Deprecated) {
- j_audio_data_ = env->NewByteArray(channels_ * GetSampleSize(sample_type_) *
- max_frames_per_request_);
- } else {
- SB_NOTREACHED();
- }
- SB_DCHECK(j_audio_data_) << "Failed to allocate |j_audio_data_|";
-
- j_audio_data_ = env->ConvertLocalRefToGlobalRef(j_audio_data_);
audio_out_thread_ = SbThreadCreate(
0, kSbThreadPriorityRealTime, kSbThreadNoAffinity, true,
@@ -184,24 +136,6 @@
if (SbThreadIsValid(audio_out_thread_)) {
SbThreadJoin(audio_out_thread_, NULL);
}
-
- JniEnvExt* env = JniEnvExt::Get();
- if (j_audio_track_bridge_) {
- ScopedLocalJavaRef<jobject> j_audio_output_manager(
- env->CallStarboardObjectMethodOrAbort(
- "getAudioOutputManager",
- "()Ldev/cobalt/media/AudioOutputManager;"));
- env->CallVoidMethodOrAbort(
- j_audio_output_manager.Get(), "destroyAudioTrackBridge",
- "(Ldev/cobalt/media/AudioTrackBridge;)V", j_audio_track_bridge_);
- env->DeleteGlobalRef(j_audio_track_bridge_);
- j_audio_track_bridge_ = NULL;
- }
-
- if (j_audio_data_) {
- env->DeleteGlobalRef(j_audio_data_);
- j_audio_data_ = NULL;
- }
}
void AudioTrackAudioSink::SetPlaybackRate(double playback_rate) {
@@ -244,9 +178,7 @@
while (!quit_) {
int playback_head_position = 0;
SbTime frames_consumed_at = 0;
- bool new_audio_device_added = env->CallBooleanMethodOrAbort(
- j_audio_track_bridge_, "getAndResetHasNewAudioDeviceAdded", "()Z");
- if (new_audio_device_added) {
+ if (bridge_.GetAndResetHasNewAudioDeviceAdded(env)) {
SB_LOG(INFO) << "New audio device added.";
error_func_(kSbPlayerErrorCapabilityChanged, "New audio device added.",
context_);
@@ -254,16 +186,8 @@
}
if (was_playing) {
- ScopedLocalJavaRef<jobject> j_audio_timestamp(
- env->CallObjectMethodOrAbort(j_audio_track_bridge_,
- "getAudioTimestamp",
- "()Landroid/media/AudioTimestamp;"));
- playback_head_position = env->GetLongFieldOrAbort(j_audio_timestamp.Get(),
- "framePosition", "J");
- frames_consumed_at =
- env->GetLongFieldOrAbort(j_audio_timestamp.Get(), "nanoTime", "J") /
- 1000;
-
+ playback_head_position =
+ bridge_.GetPlaybackHeadPosition(&frames_consumed_at, env);
SB_DCHECK(playback_head_position >= last_playback_head_position_);
playback_head_position =
@@ -315,15 +239,13 @@
if (was_playing && !is_playing) {
was_playing = false;
- env->CallVoidMethodOrAbort(j_audio_track_bridge_, "pause", "()V");
- SB_LOG(INFO) << "AudioTrackAudioSink paused.";
+ bridge_.Pause();
} else if (!was_playing && is_playing) {
was_playing = true;
last_playback_head_changed_at = -1;
playback_head_not_changed_duration = 0;
last_written_succeeded_at = -1;
- env->CallVoidMethodOrAbort(j_audio_track_bridge_, "play", "()V");
- SB_LOG(INFO) << "AudioTrackAudioSink playing.";
+ bridge_.Play();
}
if (!is_playing || frames_in_buffer == 0) {
@@ -358,7 +280,7 @@
const int silence_frames_per_append =
std::min<int>(kSilenceFramesPerAppend, max_frames_per_request_);
std::vector<uint8_t> silence_buffer(channels_ *
- GetSampleSize(sample_type_) *
+ GetBytesPerSample(sample_type_) *
silence_frames_per_append);
auto sync_time = start_time_ + accumulated_written_frames *
kSbTimeSecond /
@@ -387,11 +309,12 @@
<< ", frames_in_audio_track: " << frames_in_audio_track
<< ", offset_in_frames: " << offset_in_frames;
- int written_frames = WriteData(
- env,
- IncrementPointerByBytes(frame_buffer_, start_position * channels_ *
- GetSampleSize(sample_type_)),
- expected_written_frames, sync_time);
+ int written_frames =
+ WriteData(env,
+ IncrementPointerByBytes(frame_buffer_,
+ start_position * channels_ *
+ GetBytesPerSample(sample_type_)),
+ expected_written_frames, sync_time);
SbTime now = SbTimeGetMonotonicNow();
if (written_frames < 0) {
@@ -399,7 +322,8 @@
// dead.
consume_frames_func_(frames_in_audio_track, now, context_);
- bool capabilities_changed = written_frames == kAudioTrackErrorDeadObject;
+ bool capabilities_changed =
+ written_frames == AudioTrackBridge::kAudioTrackErrorDeadObject;
error_func_(
capabilities_changed,
FormatString("Error while writing frames: %d", written_frames),
@@ -428,68 +352,39 @@
}
}
- // For an immediate stop, use pause(), followed by flush() to discard audio
- // data that hasn't been played back yet.
- env->CallVoidMethodOrAbort(j_audio_track_bridge_, "pause", "()V");
- // Flushes the audio data currently queued for playback. Any data that has
- // been written but not yet presented will be discarded.
- env->CallVoidMethodOrAbort(j_audio_track_bridge_, "flush", "()V");
+ bridge_.PauseAndFlush();
}
int AudioTrackAudioSink::WriteData(JniEnvExt* env,
- void* buffer,
+ const void* buffer,
int expected_written_frames,
SbTime sync_time) {
+ int samples_written = 0;
if (sample_type_ == kSbMediaAudioSampleTypeFloat32) {
- int expected_written_size = expected_written_frames * channels_;
- env->SetFloatArrayRegion(static_cast<jfloatArray>(j_audio_data_), kNoOffset,
- expected_written_size,
- static_cast<const float*>(buffer));
- int written =
- env->CallIntMethodOrAbort(j_audio_track_bridge_, "write", "([FI)I",
- j_audio_data_, expected_written_size);
- if (written < 0) {
- // Error code returned as negative value, like kAudioTrackErrorDeadObject.
- return written;
- }
- SB_DCHECK(written % channels_ == 0);
- return written / channels_;
+ samples_written =
+ bridge_.WriteSample(static_cast<const float*>(buffer),
+ expected_written_frames * channels_, env);
+ } else if (sample_type_ == kSbMediaAudioSampleTypeInt16Deprecated) {
+ samples_written = bridge_.WriteSample(static_cast<const uint16_t*>(buffer),
+ expected_written_frames * channels_,
+ sync_time, env);
+ } else {
+ SB_NOTREACHED();
}
- if (sample_type_ == kSbMediaAudioSampleTypeInt16Deprecated) {
- int expected_written_size =
- expected_written_frames * channels_ * GetSampleSize(sample_type_);
- env->SetByteArrayRegion(static_cast<jbyteArray>(j_audio_data_), kNoOffset,
- expected_written_size,
- static_cast<const jbyte*>(buffer));
-
- int written = env->CallIntMethodOrAbort(j_audio_track_bridge_, "write",
- "([BIJ)I", j_audio_data_,
- expected_written_size, sync_time);
- if (written < 0) {
- // Error code returned as negative value, like kAudioTrackErrorDeadObject.
- return written;
- }
- SB_DCHECK(written % (channels_ * GetSampleSize(sample_type_)) == 0);
- return written / (channels_ * GetSampleSize(sample_type_));
+ if (samples_written < 0) {
+ // Error code returned as negative value, like kAudioTrackErrorDeadObject.
+ return samples_written;
}
- SB_NOTREACHED();
- return 0;
+ SB_DCHECK(samples_written % channels_ == 0);
+ return samples_written / channels_;
}
void AudioTrackAudioSink::SetVolume(double volume) {
- auto* env = JniEnvExt::Get();
- jint status = env->CallIntMethodOrAbort(j_audio_track_bridge_, "setVolume",
- "(F)I", static_cast<float>(volume));
- if (status != 0) {
- SB_LOG(ERROR) << "Failed to set volume";
- }
+ bridge_.SetVolume(volume);
}
int AudioTrackAudioSink::GetUnderrunCount() {
- auto* env = JniEnvExt::Get();
- jint underrun_count = env->CallIntMethodOrAbort(j_audio_track_bridge_,
- "getUnderrunCount", "()I");
- return underrun_count;
+ return bridge_.GetUnderrunCount();
}
// static
@@ -499,17 +394,9 @@
int sampling_frequency_hz) {
SB_DCHECK(audio_track_audio_sink_type_);
- JniEnvExt* env = JniEnvExt::Get();
- ScopedLocalJavaRef<jobject> j_audio_output_manager(
- env->CallStarboardObjectMethodOrAbort(
- "getAudioOutputManager", "()Ldev/cobalt/media/AudioOutputManager;"));
- int audio_track_min_buffer_size = static_cast<int>(env->CallIntMethodOrAbort(
- j_audio_output_manager.Get(), "getMinBufferSize", "(III)I",
- GetAudioFormatSampleType(sample_type), sampling_frequency_hz, channels));
- int audio_track_min_buffer_size_in_frames =
- audio_track_min_buffer_size / channels / GetSampleSize(sample_type);
return std::max(
- audio_track_min_buffer_size_in_frames,
+ AudioTrackBridge::GetMinBufferSizeInFrames(sample_type, channels,
+ sampling_frequency_hz),
audio_track_audio_sink_type_->GetMinBufferSizeInFramesInternal(
channels, sample_type, sampling_frequency_hz));
}
@@ -558,7 +445,7 @@
channels, audio_sample_type, sampling_frequency_hz);
SB_DCHECK(frames_per_channel >= min_required_frames);
int preferred_buffer_size_in_bytes =
- min_required_frames * channels * GetSampleSize(audio_sample_type);
+ min_required_frames * channels * GetBytesPerSample(audio_sample_type);
AudioTrackAudioSink* audio_sink = new AudioTrackAudioSink(
this, channels, sampling_frequency_hz, audio_sample_type, frame_buffers,
frames_per_channel, preferred_buffer_size_in_bytes,
diff --git a/src/starboard/android/shared/audio_track_audio_sink_type.h b/src/starboard/android/shared/audio_track_audio_sink_type.h
index 88793c3..5ae9f7b 100644
--- a/src/starboard/android/shared/audio_track_audio_sink_type.h
+++ b/src/starboard/android/shared/audio_track_audio_sink_type.h
@@ -21,6 +21,7 @@
#include <vector>
#include "starboard/android/shared/audio_sink_min_required_frames_tester.h"
+#include "starboard/android/shared/audio_track_bridge.h"
#include "starboard/android/shared/jni_env_ext.h"
#include "starboard/android/shared/jni_utils.h"
#include "starboard/audio_sink.h"
@@ -114,7 +115,7 @@
void* context);
~AudioTrackAudioSink() override;
- bool IsAudioTrackValid() const { return j_audio_track_bridge_; }
+ bool IsAudioTrackValid() const { return bridge_.is_valid(); }
bool IsType(Type* type) override { return type_ == type; }
void SetPlaybackRate(double playback_rate) override;
@@ -125,7 +126,7 @@
static void* ThreadEntryPoint(void* context);
void AudioThreadFunc();
- int WriteData(JniEnvExt* env, void* buffer, int size, SbTime sync_time);
+ int WriteData(JniEnvExt* env, const void* buffer, int size, SbTime sync_time);
Type* const type_;
const int channels_;
@@ -139,11 +140,11 @@
const SbTime start_time_;
const int tunnel_mode_audio_session_id_;
const int max_frames_per_request_;
-
void* const context_;
+
+ AudioTrackBridge bridge_;
+
int last_playback_head_position_ = 0;
- jobject j_audio_track_bridge_ = nullptr;
- jobject j_audio_data_ = nullptr;
volatile bool quit_ = false;
SbThread audio_out_thread_ = kSbThreadInvalid;
diff --git a/src/starboard/android/shared/audio_track_bridge.cc b/src/starboard/android/shared/audio_track_bridge.cc
new file mode 100644
index 0000000..572e759
--- /dev/null
+++ b/src/starboard/android/shared/audio_track_bridge.cc
@@ -0,0 +1,294 @@
+// Copyright 2021 The Cobalt Authors. 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 "starboard/android/shared/audio_track_bridge.h"
+
+#include <algorithm>
+
+#include "starboard/android/shared/jni_utils.h"
+#include "starboard/android/shared/media_common.h"
+#include "starboard/audio_sink.h"
+#include "starboard/common/log.h"
+#include "starboard/shared/starboard/media/media_util.h"
+
+namespace starboard {
+namespace android {
+namespace shared {
+
+namespace {
+
+using ::starboard::shared::starboard::media::GetBytesPerSample;
+
+const jint kNoOffset = 0;
+
+} // namespace
+
+AudioTrackBridge::AudioTrackBridge(SbMediaAudioCodingType coding_type,
+ optional<SbMediaAudioSampleType> sample_type,
+ int channels,
+ int sampling_frequency_hz,
+ int preferred_buffer_size_in_bytes,
+ bool enable_audio_routing,
+ int tunnel_mode_audio_session_id) {
+ if (coding_type == kSbMediaAudioCodingTypePcm) {
+ SB_DCHECK(SbAudioSinkIsAudioSampleTypeSupported(sample_type.value()));
+
+ // TODO: Support query if platform supports float type for tunnel mode.
+ if (tunnel_mode_audio_session_id != -1) {
+ SB_DCHECK(sample_type.value() == kSbMediaAudioSampleTypeInt16Deprecated);
+ }
+ } else {
+ SB_DCHECK(coding_type == kSbMediaAudioCodingTypeAc3 ||
+ coding_type == kSbMediaAudioCodingTypeDolbyDigitalPlus);
+ // TODO: Support passthrough under tunnel mode.
+ SB_DCHECK(tunnel_mode_audio_session_id == -1);
+ // TODO: |sample_type| is not used in passthrough mode, we should make this
+ // explicit.
+ }
+
+ JniEnvExt* env = JniEnvExt::Get();
+ ScopedLocalJavaRef<jobject> j_audio_output_manager(
+ env->CallStarboardObjectMethodOrAbort(
+ "getAudioOutputManager", "()Ldev/cobalt/media/AudioOutputManager;"));
+ jobject j_audio_track_bridge = env->CallObjectMethodOrAbort(
+ j_audio_output_manager.Get(), "createAudioTrackBridge",
+ "(IIIIZI)Ldev/cobalt/media/AudioTrackBridge;",
+ GetAudioFormatSampleType(coding_type, sample_type), sampling_frequency_hz,
+ channels, preferred_buffer_size_in_bytes, enable_audio_routing,
+ tunnel_mode_audio_session_id);
+ if (!j_audio_track_bridge) {
+ // One of the cases that this may hit is when output happened to be switched
+ // to a device that doesn't support tunnel mode.
+ // TODO: Find a way to exclude the device from tunnel mode playback, to
+ // avoid infinite loop in creating the audio sink on a device
+ // claims to support tunnel mode but fails to create the audio sink.
+ // TODO: Currently this will be reported as a general decode error,
+ // investigate if this can be reported as a capability changed error.
+ SB_LOG(WARNING) << "Failed to create |j_audio_track_bridge|.";
+ return;
+ }
+ j_audio_track_bridge_ = env->ConvertLocalRefToGlobalRef(j_audio_track_bridge);
+ if (coding_type != kSbMediaAudioCodingTypePcm) {
+ // This must be passthrough.
+ SB_DCHECK(!sample_type);
+ max_samples_per_write_ = kMaxFramesPerRequest;
+ j_audio_data_ = env->NewByteArray(max_samples_per_write_);
+ } else if (sample_type == kSbMediaAudioSampleTypeFloat32) {
+ max_samples_per_write_ = channels * kMaxFramesPerRequest;
+ j_audio_data_ = env->NewFloatArray(channels * kMaxFramesPerRequest);
+ } else if (sample_type == kSbMediaAudioSampleTypeInt16Deprecated) {
+ max_samples_per_write_ = channels * kMaxFramesPerRequest;
+ j_audio_data_ =
+ env->NewByteArray(channels * GetBytesPerSample(sample_type.value()) *
+ kMaxFramesPerRequest);
+ } else {
+ SB_NOTREACHED();
+ }
+ SB_DCHECK(j_audio_data_) << "Failed to allocate |j_audio_data_|";
+
+ j_audio_data_ = env->ConvertLocalRefToGlobalRef(j_audio_data_);
+}
+
+AudioTrackBridge::~AudioTrackBridge() {
+ JniEnvExt* env = JniEnvExt::Get();
+ if (j_audio_track_bridge_) {
+ ScopedLocalJavaRef<jobject> j_audio_output_manager(
+ env->CallStarboardObjectMethodOrAbort(
+ "getAudioOutputManager",
+ "()Ldev/cobalt/media/AudioOutputManager;"));
+ env->CallVoidMethodOrAbort(
+ j_audio_output_manager.Get(), "destroyAudioTrackBridge",
+ "(Ldev/cobalt/media/AudioTrackBridge;)V", j_audio_track_bridge_);
+ env->DeleteGlobalRef(j_audio_track_bridge_);
+ j_audio_track_bridge_ = nullptr;
+ }
+
+ if (j_audio_data_) {
+ env->DeleteGlobalRef(j_audio_data_);
+ j_audio_data_ = nullptr;
+ }
+}
+
+// static
+int AudioTrackBridge::GetMinBufferSizeInFrames(
+ SbMediaAudioSampleType sample_type,
+ int channels,
+ int sampling_frequency_hz,
+ JniEnvExt* env /*= JniEnvExt::Get()*/) {
+ SB_DCHECK(env);
+
+ ScopedLocalJavaRef<jobject> j_audio_output_manager(
+ env->CallStarboardObjectMethodOrAbort(
+ "getAudioOutputManager", "()Ldev/cobalt/media/AudioOutputManager;"));
+ int audio_track_min_buffer_size = static_cast<int>(env->CallIntMethodOrAbort(
+ j_audio_output_manager.Get(), "getMinBufferSize", "(III)I",
+ GetAudioFormatSampleType(kSbMediaAudioCodingTypePcm, sample_type),
+ sampling_frequency_hz, channels));
+ return audio_track_min_buffer_size / channels /
+ GetBytesPerSample(sample_type);
+}
+
+void AudioTrackBridge::Play(JniEnvExt* env /*= JniEnvExt::Get()*/) {
+ SB_DCHECK(env);
+ SB_DCHECK(is_valid());
+
+ env->CallVoidMethodOrAbort(j_audio_track_bridge_, "play", "()V");
+ SB_LOG(INFO) << "AudioTrackBridge playing.";
+}
+
+void AudioTrackBridge::Pause(JniEnvExt* env /*= JniEnvExt::Get()*/) {
+ SB_DCHECK(env);
+ SB_DCHECK(is_valid());
+
+ env->CallVoidMethodOrAbort(j_audio_track_bridge_, "pause", "()V");
+ SB_LOG(INFO) << "AudioTrackBridge paused.";
+}
+
+void AudioTrackBridge::Stop(JniEnvExt* env /*= JniEnvExt::Get()*/) {
+ SB_DCHECK(env);
+ SB_DCHECK(is_valid());
+
+ env->CallVoidMethodOrAbort(j_audio_track_bridge_, "stop", "()V");
+ SB_LOG(INFO) << "AudioTrackBridge stopped.";
+}
+
+void AudioTrackBridge::PauseAndFlush(JniEnvExt* env /*= JniEnvExt::Get()*/) {
+ SB_DCHECK(env);
+ SB_DCHECK(is_valid());
+
+ // For an immediate stop, use pause(), followed by flush() to discard audio
+ // data that hasn't been played back yet.
+ env->CallVoidMethodOrAbort(j_audio_track_bridge_, "pause", "()V");
+ // Flushes the audio data currently queued for playback. Any data that has
+ // been written but not yet presented will be discarded.
+ env->CallVoidMethodOrAbort(j_audio_track_bridge_, "flush", "()V");
+}
+
+int AudioTrackBridge::WriteSample(const float* samples,
+ int num_of_samples,
+ JniEnvExt* env /*= JniEnvExt::Get()*/) {
+ SB_DCHECK(env);
+ SB_DCHECK(is_valid());
+ SB_DCHECK(num_of_samples <= max_samples_per_write_);
+
+ num_of_samples = std::min(num_of_samples, max_samples_per_write_);
+
+ // TODO: Test this code path
+ env->SetFloatArrayRegion(static_cast<jfloatArray>(j_audio_data_), kNoOffset,
+ num_of_samples, samples);
+ int samples_written = env->CallIntMethodOrAbort(
+ j_audio_track_bridge_, "write", "([FI)I", j_audio_data_, num_of_samples);
+ return samples_written;
+}
+
+int AudioTrackBridge::WriteSample(const uint16_t* samples,
+ int num_of_samples,
+ SbTime sync_time,
+ JniEnvExt* env /*= JniEnvExt::Get()*/) {
+ SB_DCHECK(env);
+ SB_DCHECK(is_valid());
+ SB_DCHECK(num_of_samples <= max_samples_per_write_);
+
+ num_of_samples = std::min(num_of_samples, max_samples_per_write_);
+
+ // TODO: Test this code path
+ env->SetByteArrayRegion(static_cast<jbyteArray>(j_audio_data_), kNoOffset,
+ num_of_samples * sizeof(uint16_t),
+ reinterpret_cast<const jbyte*>(samples));
+
+ int bytes_written = env->CallIntMethodOrAbort(
+ j_audio_track_bridge_, "write", "([BIJ)I", j_audio_data_,
+ num_of_samples * sizeof(uint16_t), sync_time);
+ if (bytes_written < 0) {
+ // Error code returned as negative value, like AudioTrack.ERROR_DEAD_OBJECT.
+ return bytes_written;
+ }
+ SB_DCHECK(bytes_written % sizeof(uint16_t) == 0);
+ return bytes_written / sizeof(uint16_t);
+}
+
+int AudioTrackBridge::WriteSample(const uint8_t* samples,
+ int num_of_samples,
+ SbTime sync_time,
+ JniEnvExt* env /*= JniEnvExt::Get()*/) {
+ SB_DCHECK(env);
+ SB_DCHECK(is_valid());
+ SB_DCHECK(num_of_samples <= max_samples_per_write_);
+
+ num_of_samples = std::min(num_of_samples, max_samples_per_write_);
+
+ env->SetByteArrayRegion(static_cast<jbyteArray>(j_audio_data_), kNoOffset,
+ num_of_samples,
+ reinterpret_cast<const jbyte*>(samples));
+
+ int bytes_written =
+ env->CallIntMethodOrAbort(j_audio_track_bridge_, "write", "([BIJ)I",
+ j_audio_data_, num_of_samples, sync_time);
+ if (bytes_written < 0) {
+ // Error code returned as negative value, like AudioTrack.ERROR_DEAD_OBJECT.
+ return bytes_written;
+ }
+ return bytes_written;
+}
+
+void AudioTrackBridge::SetVolume(double volume,
+ JniEnvExt* env /*= JniEnvExt::Get()*/) {
+ SB_DCHECK(env);
+ SB_DCHECK(is_valid());
+
+ jint status = env->CallIntMethodOrAbort(j_audio_track_bridge_, "setVolume",
+ "(F)I", static_cast<float>(volume));
+ if (status != 0) {
+ SB_LOG(ERROR) << "Failed to set volume to " << volume;
+ }
+}
+
+int64_t AudioTrackBridge::GetPlaybackHeadPosition(
+ SbTime* updated_at,
+ JniEnvExt* env /*= JniEnvExt::Get()*/) {
+ SB_DCHECK(env);
+ SB_DCHECK(is_valid());
+
+ ScopedLocalJavaRef<jobject> j_audio_timestamp(
+ env->CallObjectMethodOrAbort(j_audio_track_bridge_, "getAudioTimestamp",
+ "()Landroid/media/AudioTimestamp;"));
+ if (updated_at) {
+ *updated_at =
+ env->GetLongFieldOrAbort(j_audio_timestamp.Get(), "nanoTime", "J") /
+ kSbTimeNanosecondsPerMicrosecond;
+ }
+ return env->GetLongFieldOrAbort(j_audio_timestamp.Get(), "framePosition",
+ "J");
+}
+
+bool AudioTrackBridge::GetAndResetHasNewAudioDeviceAdded(
+ JniEnvExt* env /*= JniEnvExt::Get()*/) {
+ SB_DCHECK(env);
+ SB_DCHECK(is_valid());
+
+ return env->CallBooleanMethodOrAbort(
+ j_audio_track_bridge_, "getAndResetHasNewAudioDeviceAdded", "()Z");
+}
+
+int AudioTrackBridge::GetUnderrunCount(JniEnvExt* env /*= JniEnvExt::Get()*/) {
+ SB_DCHECK(env);
+ SB_DCHECK(is_valid());
+
+ return env->CallIntMethodOrAbort(j_audio_track_bridge_, "getUnderrunCount",
+ "()I");
+}
+
+} // namespace shared
+} // namespace android
+} // namespace starboard
diff --git a/src/starboard/android/shared/audio_track_bridge.h b/src/starboard/android/shared/audio_track_bridge.h
new file mode 100644
index 0000000..e18e498
--- /dev/null
+++ b/src/starboard/android/shared/audio_track_bridge.h
@@ -0,0 +1,99 @@
+// Copyright 2021 The Cobalt Authors. 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.
+
+#ifndef STARBOARD_ANDROID_SHARED_AUDIO_TRACK_BRIDGE_H_
+#define STARBOARD_ANDROID_SHARED_AUDIO_TRACK_BRIDGE_H_
+
+#include <jni.h>
+
+#include "starboard/android/shared/jni_env_ext.h"
+#include "starboard/common/optional.h"
+#include "starboard/media.h"
+#include "starboard/time.h"
+#include "starboard/types.h"
+
+namespace starboard {
+namespace android {
+namespace shared {
+
+// The C++ encapsulation of the Java class AudioTrackBridge.
+class AudioTrackBridge {
+ public:
+ // The maximum number of frames that can be written to android audio track per
+ // write request. It is used to pre-allocate |j_audio_data_|.
+ static constexpr int kMaxFramesPerRequest = 65536;
+ // The same as Android AudioTrack.ERROR_DEAD_OBJECT.
+ static constexpr int kAudioTrackErrorDeadObject = -6;
+
+ AudioTrackBridge(SbMediaAudioCodingType coding_type,
+ optional<SbMediaAudioSampleType> sample_type,
+ int channels,
+ int sampling_frequency_hz,
+ int preferred_buffer_size_in_bytes,
+ bool enable_audio_routing,
+ int tunnel_mode_audio_session_id);
+ ~AudioTrackBridge();
+
+ static int GetMinBufferSizeInFrames(SbMediaAudioSampleType sample_type,
+ int channels,
+ int sampling_frequency_hz,
+ JniEnvExt* env = JniEnvExt::Get());
+
+ bool is_valid() const {
+ return j_audio_track_bridge_ != nullptr && j_audio_data_ != nullptr;
+ }
+
+ void Play(JniEnvExt* env = JniEnvExt::Get());
+ void Pause(JniEnvExt* env = JniEnvExt::Get());
+ void Stop(JniEnvExt* env = JniEnvExt::Get());
+ void PauseAndFlush(JniEnvExt* env = JniEnvExt::Get());
+
+ int WriteSample(const float* samples,
+ int num_of_samples,
+ JniEnvExt* env = JniEnvExt::Get());
+ // Returns samples written.
+ int WriteSample(const uint16_t* samples,
+ int num_of_samples,
+ SbTime sync_time,
+ JniEnvExt* env = JniEnvExt::Get());
+ // This is used by passthrough, it treats samples as if they are in bytes.
+ int WriteSample(const uint8_t* buffer,
+ int num_of_samples,
+ SbTime sync_time,
+ JniEnvExt* env = JniEnvExt::Get());
+
+ void SetVolume(double volume, JniEnvExt* env = JniEnvExt::Get());
+
+ // |updated_at| contains the timestamp when the playback head position is
+ // updated on return. It can be nullptr.
+ int64_t GetPlaybackHeadPosition(SbTime* updated_at,
+ JniEnvExt* env = JniEnvExt::Get());
+ bool GetAndResetHasNewAudioDeviceAdded(JniEnvExt* env = JniEnvExt::Get());
+ int GetUnderrunCount(JniEnvExt* env = JniEnvExt::Get());
+
+ private:
+ int max_samples_per_write_;
+
+ jobject j_audio_track_bridge_ = nullptr;
+ // The audio data has to be copied into a Java Array before writing into the
+ // audio track. Allocating a large array and saves as a member variable
+ // avoids an array being allocated repeatedly.
+ jobject j_audio_data_ = nullptr;
+};
+
+} // namespace shared
+} // namespace android
+} // namespace starboard
+
+#endif // STARBOARD_ANDROID_SHARED_AUDIO_TRACK_BRIDGE_H_
diff --git a/src/starboard/android/shared/gyp_configuration.py b/src/starboard/android/shared/gyp_configuration.py
index 4a8fd94..e38efdf 100644
--- a/src/starboard/android/shared/gyp_configuration.py
+++ b/src/starboard/android/shared/gyp_configuration.py
@@ -277,6 +277,51 @@
# A map of failing or crashing tests per target.
__FILTERED_TESTS = { # pylint: disable=invalid-name
'player_filter_tests': [
+ # All e/ac3 related decoder tests are disabled. They will be
+ # re-enabled soon once we can filter out audio decoder tests for
+ # passthrough decoders.
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/12',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/26',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/40',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/54',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/68',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/82',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/84',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/86',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/88',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/90',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/92',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/94',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/96',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/98',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/100',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/102',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.SingleInput/104',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/12',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/26',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/40',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/54',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/68',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/82',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/84',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/86',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/88',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/90',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/92',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/94',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/96',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.MultipleInput/98',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.' +
+ 'MultipleInput/100',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.' +
+ 'MultipleInput/102',
+ 'AdaptiveAudioDecoderTests/AdaptiveAudioDecoderTest.' +
+ 'MultipleInput/104',
+ 'AudioDecoderTests/AudioDecoderTest.SingleInput/12',
+ 'AudioDecoderTests/AudioDecoderTest.ResetBeforeInput/12',
+ 'AudioDecoderTests/AudioDecoderTest.MultipleInputs/12',
+ 'AudioDecoderTests/AudioDecoderTest.LimitedInput/12',
+ 'AudioDecoderTests/AudioDecoderTest.ContinuedLimitedInput/12',
# GetMaxNumberOfCachedFrames() on Android is device dependent,
# and Android doesn't provide an API to get it. So, this function
@@ -296,6 +341,9 @@
# The video pipeline will hang if it doesn't receive any input.
'PlayerComponentsTests/PlayerComponentsTest.EOSWithoutInput/*',
+
+ # The e/eac3 audio time reporting during pause will be revisitied.
+ 'PlayerComponentsTests/PlayerComponentsTest.Pause/15',
],
'nplb': [
# This test is failing because localhost is not defined for IPv6 in
@@ -316,6 +364,17 @@
# These tests are disabled due to not receiving the kEndOfStream
# player state update within the specified timeout.
'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.NoInput/*',
+
+ # Android does not use SbDrmSessionClosedFunc, which these tests
+ # depend on.
+ 'SbDrmSessionTest.SunnyDay',
+ 'SbDrmSessionTest.CloseDrmSessionBeforeUpdateSession',
+
+ # This test is failing because Android calls the
+ # SbDrmSessionUpdateRequestFunc with SbDrmStatus::kSbDrmStatusSuccess
+ # when invalid initialization data is passed to
+ # SbDrmGenerateSessionUpdateRequest().
+ 'SbDrmSessionTest.InvalidSessionUpdateRequestParams',
],
}
diff --git a/src/starboard/android/shared/launcher.py b/src/starboard/android/shared/launcher.py
index 5f591dc..abd2787 100644
--- a/src/starboard/android/shared/launcher.py
+++ b/src/starboard/android/shared/launcher.py
@@ -279,7 +279,11 @@
# Setup for running executable
self._CheckCallAdb('wait-for-device')
self._Shutdown()
-
+ # TODO: Need to wait until cobalt fully shutdown. Otherwise, it may get
+ # dirty logs from previous test, and logs like "***Application Stopped***"
+ # will cause unexpected errors.
+ # Simply wait 2s as a temperary solution.
+ time.sleep(2)
# Clear logcat
self._CheckCallAdb('logcat', '-c')
diff --git a/src/starboard/android/shared/media_codec_bridge.cc b/src/starboard/android/shared/media_codec_bridge.cc
index 188f90f..0415adc 100644
--- a/src/starboard/android/shared/media_codec_bridge.cc
+++ b/src/starboard/android/shared/media_codec_bridge.cc
@@ -159,7 +159,9 @@
const SbMediaAudioSampleInfo& audio_sample_info,
Handler* handler,
jobject j_media_crypto) {
- const char* mime = SupportedAudioCodecToMimeType(audio_codec);
+ bool is_passthrough = false;
+ const char* mime =
+ SupportedAudioCodecToMimeType(audio_codec, &is_passthrough);
if (!mime) {
return scoped_ptr<MediaCodecBridge>(NULL);
}
diff --git a/src/starboard/android/shared/media_common.h b/src/starboard/android/shared/media_common.h
index 02feffb..5a8d57c 100644
--- a/src/starboard/android/shared/media_common.h
+++ b/src/starboard/android/shared/media_common.h
@@ -21,6 +21,7 @@
#include "starboard/android/shared/jni_env_ext.h"
#include "starboard/common/log.h"
#include "starboard/common/mutex.h"
+#include "starboard/common/optional.h"
#include "starboard/common/string.h"
#include "starboard/configuration.h"
#include "starboard/media.h"
@@ -30,8 +31,6 @@
namespace android {
namespace shared {
-const int64_t kSecondInMicroseconds = 1000 * 1000;
-
inline bool IsWidevineL1(const char* key_system) {
return strcmp(key_system, "com.widevine") == 0 ||
strcmp(key_system, "com.widevine.alpha") == 0;
@@ -42,17 +41,30 @@
}
// Map a supported |SbMediaAudioCodec| into its corresponding mime type
-// string. Returns |NULL| if |audio_codec| is not supported.
+// string. Returns |nullptr| if |audio_codec| is not supported.
+// On return, |is_passthrough| will be set to true if the codec should be played
+// in passthrough mode, i.e. the AudioDecoder shouldn't decode the input to pcm,
+// and should rely on the audio output device to decode and play the input.
inline const char* SupportedAudioCodecToMimeType(
- const SbMediaAudioCodec audio_codec) {
+ const SbMediaAudioCodec audio_codec,
+ bool* is_passthrough) {
+ SB_DCHECK(is_passthrough);
+
+ *is_passthrough = false;
+
+ if (audio_codec == kSbMediaAudioCodecAc3 ||
+ audio_codec == kSbMediaAudioCodecEac3) {
+ *is_passthrough = true;
+ return "audio/raw";
+ }
if (audio_codec == kSbMediaAudioCodecAac) {
return "audio/mp4a-latm";
}
- return NULL;
+ return nullptr;
}
// Map a supported |SbMediaVideoCodec| into its corresponding mime type
-// string. Returns |NULL| if |video_codec| is not supported.
+// string. Returns |nullptr| if |video_codec| is not supported.
inline const char* SupportedVideoCodecToMimeType(
const SbMediaVideoCodec video_codec) {
if (video_codec == kSbMediaVideoCodecVp9) {
@@ -64,39 +76,35 @@
} else if (video_codec == kSbMediaVideoCodecAv1) {
return "video/av01";
}
- return NULL;
+ return nullptr;
}
-// A simple thread-safe queue for events of type |E|, that supports polling
-// based access only.
-template <typename E>
-class EventQueue {
- public:
- E PollFront() {
- ScopedLock lock(mutex_);
- if (!deque_.empty()) {
- E event = deque_.front();
- deque_.pop_front();
- return event;
- }
-
- return E();
+inline int GetAudioFormatSampleType(
+ SbMediaAudioCodingType coding_type,
+ const optional<SbMediaAudioSampleType>& sample_type =
+ optional<SbMediaAudioSampleType>()) {
+ if (coding_type == kSbMediaAudioCodingTypeAc3) {
+ SB_DCHECK(!sample_type);
+ return 5; // Android AudioFormat.ENCODING_AC3.
+ }
+ if (coding_type == kSbMediaAudioCodingTypeDolbyDigitalPlus) {
+ SB_DCHECK(!sample_type);
+ return 6; // Android AudioFormat.ENCODING_E_AC3.
+ // TODO: Consider using 18 (AudioFormat.ENCODING_E_AC3_JOC) when supported.
}
- void PushBack(const E& event) {
- ScopedLock lock(mutex_);
- deque_.push_back(event);
- }
+ SB_DCHECK(coding_type == kSbMediaAudioCodingTypePcm);
+ SB_DCHECK(sample_type);
- void Clear() {
- ScopedLock lock(mutex_);
- deque_.clear();
+ switch (sample_type.value()) {
+ case kSbMediaAudioSampleTypeFloat32:
+ return 4; // Android AudioFormat.ENCODING_PCM_FLOAT.
+ case kSbMediaAudioSampleTypeInt16Deprecated:
+ return 2; // Android AudioFormat.ENCODING_PCM_16BIT.
}
-
- private:
- ::starboard::Mutex mutex_;
- std::deque<E> deque_;
-};
+ SB_NOTREACHED();
+ return 0u;
+}
} // namespace shared
} // namespace android
diff --git a/src/starboard/android/shared/media_decoder.h b/src/starboard/android/shared/media_decoder.h
index cb4d63f..6550cdd 100644
--- a/src/starboard/android/shared/media_decoder.h
+++ b/src/starboard/android/shared/media_decoder.h
@@ -49,6 +49,7 @@
// This class should be implemented by the users of MediaDecoder to receive
// various notifications. Note that all such functions are called on the
// decoder thread.
+ // TODO: Replace this with std::function<> based callbacks.
class Host {
public:
virtual void ProcessOutputBuffer(MediaCodecBridge* media_codec_bridge,
diff --git a/src/starboard/android/shared/media_is_audio_supported.cc b/src/starboard/android/shared/media_is_audio_supported.cc
index fe8b4ec..334c7dd 100644
--- a/src/starboard/android/shared/media_is_audio_supported.cc
+++ b/src/starboard/android/shared/media_is_audio_supported.cc
@@ -30,12 +30,18 @@
bool SbMediaIsAudioSupported(SbMediaAudioCodec audio_codec,
const char* content_type,
int64_t bitrate) {
+ if (bitrate >= kSbMediaMaxAudioBitrateInBitsPerSecond) {
+ return false;
+ }
+
// Android now uses libopus based opus decoder.
- if (audio_codec == kSbMediaAudioCodecOpus &&
- bitrate < kSbMediaMaxAudioBitrateInBitsPerSecond) {
+ if (audio_codec == kSbMediaAudioCodecOpus) {
return true;
}
- const char* mime = SupportedAudioCodecToMimeType(audio_codec);
+
+ bool is_passthrough = false;
+ const char* mime =
+ SupportedAudioCodecToMimeType(audio_codec, &is_passthrough);
if (!mime) {
return false;
}
@@ -76,8 +82,34 @@
ScopedLocalJavaRef<jstring> j_mime(env->NewStringStandardUTFOrAbort(mime));
const bool must_support_tunnel_mode =
enable_tunnel_mode_parameter_value == "true";
- return env->CallStaticBooleanMethodOrAbort(
- "dev/cobalt/media/MediaCodecUtil", "hasAudioDecoderFor",
- "(Ljava/lang/String;IZ)Z", j_mime.Get(),
- static_cast<jint>(bitrate), must_support_tunnel_mode) == JNI_TRUE;
+ auto media_codec_supported =
+ env->CallStaticBooleanMethodOrAbort(
+ "dev/cobalt/media/MediaCodecUtil", "hasAudioDecoderFor",
+ "(Ljava/lang/String;IZ)Z", j_mime.Get(), static_cast<jint>(bitrate),
+ must_support_tunnel_mode) == JNI_TRUE;
+ if (!media_codec_supported) {
+ return false;
+ }
+ if (!is_passthrough) {
+ return true;
+ }
+ SbMediaAudioCodingType coding_type;
+ switch (audio_codec) {
+ case kSbMediaAudioCodecAc3:
+ coding_type = kSbMediaAudioCodingTypeAc3;
+ break;
+ case kSbMediaAudioCodecEac3:
+ coding_type = kSbMediaAudioCodingTypeDolbyDigitalPlus;
+ break;
+ default:
+ return false;
+ }
+ int encoding =
+ ::starboard::android::shared::GetAudioFormatSampleType(coding_type);
+ ScopedLocalJavaRef<jobject> j_audio_output_manager(
+ env->CallStarboardObjectMethodOrAbort(
+ "getAudioOutputManager", "()Ldev/cobalt/media/AudioOutputManager;"));
+ return env->CallBooleanMethodOrAbort(j_audio_output_manager.Get(),
+ "hasPassthroughSupportFor", "(I)Z",
+ encoding) == JNI_TRUE;
}
diff --git a/src/starboard/android/shared/media_is_supported.cc b/src/starboard/android/shared/media_is_supported.cc
index 14db015..bd1f79e 100644
--- a/src/starboard/android/shared/media_is_supported.cc
+++ b/src/starboard/android/shared/media_is_supported.cc
@@ -30,11 +30,12 @@
return false;
}
- // Filter anything other then aac as we only support paid content on aac.
- // TODO: Add support of Opus if we are going to support software based drm
- // systems.
+ // We support all codecs except Opus in L1. Use allow list to avoid
+ // accidentally introducing the support of a codec brought in in future.
if (audio_codec != kSbMediaAudioCodecNone &&
- audio_codec != kSbMediaAudioCodecAac) {
+ audio_codec != kSbMediaAudioCodecAac &&
+ audio_codec != kSbMediaAudioCodecAc3 &&
+ audio_codec != kSbMediaAudioCodecEac3) {
return false;
}
if (!IsWidevineL1(key_system)) {
diff --git a/src/starboard/android/shared/platform_configuration/configuration.gni b/src/starboard/android/shared/platform_configuration/configuration.gni
index f0e73b2..19850b6 100644
--- a/src/starboard/android/shared/platform_configuration/configuration.gni
+++ b/src/starboard/android/shared/platform_configuration/configuration.gni
@@ -47,3 +47,5 @@
[ "//starboard/android/shared/platform_configuration:library_config" ]
install_target_path = "//starboard/android/shared/install_target.gni"
+
+sb_widevine_platform = "android"
diff --git a/src/starboard/android/shared/player_components_factory.h b/src/starboard/android/shared/player_components_factory.h
index 7caf57b..fa64270 100644
--- a/src/starboard/android/shared/player_components_factory.h
+++ b/src/starboard/android/shared/player_components_factory.h
@@ -19,6 +19,7 @@
#include <vector>
#include "starboard/android/shared/audio_decoder.h"
+#include "starboard/android/shared/audio_renderer_passthrough.h"
#include "starboard/android/shared/audio_track_audio_sink_type.h"
#include "starboard/android/shared/drm_system.h"
#include "starboard/android/shared/jni_env_ext.h"
@@ -41,14 +42,13 @@
#include "starboard/shared/starboard/player/filter/video_decoder_internal.h"
#include "starboard/shared/starboard/player/filter/video_render_algorithm.h"
#include "starboard/shared/starboard/player/filter/video_render_algorithm_impl.h"
+#include "starboard/shared/starboard/player/filter/video_renderer_internal_impl.h"
#include "starboard/shared/starboard/player/filter/video_renderer_sink.h"
namespace starboard {
namespace android {
namespace shared {
-using starboard::shared::starboard::media::MimeType;
-
// Tunnel mode has to be enabled explicitly by the web app via mime attributes
// "tunnelmode", set the following variable to true to force enabling tunnel
// mode on all playbacks.
@@ -126,6 +126,29 @@
atomic_bool error_occurred_;
};
+class PlayerComponentsPassthrough
+ : public starboard::shared::starboard::player::filter::PlayerComponents {
+ public:
+ PlayerComponentsPassthrough(
+ scoped_ptr<AudioRendererPassthrough> audio_renderer,
+ scoped_ptr<VideoRenderer> video_renderer)
+ : audio_renderer_(audio_renderer.Pass()),
+ video_renderer_(video_renderer.Pass()) {}
+
+ private:
+ // PlayerComponents methods
+ MediaTimeProvider* GetMediaTimeProvider() override {
+ return audio_renderer_.get();
+ }
+ AudioRenderer* GetAudioRenderer() override { return audio_renderer_.get(); }
+ VideoRenderer* GetVideoRenderer() override { return video_renderer_.get(); }
+
+ scoped_ptr<AudioRendererPassthrough> audio_renderer_;
+ scoped_ptr<VideoRenderer> video_renderer_;
+};
+
+// TODO: Invesigate if the implementation of member functions should be moved
+// into .cc file.
class PlayerComponentsFactory : public starboard::shared::starboard::player::
filter::PlayerComponents::Factory {
typedef starboard::shared::opus::OpusAudioDecoder OpusAudioDecoder;
@@ -137,6 +160,8 @@
AudioRendererSink;
typedef starboard::shared::starboard::player::filter::AudioRendererSinkImpl
AudioRendererSinkImpl;
+ typedef starboard::shared::starboard::player::filter::PlayerComponents
+ PlayerComponents;
typedef starboard::shared::starboard::player::filter::VideoDecoder
VideoDecoderBase;
typedef starboard::shared::starboard::player::filter::VideoRenderAlgorithm
@@ -157,6 +182,56 @@
return (value + alignment - 1) / alignment * alignment;
}
+ scoped_ptr<PlayerComponents> CreateComponents(
+ const CreationParameters& creation_parameters,
+ std::string* error_message) override {
+ SB_DCHECK(error_message);
+
+ if (creation_parameters.audio_codec() != kSbMediaAudioCodecAc3 &&
+ creation_parameters.audio_codec() != kSbMediaAudioCodecEac3) {
+ SB_LOG(INFO) << "Creating non-passthrough components.";
+ return PlayerComponents::Factory::CreateComponents(creation_parameters,
+ error_message);
+ }
+
+ SB_LOG(INFO) << "Creating passthrough components.";
+ // TODO: Enable tunnel mode for passthrough
+ scoped_ptr<AudioRendererPassthrough> audio_renderer;
+ audio_renderer.reset(new AudioRendererPassthrough(
+ creation_parameters.audio_sample_info(),
+ GetExtendedDrmSystem(creation_parameters.drm_system())));
+ if (!audio_renderer->is_valid()) {
+ return scoped_ptr<PlayerComponents>();
+ }
+
+ scoped_ptr<::starboard::shared::starboard::player::filter::VideoRenderer>
+ video_renderer;
+ if (creation_parameters.video_codec() != kSbMediaVideoCodecNone) {
+ constexpr int kTunnelModeAudioSessionId = -1;
+ constexpr bool kForceSecurePipelineUnderTunnelMode = false;
+
+ scoped_ptr<VideoDecoder> video_decoder = CreateVideoDecoder(
+ creation_parameters, kTunnelModeAudioSessionId,
+ kForceSecurePipelineUnderTunnelMode, error_message);
+ if (video_decoder) {
+ using starboard::shared::starboard::player::filter::VideoRendererImpl;
+
+ auto video_render_algorithm = video_decoder->GetRenderAlgorithm();
+ auto video_renderer_sink = video_decoder->GetSink();
+ auto media_time_provider = audio_renderer.get();
+
+ video_renderer.reset(new VideoRendererImpl(
+ scoped_ptr<VideoDecoderBase>(video_decoder.Pass()),
+ media_time_provider, video_render_algorithm.Pass(),
+ video_renderer_sink));
+ } else {
+ return scoped_ptr<PlayerComponents>();
+ }
+ }
+ return scoped_ptr<PlayerComponents>(new PlayerComponentsPassthrough(
+ audio_renderer.Pass(), video_renderer.Pass()));
+ }
+
bool CreateSubComponents(
const CreationParameters& creation_parameters,
scoped_ptr<AudioDecoderBase>* audio_decoder,
@@ -165,6 +240,7 @@
scoped_ptr<VideoRenderAlgorithmBase>* video_render_algorithm,
scoped_refptr<VideoRendererSink>* video_renderer_sink,
std::string* error_message) override {
+ using starboard::shared::starboard::media::MimeType;
SB_DCHECK(error_message);
int tunnel_mode_audio_session_id = -1;
@@ -242,7 +318,8 @@
return audio_decoder_impl.PassAs<AudioDecoderBase>();
}
} else {
- SB_NOTREACHED();
+ SB_LOG(ERROR) << "Unsupported audio codec "
+ << audio_sample_info.codec;
}
return scoped_ptr<AudioDecoderBase>();
};
@@ -288,24 +365,16 @@
force_secure_pipeline_under_tunnel_mode = false;
}
- scoped_ptr<VideoDecoder> video_decoder_impl(new VideoDecoder(
- creation_parameters.video_codec(),
- GetExtendedDrmSystem(creation_parameters.drm_system()),
- creation_parameters.output_mode(),
- creation_parameters.decode_target_graphics_context_provider(),
- creation_parameters.max_video_capabilities(),
- tunnel_mode_audio_session_id, force_secure_pipeline_under_tunnel_mode,
- error_message));
- if (creation_parameters.video_codec() == kSbMediaVideoCodecAv1 ||
- video_decoder_impl->is_decoder_created()) {
+ scoped_ptr<VideoDecoder> video_decoder_impl = CreateVideoDecoder(
+ creation_parameters, tunnel_mode_audio_session_id,
+ force_secure_pipeline_under_tunnel_mode, error_message);
+ if (video_decoder_impl) {
*video_render_algorithm = video_decoder_impl->GetRenderAlgorithm();
*video_renderer_sink = video_decoder_impl->GetSink();
video_decoder->reset(video_decoder_impl.release());
} else {
video_decoder->reset();
*video_renderer_sink = NULL;
- *error_message =
- "Failed to create video decoder with error: " + *error_message;
return false;
}
}
@@ -338,6 +407,28 @@
*max_cached_frames = AlignUp(*max_cached_frames, kAudioSinkFramesAlignment);
}
+ scoped_ptr<VideoDecoder> CreateVideoDecoder(
+ const CreationParameters& creation_parameters,
+ int tunnel_mode_audio_session_id,
+ bool force_secure_pipeline_under_tunnel_mode,
+ std::string* error_message) {
+ scoped_ptr<VideoDecoder> video_decoder(new VideoDecoder(
+ creation_parameters.video_codec(),
+ GetExtendedDrmSystem(creation_parameters.drm_system()),
+ creation_parameters.output_mode(),
+ creation_parameters.decode_target_graphics_context_provider(),
+ creation_parameters.max_video_capabilities(),
+ tunnel_mode_audio_session_id, force_secure_pipeline_under_tunnel_mode,
+ error_message));
+ if (creation_parameters.video_codec() == kSbMediaVideoCodecAv1 ||
+ video_decoder->is_decoder_created()) {
+ return video_decoder.Pass();
+ }
+ *error_message =
+ "Failed to create video decoder with error: " + *error_message;
+ return scoped_ptr<VideoDecoder>();
+ }
+
bool IsTunnelModeSupported(const CreationParameters& creation_parameters,
bool* force_secure_pipeline_under_tunnel_mode) {
SB_DCHECK(force_secure_pipeline_under_tunnel_mode);
diff --git a/src/starboard/android/shared/player_create.cc b/src/starboard/android/shared/player_create.cc
index 3cb64f9..f4c4083 100644
--- a/src/starboard/android/shared/player_create.cc
+++ b/src/starboard/android/shared/player_create.cc
@@ -83,6 +83,8 @@
if (audio_codec != kSbMediaAudioCodecNone &&
audio_codec != kSbMediaAudioCodecAac &&
+ audio_codec != kSbMediaAudioCodecAc3 &&
+ audio_codec != kSbMediaAudioCodecEac3 &&
audio_codec != kSbMediaAudioCodecOpus) {
SB_LOG(ERROR) << "Unsupported audio codec " << audio_codec;
return kSbPlayerInvalid;
diff --git a/src/starboard/android/shared/starboard_platform.gypi b/src/starboard/android/shared/starboard_platform.gypi
index 87bad6c..8338cbc 100644
--- a/src/starboard/android/shared/starboard_platform.gypi
+++ b/src/starboard/android/shared/starboard_platform.gypi
@@ -65,7 +65,9 @@
'atomic_public.h',
'audio_decoder.cc',
'audio_decoder.h',
- 'audio_renderer.h',
+ 'audio_decoder_passthrough.h',
+ 'audio_renderer_passthrough.cc',
+ 'audio_renderer_passthrough.h',
'audio_sink_get_max_channels.cc',
'audio_sink_get_min_buffer_size_in_frames.cc',
'audio_sink_min_required_frames_tester.cc',
@@ -75,6 +77,8 @@
'audio_sink_is_audio_sample_type_supported.cc',
'audio_track_audio_sink_type.cc',
'audio_track_audio_sink_type.h',
+ 'audio_track_bridge.cc',
+ 'audio_track_bridge.h',
'bionic/bionic_netlink.cpp',
'bionic/bionic_netlink.h',
'bionic/ifaddrs.cpp',
diff --git a/src/starboard/build/collect_deploy_content.py b/src/starboard/build/collect_deploy_content.py
index 7009367..3f03b9d 100755
--- a/src/starboard/build/collect_deploy_content.py
+++ b/src/starboard/build/collect_deploy_content.py
@@ -60,6 +60,19 @@
raise RuntimeError('Content is %d levels deep (max allowed is %d): %s' %
(depth, max_depth, deepest_file))
+def _CopyTree(src_path, dst_path):
+ """Copy tree with a safeguard for windows long path (>260).
+
+ On Windows Python is facing long path limitation, for more details see
+ https://bugs.python.org/issue27730
+ """
+ if os.sep == '\\':
+ prefix = '\\\\?\\'
+ if prefix not in src_path:
+ src_path = prefix + src_path
+ if prefix not in dst_path:
+ dst_path = prefix + dst_path
+ shutil.copytree(src_path, dst_path)
def main(argv):
parser = argparse.ArgumentParser()
@@ -141,7 +154,7 @@
logging.error(msg)
if options.copy_override:
- shutil.copytree(src_path, dst_path)
+ _CopyTree(src_path, dst_path)
elif options.use_absolute_symlinks:
port_symlink.MakeSymLink(
target_path=os.path.abspath(src_path),
diff --git a/src/starboard/build/config/BUILDCONFIG.gn b/src/starboard/build/config/BUILDCONFIG.gn
index 4b455b3..31a8fd5 100644
--- a/src/starboard/build/config/BUILDCONFIG.gn
+++ b/src/starboard/build/config/BUILDCONFIG.gn
@@ -24,6 +24,8 @@
is_starboard = true
cobalt_fastbuild = getenv("IS_CI") == 1
+
+ is_internal_build = false
}
is_debug = build_type == "debug"
diff --git a/src/starboard/build/config/sabi/BUILD.gn b/src/starboard/build/config/sabi/BUILD.gn
index 8b03959..081e595 100644
--- a/src/starboard/build/config/sabi/BUILD.gn
+++ b/src/starboard/build/config/sabi/BUILD.gn
@@ -38,10 +38,15 @@
],
"trim string")
- mock_sabi_id = "\"MOCK_SABI_ID\""
+ sabi_id = exec_script("//starboard/sabi/generate_sabi_id.py",
+ [
+ "-f",
+ rebase_path(sabi_path, root_build_dir),
+ ],
+ "trim string")
defines = [
- "SB_SABI_JSON_ID=$mock_sabi_id",
+ "SB_SABI_JSON_ID=R\"($sabi_id)\"",
"SB_API_VERSION=$sb_api_version",
"SB_IS_ARCH_${arch_uppercase}=1",
diff --git a/src/starboard/build/doc/migration_changes.md b/src/starboard/build/doc/migration_changes.md
index 6ff5712..145ed7b 100644
--- a/src/starboard/build/doc/migration_changes.md
+++ b/src/starboard/build/doc/migration_changes.md
@@ -11,6 +11,10 @@
:---------------------------------------- | :--------------------------------------------------- | :----------
`OS` ("starboard"/other) | `is_starboard` (true/false) | (global)
`clang` (0/1) | `is_clang` (true/false) | (global)
+`has_input_events_filter` | `is_internal_build` (true/false) | (global)
+`has_drm_system_extension` | `is_internal_build` (true/false) | (global)
+`has_cdm` | `is_internal_build` (true/false) | (global)
+`has_private_system_properties` | `is_internal_build` (true/false) | (global)
`sb_deploy_output_dir` | `sb_install_output_dir` | `//starboard/build/config/base_configuration.gni`
`sb_evergreen` (0/1) | `sb_is_evergreen` (true/false) | `//starboard/build/config/base_configuration.gni`
`sb_evergreen_compatible` (0/1) | `sb_is_evergreen_compatible` (true/false) | `//starboard/build/config/base_configuration.gni`
diff --git a/src/starboard/common/log.h b/src/starboard/common/log.h
index 61a6ebf..9438a17 100644
--- a/src/starboard/common/log.h
+++ b/src/starboard/common/log.h
@@ -168,8 +168,10 @@
#if SB_LOGGING_IS_OFFICIAL_BUILD || \
(defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON))
#define SB_DCHECK(condition) SB_EAT_STREAM_PARAMETERS
+#define SB_DCHECK_ENABLED 0
#else
#define SB_DCHECK(condition) SB_CHECK(condition)
+#define SB_DCHECK_ENABLED 1
#endif
#define SB_DLOG(severity) SB_DLOG_IF(severity, SB_DLOG_IS_ON(severity))
@@ -224,8 +226,10 @@
#if SB_LOGGING_IS_OFFICIAL_BUILD
#define SB_NOTIMPLEMENTED()
#define SB_DCHECK(condition)
+#define SB_DCHECK_ENABLED 0
#else
#define SB_DCHECK(condition) SB_CHECK(condition)
+#define SB_DCHECK_ENABLED 1
#define SB_NOTIMPLEMENTED() \
do { \
static int count = 0; \
diff --git a/src/starboard/doc/evergreen/cobalt_evergreen_overview.md b/src/starboard/doc/evergreen/cobalt_evergreen_overview.md
index 93bcde0..75b6940 100644
--- a/src/starboard/doc/evergreen/cobalt_evergreen_overview.md
+++ b/src/starboard/doc/evergreen/cobalt_evergreen_overview.md
@@ -111,12 +111,12 @@
The gyp variable `sb_evergreen` is set to 1 when building `libcobalt.so`.
The partner port of Starboard is built with the partner’s toolchain and is
-linked into the **`loader_app` which knows how to dynamically load
+linked into the `loader_app` which knows how to dynamically load
`libcobalt.so`, and the `crashpad_handler` which handles crashes.
```
-cobalt/build/gyp_cobalt <partner_port_name>
-ninja -C out/<partner_port_name>_qa loader_app crashpad_handler
+$ cobalt/build/gyp_cobalt <partner_port_name>
+$ ninja -C out/<partner_port_name>_qa loader_app crashpad_handler
```
Partners should set `sb_evergreen_compatible` to 1 in their gyp platform config.
@@ -254,7 +254,7 @@
## Verifying Platform Requirements
In order to verify the platform requirements you should run the
-‘nplb\_evergreen\_compat\_tests’. These tests ensure that the platform is
+`nplb_evergreen_compat_tests`. These tests ensure that the platform is
configured appropriately for Evergreen.
To enable the test, set the `sb_evergreen_compatible gyp` variable to 1 in the
@@ -264,6 +264,44 @@
There is a reference implementation available for Raspberry Pi 2 with
instructions available [here](cobalt_evergreen_reference_port_raspi2.md).
+### Verifying Crashpad Uploads
+
+1. Build the `crashpad_database_util` target and deploy it onto the device.
+```
+$ cobalt/build/gyp_cobalt <partner_port_name>
+$ ninja -C out/<partner_port_name>_qa crashpad_database_util
+```
+2. Remove the existing state for crashpad as it throttles uploads to 1 per hour:
+```
+$ rm -rf <kSbSystemPathCacheDirectory>/crashpad_database/
+
+```
+3. Launch Cobalt.
+4. Trigger crash by sending `abort` signal to the `loader_app` process:
+```
+$ kill -6 <pid>
+```
+5. Verify the crash was uploaded through running `crashpad_database_util` on the device
+pointing it to the cache directory, where the crash data is stored.
+
+```
+$ crashpad_database_util -d <kSbSystemPathCacheDirectory>/crashpad_database/ --show-completed-reports --show-all-report-info
+```
+
+```
+8c3af145-30a0-43c7-a3a5-0952dea230e4:
+ Path: cobalt/cache/crashpad_database/completed/8c3af145-30a0-43c7-a3a5-0952dea230e4.dmp
+ Remote ID: c9b14b489a895093
+ Creation time: 2021-06-01 17:01:19 HDT
+ Uploaded: true
+ Last upload attempt time: 2021-06-01 17:01:19 HDT
+ Upload attempts: 1
+```
+
+In this example the minidump was successfully uploaded because we see `Uploaded: true`.
+
+Reference for [crashpad_database_util](https://chromium.googlesource.com/crashpad/crashpad/+/refs/heads/main/tools/crashpad_database_util.md)
+
## System Design
![Cobalt Evergreen
diff --git a/src/starboard/elf_loader/BUILD.gn b/src/starboard/elf_loader/BUILD.gn
index e150d2f..9ce393b 100644
--- a/src/starboard/elf_loader/BUILD.gn
+++ b/src/starboard/elf_loader/BUILD.gn
@@ -12,6 +12,153 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+_elf_loader_sources = [
+ "dynamic_section.cc",
+ "dynamic_section.h",
+ "elf_hash_table.cc",
+ "elf_hash_table.h",
+ "elf_header.cc",
+ "elf_header.h",
+ "elf_loader.cc",
+ "elf_loader.h",
+ "elf_loader_constants.cc",
+ "elf_loader_constants.h",
+ "exported_symbols.cc",
+ "file.h",
+ "file_impl.cc",
+ "file_impl.h",
+ "gnu_hash_table.cc",
+ "gnu_hash_table.h",
+ "lz4_file_impl.cc",
+ "lz4_file_impl.h",
+ "program_table.cc",
+ "program_table.h",
+ "relocations.cc",
+ "relocations.h",
+]
+
+config("elf_loader_config") {
+ include_dirs = [
+ "src/include",
+ "src/src",
+ ]
+}
+
+static_library("elf_loader") {
+ sources = _elf_loader_sources + [
+ "elf_loader_impl.cc",
+ "elf_loader_impl.h",
+ ]
+
+ configs += [ ":elf_loader_config" ]
+
+ deps = [
+ ":evergreen_config",
+ ":evergreen_info",
+ "//starboard",
+ "//third_party/lz4_lib:lz4",
+ ]
+}
+
+static_library("elf_loader_sys") {
+ # System loader based on dlopen/dlsym.
+ # Should be used only for debugging/troubleshooting.
+ sources = _elf_loader_sources + [
+ "elf_loader_impl.h",
+ "elf_loader_sys_impl.cc",
+ "elf_loader_sys_impl.h",
+ ]
+
+ configs += [ ":elf_loader_config" ]
+
+ deps = [
+ ":evergreen_config",
+ ":evergreen_info",
+ "//starboard",
+ ]
+
+ if (sb_is_evergreen_compatible) {
+ deps += [ "//third_party/crashpad/wrapper" ]
+ } else {
+ deps += [ "//third_party/crashpad/wrapper:wrapper_stub" ]
+ }
+}
+
+target(final_executable_type, "elf_loader_sandbox") {
+ sources = [ "sandbox.cc" ]
+ configs += [ ":elf_loader_config" ]
+
+ deps = [
+ ":elf_loader",
+ ":evergreen_info",
+ ":sabi_string",
+ "//cobalt/content/fonts:copy_font_data",
+ "//starboard",
+ ]
+}
+
+target(final_executable_type, "elf_loader_sys_sandbox") {
+ # To properly function the system loader requires the starboard
+ # symbols to be exported from the binary.
+ # To allow symbols to be exported remove the '-fvisibility=hidden' flag
+ # from your compiler_flags.gypi. For Linux this would be:
+ # starboard/linux/shared/compiler_flags.gypi
+ # Example run:
+ # export LD_LIBRARY_PATH=.
+ # ./elf_loader_sys_sandbox --evergreen_library=app/cobalt/lib/libcobalt.so --evergreen_content=app/cobalt/content
+ sources = [ "sandbox.cc" ]
+ configs += [ ":elf_loader_config" ]
+
+ starboard_syms_path =
+ rebase_path("//starboard/starboard.syms", root_build_dir)
+ ldflags = [
+ "-Wl,--dynamic-list=$starboard_syms_path",
+ "-ldl",
+ ]
+
+ deps = [
+ ":elf_loader_sys",
+ ":evergreen_info",
+ ":sabi_string",
+ "//starboard",
+ ]
+}
+
+target(gtest_target_type, "elf_loader_test") {
+ testonly = true
+ sources = [ "//starboard/common/test_main.cc" ]
+ deps = [
+ "//starboard",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+
+ if (target_cpu == "x86" || target_cpu == "x64" || target_cpu == "arm" ||
+ target_cpu == "arm64") {
+ sources += [
+ "dynamic_section_test.cc",
+ "elf_header_test.cc",
+ "elf_loader_test.cc",
+ "lz4_file_impl_test.cc",
+ "program_table_test.cc",
+ "relocations_test.cc",
+ ]
+ deps += [
+ ":copy_elf_loader_testdata",
+ ":elf_loader",
+ ]
+ }
+}
+
+copy("copy_elf_loader_testdata") {
+ sources = [
+ "testdata/compressed.lz4",
+ "testdata/uncompressed",
+ ]
+ subdir = "starboard/elf_loader"
+ outputs = [ "$sb_static_contents_output_data_dir/test/$subdir/{{source_target_relative}}" ]
+}
+
static_library("evergreen_info") {
sources = [
"evergreen_info.cc",
@@ -29,3 +176,12 @@
public_deps = [ "//starboard/common" ]
}
+
+static_library("sabi_string") {
+ sources = [
+ "sabi_string.cc",
+ "sabi_string.h",
+ ]
+
+ deps = [ "//starboard/common" ]
+}
diff --git a/src/starboard/elf_loader/exported_symbols.cc b/src/starboard/elf_loader/exported_symbols.cc
index c6b56f6..791b129 100644
--- a/src/starboard/elf_loader/exported_symbols.cc
+++ b/src/starboard/elf_loader/exported_symbols.cc
@@ -231,7 +231,7 @@
REGISTER_SYMBOL(SbStringConcatWide);
REGISTER_SYMBOL(SbStringCopy);
REGISTER_SYMBOL(SbStringCopyWide);
-#endif // SB_API_VERSION >= 13
+#endif // SB_API_VERSION < 13
REGISTER_SYMBOL(SbStringDuplicate);
#if SB_API_VERSION < 13
REGISTER_SYMBOL(SbStringFindCharacter);
diff --git a/src/starboard/evergreen/testing/linux/start_cobalt.sh b/src/starboard/evergreen/testing/linux/start_cobalt.sh
index b060bbc..70dc749 100755
--- a/src/starboard/evergreen/testing/linux/start_cobalt.sh
+++ b/src/starboard/evergreen/testing/linux/start_cobalt.sh
@@ -30,7 +30,7 @@
URL="${1}"
LOG="${2}"
- __LOADER="${3}"
+ declare -n loader_pid_ref=$3
ARGS="${4}"
stop_cobalt
@@ -44,9 +44,9 @@
log "info" " Logs will be output to '${LOG_PATH}/${LOG}'"
- eval "${OUT}/loader_app --url=\"\"${URL}\"\" ${ARGS} 2>&1 | tee \"${LOG_PATH}/${LOG}\"" &
+ eval "${OUT}/loader_app --url=\"\"${URL}\"\" ${ARGS} &> >(tee \"${LOG_PATH}/${LOG}\") &"
- eval $__LOADER=$!
+ loader_pid_ref=$!
- log "info" " Cobalt process ID is ${__LOADER}"
+ log "info" " Cobalt process ID is ${loader_pid_ref}"
}
diff --git a/src/starboard/linux/shared/BUILD.gn b/src/starboard/linux/shared/BUILD.gn
index c45fdac..522b781 100644
--- a/src/starboard/linux/shared/BUILD.gn
+++ b/src/starboard/linux/shared/BUILD.gn
@@ -14,10 +14,6 @@
import("//starboard/shared/starboard/player/buildfiles.gni")
-declare_args() {
- has_cdm = false
-}
-
group("starboard_platform") {
public_deps = [
":starboard_base_symbolize",
@@ -68,7 +64,11 @@
"//starboard/linux/shared/decode_target_release.cc",
"//starboard/linux/shared/media_is_audio_supported.cc",
"//starboard/linux/shared/media_is_video_supported.cc",
+ "//starboard/linux/shared/netlink.cc",
+ "//starboard/linux/shared/netlink.h",
"//starboard/linux/shared/player_components_factory.cc",
+ "//starboard/linux/shared/routes.cc",
+ "//starboard/linux/shared/routes.h",
"//starboard/linux/shared/system_get_connection_type.cc",
"//starboard/linux/shared/system_get_device_type.cc",
"//starboard/linux/shared/system_get_extensions.cc",
@@ -386,8 +386,42 @@
sources += common_player_sources
- if (has_cdm) {
- # TODO(andrewsavage)
+ configs += [
+ "//starboard/build/config:starboard_implementation",
+ "//third_party/de265_includes",
+ "//third_party/pulseaudio_includes",
+ ]
+
+ public_deps = [
+ "//starboard:starboard_headers_only",
+ "//starboard/shared/starboard/player/filter:filter_based_player_sources",
+ ]
+ deps = [ "//third_party/boringssl:crypto" ]
+
+ if (is_internal_build) {
+ sources += [
+ "//starboard/linux/shared/drm_create_system.cc",
+ "//starboard/linux/shared/oemcrypto_engine_device_properties_linux.cc",
+ "//starboard/shared/starboard/drm/drm_close_session.cc",
+ "//starboard/shared/starboard/drm/drm_destroy_system.cc",
+ "//starboard/shared/starboard/drm/drm_generate_session_update_request.cc",
+ "//starboard/shared/starboard/drm/drm_get_metrics.cc",
+ "//starboard/shared/starboard/drm/drm_is_server_certificate_updatable.cc",
+ "//starboard/shared/starboard/drm/drm_system_internal.h",
+ "//starboard/shared/starboard/drm/drm_update_server_certificate.cc",
+ "//starboard/shared/starboard/drm/drm_update_session.cc",
+ "//starboard/shared/widevine/drm_system_widevine.cc",
+ "//starboard/shared/widevine/drm_system_widevine.h",
+ "//starboard/shared/widevine/media_is_supported.cc",
+ "//starboard/shared/widevine/widevine_storage.cc",
+ "//starboard/shared/widevine/widevine_storage.h",
+ "//starboard/shared/widevine/widevine_timer.cc",
+ "//starboard/shared/widevine/widevine_timer.h",
+ ]
+ deps += [
+ "//starboard/shared/widevine:oemcrypto",
+ "//third_party/ce_cdm/cdm:widevine_ce_cdm_static",
+ ]
} else {
sources += [
"//starboard/shared/stub/drm_close_session.cc",
@@ -401,15 +435,4 @@
"//starboard/shared/stub/media_is_supported.cc",
]
}
-
- public_deps = [
- "//starboard:starboard_headers_only",
- "//starboard/shared/starboard/player/filter:filter_based_player_sources",
- ]
- deps = [ "//third_party/boringssl:crypto" ]
- configs += [
- "//starboard/build/config:starboard_implementation",
- "//third_party/de265_includes",
- "//third_party/pulseaudio_includes",
- ]
}
diff --git a/src/starboard/linux/shared/netlink.cc b/src/starboard/linux/shared/netlink.cc
new file mode 100644
index 0000000..69378a2
--- /dev/null
+++ b/src/starboard/linux/shared/netlink.cc
@@ -0,0 +1,169 @@
+// Copyright 2021 The Cobalt Authors. 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 "starboard/linux/shared/netlink.h"
+
+#include <linux/netlink.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "starboard/common/log.h"
+#include "starboard/types.h"
+
+// Omit namespace linux due to symbol name conflict.
+namespace starboard {
+namespace shared {
+
+namespace {
+void LogLastError(const char* msg) {
+ const int kErrorMessageBufferSize = 256;
+ char msgbuf[kErrorMessageBufferSize];
+ SbSystemError error_code = SbSystemGetLastError();
+ if (SbSystemGetErrorString(error_code, msgbuf, kErrorMessageBufferSize) > 0) {
+ SB_LOG(ERROR) << msg << ": " << msgbuf;
+ }
+}
+
+// Buffer size for receiving netlink messages. Should be large enough to hold
+// the full routing table dump.
+const size_t kNetlinkMessageBufferSize = 32768;
+} // namespace
+
+// Open the netlink socket.
+bool NetLink::Open(int type, int protocol) {
+ // https://man7.org/linux/man-pages/man7/netlink.7.html
+ // https://datatracker.ietf.org/doc/html/rfc3549#section-2
+ socket_fd_ = socket(AF_NETLINK, type, protocol);
+ if (socket_fd_ == -1) {
+ LogLastError("Netlink Request socket could not be opened");
+ return false;
+ }
+
+#if !defined(MSG_NOSIGNAL) && defined(SO_NOSIGPIPE)
+ {
+ // Use SO_NOSIGPIPE to mute SIGPIPE on darwin systems.
+ int optval_set = 1;
+ setsockopt(socket_fd_, SOL_SOCKET, SO_NOSIGPIPE,
+ reinterpret_cast<void*>(&optval_set), sizeof(int));
+ }
+#endif
+
+#if defined(NETLINK_DUMP_STRICT_CHK)
+ {
+ int optval_set = 1;
+ setsockopt(socket_fd_, SOL_NETLINK, NETLINK_DUMP_STRICT_CHK,
+ reinterpret_cast<void*>(&optval_set), sizeof(int));
+ }
+#endif
+ return true;
+}
+
+bool NetLink::IsOpened() {
+ return socket_fd_ != -1;
+}
+
+void NetLink::Close() {
+ if (socket_fd_ != -1) {
+ shutdown(socket_fd_, SHUT_RDWR);
+ close(socket_fd_);
+ socket_fd_ = -1;
+ }
+ request_sent_ = false;
+}
+
+// Send a netlink request.
+bool NetLink::Request(uint16_t type,
+ uint16_t message_flags,
+ void* payload,
+ int payload_length) {
+ if (!IsOpened())
+ return false;
+ std::vector<char> netlink_buffer(NLMSG_LENGTH(payload_length));
+ auto header = reinterpret_cast<struct nlmsghdr*>(netlink_buffer.data());
+ memcpy(NLMSG_DATA(header), payload, payload_length);
+
+ header->nlmsg_len = netlink_buffer.size();
+ header->nlmsg_type = type;
+ header->nlmsg_flags = NLM_F_REQUEST | message_flags;
+ header->nlmsg_seq = ++request_sequence_;
+ request_sent_ =
+ send(socket_fd_, netlink_buffer.data(), netlink_buffer.size(), 0) != -1;
+ return request_sent_;
+}
+
+// Return the next netlink message. Returns nullptr if there are no more
+// messages.
+struct nlmsghdr* NetLink::GetNextMessage() {
+ // If we already have a message header, return the next header in the
+ // message if there is one.
+ if (header_) {
+ if ((header_->nlmsg_type == NLMSG_DONE) ||
+ ((header_->nlmsg_flags & NLM_F_MULTI) == 0)) {
+ // This is not a multipart response, or the last header.
+ message_length_ = 0;
+ header_ = nullptr;
+ } else {
+ // Get the next header.
+ header_ = NLMSG_NEXT(header_, message_length_);
+ if ((NLMSG_OK(header_, message_length_) == 0) ||
+ (header_->nlmsg_type == NLMSG_ERROR)) {
+ header_ = nullptr;
+ }
+ }
+ }
+
+ if (header_)
+ return header_;
+
+ // Receive the next message with netlink headers.
+ if (!request_sent_)
+ return nullptr;
+ if (message_buffer_.size() == 0) {
+ message_buffer_.resize(kNetlinkMessageBufferSize);
+ }
+ message_length_ =
+ recv(socket_fd_, message_buffer_.data(), message_buffer_.size(), 0);
+ if (message_length_ == -1) {
+ Close();
+ return nullptr;
+ }
+
+ header_ = reinterpret_cast<struct nlmsghdr*>(message_buffer_.data());
+ if ((NLMSG_OK(header_, message_length_) == 0) ||
+ (header_->nlmsg_type == NLMSG_ERROR)) {
+ Close();
+ return nullptr;
+ }
+
+ if ((header_->nlmsg_type == NLMSG_DONE) ||
+ ((header_->nlmsg_flags & NLM_F_MULTI) == 0) ||
+ (header_->nlmsg_pid == 0)) {
+ request_sent_ = false;
+ }
+
+ if ((header_->nlmsg_seq != request_sequence_)) {
+ SB_LOG(WARNING) << "Unexpected different sequence " << header_->nlmsg_seq
+ << "!= " << request_sequence_ << ".";
+ Close();
+ return nullptr;
+ }
+
+ return header_;
+}
+
+} // namespace shared
+} // namespace starboard
diff --git a/src/starboard/linux/shared/netlink.h b/src/starboard/linux/shared/netlink.h
new file mode 100644
index 0000000..2b7f2ca
--- /dev/null
+++ b/src/starboard/linux/shared/netlink.h
@@ -0,0 +1,70 @@
+// Copyright 2021 The Cobalt Authors. 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.
+
+#ifndef STARBOARD_LINUX_SHARED_NETLINK_H_
+#define STARBOARD_LINUX_SHARED_NETLINK_H_
+
+#include <linux/netlink.h>
+
+#include <vector>
+
+#include "starboard/types.h"
+
+// Omit namespace linux due to symbol name conflict.
+namespace starboard {
+namespace shared {
+
+// Support class for netlink sockets.
+// https://man7.org/linux/man-pages/man7/netlink.7.html
+
+// Helper class for the netlink socket API.
+class NetLink {
+ public:
+ NetLink() {}
+ virtual ~NetLink() { Close(); }
+
+ // Open the netlink socket.
+ bool Open(int type, int protocol);
+
+ bool IsOpened();
+
+ void Close();
+
+ // Send a netlink request.
+ bool Request(uint16_t type,
+ uint16_t message_flags,
+ void* payload = nullptr,
+ int payload_length = 0);
+
+ // Return the next netlink message. Returns nullptr if there are no more
+ // messages.
+ struct nlmsghdr* GetNextMessage();
+
+ private:
+ NetLink(const NetLink&) = delete;
+ NetLink& operator=(NetLink&&) = delete;
+ void operator=(const NetLink&) = delete;
+
+ int socket_fd_ = -1;
+ int request_sequence_ = 0;
+ bool request_sent_ = false;
+ std::vector<char> message_buffer_;
+ int message_length_ = 0;
+ struct nlmsghdr* header_ = nullptr;
+};
+
+} // namespace shared
+} // namespace starboard
+
+#endif // STARBOARD_LINUX_SHARED_NETLINK_H_
diff --git a/src/starboard/linux/shared/platform_configuration/configuration.gni b/src/starboard/linux/shared/platform_configuration/configuration.gni
index 437b035..3618b00 100644
--- a/src/starboard/linux/shared/platform_configuration/configuration.gni
+++ b/src/starboard/linux/shared/platform_configuration/configuration.gni
@@ -26,3 +26,5 @@
speed_config_path = "//starboard/linux/shared/platform_configuration:speed"
size_config_path = "//starboard/linux/shared/platform_configuration:size"
+
+sb_widevine_platform = "linux"
diff --git a/src/starboard/linux/shared/routes.cc b/src/starboard/linux/shared/routes.cc
new file mode 100644
index 0000000..0c3c613
--- /dev/null
+++ b/src/starboard/linux/shared/routes.cc
@@ -0,0 +1,153 @@
+// Copyright 2021 The Cobalt Authors. 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 "starboard/linux/shared/routes.h"
+
+#include <arpa/inet.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+// This include has to be loaded after net/if.h.
+#include <linux/wireless.h> // NOLINT(build/include_order)
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "starboard/common/log.h"
+#include "starboard/linux/shared/netlink.h"
+
+// Omit namespace linux due to symbol name conflict.
+namespace starboard {
+namespace shared {
+
+namespace {
+void LogLastError(const char* msg) {
+ const int kErrorMessageBufferSize = 256;
+ char msgbuf[kErrorMessageBufferSize];
+ SbSystemError error_code = SbSystemGetLastError();
+ if (SbSystemGetErrorString(error_code, msgbuf, kErrorMessageBufferSize) > 0) {
+ SB_LOG(ERROR) << msg << ": " << msgbuf;
+ }
+}
+} // namespace
+
+// Return true if the route has the default destination address.
+// static
+bool Routes::IsDefaultRoute(const Route& route) {
+ switch (route.family) {
+ case AF_INET6:
+ return memcmp(&route.dst_addr6, &in6addr_any, sizeof(in6addr_any)) == 0;
+ case AF_INET:
+ return route.dst_addr == INADDR_ANY;
+ default:
+ return false;
+ }
+}
+
+// Return true if the route uses a wireless interface.
+// static
+bool Routes::IsWirelessInterface(const Route& route) {
+ int socket_fd = -1;
+
+ if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+ LogLastError("socket");
+ return false;
+ }
+
+ struct iwreq request;
+ memset(&request, 0, sizeof(request));
+ strncpy(request.ifr_name, route.name, IFNAMSIZ);
+ if (ioctl(socket_fd, SIOCGIWNAME, &request) != -1) {
+ close(socket_fd);
+ return true;
+ }
+
+ close(socket_fd);
+ return false;
+}
+
+// Open the netlink socket for routing table information.
+bool Routes::Open() {
+ // https://datatracker.ietf.org/doc/html/rfc3549#section-3.1
+
+ // https://man7.org/linux/man-pages/man7/rtnetlink.7.html
+ return NetLink::Open(SOCK_DGRAM, NETLINK_ROUTE);
+}
+
+// Request a dump of the routing tables from the netlink socket.
+bool Routes::RequestDump() {
+ if (!IsOpened())
+ Open();
+ struct rtmsg header;
+ memset(&header, 0, sizeof(header));
+ // header.rtm_family=AF_INET6;
+ header.rtm_table = RT_TABLE_UNSPEC;
+ header.rtm_protocol = RTPROT_UNSPEC;
+ header.rtm_scope = RT_SCOPE_UNIVERSE;
+ header.rtm_type = RTN_UNSPEC;
+ return Request(RTM_GETROUTE, NLM_F_DUMP, &header, sizeof(header));
+}
+
+// static
+void Routes::GetRouteFromNetlinkMessage(struct nlmsghdr* message,
+ Route& route) {
+ auto route_message = reinterpret_cast<struct rtmsg*>(NLMSG_DATA(message));
+ memset(&route, 0, sizeof(route));
+ route.family = route_message->rtm_family;
+ int payload = RTM_PAYLOAD(message);
+ for (struct rtattr* attribute = RTM_RTA(route_message);
+ RTA_OK(attribute, payload); attribute = RTA_NEXT(attribute, payload)) {
+ void* data = RTA_DATA(attribute);
+ const int& value(*reinterpret_cast<int*>(data));
+ switch (attribute->rta_type) {
+ case RTA_OIF:
+ if (!if_indextoname(value, route.name)) {
+ continue;
+ }
+ break;
+ case RTA_DST:
+ if (route.family == AF_INET6) {
+ memcpy(&route.dst_addr6, data, sizeof(route.dst_addr6));
+ } else {
+ SB_DCHECK(route.family == AF_INET);
+ memcpy(&route.dst_addr, data, sizeof(route.dst_addr));
+ }
+ break;
+ case RTA_PRIORITY:
+ route.priority = value;
+ }
+ }
+}
+
+// Return the next route from the netlink interface message. Returns nullptr
+// when no more routes are available.
+Routes::Route* Routes::GetNextRoute() {
+ struct nlmsghdr* message = nullptr;
+ while ((message = GetNextMessage())) {
+ auto route = reinterpret_cast<struct rtmsg*>(NLMSG_DATA(message));
+ if (route->rtm_table != RT_TABLE_MAIN) {
+ continue;
+ }
+ if (route->rtm_family == AF_INET || route->rtm_family == AF_INET6) {
+ GetRouteFromNetlinkMessage(message, last_route_);
+ return &last_route_;
+ }
+ }
+ return nullptr;
+}
+
+} // namespace shared
+} // namespace starboard
diff --git a/src/starboard/linux/shared/routes.h b/src/starboard/linux/shared/routes.h
new file mode 100644
index 0000000..4f7073f
--- /dev/null
+++ b/src/starboard/linux/shared/routes.h
@@ -0,0 +1,71 @@
+// Copyright 2021 The Cobalt Authors. 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.
+
+#ifndef STARBOARD_LINUX_SHARED_ROUTES_H_
+#define STARBOARD_LINUX_SHARED_ROUTES_H_
+
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include "starboard/common/log.h"
+#include "starboard/linux/shared/netlink.h"
+#include "starboard/system.h"
+
+// Omit namespace linux due to symbol name conflict.
+namespace starboard {
+namespace shared {
+
+// Helper class for examining device routes from the netlink socket API.
+class Routes : public NetLink {
+ public:
+ struct Route {
+ sa_family_t family;
+ union {
+ in_addr_t dst_addr;
+ struct in6_addr dst_addr6;
+ };
+ int priority;
+ char name[IF_NAMESIZE];
+ };
+
+ // Return true if the route has the default destination address.
+ static bool IsDefaultRoute(const Route& route);
+
+ // Return true if the route uses a wireless interface.
+ static bool IsWirelessInterface(const Route& route);
+
+ Routes() {}
+ ~Routes() {}
+
+ // Open the netlink socket for routing table information.
+ bool Open();
+
+ // Request a dump of the routing tables from the netlink socket.
+ bool RequestDump();
+
+ // Return the next route from the netlink interface message. Returns nullptr
+ // when no more routes are available.
+ Route* GetNextRoute();
+
+ private:
+ static void GetRouteFromNetlinkMessage(struct nlmsghdr* message,
+ Route& route);
+
+ Route last_route_;
+};
+
+} // namespace shared
+} // namespace starboard
+
+#endif // STARBOARD_LINUX_SHARED_ROUTES_H_
diff --git a/src/starboard/linux/shared/starboard_platform.gypi b/src/starboard/linux/shared/starboard_platform.gypi
index 76f7cc1..5387624 100644
--- a/src/starboard/linux/shared/starboard_platform.gypi
+++ b/src/starboard/linux/shared/starboard_platform.gypi
@@ -35,7 +35,11 @@
'<(DEPTH)/starboard/linux/shared/decode_target_release.cc',
'<(DEPTH)/starboard/linux/shared/media_is_audio_supported.cc',
'<(DEPTH)/starboard/linux/shared/media_is_video_supported.cc',
+ '<(DEPTH)/starboard/linux/shared/netlink.cc',
+ '<(DEPTH)/starboard/linux/shared/netlink.h',
'<(DEPTH)/starboard/linux/shared/player_components_factory.cc',
+ '<(DEPTH)/starboard/linux/shared/routes.cc',
+ '<(DEPTH)/starboard/linux/shared/routes.h',
'<(DEPTH)/starboard/linux/shared/system_get_connection_type.cc',
'<(DEPTH)/starboard/linux/shared/system_get_device_type.cc',
'<(DEPTH)/starboard/linux/shared/system_get_extensions.cc',
diff --git a/src/starboard/linux/shared/system_get_connection_type.cc b/src/starboard/linux/shared/system_get_connection_type.cc
index 92a96a8..7795c20 100644
--- a/src/starboard/linux/shared/system_get_connection_type.cc
+++ b/src/starboard/linux/shared/system_get_connection_type.cc
@@ -14,9 +14,31 @@
#include "starboard/system.h"
-#include "starboard/common/log.h"
+#include "starboard/linux/shared/routes.h"
+
+using starboard::shared::Routes;
SbSystemConnectionType SbSystemGetConnectionType() {
- SB_NOTIMPLEMENTED();
+ Routes routes;
+
+ if (!routes.RequestDump()) {
+ return kSbSystemConnectionTypeUnknown;
+ }
+
+ // Find the top priority route and return if the corresponding route uses a
+ // wireless interface.
+ int priority = INT_MAX;
+ bool is_wireless = false;
+ while (auto route = routes.GetNextRoute()) {
+ if (Routes::IsDefaultRoute(*route)) {
+ if (route->priority < priority) {
+ priority = route->priority;
+ is_wireless = Routes::IsWirelessInterface(*route);
+ }
+ }
+ }
+ if (priority != INT_MAX)
+ return is_wireless ? kSbSystemConnectionTypeWireless
+ : kSbSystemConnectionTypeWired;
return kSbSystemConnectionTypeUnknown;
}
diff --git a/src/starboard/linux/x64x11/shared/BUILD.gn b/src/starboard/linux/x64x11/shared/BUILD.gn
index c433086..3238904a 100644
--- a/src/starboard/linux/x64x11/shared/BUILD.gn
+++ b/src/starboard/linux/x64x11/shared/BUILD.gn
@@ -12,10 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-declare_args() {
- has_private_system_properties = false
-}
-
group("starboard_platform") {
public_deps = [
":starboard_platform_sources",
@@ -47,7 +43,7 @@
"//starboard/shared/x11/window_internal.cc",
]
- if (has_private_system_properties) {
+ if (is_internal_build) {
sources += [ "//starboard/keyboxes/linux/system_properties.cc" ]
} else {
sources += [ "//starboard/linux/x64x11/public_system_properties.cc" ]
diff --git a/src/starboard/linux/x64x11/system_get_property_impl.cc b/src/starboard/linux/x64x11/system_get_property_impl.cc
index 37de482..f08fa2c 100644
--- a/src/starboard/linux/x64x11/system_get_property_impl.cc
+++ b/src/starboard/linux/x64x11/system_get_property_impl.cc
@@ -14,19 +14,40 @@
#include "starboard/linux/x64x11/system_get_property_impl.h"
-#include <netdb.h>
-#include <linux/if.h> // NOLINT(build/include_alpha)
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
#include "starboard/common/log.h"
#include "starboard/common/string.h"
#include "starboard/linux/x64x11/system_properties.h"
namespace {
-const char* kFriendlyName = "Linux Desktop";
-const char* kPlatformName = "X11; Linux x86_64";
+const char kBrandName[] = "BrandName";
+const char kChipsetModelNumber[] = "ChipsetModelNumber";
+const char kFirmwareVersion[] = "FirmwareVersion";
+const char kFriendlyName[] = "Linux Desktop";
+const char kModelName[] = "ModelName";
+const char kPlatformName[] = "X11; Linux x86_64";
+
+#if SB_API_VERSION >= 12
+const char kSystemIntegratorName[] = "SystemIntegratorName";
+#else
+const char kOriginalDesignManufacturerName[] = "OriginalDesignManufacturerName";
+#endif
+
+#if SB_API_VERSION >= 13
+const char kModelYear[] = "2022";
+#elif SB_API_VERSION >= 12
+const char kModelYear[] = "2021";
+#elif SB_API_VERSION >= 11
+const char kModelYear[] = "2020";
+#elif SB_API_VERSION >= 10
+const char kModelYear[] = "2019";
+#elif SB_API_VERSION >= 6
+const char kModelYear[] = "2018";
+#elif SB_API_VERSION >= 2
+const char kModelYear[] = "2017";
+#else
+const char kModelYear[] = "2016";
+#endif // SB_API_VERSION
} // namespace
@@ -52,32 +73,38 @@
switch (property_id) {
case kSbSystemPropertyBrandName:
- case kSbSystemPropertyChipsetModelNumber:
- case kSbSystemPropertyFirmwareVersion:
- case kSbSystemPropertyModelName:
- case kSbSystemPropertyModelYear:
-#if SB_API_VERSION >= 12
- case kSbSystemPropertySystemIntegratorName:
-#else
- case kSbSystemPropertyOriginalDesignManufacturerName:
-#endif
- case kSbSystemPropertySpeechApiKey:
- return false;
- case kSbSystemPropertyUserAgentAuxField:
- return false;
- case kSbSystemPropertyFriendlyName:
- return CopyStringAndTestIfSuccess(out_value, value_length, kFriendlyName);
-
- case kSbSystemPropertyPlatformName:
- return CopyStringAndTestIfSuccess(out_value, value_length, kPlatformName);
-
+ return CopyStringAndTestIfSuccess(out_value, value_length, kBrandName);
case kSbSystemPropertyCertificationScope:
if (kCertificationScope[0] == '\0')
return false;
return CopyStringAndTestIfSuccess(out_value, value_length,
kCertificationScope);
-
-
+ case kSbSystemPropertyChipsetModelNumber:
+ return CopyStringAndTestIfSuccess(out_value, value_length,
+ kChipsetModelNumber);
+ case kSbSystemPropertyFirmwareVersion:
+ return CopyStringAndTestIfSuccess(out_value, value_length,
+ kFirmwareVersion);
+ case kSbSystemPropertyFriendlyName:
+ return CopyStringAndTestIfSuccess(out_value, value_length, kFriendlyName);
+ case kSbSystemPropertyModelName:
+ return CopyStringAndTestIfSuccess(out_value, value_length, kModelName);
+ case kSbSystemPropertyModelYear:
+ return CopyStringAndTestIfSuccess(out_value, value_length, kModelYear);
+ case kSbSystemPropertyPlatformName:
+ return CopyStringAndTestIfSuccess(out_value, value_length, kPlatformName);
+#if SB_API_VERSION >= 12
+ case kSbSystemPropertySystemIntegratorName:
+ return CopyStringAndTestIfSuccess(out_value, value_length,
+ kSystemIntegratorName);
+#else
+ case kSbSystemPropertyOriginalDesignManufacturerName:
+ return CopyStringAndTestIfSuccess(out_value, value_length,
+ kOriginalDesignManufacturerName);
+#endif
+ case kSbSystemPropertySpeechApiKey:
+ case kSbSystemPropertyUserAgentAuxField:
+ return false;
default:
SB_DLOG(WARNING) << __FUNCTION__
<< ": Unrecognized property: " << property_id;
diff --git a/src/starboard/loader_app/BUILD.gn b/src/starboard/loader_app/BUILD.gn
index dba9360..481ccc8 100644
--- a/src/starboard/loader_app/BUILD.gn
+++ b/src/starboard/loader_app/BUILD.gn
@@ -12,6 +12,204 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+_common_loader_app_sources = [
+ "loader_app.cc",
+ "loader_app_switches.cc",
+ "loader_app_switches.h",
+ "system_get_extension_shim.cc",
+ "system_get_extension_shim.h",
+]
+
+group("common_loader_app_dependencies") {
+ public_deps = [
+ ":app_key",
+ ":installation_manager",
+ ":slot_management",
+ "//starboard",
+ "//starboard/elf_loader:sabi_string",
+ ]
+}
+
+target(final_executable_type, "loader_app") {
+ if (target_cpu == "x86" || target_cpu == "x64" || target_cpu == "arm" ||
+ target_cpu == "arm64") {
+ sources = _common_loader_app_sources
+ deps = [
+ ":common_loader_app_dependencies",
+ "//cobalt/content/fonts:copy_font_data",
+ "//starboard/elf_loader",
+ ]
+ }
+}
+
+target(final_executable_type, "loader_app_sys") {
+ if (target_cpu == "x86" || target_cpu == "x64" || target_cpu == "arm" ||
+ target_cpu == "arm64") {
+ sources = _common_loader_app_sources
+
+ starboard_syms_path =
+ rebase_path("//starboard/starboard.syms", root_build_dir)
+ ldflags = [
+ "-Wl,--dynamic-list=$starboard_syms_path",
+ "-ldl",
+ ]
+ deps = [
+ ":common_loader_app_dependencies",
+ "//cobalt/content/fonts:copy_font_data",
+ "//starboard/elf_loader:elf_loader_sys",
+ ]
+ }
+}
+
+static_library("app_key_files") {
+ sources = [
+ "app_key_files.cc",
+ "app_key_files.h",
+ ]
+ deps = [ "//starboard" ]
+}
+
+target(gtest_target_type, "app_key_files_test") {
+ testonly = true
+ sources = [
+ "//starboard/common/test_main.cc",
+ "app_key_files_test.cc",
+ ]
+ deps = [
+ ":app_key_files",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
+
+static_library("app_key") {
+ sources = [
+ "app_key.cc",
+ "app_key.h",
+ "app_key_internal.cc",
+ "app_key_internal.h",
+ ]
+ deps = [
+ "//starboard",
+ "//third_party/modp_b64",
+ ]
+}
+
+target(gtest_target_type, "app_key_test") {
+ testonly = true
+ sources = [
+ "//starboard/common/test_main.cc",
+ "app_key_test.cc",
+ ]
+ deps = [
+ ":app_key",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
+
+static_library("drain_file") {
+ sources = [
+ "drain_file.cc",
+ "drain_file.h",
+ ]
+ deps = [ "//starboard/common" ]
+}
+
+target(gtest_target_type, "drain_file_test") {
+ testonly = true
+ sources = [
+ "//starboard/common/test_main.cc",
+ "drain_file_helper.cc",
+ "drain_file_helper.h",
+ "drain_file_test.cc",
+ ]
+ deps = [
+ ":drain_file",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
+
+static_library("installation_store_proto") {
+ sources = [
+ "installation_store.pb.cc",
+ "installation_store.pb.h",
+ ]
+ public_deps = [ "//third_party/protobuf:protobuf_lite" ]
+}
+
+static_library("installation_manager") {
+ sources = [
+ "installation_manager.cc",
+ "installation_manager.h",
+ ]
+
+ include_dirs = [
+ # Get protobuf headers from the chromium tree.
+ "//third_party/protobuf/src",
+ ]
+
+ deps = [
+ ":installation_store_proto",
+ "//starboard",
+ ]
+
+ if (sb_evergreen_compatible_enable_lite) {
+ deps += [ ":pending_restart" ]
+ }
+}
+
+target(gtest_target_type, "installation_manager_test") {
+ testonly = true
+ sources = [
+ "//starboard/common/test_main.cc",
+ "installation_manager_test.cc",
+ ]
+ if (sb_evergreen_compatible_enable_lite) {
+ sources += [ "pending_restart_test.cc" ]
+ }
+ deps = [
+ ":installation_manager",
+ ":installation_store_proto",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
+
+static_library("slot_management") {
+ sources = [
+ "slot_management.cc",
+ "slot_management.h",
+ ]
+ deps = [
+ ":app_key_files",
+ ":drain_file",
+ ":installation_manager",
+ "//starboard",
+ "//starboard/elf_loader",
+ "//starboard/elf_loader:sabi_string",
+ ]
+}
+
+target(gtest_target_type, "slot_management_test") {
+ testonly = true
+ sources = [
+ "//starboard/common/test_main.cc",
+ "slot_management_test.cc",
+ ]
+ deps = [
+ ":app_key_files",
+ ":drain_file",
+ ":installation_manager",
+ ":installation_store_proto",
+ ":slot_management",
+ "//starboard/elf_loader:sabi_string",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
+
static_library("pending_restart") {
sources = [
"pending_restart.cc",
diff --git a/src/starboard/nplb/BUILD.gn b/src/starboard/nplb/BUILD.gn
index 52e56bd..a53df6a 100644
--- a/src/starboard/nplb/BUILD.gn
+++ b/src/starboard/nplb/BUILD.gn
@@ -103,7 +103,6 @@
"double_floor_test.cc",
"double_is_finite_test.cc",
"double_is_nan_test.cc",
- "drm_create_system_test.cc",
"drm_get_metrics_test.cc",
"drm_helpers.cc",
"drm_helpers.h",
@@ -142,7 +141,6 @@
# TODO: Separate functions tested by media buffer test into multiple
# files.
"media_buffer_test.cc",
- "media_can_play_mime_and_key_system_test.cc",
"media_configuration_test.cc",
"memory_align_to_page_size_test.cc",
"memory_allocate_aligned_test.cc",
@@ -241,6 +239,7 @@
"string_scan_test.cc",
"system_binary_search_test.cc",
"system_clear_last_error_test.cc",
+ "system_get_connection_type_test.cc",
"system_get_error_string_test.cc",
"system_get_extension_test.cc",
"system_get_last_error_test.cc",
@@ -295,6 +294,13 @@
"window_get_size_test.cc",
]
+ if (is_internal_build) {
+ sources += [
+ "drm_create_system_test.cc",
+ "media_can_play_mime_and_key_system_test.cc",
+ ]
+ }
+
deps = [ "//starboard/nplb/testdata/file_tests:nplb_file_tests_data" ]
public_deps = [
diff --git a/src/starboard/nplb/drm_helpers.h b/src/starboard/nplb/drm_helpers.h
index e6b0972..be29b72 100644
--- a/src/starboard/nplb/drm_helpers.h
+++ b/src/starboard/nplb/drm_helpers.h
@@ -62,9 +62,7 @@
SbDrmSystem CreateDummyDrmSystem(const char* key_system);
static const char* kKeySystems[] = {
- "com.widevine",
- "com.widevine.alpha",
- "com.youtube.playready",
+ "com.widevine", "com.widevine.alpha", "com.youtube.playready",
"com.youtube.fairplay",
};
@@ -72,6 +70,138 @@
"cenc", "cbcs", "cbcs-1-9",
};
+static constexpr uint8_t kWidevineCertificate[] = {
+ 0x0a, 0xc1, 0x02, 0x08, 0x03, 0x12, 0x10, 0x17, 0x05, 0xb9, 0x17, 0xcc,
+ 0x12, 0x04, 0x86, 0x8b, 0x06, 0x33, 0x3a, 0x2f, 0x77, 0x2a, 0x8c, 0x18,
+ 0x82, 0xb4, 0x82, 0x92, 0x05, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a,
+ 0x02, 0x82, 0x01, 0x01, 0x00, 0x99, 0xed, 0x5b, 0x3b, 0x32, 0x7d, 0xab,
+ 0x5e, 0x24, 0xef, 0xc3, 0xb6, 0x2a, 0x95, 0xb5, 0x98, 0x52, 0x0a, 0xd5,
+ 0xbc, 0xcb, 0x37, 0x50, 0x3e, 0x06, 0x45, 0xb8, 0x14, 0xd8, 0x76, 0xb8,
+ 0xdf, 0x40, 0x51, 0x04, 0x41, 0xad, 0x8c, 0xe3, 0xad, 0xb1, 0x1b, 0xb8,
+ 0x8c, 0x4e, 0x72, 0x5a, 0x5e, 0x4a, 0x9e, 0x07, 0x95, 0x29, 0x1d, 0x58,
+ 0x58, 0x40, 0x23, 0xa7, 0xe1, 0xaf, 0x0e, 0x38, 0xa9, 0x12, 0x79, 0x39,
+ 0x30, 0x08, 0x61, 0x0b, 0x6f, 0x15, 0x8c, 0x87, 0x8c, 0x7e, 0x21, 0xbf,
+ 0xfb, 0xfe, 0xea, 0x77, 0xe1, 0x01, 0x9e, 0x1e, 0x57, 0x81, 0xe8, 0xa4,
+ 0x5f, 0x46, 0x26, 0x3d, 0x14, 0xe6, 0x0e, 0x80, 0x58, 0xa8, 0x60, 0x7a,
+ 0xdc, 0xe0, 0x4f, 0xac, 0x84, 0x57, 0xb1, 0x37, 0xa8, 0xd6, 0x7c, 0xcd,
+ 0xeb, 0x33, 0x70, 0x5d, 0x98, 0x3a, 0x21, 0xfb, 0x4e, 0xec, 0xbd, 0x4a,
+ 0x10, 0xca, 0x47, 0x49, 0x0c, 0xa4, 0x7e, 0xaa, 0x5d, 0x43, 0x82, 0x18,
+ 0xdd, 0xba, 0xf1, 0xca, 0xde, 0x33, 0x92, 0xf1, 0x3d, 0x6f, 0xfb, 0x64,
+ 0x42, 0xfd, 0x31, 0xe1, 0xbf, 0x40, 0xb0, 0xc6, 0x04, 0xd1, 0xc4, 0xba,
+ 0x4c, 0x95, 0x20, 0xa4, 0xbf, 0x97, 0xee, 0xbd, 0x60, 0x92, 0x9a, 0xfc,
+ 0xee, 0xf5, 0x5b, 0xba, 0xf5, 0x64, 0xe2, 0xd0, 0xe7, 0x6c, 0xd7, 0xc5,
+ 0x5c, 0x73, 0xa0, 0x82, 0xb9, 0x96, 0x12, 0x0b, 0x83, 0x59, 0xed, 0xce,
+ 0x24, 0x70, 0x70, 0x82, 0x68, 0x0d, 0x6f, 0x67, 0xc6, 0xd8, 0x2c, 0x4a,
+ 0xc5, 0xf3, 0x13, 0x44, 0x90, 0xa7, 0x4e, 0xec, 0x37, 0xaf, 0x4b, 0x2f,
+ 0x01, 0x0c, 0x59, 0xe8, 0x28, 0x43, 0xe2, 0x58, 0x2f, 0x0b, 0x6b, 0x9f,
+ 0x5d, 0xb0, 0xfc, 0x5e, 0x6e, 0xdf, 0x64, 0xfb, 0xd3, 0x08, 0xb4, 0x71,
+ 0x1b, 0xcf, 0x12, 0x50, 0x01, 0x9c, 0x9f, 0x5a, 0x09, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0x3a, 0x14, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2e,
+ 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x12, 0x80, 0x03, 0xae, 0x34, 0x73, 0x14, 0xb5, 0xa8, 0x35, 0x29, 0x7f,
+ 0x27, 0x13, 0x88, 0xfb, 0x7b, 0xb8, 0xcb, 0x52, 0x77, 0xd2, 0x49, 0x82,
+ 0x3c, 0xdd, 0xd1, 0xda, 0x30, 0xb9, 0x33, 0x39, 0x51, 0x1e, 0xb3, 0xcc,
+ 0xbd, 0xea, 0x04, 0xb9, 0x44, 0xb9, 0x27, 0xc1, 0x21, 0x34, 0x6e, 0xfd,
+ 0xbd, 0xea, 0xc9, 0xd4, 0x13, 0x91, 0x7e, 0x6e, 0xc1, 0x76, 0xa1, 0x04,
+ 0x38, 0x46, 0x0a, 0x50, 0x3b, 0xc1, 0x95, 0x2b, 0x9b, 0xa4, 0xe4, 0xce,
+ 0x0f, 0xc4, 0xbf, 0xc2, 0x0a, 0x98, 0x08, 0xaa, 0xaf, 0x4b, 0xfc, 0xd1,
+ 0x9c, 0x1d, 0xcf, 0xcd, 0xf5, 0x74, 0xcc, 0xac, 0x28, 0xd1, 0xb4, 0x10,
+ 0x41, 0x6c, 0xf9, 0xde, 0x88, 0x04, 0x30, 0x1c, 0xbd, 0xb3, 0x34, 0xca,
+ 0xfc, 0xd0, 0xd4, 0x09, 0x78, 0x42, 0x3a, 0x64, 0x2e, 0x54, 0x61, 0x3d,
+ 0xf0, 0xaf, 0xcf, 0x96, 0xca, 0x4a, 0x92, 0x49, 0xd8, 0x55, 0xe4, 0x2b,
+ 0x3a, 0x70, 0x3e, 0xf1, 0x76, 0x7f, 0x6a, 0x9b, 0xd3, 0x6d, 0x6b, 0xf8,
+ 0x2b, 0xe7, 0x6b, 0xbf, 0x0c, 0xba, 0x4f, 0xde, 0x59, 0xd2, 0xab, 0xcc,
+ 0x76, 0xfe, 0xb6, 0x42, 0x47, 0xb8, 0x5c, 0x43, 0x1f, 0xbc, 0xa5, 0x22,
+ 0x66, 0xb6, 0x19, 0xfc, 0x36, 0x97, 0x95, 0x43, 0xfc, 0xa9, 0xcb, 0xbd,
+ 0xbb, 0xfa, 0xfa, 0x0e, 0x1a, 0x55, 0xe7, 0x55, 0xa3, 0xc7, 0xbc, 0xe6,
+ 0x55, 0xf9, 0x64, 0x6f, 0x58, 0x2a, 0xb9, 0xcf, 0x70, 0xaa, 0x08, 0xb9,
+ 0x79, 0xf8, 0x67, 0xf6, 0x3a, 0x0b, 0x2b, 0x7f, 0xdb, 0x36, 0x2c, 0x5b,
+ 0xc4, 0xec, 0xd5, 0x55, 0xd8, 0x5b, 0xca, 0xa9, 0xc5, 0x93, 0xc3, 0x83,
+ 0xc8, 0x57, 0xd4, 0x9d, 0xaa, 0xb7, 0x7e, 0x40, 0xb7, 0x85, 0x1d, 0xdf,
+ 0xd2, 0x49, 0x98, 0x80, 0x8e, 0x35, 0xb2, 0x58, 0xe7, 0x5d, 0x78, 0xea,
+ 0xc0, 0xca, 0x16, 0xf7, 0x04, 0x73, 0x04, 0xc2, 0x0d, 0x93, 0xed, 0xe4,
+ 0xe8, 0xff, 0x1c, 0x6f, 0x17, 0xe6, 0x24, 0x3e, 0x3f, 0x3d, 0xa8, 0xfc,
+ 0x17, 0x09, 0x87, 0x0e, 0xc4, 0x5f, 0xba, 0x82, 0x3a, 0x26, 0x3f, 0x0c,
+ 0xef, 0xa1, 0xf7, 0x09, 0x3b, 0x19, 0x09, 0x92, 0x83, 0x26, 0x33, 0x37,
+ 0x05, 0x04, 0x3a, 0x29, 0xbd, 0xa6, 0xf9, 0xb4, 0x34, 0x2c, 0xc8, 0xdf,
+ 0x54, 0x3c, 0xb1, 0xa1, 0x18, 0x2f, 0x7c, 0x5f, 0xff, 0x33, 0xf1, 0x04,
+ 0x90, 0xfa, 0xca, 0x5b, 0x25, 0x36, 0x0b, 0x76, 0x01, 0x5e, 0x9c, 0x5a,
+ 0x06, 0xab, 0x8e, 0xe0, 0x2f, 0x00, 0xd2, 0xe8, 0xd5, 0x98, 0x61, 0x04,
+ 0xaa, 0xcc, 0x4d, 0xd4, 0x75, 0xfd, 0x96, 0xee, 0x9c, 0xe4, 0xe3, 0x26,
+ 0xf2, 0x1b, 0x83, 0xc7, 0x05, 0x85, 0x77, 0xb3, 0x87, 0x32, 0xcd, 0xda,
+ 0xbc, 0x6a, 0x6b, 0xed, 0x13, 0xfb, 0x0d, 0x49, 0xd3, 0x8a, 0x45, 0xeb,
+ 0x87, 0xa5, 0xf4};
+
+static constexpr uint8_t kCencInitData[] = {
+ 0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68, 0x00, 0x00, 0x00, 0x00,
+ 0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc,
+ 0xd5, 0x1d, 0x21, 0xed, 0x00, 0x00, 0x00, 0x14, 0x08, 0x01, 0x12, 0x10,
+ 0x31, 0xfd, 0x5b, 0x66, 0x19, 0xfc, 0x5e, 0xad, 0x86, 0x7c, 0xff, 0xb5,
+ 0x84, 0xed, 0x4c, 0x19, 0x00, 0x00, 0x02, 0xf4, 0x70, 0x73, 0x73, 0x68,
+ 0x00, 0x00, 0x00, 0x00, 0x9a, 0x04, 0xf0, 0x79, 0x98, 0x40, 0x42, 0x86,
+ 0xab, 0x92, 0xe6, 0x5b, 0xe0, 0x88, 0x5f, 0x95, 0x00, 0x00, 0x02, 0xd4,
+ 0xd4, 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xca, 0x02, 0x3c, 0x00,
+ 0x57, 0x00, 0x52, 0x00, 0x4d, 0x00, 0x48, 0x00, 0x45, 0x00, 0x41, 0x00,
+ 0x44, 0x00, 0x45, 0x00, 0x52, 0x00, 0x20, 0x00, 0x78, 0x00, 0x6d, 0x00,
+ 0x6c, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x3d, 0x00, 0x22, 0x00, 0x68, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00,
+ 0x73, 0x00, 0x63, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x61, 0x00,
+ 0x73, 0x00, 0x2e, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00,
+ 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x2e, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2f, 0x00, 0x44, 0x00, 0x52, 0x00,
+ 0x4d, 0x00, 0x2f, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x37, 0x00,
+ 0x2f, 0x00, 0x30, 0x00, 0x33, 0x00, 0x2f, 0x00, 0x50, 0x00, 0x6c, 0x00,
+ 0x61, 0x00, 0x79, 0x00, 0x52, 0x00, 0x65, 0x00, 0x61, 0x00, 0x64, 0x00,
+ 0x79, 0x00, 0x48, 0x00, 0x65, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x22, 0x00, 0x20, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x3d, 0x00, 0x22, 0x00,
+ 0x34, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x2e, 0x00,
+ 0x30, 0x00, 0x22, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x44, 0x00, 0x41, 0x00,
+ 0x54, 0x00, 0x41, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x50, 0x00, 0x52, 0x00,
+ 0x4f, 0x00, 0x54, 0x00, 0x45, 0x00, 0x43, 0x00, 0x54, 0x00, 0x49, 0x00,
+ 0x4e, 0x00, 0x46, 0x00, 0x4f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x4b, 0x00,
+ 0x45, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x3e, 0x00,
+ 0x31, 0x00, 0x36, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x4b, 0x00, 0x45, 0x00,
+ 0x59, 0x00, 0x4c, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x3c, 0x00,
+ 0x41, 0x00, 0x4c, 0x00, 0x47, 0x00, 0x49, 0x00, 0x44, 0x00, 0x3e, 0x00,
+ 0x41, 0x00, 0x45, 0x00, 0x53, 0x00, 0x43, 0x00, 0x54, 0x00, 0x52, 0x00,
+ 0x3c, 0x00, 0x2f, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x47, 0x00, 0x49, 0x00,
+ 0x44, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x50, 0x00, 0x52, 0x00,
+ 0x4f, 0x00, 0x54, 0x00, 0x45, 0x00, 0x43, 0x00, 0x54, 0x00, 0x49, 0x00,
+ 0x4e, 0x00, 0x46, 0x00, 0x4f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x4b, 0x00,
+ 0x49, 0x00, 0x44, 0x00, 0x3e, 0x00, 0x5a, 0x00, 0x6c, 0x00, 0x76, 0x00,
+ 0x39, 0x00, 0x4d, 0x00, 0x66, 0x00, 0x77, 0x00, 0x5a, 0x00, 0x72, 0x00,
+ 0x56, 0x00, 0x36, 0x00, 0x47, 0x00, 0x66, 0x00, 0x50, 0x00, 0x2b, 0x00,
+ 0x31, 0x00, 0x68, 0x00, 0x4f, 0x00, 0x31, 0x00, 0x4d, 0x00, 0x47, 0x00,
+ 0x51, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x4b, 0x00,
+ 0x49, 0x00, 0x44, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x43, 0x00, 0x48, 0x00,
+ 0x45, 0x00, 0x43, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x55, 0x00, 0x4d, 0x00,
+ 0x3e, 0x00, 0x4a, 0x00, 0x58, 0x00, 0x46, 0x00, 0x36, 0x00, 0x57, 0x00,
+ 0x38, 0x00, 0x41, 0x00, 0x64, 0x00, 0x51, 0x00, 0x2b, 0x00, 0x49, 0x00,
+ 0x3d, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x43, 0x00, 0x48, 0x00, 0x45, 0x00,
+ 0x43, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x55, 0x00, 0x4d, 0x00, 0x3e, 0x00,
+ 0x3c, 0x00, 0x4c, 0x00, 0x41, 0x00, 0x5f, 0x00, 0x55, 0x00, 0x52, 0x00,
+ 0x4c, 0x00, 0x3e, 0x00, 0x68, 0x00, 0x74, 0x00, 0x74, 0x00, 0x70, 0x00,
+ 0x73, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x77, 0x00, 0x77, 0x00,
+ 0x77, 0x00, 0x2e, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00,
+ 0x75, 0x00, 0x62, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0x6d, 0x00, 0x2f, 0x00, 0x61, 0x00, 0x70, 0x00, 0x69, 0x00, 0x2f, 0x00,
+ 0x64, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x2f, 0x00, 0x70, 0x00, 0x6c, 0x00,
+ 0x61, 0x00, 0x79, 0x00, 0x72, 0x00, 0x65, 0x00, 0x61, 0x00, 0x64, 0x00,
+ 0x79, 0x00, 0x3f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x72, 0x00,
+ 0x63, 0x00, 0x65, 0x00, 0x3d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x55, 0x00,
+ 0x54, 0x00, 0x55, 0x00, 0x42, 0x00, 0x45, 0x00, 0x26, 0x00, 0x61, 0x00,
+ 0x6d, 0x00, 0x70, 0x00, 0x3b, 0x00, 0x76, 0x00, 0x69, 0x00, 0x64, 0x00,
+ 0x65, 0x00, 0x6f, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x3d, 0x00,
+ 0x39, 0x00, 0x33, 0x00, 0x39, 0x00, 0x35, 0x00, 0x62, 0x00, 0x34, 0x00,
+ 0x36, 0x00, 0x64, 0x00, 0x37, 0x00, 0x64, 0x00, 0x63, 0x00, 0x64, 0x00,
+ 0x37, 0x00, 0x38, 0x00, 0x38, 0x00, 0x66, 0x00, 0x3c, 0x00, 0x2f, 0x00,
+ 0x4c, 0x00, 0x41, 0x00, 0x5f, 0x00, 0x55, 0x00, 0x52, 0x00, 0x4c, 0x00,
+ 0x3e, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x44, 0x00, 0x41, 0x00, 0x54, 0x00,
+ 0x41, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x57, 0x00, 0x52, 0x00,
+ 0x4d, 0x00, 0x48, 0x00, 0x45, 0x00, 0x41, 0x00, 0x44, 0x00, 0x45, 0x00,
+ 0x52, 0x00, 0x3e, 0x00, 0x00};
+
} // namespace nplb
} // namespace starboard
diff --git a/src/starboard/nplb/drm_session_test.cc b/src/starboard/nplb/drm_session_test.cc
new file mode 100644
index 0000000..0e911a3
--- /dev/null
+++ b/src/starboard/nplb/drm_session_test.cc
@@ -0,0 +1,413 @@
+// Copyright 2021 The Cobalt Authors. 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 <string>
+#include <vector>
+
+#include "starboard/drm.h"
+
+#include "starboard/common/log.h"
+#include "starboard/common/queue.h"
+#include "starboard/nplb/drm_helpers.h"
+#include "starboard/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr SbTimeMonotonic kDefaultWaitForCallbackTimeout = kSbTimeSecond;
+constexpr char kWidevineKeySystem[] = "com.widevine.alpha";
+constexpr char kCencInitDataType[] = "cenc";
+constexpr int kInitialTicket = kSbDrmTicketInvalid + 1;
+
+class SbDrmSessionTest : public ::testing::Test {
+ protected:
+ struct SessionUpdateRequestGeneratedCallbackEvent {
+ SessionUpdateRequestGeneratedCallbackEvent() {}
+
+ SessionUpdateRequestGeneratedCallbackEvent(
+ SbDrmSystem drm_system,
+ const int ticket,
+ const SbDrmStatus status,
+ const SbDrmSessionRequestType type,
+ const std::string& error_message,
+ const std::string& session_id,
+ const std::vector<uint8_t>& content)
+ : drm_system(drm_system),
+ ticket(ticket),
+ drm_status(status),
+ type(type),
+ error_message(error_message),
+ session_id(session_id),
+ content(content),
+ is_valid(true) {}
+
+ SbDrmSystem drm_system = kSbDrmSystemInvalid;
+ int ticket = kSbDrmTicketInvalid;
+ SbDrmStatus drm_status = kSbDrmStatusUnknownError;
+ SbDrmSessionRequestType type = kSbDrmSessionRequestTypeLicenseRequest;
+ std::string error_message;
+ std::string session_id;
+ std::vector<uint8_t> content;
+ bool is_valid = false;
+ };
+
+ struct ServerCertificateUpdatedCallbackEvent {
+ ServerCertificateUpdatedCallbackEvent() {}
+
+ ServerCertificateUpdatedCallbackEvent(SbDrmSystem drm_system,
+ const int ticket,
+ const SbDrmStatus status,
+ const std::string& error_message)
+ : drm_system(drm_system),
+ ticket(ticket),
+ drm_status(status),
+ error_message(error_message),
+ is_valid(true) {}
+
+ SbDrmSystem drm_system = kSbDrmSystemInvalid;
+ int ticket = kSbDrmTicketInvalid;
+ SbDrmStatus drm_status = kSbDrmStatusUnknownError;
+ std::string error_message;
+ bool is_valid = false;
+ };
+
+ struct SessionClosedCallbackEvent {
+ SessionClosedCallbackEvent() {}
+
+ SessionClosedCallbackEvent(SbDrmSystem drm_system,
+ const std::string& session_id)
+ : drm_system(drm_system), session_id(session_id), is_valid(true) {}
+
+ SbDrmSystem drm_system = kSbDrmSystemInvalid;
+ std::string session_id;
+ bool is_valid = false;
+ };
+
+ SbDrmSessionTest() {}
+
+ void SetUp() override;
+ void TearDown() override;
+
+ // Checks callback parameters to determine if their respective SbDrm*
+ // functions executed successfully.
+ void CheckSessionUpdateRequestGeneratedCallback(
+ const SessionUpdateRequestGeneratedCallbackEvent& event,
+ const int ticket) const;
+ void CheckServerCertificateUpdatedCallback(
+ const ServerCertificateUpdatedCallbackEvent& event,
+ const int ticket) const;
+ void CheckSessionClosedCallback(const SessionClosedCallbackEvent& event,
+ const std::string& session_id) const;
+
+ void OnSessionUpdateRequestGenerated(SbDrmSystem drm_system,
+ const int ticket,
+ const SbDrmStatus status,
+ const SbDrmSessionRequestType type,
+ const std::string& error_message,
+ const std::string& session_id,
+ const std::vector<uint8_t>& content);
+ void OnServerCertificateUpdated(SbDrmSystem drm_system,
+ const int ticket,
+ const SbDrmStatus status,
+ const std::string& error_message);
+ void OnSessionClosed(SbDrmSystem drm_system, const std::string& session_id);
+
+ static void OnSessionUpdateRequestGeneratedFunc(SbDrmSystem drm_system,
+ void* context,
+ int ticket,
+ SbDrmStatus status,
+ SbDrmSessionRequestType type,
+ const char* error_message,
+ const void* session_id,
+ int session_id_size,
+ const void* content,
+ int content_size,
+ const char* url);
+ static void OnServerCertificateUpdatedFunc(SbDrmSystem drm_system,
+ void* context,
+ int ticket,
+ SbDrmStatus status,
+ const char* error_message);
+ static void OnSessionClosedFunc(SbDrmSystem drm_system,
+ void* context,
+ const void* session_id,
+ int session_id_size);
+
+ // Queue containing callback events for OnSessionUpdateRequestGeneratedFunc().
+ Queue<SessionUpdateRequestGeneratedCallbackEvent>
+ session_update_request_callback_event_queue_;
+ // Queue containing callback events for OnServerCertificateUpdatedFunc().
+ Queue<ServerCertificateUpdatedCallbackEvent>
+ server_certificate_updated_callback_event_queue_;
+ // Queue containing callback events for OnSessionClosedFunc().
+ Queue<SessionClosedCallbackEvent> session_closed_callback_event_queue_;
+
+ SbDrmSystem drm_system_ = kSbDrmSystemInvalid;
+};
+
+void SbDrmSessionTest::SetUp() {
+ drm_system_ = SbDrmCreateSystem(
+ kWidevineKeySystem, this, OnSessionUpdateRequestGeneratedFunc,
+ DummySessionUpdatedFunc, DummySessionKeyStatusesChangedFunc,
+ OnServerCertificateUpdatedFunc, OnSessionClosedFunc);
+}
+
+void SbDrmSessionTest::TearDown() {
+ SbDrmDestroySystem(drm_system_);
+}
+
+void SbDrmSessionTest::CheckSessionUpdateRequestGeneratedCallback(
+ const SessionUpdateRequestGeneratedCallbackEvent& event,
+ const int ticket) const {
+ ASSERT_TRUE(event.is_valid);
+ ASSERT_EQ(event.drm_system, drm_system_);
+ ASSERT_EQ(event.ticket, ticket);
+ ASSERT_EQ(event.drm_status, kSbDrmStatusSuccess);
+ ASSERT_TRUE(event.error_message.empty());
+ ASSERT_FALSE(event.session_id.empty());
+ ASSERT_FALSE(event.content.empty());
+}
+
+void SbDrmSessionTest::CheckServerCertificateUpdatedCallback(
+ const ServerCertificateUpdatedCallbackEvent& event,
+ const int ticket) const {
+ ASSERT_TRUE(event.is_valid);
+ ASSERT_EQ(event.drm_system, drm_system_);
+ ASSERT_EQ(event.ticket, ticket);
+ ASSERT_EQ(event.drm_status, kSbDrmStatusSuccess);
+ ASSERT_TRUE(event.error_message.empty());
+}
+
+void SbDrmSessionTest::CheckSessionClosedCallback(
+ const SessionClosedCallbackEvent& event,
+ const std::string& session_id) const {
+ ASSERT_TRUE(event.is_valid);
+ ASSERT_EQ(event.drm_system, drm_system_);
+ ASSERT_EQ(event.session_id, session_id);
+}
+
+void SbDrmSessionTest::OnSessionUpdateRequestGenerated(
+ SbDrmSystem drm_system,
+ const int ticket,
+ const SbDrmStatus status,
+ const SbDrmSessionRequestType type,
+ const std::string& error_message,
+ const std::string& session_id,
+ const std::vector<uint8_t>& content) {
+ session_update_request_callback_event_queue_.Put(
+ SessionUpdateRequestGeneratedCallbackEvent(drm_system, ticket, status,
+ type, error_message,
+ session_id, content));
+}
+
+void SbDrmSessionTest::OnServerCertificateUpdated(
+ SbDrmSystem drm_system,
+ const int ticket,
+ const SbDrmStatus status,
+ const std::string& error_message) {
+ server_certificate_updated_callback_event_queue_.Put(
+ ServerCertificateUpdatedCallbackEvent(drm_system, ticket, status,
+ error_message));
+}
+
+void SbDrmSessionTest::OnSessionClosed(SbDrmSystem drm_system,
+ const std::string& session_id) {
+ session_closed_callback_event_queue_.Put(
+ SessionClosedCallbackEvent(drm_system, session_id));
+}
+
+// static.
+void SbDrmSessionTest::OnSessionUpdateRequestGeneratedFunc(
+ SbDrmSystem drm_system,
+ void* context,
+ int ticket,
+ SbDrmStatus status,
+ SbDrmSessionRequestType type,
+ const char* error_message,
+ const void* session_id,
+ int session_id_size,
+ const void* content,
+ int content_size,
+ const char* url) {
+ SB_DCHECK(context);
+ static_cast<SbDrmSessionTest*>(context)->OnSessionUpdateRequestGenerated(
+ drm_system, ticket, status, type,
+ error_message ? std::string(error_message) : "",
+ session_id
+ ? std::string(static_cast<const char*>(session_id),
+ static_cast<const char*>(session_id) + session_id_size)
+ : "",
+ content ? std::vector<uint8_t>(
+ static_cast<const uint8_t*>(content),
+ static_cast<const uint8_t*>(content) + content_size)
+ : std::vector<uint8_t>());
+}
+
+// static.
+void SbDrmSessionTest::OnServerCertificateUpdatedFunc(
+ SbDrmSystem drm_system,
+ void* context,
+ int ticket,
+ SbDrmStatus status,
+ const char* error_message) {
+ SB_DCHECK(context);
+ static_cast<SbDrmSessionTest*>(context)->OnServerCertificateUpdated(
+ drm_system, ticket, status,
+ error_message ? std::string(error_message) : "");
+}
+
+// static.
+void SbDrmSessionTest::OnSessionClosedFunc(SbDrmSystem drm_system,
+ void* context,
+ const void* session_id,
+ int session_id_size) {
+ SB_DCHECK(context);
+ static_cast<SbDrmSessionTest*>(context)->OnSessionClosed(
+ drm_system,
+ session_id
+ ? std::string(static_cast<const char*>(session_id),
+ static_cast<const char*>(session_id) + session_id_size)
+ : "");
+}
+
+TEST_F(SbDrmSessionTest, SunnyDay) {
+ if (!SbDrmSystemIsValid(drm_system_)) {
+ SB_LOG(INFO) << "Skipping test, DRM system Widevine is not supported on "
+ "this platform.";
+ return;
+ }
+
+ if (SbDrmIsServerCertificateUpdatable(drm_system_)) {
+ SbDrmUpdateServerCertificate(drm_system_, kInitialTicket,
+ kWidevineCertificate,
+ SB_ARRAY_SIZE_INT(kWidevineCertificate));
+ ASSERT_NO_FATAL_FAILURE(CheckServerCertificateUpdatedCallback(
+ server_certificate_updated_callback_event_queue_.GetTimed(
+ kDefaultWaitForCallbackTimeout),
+ kInitialTicket));
+ }
+
+ SbDrmGenerateSessionUpdateRequest(drm_system_, kInitialTicket,
+ kCencInitDataType, kCencInitData,
+ SB_ARRAY_SIZE_INT(kCencInitData));
+ auto session_update_request_generated_event =
+ session_update_request_callback_event_queue_.GetTimed(
+ kDefaultWaitForCallbackTimeout);
+ ASSERT_NO_FATAL_FAILURE(CheckSessionUpdateRequestGeneratedCallback(
+ session_update_request_generated_event, kInitialTicket));
+
+ SbDrmCloseSession(drm_system_,
+ session_update_request_generated_event.session_id.c_str(),
+ session_update_request_generated_event.session_id.size());
+ ASSERT_NO_FATAL_FAILURE(CheckSessionClosedCallback(
+ session_closed_callback_event_queue_.GetTimed(
+ kDefaultWaitForCallbackTimeout),
+ session_update_request_generated_event.session_id));
+}
+
+TEST_F(SbDrmSessionTest, CloseDrmSessionBeforeUpdateSession) {
+ if (!SbDrmSystemIsValid(drm_system_)) {
+ SB_LOG(INFO) << "Skipping test, DRM system Widevine is not supported on "
+ "this platform.";
+ return;
+ }
+
+ SbDrmGenerateSessionUpdateRequest(drm_system_, kInitialTicket,
+ kCencInitDataType, kCencInitData,
+ SB_ARRAY_SIZE_INT(kCencInitData));
+ auto session_update_request_generated_event =
+ session_update_request_callback_event_queue_.GetTimed(
+ kDefaultWaitForCallbackTimeout);
+ ASSERT_NO_FATAL_FAILURE(CheckSessionUpdateRequestGeneratedCallback(
+ session_update_request_generated_event, kInitialTicket));
+
+ // Some implementations may send a server certificate request with a fake
+ // session ID before the underlying CDM session is established. This test
+ // ensures that the fake session ID can be used to close the session, and that
+ // the session closed callback is still called.
+ SbDrmCloseSession(drm_system_,
+ session_update_request_generated_event.session_id.c_str(),
+ session_update_request_generated_event.session_id.size());
+ ASSERT_NO_FATAL_FAILURE(CheckSessionClosedCallback(
+ session_closed_callback_event_queue_.GetTimed(
+ kDefaultWaitForCallbackTimeout),
+ session_update_request_generated_event.session_id));
+}
+
+TEST_F(SbDrmSessionTest, InvalidSessionUpdateRequestParams) {
+ if (!SbDrmSystemIsValid(drm_system_)) {
+ SB_LOG(INFO) << "Skipping test, DRM system Widevine is not supported on "
+ "this platform.";
+ return;
+ }
+
+ SbDrmGenerateSessionUpdateRequest(drm_system_, kSbDrmTicketInvalid,
+ kCencInitDataType, kCencInitData,
+ SB_ARRAY_SIZE_INT(kCencInitData));
+ auto session_update_request_generated_event =
+ session_update_request_callback_event_queue_.GetTimed(
+ kDefaultWaitForCallbackTimeout);
+ // Check that the session update request callback is not called when the
+ // ticket is invalid.
+ ASSERT_FALSE(session_update_request_generated_event.is_valid);
+
+ SbDrmGenerateSessionUpdateRequest(kSbDrmSystemInvalid, kInitialTicket,
+ kCencInitDataType, kCencInitData,
+ SB_ARRAY_SIZE_INT(kCencInitData));
+ session_update_request_generated_event =
+ session_update_request_callback_event_queue_.GetTimed(
+ kDefaultWaitForCallbackTimeout);
+ // Check that the session update request callback is not called when the
+ // DRM system is invalid.
+ ASSERT_FALSE(session_update_request_generated_event.is_valid);
+
+ constexpr int ticket = kInitialTicket + 1;
+
+ if (SbDrmIsServerCertificateUpdatable(drm_system_)) {
+ SbDrmUpdateServerCertificate(drm_system_, ticket, kWidevineCertificate,
+ SB_ARRAY_SIZE_INT(kWidevineCertificate));
+ ASSERT_NO_FATAL_FAILURE(CheckServerCertificateUpdatedCallback(
+ server_certificate_updated_callback_event_queue_.GetTimed(
+ kDefaultWaitForCallbackTimeout),
+ ticket));
+ }
+
+ // Check that the session update request callback is still called when the
+ // CENC initialization data is invalid.
+ constexpr char kInvalidCencInitData[] = "invalidcencinitializationdata";
+ SbDrmGenerateSessionUpdateRequest(
+ drm_system_, ticket, kCencInitDataType, kInvalidCencInitData,
+ SB_ARRAY_SIZE_INT(kInvalidCencInitData) - 1);
+ session_update_request_generated_event =
+ session_update_request_callback_event_queue_.GetTimed(
+ kDefaultWaitForCallbackTimeout);
+ ASSERT_TRUE(session_update_request_generated_event.is_valid);
+ ASSERT_EQ(session_update_request_generated_event.ticket, ticket);
+ if (session_update_request_generated_event.type ==
+ kSbDrmSessionRequestTypeIndividualizationRequest) {
+ SB_DLOG(ERROR) << "The session update request generated callback type is "
+ "|SbDrmSessionRequestType::"
+ "kSbDrmSessionRequestTypeIndividualizationRequest|. "
+ "The CDM is unprovisioned.";
+ } else {
+ ASSERT_NE(session_update_request_generated_event.drm_status,
+ kSbDrmStatusSuccess);
+ }
+}
+
+} // namespace
+} // namespace nplb
+} // namespace starboard
diff --git a/src/starboard/nplb/nplb.gyp b/src/starboard/nplb/nplb.gyp
index 5d44daa..b0f9f91 100644
--- a/src/starboard/nplb/nplb.gyp
+++ b/src/starboard/nplb/nplb.gyp
@@ -122,6 +122,7 @@
'drm_helpers.cc',
'drm_helpers.h',
'drm_is_server_certificate_updatable_test.cc',
+ 'drm_session_test.cc',
'drm_update_server_certificate_test.cc',
'egl_test.cc',
'extern_c_test.cc',
@@ -255,6 +256,7 @@
'system_binary_search_test.cc',
'system_clear_last_error_test.cc',
'system_get_error_string_test.cc',
+ 'system_get_connection_type_test.cc',
'system_get_extension_test.cc',
'system_get_last_error_test.cc',
'system_get_locale_id_test.cc',
diff --git a/src/starboard/nplb/system_get_connection_type_test.cc b/src/starboard/nplb/system_get_connection_type_test.cc
new file mode 100644
index 0000000..4c21b30
--- /dev/null
+++ b/src/starboard/nplb/system_get_connection_type_test.cc
@@ -0,0 +1,44 @@
+// Copyright 2021 The Cobalt Authors. 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.
+
+// Here we are not trying to do anything fancy, just to really sanity check that
+// this is hooked up to something.
+
+#include "starboard/common/log.h"
+#include "starboard/common/string.h"
+#include "starboard/system.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+TEST(SbSystemGetConnectionTypeTest, SunnyDay) {
+ SbSystemConnectionType type = SbSystemGetConnectionType();
+}
+
+TEST(SbSystemGetConnectionTypeTest, ConnectionIsKnown) {
+ SbSystemConnectionType type = SbSystemGetConnectionType();
+ EXPECT_NE(type, kSbSystemConnectionTypeUnknown);
+}
+
+TEST(SbSystemGetConnectionTypeTest, ConnectionIsWiredOrWireless) {
+ SbSystemConnectionType type = SbSystemGetConnectionType();
+ EXPECT_TRUE(type == kSbSystemConnectionTypeWired ||
+ type == kSbSystemConnectionTypeWireless);
+}
+
+} // namespace
+} // namespace nplb
+} // namespace starboard
diff --git a/src/starboard/raspi/shared/starboard_platform.gypi b/src/starboard/raspi/shared/starboard_platform.gypi
index 0cdabb0..46c8a8f 100644
--- a/src/starboard/raspi/shared/starboard_platform.gypi
+++ b/src/starboard/raspi/shared/starboard_platform.gypi
@@ -44,6 +44,10 @@
'<(DEPTH)/starboard/linux/shared/atomic_public.h',
'<(DEPTH)/starboard/linux/shared/configuration_constants.cc',
'<(DEPTH)/starboard/linux/shared/configuration_public.h',
+ '<(DEPTH)/starboard/linux/shared/netlink.cc',
+ '<(DEPTH)/starboard/linux/shared/netlink.h',
+ '<(DEPTH)/starboard/linux/shared/routes.cc',
+ '<(DEPTH)/starboard/linux/shared/routes.h',
'<(DEPTH)/starboard/linux/shared/system_get_connection_type.cc',
'<(DEPTH)/starboard/linux/shared/system_get_path.cc',
'<(DEPTH)/starboard/linux/shared/system_has_capability.cc',
diff --git a/src/starboard/sabi/generate_sabi_id.py b/src/starboard/sabi/generate_sabi_id.py
index 2be9c29..497e409 100644
--- a/src/starboard/sabi/generate_sabi_id.py
+++ b/src/starboard/sabi/generate_sabi_id.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2020 The Cobalt Authors. All Rights Reserved.
#
@@ -15,14 +15,14 @@
# limitations under the License.
"""Generates the ID of a specified Starboard ABI JSON file."""
-import _env # pylint: disable=unused-import
-
import argparse
import json
import os
import sys
-from starboard.sabi import sabi_utils
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
+
+from starboard.sabi import sabi_utils # pylint:disable=wrong-import-position
def _GenerateSabiId(sabi_json, omaha):
@@ -62,7 +62,7 @@
)
sabi_utils.AddSabiArguments(arg_parser)
args, _ = arg_parser.parse_known_args(argv)
- sabi_json = sabi_utils.LoadSabi(args.filename, args.platform)
+ sabi_json = sabi_utils.LoadSabi(args.filename)
return _GenerateSabiId(sabi_json, args.omaha)
diff --git a/src/starboard/sabi/generate_sabi_id_test.py b/src/starboard/sabi/generate_sabi_id_test.py
index 32c63e3..9eb9893 100755
--- a/src/starboard/sabi/generate_sabi_id_test.py
+++ b/src/starboard/sabi/generate_sabi_id_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2019 The Cobalt Authors. All Rights Reserved.
#
@@ -16,12 +16,15 @@
#
"""Tests the generate_sabi_id module."""
-import _env # pylint: disable=unused-import
-
+import json
import os
+import sys
import tempfile
import unittest
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
+
+# pylint: disable=wrong-import-position
from starboard.sabi import generate_sabi_id
from starboard.tools import paths
@@ -33,7 +36,7 @@
class GenerateSabiIdTest(unittest.TestCase):
def testRainyDayNoFileNoPlatform(self):
- with self.assertRaises(SystemExit):
+ with self.assertRaises(TypeError):
generate_sabi_id.DoMain([])
def testRainyDayNonexistentFile(self):
@@ -41,15 +44,11 @@
generate_sabi_id.DoMain(['-f', 'invalid_filename'])
def testRainyDayBadFile(self):
- bad_sabi_json = tempfile.NamedTemporaryFile()
+ bad_sabi_json = tempfile.NamedTemporaryFile(mode='w')
bad_sabi_json.write('{}')
- with self.assertRaises(ValueError):
+ with self.assertRaises(json.decoder.JSONDecodeError):
generate_sabi_id.DoMain(['-f', bad_sabi_json.name])
- def testRainyDayBadPlatform(self):
- with self.assertRaises(ValueError):
- generate_sabi_id.DoMain(['-p', 'ms-dos'])
-
def testSunnyDayNotOmaha(self):
sabi_id = generate_sabi_id.DoMain(['-f', _TEST_SABI])
self.assertEqual(_TEST_SABI_ID, sabi_id)
diff --git a/src/starboard/sabi/sabi_utils.py b/src/starboard/sabi/sabi_utils.py
index 4a279af..7762e36 100644
--- a/src/starboard/sabi/sabi_utils.py
+++ b/src/starboard/sabi/sabi_utils.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2020 The Cobalt Authors. All Rights Reserved.
#
@@ -15,113 +15,54 @@
# limitations under the License.
"""Utility functions for interacting with Starboard ABI JSON files."""
-import _env # pylint: disable=unused-import
-
import json
import os
import re
+import sys
-from starboard.sabi import sabi
-from starboard.tools import build
-from starboard.tools import paths
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
+
+from starboard.tools import paths # pylint:disable=wrong-import-position
SABI_SCHEMA_PATH = os.path.join(paths.STARBOARD_ROOT, 'sabi', 'schema')
SB_API_VERSION_FROM_SABI_RE = re.compile('sabi-v([0-9]+).json')
-def _PlatformToSabiFile(platform):
- """Returns the Starboard ABI file for the given platform.
-
- Args:
- platform: The platform of the desired Starboard ABI file.
-
- Raises:
- ValueError: When |platform| is not provided, or when |platform| is provided
- and it fails to load the platform configuration.
-
- Returns:
- The path to the Starboard ABI file associated with the provided platform.
- """
- if not platform:
- raise ValueError('A platform must be specified.')
- platform_configuration = build.GetPlatformConfig(platform)
- if not platform_configuration:
- raise ValueError('Failed to get platform configuration.')
- filename = platform_configuration.GetPathToSabiJsonFile().format(
- sb_api_version=sabi.SB_API_VERSION)
- return os.path.join(paths.REPOSITORY_ROOT, filename)
-
-
def AddSabiArguments(arg_parser):
- group = arg_parser.add_mutually_exclusive_group(required=True)
- group.add_argument(
+ arg_parser.add_argument(
'-f',
'--filename',
default=None,
help='The Starboard ABI JSON file that should be used.',
)
- group.add_argument(
- '-p',
- '--platform',
- default=None,
- help='The platform whose Starboard ABI JSON should be used.',
- )
-def LoadSabi(filename=None, platform=None):
+def LoadSabi(filename):
"""Returns the contents of the desired Starboard ABI file.
- This function will use either the provided |filename| or the provided
- |platform| to locate the desired Starboard ABI file.
+ This function will use the provided |filename| to locate the desired
+ Starboard ABI file.
Args:
filename: The path, can be relative or absolute, to the desired Starboard
ABI file.
- platform: The platform of the desired Starboard ABI file.
-
- Raises:
- ValueError: When both |filename| and |platform| are provided.
Returns:
The contents of the desired Starboard ABI file.
"""
- if (filename and platform) or (not filename and not platform):
- raise ValueError('Either |filename| or |platform| must be provided.')
- if platform:
- filename = _PlatformToSabiFile(platform)
with open(filename) as f:
return json.load(f)['variables']
-def LoadSabiSchema(filename=None, platform=None):
+def LoadSabiSchema(filename):
"""Returns the contents of the schema associated with the Starboard ABI file.
Args:
filename: The path, can be relative or absolute, to the desired Starboard
ABI schema file.
- platform: A platform whose Starboard ABI file can be validated with the
- desired Starboard ABI schema file.
-
- Raises:
- ValueError: When both |filename| and |platform| are provided, or when
- |platform| is provided and Starboard API version could not be parsed
- from the associated Starboard ABI filename.
Returns:
The contents of the schema associated with the provided Starboard ABI file.
"""
- if (filename and platform) or (not filename and not platform):
- raise ValueError('Either |filename| or |platform| must be provided.')
- if platform:
- filename = _PlatformToSabiFile(platform)
- filename = os.path.basename(filename)
- match = SB_API_VERSION_FROM_SABI_RE.search(filename)
- if not match:
- raise ValueError(
- 'The Starboard API version could not be parsed from the filename: {}'
- .format(filename))
- filename = os.path.join(
- SABI_SCHEMA_PATH, 'sabi-v{sb_api_version}.schema.json'.format(
- sb_api_version=match.group(1)))
with open(filename) as f:
return json.load(f)
diff --git a/src/starboard/sabi/validate_sabi.py b/src/starboard/sabi/validate_sabi.py
index 88e3e61..853df34 100644
--- a/src/starboard/sabi/validate_sabi.py
+++ b/src/starboard/sabi/validate_sabi.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2019 The Cobalt Authors. All Rights Reserved.
#
@@ -15,12 +15,13 @@
# limitations under the License.
"""Validates a specified Starboard ABI JSON file."""
-import _env # pylint: disable=unused-import
-
import argparse
+import os
import sys
-from starboard.sabi import sabi_utils
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
+
+from starboard.sabi import sabi_utils # pylint:disable=wrong-import-position
# Starboard ABI files are considered invalid unless 'jsonschema' is installed
# and used to verify them.
@@ -56,8 +57,8 @@
sabi_utils.AddSabiArguments(arg_parser)
args, _ = arg_parser.parse_known_args()
return ValidateSabi(
- sabi_utils.LoadSabi(args.filename, args.platform),
- sabi_utils.LoadSabiSchema(args.filename, args.platform))
+ sabi_utils.LoadSabi(args.filename),
+ sabi_utils.LoadSabiSchema(args.filename))
if __name__ == '__main__':
diff --git a/src/starboard/sabi/validate_sabi_test.py b/src/starboard/sabi/validate_sabi_test.py
index 4610184..3b54b0d 100644
--- a/src/starboard/sabi/validate_sabi_test.py
+++ b/src/starboard/sabi/validate_sabi_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2019 The Cobalt Authors. All Rights Reserved.
#
@@ -16,21 +16,22 @@
#
"""Tests the validate_sabi module."""
-import _env # pylint: disable=unused-import
-
import copy
import os
+import sys
import unittest
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
+
+# pylint: disable=wrong-import-position
from starboard.sabi import sabi_utils
from starboard.sabi import validate_sabi
from starboard.tools import paths
_TEST_SABI_JSON = sabi_utils.LoadSabi(
- os.path.join(paths.STARBOARD_ROOT, 'sabi', 'test', 'sabi.json'), None)
+ os.path.join(paths.STARBOARD_ROOT, 'sabi', 'test', 'sabi.json'))
_TEST_SABI_SCHEMA = sabi_utils.LoadSabiSchema(
- os.path.join(paths.STARBOARD_ROOT, 'sabi', 'test', 'sabi.schema.json'),
- None)
+ os.path.join(paths.STARBOARD_ROOT, 'sabi', 'test', 'sabi.schema.json'))
class ValidateSabiTest(unittest.TestCase):
@@ -49,8 +50,8 @@
sabi_schema_path = os.path.join(
sabi_utils.SABI_SCHEMA_PATH,
'sabi-v{}.schema.json'.format(match.group(1)))
- sabi_json = sabi_utils.LoadSabi(os.path.join(root, f), None)
- sabi_schema = sabi_utils.LoadSabiSchema(sabi_schema_path, None)
+ sabi_json = sabi_utils.LoadSabi(os.path.join(root, f))
+ sabi_schema = sabi_utils.LoadSabiSchema(sabi_schema_path)
self.assertTrue(validate_sabi.ValidateSabi(sabi_json, sabi_schema))
def testRainyDayValidateSabiSabiJsonWithMissingEntry(self):
@@ -65,7 +66,7 @@
def testRainyDayValidateSabiSabiJsonWithInvalidEntry(self):
sabi_json = copy.deepcopy(_TEST_SABI_JSON)
- sabi_json[sabi_json.keys()[0]] = 'invalid_value'
+ sabi_json[list(sabi_json.keys())[0]] = 'invalid_value'
self.assertFalse(validate_sabi.ValidateSabi(sabi_json, _TEST_SABI_SCHEMA))
diff --git a/src/starboard/shared/posix/socket_create.cc b/src/starboard/shared/posix/socket_create.cc
index 86815f7..5c0922c 100644
--- a/src/starboard/shared/posix/socket_create.cc
+++ b/src/starboard/shared/posix/socket_create.cc
@@ -76,9 +76,9 @@
#if !defined(MSG_NOSIGNAL) && defined(SO_NOSIGPIPE)
// Use SO_NOSIGPIPE to mute SIGPIPE on darwin systems.
- int optval_set=1;
- setsockopt(socket_fd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&optval_set,
- sizeof(int));
+ int optval_set = 1;
+ setsockopt(socket_fd, SOL_SOCKET, SO_NOSIGPIPE,
+ reinterpret_cast<void*>(&optval_set), sizeof(int));
#endif
return new SbSocketPrivate(address_type, protocol, socket_fd);
diff --git a/src/starboard/shared/starboard/application.cc b/src/starboard/shared/starboard/application.cc
index 1500f42..c54fa31 100644
--- a/src/starboard/shared/starboard/application.cc
+++ b/src/starboard/shared/starboard/application.cc
@@ -233,21 +233,33 @@
}
}
+#if SB_API_VERSION >= 13
+void Application::DispatchStart(SbTimeMonotonic timestamp) {
+ SB_DCHECK(IsCurrentThread());
+ SB_DCHECK(state_ == kStateUnstarted);
+ DispatchAndDelete(CreateInitialEvent(kSbEventTypeStart, timestamp));
+}
+#else // SB_API_VERSION >= 13
void Application::DispatchStart() {
SB_DCHECK(IsCurrentThread());
-#if SB_API_VERSION >= 13
- SB_DCHECK(state_ == kStateUnstarted);
-#else
SB_DCHECK(state_ == kStateUnstarted || state_ == kStatePreloading);
-#endif // SB_API_VERSION >= 13
DispatchAndDelete(CreateInitialEvent(kSbEventTypeStart));
}
+#endif // SB_API_VERSION >= 13
+#if SB_API_VERSION >= 13
+void Application::DispatchPreload(SbTimeMonotonic timestamp) {
+ SB_DCHECK(IsCurrentThread());
+ SB_DCHECK(state_ == kStateUnstarted);
+ DispatchAndDelete(CreateInitialEvent(kSbEventTypePreload, timestamp));
+}
+#else // SB_API_VERSION >= 13
void Application::DispatchPreload() {
SB_DCHECK(IsCurrentThread());
SB_DCHECK(state_ == kStateUnstarted);
DispatchAndDelete(CreateInitialEvent(kSbEventTypePreload));
}
+#endif // SB_API_VERSION >= 13
bool Application::HasPreloadSwitch() {
return command_line_->HasSwitch(kPreloadSwitch);
@@ -570,7 +582,12 @@
}
}
+#if SB_API_VERSION >= 13
+Application::Event* Application::CreateInitialEvent(SbEventType type,
+ SbTimeMonotonic timestamp) {
+#else // SB_API_VERSION >= 13
Application::Event* Application::CreateInitialEvent(SbEventType type) {
+#endif // SB_API_VERSION >= 13
SB_DCHECK(type == kSbEventTypePreload || type == kSbEventTypeStart);
SbEventStartData* start_data = new SbEventStartData();
memset(start_data, 0, sizeof(SbEventStartData));
@@ -583,16 +600,28 @@
start_data->argument_values[i] = const_cast<char*>(args[i].c_str());
}
start_data->link = start_link_;
+#if SB_API_VERSION >= 13
+ return new Event(type, timestamp, start_data, &DeleteStartData);
+#else // SB_API_VERSION >= 13
return new Event(type, start_data, &DeleteStartData);
+#endif // SB_API_VERSION >= 13
}
int Application::RunLoop() {
SB_DCHECK(command_line_);
+#if SB_API_VERSION >= 13
if (IsPreloadImmediate()) {
+ DispatchPreload(SbTimeGetMonotonicNow());
+ } else if (IsStartImmediate()) {
+ DispatchStart(SbTimeGetMonotonicNow());
+ }
+#else // SB_API_VERSION >= 13
+ if (IsPreloadImmediate()) {
DispatchPreload();
} else if (IsStartImmediate()) {
DispatchStart();
}
+#endif // SB_API_VERSION >= 13
for (;;) {
if (!DispatchNextEvent()) {
diff --git a/src/starboard/shared/starboard/application.h b/src/starboard/shared/starboard/application.h
index 4e332b4..6281f00 100644
--- a/src/starboard/shared/starboard/application.h
+++ b/src/starboard/shared/starboard/application.h
@@ -475,7 +475,11 @@
// Synchronously dispatches a Start event to the system event handler. Must be
// called on the main dispatch thread.
+#if SB_API_VERSION >= 13
+ void DispatchStart(SbTimeMonotonic timestamp);
+#else // SB_API_VERSION >= 13
void DispatchStart();
+#endif // SB_API_VERSION >= 13
// Returns whether the Preload event should be sent in |Run| before entering
// the event loop. Derived classes that return true must call |Unpause| or
@@ -486,7 +490,11 @@
// Synchronously dispatches a Preload event to the system event handler. Must
// be called on the main dispatch thread.
+#if SB_API_VERSION >= 13
+ void DispatchPreload(SbTimeMonotonic timestamp);
+#else // SB_API_VERSION >= 13
void DispatchPreload();
+#endif // SB_API_VERSION >= 13
// Returns whether the '--preload' command-line argument is specified.
bool HasPreloadSwitch();
@@ -504,7 +512,11 @@
private:
// Creates an initial event type of either Start or Preload with the original
// command line and deep link.
+#if SB_API_VERSION >= 13
+ Event* CreateInitialEvent(SbEventType type, SbTimeMonotonic timestamp);
+#else // SB_API_VERSION >= 13
Event* CreateInitialEvent(SbEventType type);
+#endif // SB_API_VERSION >= 13
// Internal workhorse of the main run loop.
int RunLoop();
diff --git a/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc b/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
index c6e9f7f..dbb1d9e 100644
--- a/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
@@ -362,7 +362,8 @@
return test_params;
}
- vector<const char*> supported_files = GetSupportedAudioTestFiles(false, true);
+ vector<const char*> supported_files =
+ GetSupportedAudioTestFiles(kExcludeHeaac, 6);
// Generate test cases. For example, we have |supported_files| [A, B, C].
// Add tests A->A, A->B, A->C, B->A, B->B, B->C, C->A, C->B and C->C.
diff --git a/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc b/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
index 39fb11d..74b8adf 100644
--- a/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
@@ -454,9 +454,8 @@
i < original_audio_sample_info.audio_specific_config_size; ++i) {
std::vector<uint8_t> config(
original_audio_sample_info.audio_specific_config_size);
- memcpy(config.data(),
- original_audio_sample_info.audio_specific_config,
- original_audio_sample_info.audio_specific_config_size);
+ memcpy(config.data(), original_audio_sample_info.audio_specific_config,
+ original_audio_sample_info.audio_specific_config_size);
auto audio_sample_info = original_audio_sample_info;
config[i] = ~config[i];
audio_sample_info.audio_specific_config = config.data();
@@ -478,8 +477,7 @@
for (uint16_t i = 0;
i < original_audio_sample_info.audio_specific_config_size; ++i) {
std::vector<uint8_t> config(i);
- memcpy(config.data(),
- original_audio_sample_info.audio_specific_config, i);
+ memcpy(config.data(), original_audio_sample_info.audio_specific_config, i);
auto audio_sample_info = original_audio_sample_info;
audio_sample_info.audio_specific_config = config.data();
audio_sample_info.audio_specific_config_size = i;
@@ -637,7 +635,7 @@
INSTANTIATE_TEST_CASE_P(
AudioDecoderTests,
AudioDecoderTest,
- Combine(ValuesIn(GetSupportedAudioTestFiles(true, true)), Bool()));
+ Combine(ValuesIn(GetSupportedAudioTestFiles(kIncludeHeaac, 6)), Bool()));
} // namespace
} // namespace testing
diff --git a/src/starboard/shared/starboard/player/filter/testing/player_components_test.cc b/src/starboard/shared/starboard/player/filter/testing/player_components_test.cc
index 0b49905..fe7932f 100644
--- a/src/starboard/shared/starboard/player/filter/testing/player_components_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/player_components_test.cc
@@ -264,10 +264,14 @@
void WriteDataUntilPrerolled(SbTime timeout = kDefaultPrerollTimeOut) {
SbTimeMonotonic start_time = SbTimeGetMonotonicNow();
+ SbTime max_timestamp = GetMediaTime() + kMaxWriteAheadDuration;
while (!IsPlaybackPrerolled()) {
- ASSERT_LE(SbTimeGetMonotonicNow() - start_time, timeout);
- bool written =
- TryToWriteOneInputBuffer(GetMediaTime() + kMaxWriteAheadDuration);
+ ASSERT_LE(SbTimeGetMonotonicNow() - start_time, timeout)
+ << "WriteDataUntilPrerolled() timed out, buffered audio ("
+ << GetCurrentAudioBufferTimestamp() << "), buffered video ("
+ << GetCurrentVideoBufferTimestamp() << "), max timestamp ("
+ << max_timestamp << ").";
+ bool written = TryToWriteOneInputBuffer(max_timestamp);
if (!written) {
ASSERT_NO_FATAL_FAILURE(RenderAndProcessPendingJobs());
SbThreadSleep(5 * kSbTimeMillisecond);
@@ -275,6 +279,9 @@
}
}
+ // The function will exit after all buffers before |eos_timestamp| are written
+ // into the player. Note that, to avoid audio or video underflow, the function
+ // allow to write buffers of timestamp greater than |timestamp|.
void WriteDataUntil(SbTime timestamp, SbTime timeout = kDefaultWriteTimeOut) {
SB_CHECK(playback_rate_ != 0);
@@ -283,9 +290,14 @@
(GetAudioRenderer() && GetCurrentAudioBufferTimestamp() < timestamp) ||
(GetVideoRenderer() && GetCurrentVideoBufferTimestamp() < timestamp)) {
if (last_input_filled_time != -1) {
- ASSERT_LE(SbTimeGetMonotonicNow() - last_input_filled_time, timeout);
+ ASSERT_LE(SbTimeGetMonotonicNow() - last_input_filled_time, timeout)
+ << "WriteDataUntil() timed out, buffered audio ("
+ << GetCurrentAudioBufferTimestamp() << "), buffered video ("
+ << GetCurrentVideoBufferTimestamp() << "), timestamp (" << timestamp
+ << ").";
}
- bool written = TryToWriteOneInputBuffer(timestamp);
+ bool written =
+ TryToWriteOneInputBuffer(timestamp + kMaxWriteAheadDuration);
if (written) {
last_input_filled_time = SbTimeGetMonotonicNow();
} else {
@@ -295,7 +307,44 @@
}
}
- void WriteEOS() {
+ // The function will write EOS immediately after all buffers before
+ // |eos_timestamp| are written into the player.
+ void WriteDataAndEOS(SbTime eos_timestamp,
+ SbTime timeout = kDefaultWriteTimeOut) {
+ SB_CHECK(playback_rate_ != 0);
+ bool audio_eos_written = !GetAudioRenderer();
+ bool video_eos_written = !GetVideoRenderer();
+
+ SbTimeMonotonic last_input_filled_time = SbTimeGetMonotonicNow();
+ while (!audio_eos_written || !video_eos_written) {
+ if (!audio_eos_written &&
+ GetCurrentAudioBufferTimestamp() >= eos_timestamp) {
+ GetAudioRenderer()->WriteEndOfStream();
+ audio_eos_written = true;
+ }
+ if (!video_eos_written &&
+ GetCurrentVideoBufferTimestamp() >= eos_timestamp) {
+ GetVideoRenderer()->WriteEndOfStream();
+ video_eos_written = true;
+ }
+ if (last_input_filled_time != -1) {
+ ASSERT_LE(SbTimeGetMonotonicNow() - last_input_filled_time, timeout)
+ << "WriteDataAndEOS() timed out, buffered audio ("
+ << GetCurrentAudioBufferTimestamp() << "), buffered video ("
+ << GetCurrentVideoBufferTimestamp() << "), eos_timestamp ("
+ << eos_timestamp << ").";
+ }
+ bool written = TryToWriteOneInputBuffer(eos_timestamp);
+ if (written) {
+ last_input_filled_time = SbTimeGetMonotonicNow();
+ } else {
+ ASSERT_NO_FATAL_FAILURE(RenderAndProcessPendingJobs());
+ SbThreadSleep(5 * kSbTimeMillisecond);
+ }
+ }
+ }
+
+ void WriteEOSDirectly() {
if (GetAudioRenderer()) {
GetAudioRenderer()->WriteEndOfStream();
}
@@ -314,9 +363,14 @@
SbTimeGetMonotonicNow() +
static_cast<SbTime>((duration - current_time) / playback_rate_) +
kDefaultEndTimeOut;
+
while (!IsPlaybackEnded()) {
// If this fails, timeout must have been reached.
- ASSERT_LE(SbTimeGetMonotonicNow(), expected_end_time);
+ ASSERT_LE(SbTimeGetMonotonicNow(), expected_end_time)
+ << "WaitUntilPlaybackEnded() timed out, buffered audio ("
+ << GetCurrentAudioBufferTimestamp() << "), buffered video ("
+ << GetCurrentVideoBufferTimestamp() << "), current media time is "
+ << GetMediaTime() << ".";
ASSERT_NO_FATAL_FAILURE(RenderAndProcessPendingJobs());
SbThreadSleep(5 * kSbTimeMillisecond);
}
@@ -358,9 +412,11 @@
}
void OnEnded(SbMediaType media_type) {
if (media_type == kSbMediaTypeAudio) {
+ SB_DLOG(INFO) << "Audio OnEnded is called.";
audio_ended_ = true;
} else {
EXPECT_EQ(media_type, kSbMediaTypeVideo);
+ SB_DLOG(INFO) << "Video OnEnded is called.";
video_ended_ = true;
}
}
@@ -454,8 +510,7 @@
GetCurrentAudioBufferTimestamp());
media_duration = std::max(kSbTimeSecond, media_duration);
- ASSERT_NO_FATAL_FAILURE(WriteDataUntil(media_duration));
- ASSERT_NO_FATAL_FAILURE(WriteEOS());
+ ASSERT_NO_FATAL_FAILURE(WriteDataAndEOS(media_duration));
ASSERT_NO_FATAL_FAILURE(WaitUntilPlaybackEnded());
// TODO: investigate and reduce the tolerance.
@@ -466,15 +521,14 @@
TEST_P(PlayerComponentsTest, ShortPlayback) {
Seek(0);
- ASSERT_NO_FATAL_FAILURE(WriteDataUntil(50 * kSbTimeMillisecond));
- ASSERT_NO_FATAL_FAILURE(WriteEOS());
+ ASSERT_NO_FATAL_FAILURE(WriteDataAndEOS(50 * kSbTimeMillisecond));
Play();
ASSERT_NO_FATAL_FAILURE(WaitUntilPlaybackEnded());
}
TEST_P(PlayerComponentsTest, EOSWithoutInput) {
Seek(0);
- ASSERT_NO_FATAL_FAILURE(WriteEOS());
+ ASSERT_NO_FATAL_FAILURE(WriteEOSDirectly());
Play();
ASSERT_NO_FATAL_FAILURE(WaitUntilPlaybackEnded());
// TODO: investigate and reduce the tolerance.
@@ -503,9 +557,9 @@
ASSERT_EQ(media_time, GetMediaTime());
Play();
- ASSERT_NO_FATAL_FAILURE(WriteDataUntil(std::max(
- GetCurrentAudioBufferTimestamp(), GetCurrentVideoBufferTimestamp())));
- ASSERT_NO_FATAL_FAILURE(WriteEOS());
+ SbTime duration = std::max(GetCurrentAudioBufferTimestamp(),
+ GetCurrentVideoBufferTimestamp());
+ ASSERT_NO_FATAL_FAILURE(WriteDataAndEOS(duration));
ASSERT_NO_FATAL_FAILURE(WaitUntilPlaybackEnded());
}
@@ -528,8 +582,7 @@
// SbTimeMonotonic play_requested_at = SbTimeGetMonotonicNow();
// Play();
-// ASSERT_NO_FATAL_FAILURE(WriteDataUntil(media_duration_to_write));
-// ASSERT_NO_FATAL_FAILURE(WriteEOS());
+// ASSERT_NO_FATAL_FAILURE(WriteDataAndEOS(media_duration_to_write));
// ASSERT_NO_FATAL_FAILURE(WaitUntilPlaybackEnded());
// TODO: Enable the below check after we improve the accuracy of varied
@@ -558,8 +611,7 @@
// SbTimeMonotonic play_requested_at = SbTimeGetMonotonicNow();
// Play();
-// ASSERT_NO_FATAL_FAILURE(WriteDataUntil(media_duration_to_write));
-// ASSERT_NO_FATAL_FAILURE(WriteEOS());
+// ASSERT_NO_FATAL_FAILURE(WriteDataAndEOS(media_duration_to_write));
// ASSERT_NO_FATAL_FAILURE(WaitUntilPlaybackEnded());
// playback rate time reporting.
@@ -586,8 +638,7 @@
ASSERT_FALSE(IsPlaying());
Play();
- ASSERT_NO_FATAL_FAILURE(WriteDataUntil(seek_to_time + kSbTimeSecond));
- ASSERT_NO_FATAL_FAILURE(WriteEOS());
+ ASSERT_NO_FATAL_FAILURE(WriteDataAndEOS(seek_to_time + kSbTimeSecond));
ASSERT_NO_FATAL_FAILURE(WaitUntilPlaybackEnded());
}
@@ -599,7 +650,7 @@
ASSERT_FALSE(IsPlaying());
Play();
- ASSERT_NO_FATAL_FAILURE(WriteDataUntil(seek_to_time + kSbTimeSecond));
+ ASSERT_NO_FATAL_FAILURE(WriteDataAndEOS(seek_to_time + kSbTimeSecond));
Pause();
seek_to_time = 1 * kSbTimeSecond;
@@ -609,8 +660,7 @@
ASSERT_FALSE(IsPlaying());
Play();
- ASSERT_NO_FATAL_FAILURE(WriteDataUntil(seek_to_time + kSbTimeSecond));
- ASSERT_NO_FATAL_FAILURE(WriteEOS());
+ ASSERT_NO_FATAL_FAILURE(WriteDataAndEOS(seek_to_time + kSbTimeSecond));
ASSERT_NO_FATAL_FAILURE(WaitUntilPlaybackEnded());
}
@@ -624,7 +674,8 @@
vector<PlayerComponentsTestParam> supported_parameters;
// TODO: Enable tests of "heaac.dmp".
- vector<const char*> audio_files = GetSupportedAudioTestFiles(false, false);
+ vector<const char*> audio_files =
+ GetSupportedAudioTestFiles(kExcludeHeaac, SbAudioSinkGetMaxChannels());
vector<VideoTestParam> video_params = GetSupportedVideoTests();
// Filter too short dmp files, as the tests need at least 4s of data.
diff --git a/src/starboard/shared/starboard/player/filter/testing/test_util.cc b/src/starboard/shared/starboard/player/filter/testing/test_util.cc
index 3c71cd3..759fc83 100644
--- a/src/starboard/shared/starboard/player/filter/testing/test_util.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/test_util.cc
@@ -65,8 +65,35 @@
return GetTestInputDirectory() + kSbFileSepChar + filename;
}
-std::vector<const char*> GetSupportedAudioTestFiles(bool include_heaac,
- bool ignore_channels) {
+std::string GetContentTypeFromAudioCodec(SbMediaAudioCodec audio_codec,
+ const char* mime_attributes) {
+ SB_DCHECK(audio_codec != kSbMediaAudioCodecNone);
+
+ std::string content_type;
+ switch (audio_codec) {
+ case kSbMediaAudioCodecAac:
+ content_type = "audio/mp4; codecs=\"mp4a.40.2\"";
+ break;
+ case kSbMediaAudioCodecOpus:
+ content_type = "audio/webm; codecs=\"opus\"";
+ break;
+ case kSbMediaAudioCodecAc3:
+ content_type = "audio/mp4; codecs=\"ac-3\"";
+ break;
+ case kSbMediaAudioCodecEac3:
+ content_type = "audio/mp4; codecs=\"ec-3\"";
+ break;
+ default:
+ SB_NOTREACHED();
+ }
+ return strlen(mime_attributes) > 0 ? content_type + "; " + mime_attributes
+ : content_type;
+}
+
+std::vector<const char*> GetSupportedAudioTestFiles(
+ HeaacOption heaac_option,
+ int max_channels,
+ const char* extra_mime_attributes) {
// beneath_the_canopy_aac_stereo.dmp
// codec: kSbMediaAudioCodecAac
// sampling rate: 44.1k
@@ -81,6 +108,14 @@
// filters for every platform, just in case a particular test case should be
// disabled.
+ struct AudioFileInfo {
+ const char* filename;
+ SbMediaAudioCodec audio_codec;
+ int num_channels;
+ int64_t bitrate;
+ bool is_heaac;
+ };
+
const char* kFilenames[] = {"beneath_the_canopy_aac_stereo.dmp",
"beneath_the_canopy_aac_5_1.dmp",
"beneath_the_canopy_aac_mono.dmp",
@@ -91,51 +126,50 @@
"sintel_381_ac3.dmp",
"heaac.dmp"};
- static std::vector<const char*> supported_filenames_channels_unchecked;
- static std::vector<const char*> supported_filenames_channels_checked;
+ static std::vector<AudioFileInfo> audio_file_info_cache;
+ std::vector<const char*> filenames;
- if (supported_filenames_channels_unchecked.empty()) {
- int supported_channels = SbAudioSinkGetMaxChannels();
+ if (audio_file_info_cache.empty()) {
+ audio_file_info_cache.reserve(SB_ARRAY_SIZE_INT(kFilenames));
for (auto filename : kFilenames) {
VideoDmpReader dmp_reader(ResolveTestFileName(filename).c_str(),
VideoDmpReader::kEnableReadOnDemand);
SB_DCHECK(dmp_reader.number_of_audio_buffers() > 0);
- // Filter files of unsupported codec.
- if (!SbMediaIsAudioSupported(dmp_reader.audio_codec(),
-#if SB_API_VERSION >= 12
- "", // content_type
-#endif // SB_API_VERSION >= 12
- dmp_reader.audio_bitrate())) {
- continue;
- }
- supported_filenames_channels_unchecked.push_back(filename);
-
- // Filter files of unsupported channels.
- if (dmp_reader.audio_sample_info().number_of_channels >
- supported_channels) {
- continue;
- }
- supported_filenames_channels_checked.push_back(filename);
+ audio_file_info_cache.push_back(
+ {filename, dmp_reader.audio_codec(),
+ dmp_reader.audio_sample_info().number_of_channels,
+ dmp_reader.audio_bitrate(), strstr(filename, "heaac") != nullptr});
}
}
- if (include_heaac) {
- return ignore_channels ? supported_filenames_channels_unchecked
- : supported_filenames_channels_checked;
- }
-
- // Filter heaac file.
- std::vector<const char*> test_params;
- for (auto filename :
- (ignore_channels ? supported_filenames_channels_unchecked
- : supported_filenames_channels_checked)) {
- if (strstr(filename, "heaac") != nullptr) {
+ for (auto& audio_file_info : audio_file_info_cache) {
+ // Filter files with channels exceeding |max_channels|.
+ if (audio_file_info.num_channels > max_channels) {
continue;
}
- test_params.push_back(filename);
+
+ // Filter heaac files when |heaac_option| == kExcludeHeaac.
+ if (heaac_option == kExcludeHeaac && audio_file_info.is_heaac) {
+ continue;
+ }
+
+ // Filter files of unsupported codec.
+ if (!SbMediaIsAudioSupported(
+ audio_file_info.audio_codec,
+#if SB_API_VERSION >= 12
+ GetContentTypeFromAudioCodec(audio_file_info.audio_codec,
+ extra_mime_attributes)
+ .c_str(),
+#endif // SB_API_VERSION >= 12
+ audio_file_info.bitrate)) {
+ continue;
+ }
+
+ filenames.push_back(audio_file_info.filename);
}
- return test_params;
+
+ return filenames;
}
std::vector<VideoTestParam> GetSupportedVideoTests() {
diff --git a/src/starboard/shared/starboard/player/filter/testing/test_util.h b/src/starboard/shared/starboard/player/filter/testing/test_util.h
index 9923a96..20808ec 100644
--- a/src/starboard/shared/starboard/player/filter/testing/test_util.h
+++ b/src/starboard/shared/starboard/player/filter/testing/test_util.h
@@ -35,6 +35,11 @@
typedef std::tuple<const char*, SbPlayerOutputMode> VideoTestParam;
+enum HeaacOption {
+ kIncludeHeaac,
+ kExcludeHeaac,
+};
+
// The function doesn't free the buffer, it assumes that the lifetime of the
// buffer is actually managed by other code. It can be used in the places where
// SbPlayerDeallocateSampleFunc is expected.
@@ -43,8 +48,10 @@
const void* sample_buffer);
std::string ResolveTestFileName(const char* filename);
-std::vector<const char*> GetSupportedAudioTestFiles(bool include_heaac,
- bool ignore_channels);
+std::vector<const char*> GetSupportedAudioTestFiles(
+ HeaacOption heaac_option,
+ int max_channels,
+ const char* extra_mime_attributes = "");
std::vector<VideoTestParam> GetSupportedVideoTests();
bool CreateAudioComponents(bool using_stub_decoder,
diff --git a/src/starboard/shared/starboard/player/player.gyp b/src/starboard/shared/starboard/player/player.gyp
index 264d2b8..c38e82e 100644
--- a/src/starboard/shared/starboard/player/player.gyp
+++ b/src/starboard/shared/starboard/player/player.gyp
@@ -65,7 +65,7 @@
},
'action_name': 'player_download_test_data',
'action': [
- 'python',
+ 'python2',
'<(DEPTH)/tools/download_from_gcs.py',
'--bucket', 'cobalt-static-storage',
'--sha1', '<(sha_dir)',
diff --git a/src/starboard/shared/widevine/BUILD.gn b/src/starboard/shared/widevine/BUILD.gn
new file mode 100644
index 0000000..8ab037d
--- /dev/null
+++ b/src/starboard/shared/widevine/BUILD.gn
@@ -0,0 +1,51 @@
+# Copyright 2021 The Cobalt Authors. 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.
+
+config("oemcrypto_external") {
+ include_dirs = [
+ "//third_party/ce_cdm/core/include",
+ "//third_party/ce_cdm/oemcrypto/include",
+ ]
+}
+
+config("oemcrypto_internal") {
+ defines = [
+ "COBALT_WIDEVINE_KEYBOX_TRANSFORM_FUNCTION=${sb_widevine_platform}_client",
+ "COBALT_WIDEVINE_KEYBOX_TRANSFORM_INCLUDE=\"starboard/keyboxes/${sb_widevine_platform}/${sb_widevine_platform}.h\"",
+ "COBALT_WIDEVINE_KEYBOX_INCLUDE=\"starboard/keyboxes/${sb_widevine_platform}_widevine_keybox.h\"",
+ ]
+}
+
+static_library("oemcrypto") {
+ sources = [
+ "//starboard/keyboxes/${sb_widevine_platform}/${sb_widevine_platform}.h",
+ "//starboard/keyboxes/${sb_widevine_platform}/${sb_widevine_platform}_client.c",
+ "//starboard/shared/widevine/widevine_keybox_hash.cc",
+ "//starboard/shared/widevine/wv_keybox.cc",
+ ]
+
+ public_configs = [ ":oemcrypto_external" ]
+ configs -= [ "//starboard/build/config:size" ]
+ configs += [
+ ":oemcrypto_internal",
+ "//starboard/build/config:speed",
+ "//third_party/ce_cdm/cdm:shared_config",
+ ]
+
+ deps = [
+ "//starboard/common",
+ "//third_party/boringssl:crypto",
+ "//third_party/ce_cdm/oemcrypto/mock:oec_mock",
+ ]
+}
diff --git a/src/starboard/stub/BUILD.gn b/src/starboard/stub/BUILD.gn
index 643a0a9..fa39e19 100644
--- a/src/starboard/stub/BUILD.gn
+++ b/src/starboard/stub/BUILD.gn
@@ -13,8 +13,6 @@
# limitations under the License.
static_library("starboard_platform") {
- deps = [ ":stub_sources" ]
-
sources = [
"application_stub.cc",
"application_stub.h",
@@ -30,14 +28,11 @@
"system_get_extensions.cc",
"thread_types_public.h",
]
+
+ public_deps = [ ":stub_sources" ]
}
static_library("stub_sources") {
- public_deps = [
- "//starboard:starboard_headers_only",
- "//starboard/common",
- ]
-
sources = [
"//starboard/shared/starboard/application.cc",
"//starboard/shared/starboard/command_line.cc",
@@ -338,4 +333,13 @@
]
public_configs = [ "//starboard/build/config:starboard_implementation" ]
+
+ public_deps = [
+ "//starboard:starboard_headers_only",
+ "//starboard/common",
+ ]
+
+ if (is_internal_build) {
+ deps = [ "//starboard/private/shared/stub:private_sources" ]
+ }
}
diff --git a/src/third_party/crashpad/handler/handler.gyp b/src/third_party/crashpad/handler/handler.gyp
index effe9e1..1275a4d 100644
--- a/src/third_party/crashpad/handler/handler.gyp
+++ b/src/third_party/crashpad/handler/handler.gyp
@@ -89,8 +89,21 @@
'sources': [
'main.cc',
],
-
'conditions': [
+ # Help platforms cross compiled on linux to reduce
+ # the memory footprint of crashpad_handler by eliminating
+ # unused code and unused shared libraries.
+ # The flags assume gcc/clang toolchain.
+ ['host_os=="linux"', {
+ 'cflags': [
+ '-ffunction-sections',
+ '-fdata-sections',
+ ],
+ 'ldflags': [
+ '-Wl,--as-needed',
+ '-Wl,-gc-sections',
+ ],
+ }],
['OS=="win"', {
'msvs_settings': {
'VCLinkerTool': {
diff --git a/src/third_party/protobuf/BUILD.gn b/src/third_party/protobuf/BUILD.gn
index 84c916a..46161c7 100644
--- a/src/third_party/protobuf/BUILD.gn
+++ b/src/third_party/protobuf/BUILD.gn
@@ -11,6 +11,21 @@
if (!is_win) {
defines += [ "HAVE_PTHREAD" ]
}
+
+ if (is_starboard) {
+ if (is_clang) {
+ cflags = [
+ # protobuf-3 contains a few functions that are unused.
+ "-Wno-unused-function",
+ # protobuf-3 mixes generated enum types.
+ "-Wno-enum-compare-switch",
+ # Used by older version of clang.
+ "-Wno-enum-compare",
+ # Older version of clang don't have -Wno-enum-compare-switch
+ "-Wno-unknown-warning-option",
+ ]
+ }
+ }
}
config("protobuf_warnings") {
@@ -139,7 +154,11 @@
component("protobuf_lite") {
sources = protobuf_lite_sources
- configs -= [ "//build/config/compiler:chromium_code" ]
+ if (is_starboard) {
+ deps = [ "//starboard/common" ]
+ } else {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ }
configs += [
"//build/config/compiler:no_chromium_code",
@@ -159,9 +178,11 @@
"//build/config/compiler:no_size_t_to_int_warning",
]
- deps = [
- "//build/config/sanitizers:deps",
- ]
+ if (!is_starboard) {
+ deps = [
+ "//build/config/sanitizers:deps",
+ ]
+ }
cflags = protobuf_lite_cflags
@@ -308,11 +329,14 @@
"src/google/protobuf/wrappers.pb.h",
]
- deps = [
- "//build/config/sanitizers:deps",
- ]
-
- configs -= [ "//build/config/compiler:chromium_code" ]
+ if (is_starboard) {
+ deps = [ "//starboard/common" ]
+ } else {
+ deps = [
+ "//build/config/sanitizers:deps",
+ ]
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ }
configs += [
"//build/config/compiler:no_chromium_code",
@@ -526,7 +550,9 @@
"src/google/protobuf/compiler/zip_writer.h",
]
- configs -= [ "//build/config/compiler:chromium_code" ]
+ if (!is_starboard) {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ }
configs += [
"//build/config/compiler:no_chromium_code",
@@ -553,7 +579,9 @@
"src/google/protobuf/compiler/main.cc",
]
- configs -= [ "//build/config/compiler:chromium_code" ]
+ if (!is_starboard) {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ }
configs += [ "//build/config/compiler:no_chromium_code" ]
cflags = protobuf_lite_cflags
@@ -567,86 +595,88 @@
}
}
-google_python_dir = "$root_out_dir/pyproto/google"
+if (!is_starboard) {
+ google_python_dir = "$root_out_dir/pyproto/google"
-copy("copy_google") {
- sources = [
- "__init__.py",
- ]
- outputs = [
- "$google_python_dir/{{source_file_part}}",
- ]
-}
+ copy("copy_google") {
+ sources = [
+ "__init__.py",
+ ]
+ outputs = [
+ "$google_python_dir/{{source_file_part}}",
+ ]
+ }
-copy("copy_six") {
- sources = [
- "third_party/six/six.py",
- ]
- outputs = [
- "$google_python_dir/third_party/six/{{source_file_part}}",
- ]
-}
+ copy("copy_six") {
+ sources = [
+ "third_party/six/six.py",
+ ]
+ outputs = [
+ "$google_python_dir/third_party/six/{{source_file_part}}",
+ ]
+ }
-copy("copy_google_protobuf") {
- sources = [
- "python/google/protobuf/__init__.py",
- "python/google/protobuf/descriptor.py",
- "python/google/protobuf/descriptor_database.py",
- "python/google/protobuf/descriptor_pool.py",
- "python/google/protobuf/json_format.py",
- "python/google/protobuf/message.py",
- "python/google/protobuf/message_factory.py",
- "python/google/protobuf/proto_builder.py",
- "python/google/protobuf/reflection.py",
- "python/google/protobuf/service.py",
- "python/google/protobuf/service_reflection.py",
- "python/google/protobuf/symbol_database.py",
- "python/google/protobuf/text_encoding.py",
- "python/google/protobuf/text_format.py",
+ copy("copy_google_protobuf") {
+ sources = [
+ "python/google/protobuf/__init__.py",
+ "python/google/protobuf/descriptor.py",
+ "python/google/protobuf/descriptor_database.py",
+ "python/google/protobuf/descriptor_pool.py",
+ "python/google/protobuf/json_format.py",
+ "python/google/protobuf/message.py",
+ "python/google/protobuf/message_factory.py",
+ "python/google/protobuf/proto_builder.py",
+ "python/google/protobuf/reflection.py",
+ "python/google/protobuf/service.py",
+ "python/google/protobuf/service_reflection.py",
+ "python/google/protobuf/symbol_database.py",
+ "python/google/protobuf/text_encoding.py",
+ "python/google/protobuf/text_format.py",
- # TODO(ncarter): protoc's python generator treats descriptor.proto
- # specially, but only when the input path is exactly
- # "google/protobuf/descriptor.proto". I'm not sure how to execute a rule
- # from a different directory. For now, use a manually-generated copy of
- # descriptor_pb2.py.
- "python/google/protobuf/descriptor_pb2.py",
- ]
- outputs = [
- "$google_python_dir/protobuf/{{source_file_part}}",
- ]
-}
+ # TODO(ncarter): protoc's python generator treats descriptor.proto
+ # specially, but only when the input path is exactly
+ # "google/protobuf/descriptor.proto". I'm not sure how to execute a rule
+ # from a different directory. For now, use a manually-generated copy of
+ # descriptor_pb2.py.
+ "python/google/protobuf/descriptor_pb2.py",
+ ]
+ outputs = [
+ "$google_python_dir/protobuf/{{source_file_part}}",
+ ]
+ }
-copy("copy_google_protobuf_internal") {
- sources = [
- "python/google/protobuf/internal/__init__.py",
- "python/google/protobuf/internal/_parameterized.py",
- "python/google/protobuf/internal/api_implementation.py",
- "python/google/protobuf/internal/containers.py",
- "python/google/protobuf/internal/decoder.py",
- "python/google/protobuf/internal/encoder.py",
- "python/google/protobuf/internal/enum_type_wrapper.py",
- "python/google/protobuf/internal/message_listener.py",
- "python/google/protobuf/internal/python_message.py",
- "python/google/protobuf/internal/type_checkers.py",
- "python/google/protobuf/internal/well_known_types.py",
- "python/google/protobuf/internal/wire_format.py",
- ]
- outputs = [
- "$google_python_dir/protobuf/internal/{{source_file_part}}",
- ]
-}
+ copy("copy_google_protobuf_internal") {
+ sources = [
+ "python/google/protobuf/internal/__init__.py",
+ "python/google/protobuf/internal/_parameterized.py",
+ "python/google/protobuf/internal/api_implementation.py",
+ "python/google/protobuf/internal/containers.py",
+ "python/google/protobuf/internal/decoder.py",
+ "python/google/protobuf/internal/encoder.py",
+ "python/google/protobuf/internal/enum_type_wrapper.py",
+ "python/google/protobuf/internal/message_listener.py",
+ "python/google/protobuf/internal/python_message.py",
+ "python/google/protobuf/internal/type_checkers.py",
+ "python/google/protobuf/internal/well_known_types.py",
+ "python/google/protobuf/internal/wire_format.py",
+ ]
+ outputs = [
+ "$google_python_dir/protobuf/internal/{{source_file_part}}",
+ ]
+ }
-group("py_proto") {
- public_deps = [
- ":copy_google",
- ":copy_google_protobuf",
- ":copy_google_protobuf_internal",
- ":copy_six",
- ]
+ group("py_proto") {
+ public_deps = [
+ ":copy_google",
+ ":copy_google_protobuf",
+ ":copy_google_protobuf_internal",
+ ":copy_six",
+ ]
- # Targets that depend on this should depend on the copied data files.
- data = get_target_outputs(":copy_google")
- data += get_target_outputs(":copy_six")
- data += get_target_outputs(":copy_google_protobuf")
- data += get_target_outputs(":copy_google_protobuf_internal")
+ # Targets that depend on this should depend on the copied data files.
+ data = get_target_outputs(":copy_google")
+ data += get_target_outputs(":copy_six")
+ data += get_target_outputs(":copy_google_protobuf")
+ data += get_target_outputs(":copy_google_protobuf_internal")
+ }
}
diff --git a/src/third_party/protobuf/proto_library.gni b/src/third_party/protobuf/proto_library.gni
index 84373f3..6dd4c13 100644
--- a/src/third_party/protobuf/proto_library.gni
+++ b/src/third_party/protobuf/proto_library.gni
@@ -101,7 +101,9 @@
# Platform files should have gotten filtered out in the sources assignment
# when this template was invoked. If they weren't, it was on purpose and
# this template shouldn't re-apply the filter.
- set_sources_assignment_filter([])
+ if (!is_starboard) {
+ set_sources_assignment_filter([])
+ }
if (host_os == "win") {
host_executable_suffix = ".exe"
@@ -224,20 +226,34 @@
# Generate protobuf stubs.
action(action_name) {
visibility = [ ":$source_set_name" ]
- script = "//tools/protoc_wrapper/protoc_wrapper.py"
+ if (is_starboard) {
+ script = "//tools/protoc_wrapper/gn_protoc_wrapper.py"
+ } else {
+ script = "//tools/protoc_wrapper/protoc_wrapper.py"
+ }
sources = proto_sources
outputs = get_path_info(protogens, "abspath")
args = protos
- protoc_label = "//third_party/protobuf:protoc($host_toolchain)"
- protoc_path = get_label_info(protoc_label, "root_out_dir") + "/protoc" +
- host_executable_suffix
+ if (is_starboard) {
+ args += [
+ "--protoc",
+ rebase_path("//tools/protoc", root_build_dir) + host_executable_suffix,
+ ]
+ } else {
+ protoc_label = "//third_party/protobuf:protoc($host_toolchain)"
+ protoc_path = get_label_info(protoc_label, "root_out_dir") + "/protoc" +
+ host_executable_suffix
+ args += [
+ # Wrapper should never pick a system protoc.
+ # Path should be rebased because |root_build_dir| for current toolchain
+ # may be different from |root_out_dir| of protoc built on host toolchain.
+ "--protoc",
+ "./" + rebase_path(protoc_path, root_build_dir),
+ ]
+ }
+
args += [
- # Wrapper should never pick a system protoc.
- # Path should be rebased because |root_build_dir| for current toolchain
- # may be different from |root_out_dir| of protoc built on host toolchain.
- "--protoc",
- "./" + rebase_path(protoc_path, root_build_dir),
"--proto-in-dir",
rebase_path(proto_in_dir, root_build_dir),
]
@@ -289,13 +305,18 @@
}
}
- # System protoc is not used so it's necessary to build a chromium one.
- inputs = [
- protoc_path,
- ]
- deps = [
- protoc_label,
- ]
+ if (is_starboard) {
+ inputs = []
+ deps = []
+ } else {
+ # System protoc is not used so it's necessary to build a chromium one.
+ inputs = [
+ protoc_path,
+ ]
+ deps = [
+ protoc_label,
+ ]
+ }
if (generate_with_plugin) {
inputs += [ plugin_path ]
@@ -345,6 +366,10 @@
sources = get_target_outputs(":$action_name")
+ if (generate_python) {
+ sources -= [ get_path_info("$py_out_dir/${proto_path}_pb2.py", "abspath") ]
+ }
+
if (defined(invoker.extra_configs)) {
configs += invoker.extra_configs
}
diff --git a/src/third_party/v8/BUILD.gn b/src/third_party/v8/BUILD.gn
index 04346a6..dfc2fe4 100644
--- a/src/third_party/v8/BUILD.gn
+++ b/src/third_party/v8/BUILD.gn
@@ -1983,12 +1983,6 @@
deps = [ ":v8_version" ]
}
-v8_source_set("v8_wrappers") {
- configs = [ ":internal_config" ]
-
- sources = [ "src/base/platform/wrappers.h" ]
-}
-
# This is split out to share basic headers with Torque.
v8_header_set("v8_shared_internal_headers") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
@@ -3835,7 +3829,6 @@
":v8_shared_internal_headers",
":v8_tracing",
":v8_version",
- ":v8_wrappers",
"src/inspector:inspector",
]
@@ -4002,8 +3995,8 @@
public_deps = [
":v8_libbase",
- ":v8_wrappers",
]
+ public_deps = [ ":v8_libbase" ]
# The use of exceptions for Torque in violation of the Chromium style-guide
# is justified by the fact that it is only used from the non-essential
@@ -4151,8 +4144,6 @@
deps = [ ":v8_headers" ]
- public_deps = [ ":v8_wrappers" ]
-
data = []
data_deps = []
@@ -4312,7 +4303,6 @@
":v8_headers",
":v8_libbase",
":v8_tracing",
- ":v8_wrappers",
]
if (v8_use_perfetto) {
@@ -4643,7 +4633,6 @@
":v8_libplatform",
":v8_maybe_icu",
":v8_tracing",
- ":v8_wrappers",
"//build/win:default_exe_manifest",
]
}
@@ -4984,7 +4973,6 @@
":v8_libbase",
":v8_libplatform",
":v8_tracing",
- ":v8_wrappers",
"//build/win:default_exe_manifest",
]
@@ -5123,10 +5111,7 @@
v8_source_set("multi_return_fuzzer") {
sources = [ "test/fuzzer/multi-return.cc" ]
- deps = [
- ":fuzzer_support",
- ":v8_wrappers",
- ]
+ deps = [ ":fuzzer_support" ]
configs = [
":external_config",
@@ -5140,10 +5125,7 @@
v8_source_set("parser_fuzzer") {
sources = [ "test/fuzzer/parser.cc" ]
- deps = [
- ":fuzzer_support",
- ":v8_wrappers",
- ]
+ deps = [ ":fuzzer_support" ]
configs = [
":external_config",
@@ -5160,10 +5142,7 @@
"test/fuzzer/regexp_builtins/mjsunit.js.h",
]
- deps = [
- ":fuzzer_support",
- ":v8_wrappers",
- ]
+ deps = [ ":fuzzer_support" ]
configs = [
":external_config",
@@ -5177,10 +5156,7 @@
v8_source_set("regexp_fuzzer") {
sources = [ "test/fuzzer/regexp.cc" ]
- deps = [
- ":fuzzer_support",
- ":v8_wrappers",
- ]
+ deps = [ ":fuzzer_support" ]
configs = [
":external_config",
@@ -5219,7 +5195,6 @@
deps = [
":fuzzer_support",
":lib_wasm_fuzzer_common",
- ":v8_wrappers",
":wasm_test_common",
]
@@ -5238,7 +5213,6 @@
deps = [
":fuzzer_support",
":lib_wasm_fuzzer_common",
- ":v8_wrappers",
":wasm_test_common",
]
@@ -5260,7 +5234,6 @@
deps = [
":fuzzer_support",
":lib_wasm_fuzzer_common",
- ":v8_wrappers",
":wasm_test_common",
]
@@ -5302,7 +5275,6 @@
deps = [
":fuzzer_support",
":lib_wasm_fuzzer_common",
- ":v8_wrappers",
":wasm_test_common",
]
@@ -5320,7 +5292,6 @@
deps = [
":fuzzer_support",
- ":v8_wrappers",
"test/inspector:inspector_test",
]
diff --git a/src/third_party/v8/src/api/api.cc b/src/third_party/v8/src/api/api.cc
index b9ccdc0..5997bff 100644
--- a/src/third_party/v8/src/api/api.cc
+++ b/src/third_party/v8/src/api/api.cc
@@ -136,10 +136,6 @@
#endif // V8_OS_WIN64
#endif // V8_OS_WIN
-#if defined(V8_OS_STARBOARD)
-#include "src/poems.h"
-#endif
-
#define TRACE_BS(...) \
do { \
if (i::FLAG_trace_backing_store) PrintF(__VA_ARGS__); \
diff --git a/src/third_party/v8/src/ast/ast-value-factory.cc b/src/third_party/v8/src/ast/ast-value-factory.cc
index 90d1c70..b5a39b2 100644
--- a/src/third_party/v8/src/ast/ast-value-factory.cc
+++ b/src/third_party/v8/src/ast/ast-value-factory.cc
@@ -29,7 +29,6 @@
#include "src/base/hashmap-entry.h"
#include "src/base/logging.h"
-#include "src/base/platform/wrappers.h"
#include "src/common/globals.h"
#include "src/heap/factory-inl.h"
#include "src/heap/local-factory-inl.h"
@@ -40,10 +39,6 @@
#include "src/strings/string-hasher.h"
#include "src/utils/utils-inl.h"
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/base/file-utils.cc b/src/third_party/v8/src/base/file-utils.cc
index edfa9c1..6e1c492 100644
--- a/src/third_party/v8/src/base/file-utils.cc
+++ b/src/third_party/v8/src/base/file-utils.cc
@@ -8,11 +8,6 @@
#include <string.h>
#include "src/base/platform/platform.h"
-#include "src/base/platform/wrappers.h"
-
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif // V8_OS_STARBOARD
namespace v8 {
namespace base {
diff --git a/src/third_party/v8/src/base/hashmap.h b/src/third_party/v8/src/base/hashmap.h
index 3fd9bcc..777dba3 100644
--- a/src/third_party/v8/src/base/hashmap.h
+++ b/src/third_party/v8/src/base/hashmap.h
@@ -16,10 +16,6 @@
#include "src/base/logging.h"
#include "src/base/platform/wrappers.h"
-#if defined(V8_OS_STARBOARD)
-#include "starboard/memory.h"
-#endif
-
namespace v8 {
namespace base {
diff --git a/src/third_party/v8/src/base/logging.cc b/src/third_party/v8/src/base/logging.cc
index 59c6aba..9e1cf59 100644
--- a/src/third_party/v8/src/base/logging.cc
+++ b/src/third_party/v8/src/base/logging.cc
@@ -12,10 +12,6 @@
#include "src/base/debug/stack_trace.h"
#include "src/base/platform/platform.h"
-#if defined(V8_OS_STARBOARD)
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace base {
diff --git a/src/third_party/v8/src/base/macros.h b/src/third_party/v8/src/base/macros.h
index 1fa3227..515a9e3 100644
--- a/src/third_party/v8/src/base/macros.h
+++ b/src/third_party/v8/src/base/macros.h
@@ -10,7 +10,6 @@
#include "src/base/compiler-specific.h"
#include "src/base/logging.h"
-#include "src/base/platform/wrappers.h"
// No-op macro which is used to work around MSVC's funky VA_ARGS support.
#define EXPAND(x) x
diff --git a/src/third_party/v8/src/base/memory.h b/src/third_party/v8/src/base/memory.h
index db6a9ea..e2676a8 100644
--- a/src/third_party/v8/src/base/memory.h
+++ b/src/third_party/v8/src/base/memory.h
@@ -6,7 +6,6 @@
#define V8_BASE_MEMORY_H_
#include "src/base/macros.h"
-#include "src/base/platform/wrappers.h"
namespace v8 {
namespace base {
diff --git a/src/third_party/v8/src/base/page-allocator.cc b/src/third_party/v8/src/base/page-allocator.cc
index 2defe619..9f48ee7 100644
--- a/src/third_party/v8/src/base/page-allocator.cc
+++ b/src/third_party/v8/src/base/page-allocator.cc
@@ -5,7 +5,6 @@
#include "src/base/page-allocator.h"
#include "src/base/platform/platform.h"
-#include "src/base/platform/wrappers.h"
#if V8_OS_MACOSX
#include <sys/mman.h> // For MAP_JIT.
diff --git a/src/third_party/v8/src/base/platform/wrappers.h b/src/third_party/v8/src/base/platform/wrappers.h
index a67f2bf..5de31b4 100644
--- a/src/third_party/v8/src/base/platform/wrappers.h
+++ b/src/third_party/v8/src/base/platform/wrappers.h
@@ -14,6 +14,7 @@
#if defined(V8_OS_STARBOARD)
#include "starboard/memory.h"
+#include "starboard/string.h"
#endif
namespace v8 {
@@ -33,9 +34,7 @@
inline void* Calloc(size_t count, size_t size) { return calloc(count, size); }
-inline void* Memcpy(void* dest, const void* source, size_t count) {
- return memcpy(dest, source, count);
-}
+inline char* Strdup(const char* source) { return strdup(source); }
inline FILE* Fopen(const char* filename, const char* mode) {
return fopen(filename, mode);
@@ -57,9 +56,7 @@
return SbMemoryCalloc(count, size);
}
-inline void* Memcpy(void* dest, const void* source, size_t count) {
- return memcpy(dest, source, count);
-}
+inline char* Strdup(const char* source) { return SbStringDuplicate(source); }
inline FILE* Fopen(const char* filename, const char* mode) { return NULL; }
diff --git a/src/third_party/v8/src/builtins/builtins-array-gen.cc b/src/third_party/v8/src/builtins/builtins-array-gen.cc
index 2d9cd5a..04fb751 100644
--- a/src/third_party/v8/src/builtins/builtins-array-gen.cc
+++ b/src/third_party/v8/src/builtins/builtins-array-gen.cc
@@ -3,8 +3,6 @@
// found in the LICENSE file.
#include "src/builtins/builtins-array-gen.h"
-#include "src/objects/torque-defined-classes.h"
-#include "src/objects/torque-defined-classes-inl.h"
#include "src/builtins/builtins-iterator-gen.h"
#include "src/builtins/builtins-string-gen.h"
@@ -17,7 +15,6 @@
#include "src/objects/allocation-site-inl.h"
#include "src/objects/arguments-inl.h"
#include "src/objects/property-cell.h"
-
#include "src/objects/torque-defined-classes.h"
#include "src/objects/torque-defined-classes-inl.h"
diff --git a/src/third_party/v8/src/builtins/builtins-trace.cc b/src/third_party/v8/src/builtins/builtins-trace.cc
index 96a60e0..e98b38d 100644
--- a/src/third_party/v8/src/builtins/builtins-trace.cc
+++ b/src/third_party/v8/src/builtins/builtins-trace.cc
@@ -12,7 +12,6 @@
#if defined(V8_USE_PERFETTO)
#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
-#include "src/base/platform/wrappers.h"
#endif
namespace v8 {
@@ -41,8 +40,8 @@
// strings, the bytes we get from SeqOneByteString are not. buf_ is
// guaranteed to be null terminated.
DisallowHeapAllocation no_gc;
- memcpy(
- buf_, Handle<SeqOneByteString>::cast(string)->GetChars(no_gc), len);
+ memcpy(buf_, Handle<SeqOneByteString>::cast(string)->GetChars(no_gc),
+ len);
}
} else {
Local<v8::String> local = Utils::ToLocal(string);
diff --git a/src/third_party/v8/src/codegen/arm64/assembler-arm64.h b/src/third_party/v8/src/codegen/arm64/assembler-arm64.h
index e685f88..f787bad 100644
--- a/src/third_party/v8/src/codegen/arm64/assembler-arm64.h
+++ b/src/third_party/v8/src/codegen/arm64/assembler-arm64.h
@@ -27,7 +27,6 @@
#endif
#if defined(V8_OS_WIN)
-#include "src/base/platform/wrappers.h"
#include "src/diagnostics/unwinding-info-win64.h"
#endif // V8_OS_WIN
diff --git a/src/third_party/v8/src/codegen/arm64/macro-assembler-arm64.cc b/src/third_party/v8/src/codegen/arm64/macro-assembler-arm64.cc
index 3aac779..6924248 100644
--- a/src/third_party/v8/src/codegen/arm64/macro-assembler-arm64.cc
+++ b/src/third_party/v8/src/codegen/arm64/macro-assembler-arm64.cc
@@ -27,7 +27,6 @@
// Satisfy cpplint check, but don't include platform-specific header. It is
// included recursively via macro-assembler.h.
#if 0
-#include "src/base/platform/wrappers.h"
#include "src/codegen/arm64/macro-assembler-arm64.h"
#endif
diff --git a/src/third_party/v8/src/codegen/external-reference-table.cc b/src/third_party/v8/src/codegen/external-reference-table.cc
index 2741bd8..fb7d503 100644
--- a/src/third_party/v8/src/codegen/external-reference-table.cc
+++ b/src/third_party/v8/src/codegen/external-reference-table.cc
@@ -12,7 +12,6 @@
#if defined(DEBUG) && defined(V8_OS_LINUX) && !defined(V8_OS_ANDROID)
#define SYMBOLIZE_FUNCTION
#include <execinfo.h>
-
#include <vector>
#include "src/base/platform/wrappers.h"
diff --git a/src/third_party/v8/src/codegen/external-reference.cc b/src/third_party/v8/src/codegen/external-reference.cc
index ecb5dbc..499e5c5 100644
--- a/src/third_party/v8/src/codegen/external-reference.cc
+++ b/src/third_party/v8/src/codegen/external-reference.cc
@@ -33,7 +33,6 @@
#include "src/wasm/wasm-external-refs.h"
#ifdef V8_INTL_SUPPORT
-#include "src/base/platform/wrappers.h"
#include "src/objects/intl-objects.h"
#endif // V8_INTL_SUPPORT
diff --git a/src/third_party/v8/src/codegen/optimized-compilation-info.cc b/src/third_party/v8/src/codegen/optimized-compilation-info.cc
index 98bfcd5..bf45a5f 100644
--- a/src/third_party/v8/src/codegen/optimized-compilation-info.cc
+++ b/src/third_party/v8/src/codegen/optimized-compilation-info.cc
@@ -5,7 +5,6 @@
#include "src/codegen/optimized-compilation-info.h"
#include "src/api/api.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/source-position.h"
#include "src/debug/debug.h"
#include "src/execution/isolate.h"
diff --git a/src/third_party/v8/src/codegen/x64/assembler-x64.cc b/src/third_party/v8/src/codegen/x64/assembler-x64.cc
index ac4b5e3..014a2d5 100644
--- a/src/third_party/v8/src/codegen/x64/assembler-x64.cc
+++ b/src/third_party/v8/src/codegen/x64/assembler-x64.cc
@@ -17,7 +17,6 @@
#include "src/base/bits.h"
#include "src/base/cpu.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/macro-assembler.h"
#include "src/codegen/string-constants.h"
@@ -408,7 +407,6 @@
DCHECK(options().collect_win64_unwind_info);
DCHECK_NOT_NULL(xdata_encoder_);
return win64_unwindinfo::BuiltinUnwindInfo();
- // return xdata_encoder_->unwinding_info();
}
#endif
diff --git a/src/third_party/v8/src/common/globals.h b/src/third_party/v8/src/common/globals.h
index b2d1df5..988ab10 100644
--- a/src/third_party/v8/src/common/globals.h
+++ b/src/third_party/v8/src/common/globals.h
@@ -1765,10 +1765,10 @@
struct RelaxedLoadTag {};
struct ReleaseStoreTag {};
struct RelaxedStoreTag {};
-static constexpr AcquireLoadTag kAcquireLoad{};
-static constexpr RelaxedLoadTag kRelaxedLoad{};
-static constexpr ReleaseStoreTag kReleaseStore{};
-static constexpr RelaxedStoreTag kRelaxedStore{};
+static constexpr AcquireLoadTag kAcquireLoad;
+static constexpr RelaxedLoadTag kRelaxedLoad;
+static constexpr ReleaseStoreTag kReleaseStore;
+static constexpr RelaxedStoreTag kRelaxedStore;
} // namespace v8
diff --git a/src/third_party/v8/src/compiler/backend/arm/instruction-selector-arm.cc b/src/third_party/v8/src/compiler/backend/arm/instruction-selector-arm.cc
index f310349..248f765 100644
--- a/src/third_party/v8/src/compiler/backend/arm/instruction-selector-arm.cc
+++ b/src/third_party/v8/src/compiler/backend/arm/instruction-selector-arm.cc
@@ -5,7 +5,6 @@
#include "src/base/bits.h"
#include "src/base/enum-set.h"
#include "src/base/iterator.h"
-#include "src/base/platform/wrappers.h"
#include "src/compiler/backend/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
diff --git a/src/third_party/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc b/src/third_party/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc
index e11b9fd..584cfb6 100644
--- a/src/third_party/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc
+++ b/src/third_party/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "src/base/bits.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/assembler-inl.h"
#include "src/compiler/backend/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
diff --git a/src/third_party/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc b/src/third_party/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc
index d8f2fa6..c16584a 100644
--- a/src/third_party/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc
+++ b/src/third_party/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "src/base/iterator.h"
-#include "src/base/platform/wrappers.h"
#include "src/compiler/backend/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
diff --git a/src/third_party/v8/src/compiler/backend/instruction-selector.cc b/src/third_party/v8/src/compiler/backend/instruction-selector.cc
index 706a9b2..b62cc83 100644
--- a/src/third_party/v8/src/compiler/backend/instruction-selector.cc
+++ b/src/third_party/v8/src/compiler/backend/instruction-selector.cc
@@ -7,7 +7,6 @@
#include <limits>
#include "src/base/iterator.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/tick-counter.h"
#include "src/compiler/backend/instruction-selector-impl.h"
@@ -3317,8 +3316,7 @@
void InstructionSelector::CanonicalizeShuffle(Node* node, uint8_t* shuffle,
bool* is_swizzle) {
// Get raw shuffle indices.
- memcpy(shuffle, S128ImmediateParameterOf(node->op()).data(),
- kSimd128Size);
+ memcpy(shuffle, S128ImmediateParameterOf(node->op()).data(), kSimd128Size);
bool needs_swap;
bool inputs_equal = GetVirtualRegister(node->InputAt(0)) ==
GetVirtualRegister(node->InputAt(1));
diff --git a/src/third_party/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc b/src/third_party/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc
index a4e8b1f..216b83c 100644
--- a/src/third_party/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc
+++ b/src/third_party/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "src/base/bits.h"
-#include "src/base/platform/wrappers.h"
#include "src/compiler/backend/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
diff --git a/src/third_party/v8/src/compiler/backend/s390/instruction-selector-s390.cc b/src/third_party/v8/src/compiler/backend/s390/instruction-selector-s390.cc
index c3c0cff..124193f 100644
--- a/src/third_party/v8/src/compiler/backend/s390/instruction-selector-s390.cc
+++ b/src/third_party/v8/src/compiler/backend/s390/instruction-selector-s390.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "src/base/platform/wrappers.h"
#include "src/compiler/backend/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
diff --git a/src/third_party/v8/src/compiler/backend/x64/instruction-selector-x64.cc b/src/third_party/v8/src/compiler/backend/x64/instruction-selector-x64.cc
index 95461247..7a8a2b4 100644
--- a/src/third_party/v8/src/compiler/backend/x64/instruction-selector-x64.cc
+++ b/src/third_party/v8/src/compiler/backend/x64/instruction-selector-x64.cc
@@ -7,7 +7,6 @@
#include "src/base/iterator.h"
#include "src/base/logging.h"
#include "src/base/overflowing-math.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/machine-type.h"
#include "src/compiler/backend/instruction-selector-impl.h"
#include "src/compiler/machine-operator.h"
diff --git a/src/third_party/v8/src/compiler/bytecode-graph-builder.cc b/src/third_party/v8/src/compiler/bytecode-graph-builder.cc
index 12abe01..14d014b 100644
--- a/src/third_party/v8/src/compiler/bytecode-graph-builder.cc
+++ b/src/third_party/v8/src/compiler/bytecode-graph-builder.cc
@@ -5,7 +5,6 @@
#include "src/compiler/bytecode-graph-builder.h"
#include "src/ast/ast.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/source-position-table.h"
#include "src/codegen/tick-counter.h"
#include "src/compiler/access-builder.h"
@@ -4366,8 +4365,7 @@
if (has_effect) ++input_count_with_deps;
Node** buffer = EnsureInputBufferSize(input_count_with_deps);
if (value_input_count > 0) {
- memcpy(buffer, value_inputs,
- kSystemPointerSize * value_input_count);
+ memcpy(buffer, value_inputs, kSystemPointerSize * value_input_count);
}
Node** current_input = buffer + value_input_count;
if (has_context) {
diff --git a/src/third_party/v8/src/compiler/code-assembler.cc b/src/third_party/v8/src/compiler/code-assembler.cc
index e6b29f9..87edc79 100644
--- a/src/third_party/v8/src/compiler/code-assembler.cc
+++ b/src/third_party/v8/src/compiler/code-assembler.cc
@@ -26,10 +26,6 @@
#include "src/utils/memcopy.h"
#include "src/zone/zone.h"
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/compiler/node.cc b/src/third_party/v8/src/compiler/node.cc
index a107bb7..8525fa0 100644
--- a/src/third_party/v8/src/compiler/node.cc
+++ b/src/third_party/v8/src/compiler/node.cc
@@ -4,10 +4,6 @@
#include "src/compiler/node.h"
-#if defined(V8_OS_STARBOARD)
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
namespace compiler {
diff --git a/src/third_party/v8/src/compiler/pipeline.cc b/src/third_party/v8/src/compiler/pipeline.cc
index e0b59c9..3caa6a6 100644
--- a/src/third_party/v8/src/compiler/pipeline.cc
+++ b/src/third_party/v8/src/compiler/pipeline.cc
@@ -96,10 +96,6 @@
#include "src/wasm/function-compiler.h"
#include "src/wasm/wasm-engine.h"
-#if V8_OS_STARBOARD
-#include "starboard/common/log.h"
-#endif // V8_OS_STARBOARD
-
namespace v8 {
namespace internal {
namespace compiler {
diff --git a/src/third_party/v8/src/compiler/simd-scalar-lowering.cc b/src/third_party/v8/src/compiler/simd-scalar-lowering.cc
index a1d1128e..06673c3 100644
--- a/src/third_party/v8/src/compiler/simd-scalar-lowering.cc
+++ b/src/third_party/v8/src/compiler/simd-scalar-lowering.cc
@@ -4,7 +4,6 @@
#include "src/compiler/simd-scalar-lowering.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/machine-type.h"
#include "src/common/globals.h"
#include "src/compiler/diamond.h"
diff --git a/src/third_party/v8/src/compiler/wasm-compiler.cc b/src/third_party/v8/src/compiler/wasm-compiler.cc
index c476d15..fa08578 100644
--- a/src/third_party/v8/src/compiler/wasm-compiler.cc
+++ b/src/third_party/v8/src/compiler/wasm-compiler.cc
@@ -9,7 +9,6 @@
#include "src/base/optional.h"
#include "src/base/platform/elapsed-timer.h"
#include "src/base/platform/platform.h"
-#include "src/base/platform/wrappers.h"
#include "src/base/small-vector.h"
#include "src/base/v8-fallthrough.h"
#include "src/codegen/assembler-inl.h"
diff --git a/src/third_party/v8/src/d8.isolate b/src/third_party/v8/src/d8.isolate
deleted file mode 100644
index 1c9bd9e..0000000
--- a/src/third_party/v8/src/d8.isolate
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2015 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
- 'variables': {
- 'command': [
- '<(PRODUCT_DIR)/d8<(EXECUTABLE_SUFFIX)',
- ],
- 'files': [
- '<(PRODUCT_DIR)/d8<(EXECUTABLE_SUFFIX)',
- ],
- },
- 'includes': [
- 'base.isolate',
- ],
-}
\ No newline at end of file
diff --git a/src/third_party/v8/src/d8.js b/src/third_party/v8/src/d8.js
deleted file mode 100644
index 287571b..0000000
--- a/src/third_party/v8/src/d8.js
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2008 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(function() {
-"use strict";
-
-// A more universal stringify that supports more types than JSON.
-// Used by the d8 shell to output results.
-var stringifyDepthLimit = 4; // To avoid crashing on cyclic objects
-
-// Hacky solution to circumvent forcing --allow-natives-syntax for d8
-function isProxy(o) { return false };
-function JSProxyGetTarget(proxy) { };
-function JSProxyGetHandler(proxy) { };
-
-try {
- isProxy = Function(['object'], 'return %_IsJSProxy(object)');
- JSProxyGetTarget = Function(['proxy'],
- 'return %JSProxyGetTarget(proxy)');
- JSProxyGetHandler = Function(['proxy'],
- 'return %JSProxyGetHandler(proxy)');
-} catch(e) {};
-
-
-function Stringify(x, depth) {
- if (depth === undefined)
- depth = stringifyDepthLimit;
- else if (depth === 0)
- return "...";
- if (isProxy(x)) {
- return StringifyProxy(x, depth);
- }
- switch (typeof x) {
- case "undefined":
- return "undefined";
- case "boolean":
- case "number":
- case "function":
- case "symbol":
- return x.toString();
- case "string":
- return "\"" + x.toString() + "\"";
- case "bigint":
- // TODO(neis): Use x.toString() once we have it.
- return String(x) + "n";
- case "object":
- if (IS_NULL(x)) return "null";
- if (x.constructor && x.constructor.name === "Array") {
- var elems = [];
- for (var i = 0; i < x.length; ++i) {
- elems.push(
- {}.hasOwnProperty.call(x, i) ? Stringify(x[i], depth - 1) : "");
- }
- return "[" + elems.join(", ") + "]";
- }
- try {
- var string = String(x);
- if (string && string !== "[object Object]") return string;
- } catch(e) {}
- var props = [];
- var names = Object.getOwnPropertyNames(x);
- names = names.concat(Object.getOwnPropertySymbols(x));
- for (var i in names) {
- var name = names[i];
- var desc = Object.getOwnPropertyDescriptor(x, name);
- if (IS_UNDEFINED(desc)) continue;
- if (IS_SYMBOL(name)) name = "[" + Stringify(name) + "]";
- if ("value" in desc) {
- props.push(name + ": " + Stringify(desc.value, depth - 1));
- }
- if (desc.get) {
- var getter = Stringify(desc.get);
- props.push("get " + name + getter.slice(getter.indexOf('(')));
- }
- if (desc.set) {
- var setter = Stringify(desc.set);
- props.push("set " + name + setter.slice(setter.indexOf('(')));
- }
- }
- return "{" + props.join(", ") + "}";
- default:
- return "[crazy non-standard value]";
- }
-}
-
-function StringifyProxy(proxy, depth) {
- var proxy_type = typeof proxy;
- var info_object = {
- target: JSProxyGetTarget(proxy),
- handler: JSProxyGetHandler(proxy)
- }
- return '[' + proxy_type + ' Proxy ' + Stringify(info_object, depth-1) + ']';
-}
-
-return Stringify;
-})();
diff --git a/src/third_party/v8/src/d8/d8-posix.cc b/src/third_party/v8/src/d8/d8-posix.cc
index a9a9fcd..c7313b4 100644
--- a/src/third_party/v8/src/d8/d8-posix.cc
+++ b/src/third_party/v8/src/d8/d8-posix.cc
@@ -16,7 +16,6 @@
#include <sys/wait.h>
#include <unistd.h>
-#include "src/base/platform/wrappers.h"
#include "src/d8/d8.h"
namespace v8 {
diff --git a/src/third_party/v8/src/debug/debug-coverage.cc b/src/third_party/v8/src/debug/debug-coverage.cc
index 8bc964a..bee4122 100644
--- a/src/third_party/v8/src/debug/debug-coverage.cc
+++ b/src/third_party/v8/src/debug/debug-coverage.cc
@@ -14,10 +14,6 @@
#include "src/objects/debug-objects-inl.h"
#include "src/objects/objects.h"
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/debug/wasm/gdb-server/transport.cc b/src/third_party/v8/src/debug/wasm/gdb-server/transport.cc
index 9806a72..f1aed96 100644
--- a/src/third_party/v8/src/debug/wasm/gdb-server/transport.cc
+++ b/src/third_party/v8/src/debug/wasm/gdb-server/transport.cc
@@ -3,11 +3,8 @@
// found in the LICENSE file.
#include "src/debug/wasm/gdb-server/transport.h"
-
#include <fcntl.h>
-#include "src/base/platform/wrappers.h"
-
#ifndef SD_BOTH
#define SD_BOTH 2
#endif
diff --git a/src/third_party/v8/src/debug/wasm/gdb-server/wasm-module-debug.cc b/src/third_party/v8/src/debug/wasm/gdb-server/wasm-module-debug.cc
index 50b9d8d..f0b77bc 100644
--- a/src/third_party/v8/src/debug/wasm/gdb-server/wasm-module-debug.cc
+++ b/src/third_party/v8/src/debug/wasm/gdb-server/wasm-module-debug.cc
@@ -6,7 +6,6 @@
#include "src/api/api-inl.h"
#include "src/api/api.h"
-#include "src/base/platform/wrappers.h"
#include "src/execution/frames-inl.h"
#include "src/execution/frames.h"
#include "src/objects/script.h"
diff --git a/src/third_party/v8/src/deoptimizer/deoptimizer.cc b/src/third_party/v8/src/deoptimizer/deoptimizer.cc
index 5057029..4ae51bf 100644
--- a/src/third_party/v8/src/deoptimizer/deoptimizer.cc
+++ b/src/third_party/v8/src/deoptimizer/deoptimizer.cc
@@ -33,10 +33,6 @@
// Has to be the last include (doesn't have include guards)
#include "src/objects/object-macros.h"
-#if defined(V8_OS_STARBOARD)
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/diagnostics/objects-printer.cc b/src/third_party/v8/src/diagnostics/objects-printer.cc
index 5b5413c..8ee9685 100644
--- a/src/third_party/v8/src/diagnostics/objects-printer.cc
+++ b/src/third_party/v8/src/diagnostics/objects-printer.cc
@@ -22,11 +22,6 @@
#include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-objects-inl.h"
-#if defined(STARBOARD)
-#include "starboard/common/log.h"
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
@@ -2683,7 +2678,7 @@
void* object) {
i::Object o(GetObjectFromRaw(object));
if (!o.IsLayoutDescriptor()) {
- printf("Please provide a layout descriptor\n");
+ i::PrintF("Please provide a layout descriptor\n");
} else {
i::LayoutDescriptor::cast(o).Print();
}
@@ -2697,7 +2692,7 @@
V8_EXPORT_PRIVATE extern void _v8_internal_Print_TransitionTree(void* object) {
i::Object o(GetObjectFromRaw(object));
if (!o.IsMap()) {
- printf("Please provide a valid Map\n");
+ i::PrintF("Please provide a valid Map\n");
} else {
#if defined(DEBUG) || defined(OBJECT_PRINT)
i::DisallowHeapAllocation no_gc;
diff --git a/src/third_party/v8/src/diagnostics/unwinding-info-win64.cc b/src/third_party/v8/src/diagnostics/unwinding-info-win64.cc
index 695e5ef..361935b 100644
--- a/src/third_party/v8/src/diagnostics/unwinding-info-win64.cc
+++ b/src/third_party/v8/src/diagnostics/unwinding-info-win64.cc
@@ -10,7 +10,6 @@
#if defined(V8_OS_WIN_X64)
#include "src/codegen/x64/assembler-x64.h"
#elif defined(V8_OS_WIN_ARM64)
-#include "src/base/platform/wrappers.h"
#include "src/codegen/arm64/assembler-arm64-inl.h"
#include "src/codegen/arm64/macro-assembler-arm64-inl.h"
#else
@@ -171,8 +170,7 @@
masm.movq(rax, reinterpret_cast<uint64_t>(&CRASH_HANDLER_FUNCTION_NAME));
masm.jmp(rax);
DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk));
- memcpy(&record->exception_thunk[0], masm.buffer_start(),
- masm.instruction_size());
+ memcpy(&record->exception_thunk[0], masm.buffer_start(), masm.instruction_size());
}
#elif defined(V8_OS_WIN_ARM64)
@@ -449,8 +447,7 @@
Operand(reinterpret_cast<uint64_t>(&CRASH_HANDLER_FUNCTION_NAME)));
masm.Br(x16);
DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk));
- memcpy(&record->exception_thunk[0], masm.buffer_start(),
- masm.instruction_size());
+ memcpy(&record->exception_thunk[0], masm.buffer_start(), masm.instruction_size());
}
#endif // V8_OS_WIN_X64
diff --git a/src/third_party/v8/src/execution/arm64/simulator-arm64.h b/src/third_party/v8/src/execution/arm64/simulator-arm64.h
index 93fb59a..ee6d634 100644
--- a/src/third_party/v8/src/execution/arm64/simulator-arm64.h
+++ b/src/third_party/v8/src/execution/arm64/simulator-arm64.h
@@ -11,11 +11,9 @@
#if defined(USE_SIMULATOR)
#include <stdarg.h>
-
#include <vector>
#include "src/base/compiler-specific.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/arm64/assembler-arm64.h"
#include "src/codegen/arm64/decoder-arm64.h"
#include "src/codegen/assembler.h"
@@ -340,8 +338,7 @@
DCHECK_GE(lane, 0);
DCHECK_LE(sizeof(new_value) + (lane * sizeof(new_value)),
static_cast<unsigned>(kSizeInBytes));
- memcpy(&value_[lane * sizeof(new_value)], &new_value,
- sizeof(new_value));
+ memcpy(&value_[lane * sizeof(new_value)], &new_value, sizeof(new_value));
NotifyRegisterWrite();
}
diff --git a/src/third_party/v8/src/execution/frames.cc b/src/third_party/v8/src/execution/frames.cc
index ea964e4..3288f53 100644
--- a/src/third_party/v8/src/execution/frames.cc
+++ b/src/third_party/v8/src/execution/frames.cc
@@ -8,7 +8,6 @@
#include <sstream>
#include "src/base/bits.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/interface-descriptors.h"
#include "src/codegen/macro-assembler.h"
#include "src/codegen/register-configuration.h"
diff --git a/src/third_party/v8/src/execution/isolate.cc b/src/third_party/v8/src/execution/isolate.cc
index fd12f76..ff3886f 100644
--- a/src/third_party/v8/src/execution/isolate.cc
+++ b/src/third_party/v8/src/execution/isolate.cc
@@ -98,10 +98,6 @@
#include "unicode/uobject.h"
#endif // V8_INTL_SUPPORT
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
#if defined(V8_OS_WIN64)
#include "src/diagnostics/unwinding-info-win64.h"
#endif // V8_OS_WIN64
diff --git a/src/third_party/v8/src/handles/maybe-handles.h b/src/third_party/v8/src/handles/maybe-handles.h
index f18a7a9..15397ef 100644
--- a/src/third_party/v8/src/handles/maybe-handles.h
+++ b/src/third_party/v8/src/handles/maybe-handles.h
@@ -14,7 +14,7 @@
struct NullMaybeHandleType {};
-constexpr NullMaybeHandleType kNullMaybeHandle{};
+constexpr NullMaybeHandleType kNullMaybeHandle;
// ----------------------------------------------------------------------------
// A Handle can be converted into a MaybeHandle. Converting a MaybeHandle
diff --git a/src/third_party/v8/src/init/v8.cc b/src/third_party/v8/src/init/v8.cc
index 688ca23..1bc54c3 100644
--- a/src/third_party/v8/src/init/v8.cc
+++ b/src/third_party/v8/src/init/v8.cc
@@ -27,10 +27,6 @@
#include "src/tracing/tracing-category-observer.h"
#include "src/wasm/wasm-engine.h"
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/inspector/v8-string-conversions.h b/src/third_party/v8/src/inspector/v8-string-conversions.h
index 285667e..c1d69c1 100644
--- a/src/third_party/v8/src/inspector/v8-string-conversions.h
+++ b/src/third_party/v8/src/inspector/v8-string-conversions.h
@@ -7,11 +7,6 @@
#include <string>
-// The v8config.h above is needed to turn on V8_OS_STARBOARD
-#if defined(V8_OS_STARBOARD)
-#include "starboard/types.h"
-#endif
-
// Conversion routines between UT8 and UTF16, used by string-16.{h,cc}. You may
// want to use string-16.h directly rather than these.
namespace v8_inspector {
diff --git a/src/third_party/v8/src/libplatform/tracing/tracing-controller.cc b/src/third_party/v8/src/libplatform/tracing/tracing-controller.cc
index 923ee68..115232e 100644
--- a/src/third_party/v8/src/libplatform/tracing/tracing-controller.cc
+++ b/src/third_party/v8/src/libplatform/tracing/tracing-controller.cc
@@ -11,6 +11,7 @@
#include "src/base/atomicops.h"
#include "src/base/platform/mutex.h"
#include "src/base/platform/time.h"
+#include "src/base/platform/wrappers.h"
#if V8_OS_STARBOARD
#include "src/poems.h"
@@ -329,7 +330,7 @@
// Don't hold on to the category_group pointer, so that we can create
// category groups with strings not known at compile time (this is
// required by SetWatchEvent).
- const char* new_group = strdup(category_group);
+ const char* new_group = base::Strdup(category_group);
g_category_groups[category_index] = new_group;
DCHECK(!g_category_group_enabled[category_index]);
// Note that if both included and excluded patterns in the
diff --git a/src/third_party/v8/src/logging/log-utils.cc b/src/third_party/v8/src/logging/log-utils.cc
index 7a26e4b..e017fe8 100644
--- a/src/third_party/v8/src/logging/log-utils.cc
+++ b/src/third_party/v8/src/logging/log-utils.cc
@@ -16,10 +16,6 @@
#include "src/utils/vector.h"
#include "src/utils/version.h"
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/numbers/conversions-inl.h b/src/third_party/v8/src/numbers/conversions-inl.h
index 43421e3..08502d4 100644
--- a/src/third_party/v8/src/numbers/conversions-inl.h
+++ b/src/third_party/v8/src/numbers/conversions-inl.h
@@ -16,7 +16,6 @@
#include "src/base/bits.h"
#include "src/base/platform/platform.h"
-#include "src/base/platform/wrappers.h"
#include "src/numbers/conversions.h"
#include "src/numbers/double.h"
#include "src/objects/heap-number-inl.h"
diff --git a/src/third_party/v8/src/numbers/conversions.cc b/src/third_party/v8/src/numbers/conversions.cc
index f83f19e..1423bd6 100644
--- a/src/third_party/v8/src/numbers/conversions.cc
+++ b/src/third_party/v8/src/numbers/conversions.cc
@@ -9,7 +9,6 @@
#include <cmath>
-#include "src/base/platform/wrappers.h"
#include "src/common/assert-scope.h"
#include "src/handles/handles.h"
#include "src/heap/factory.h"
@@ -1348,8 +1347,7 @@
DCHECK_LE(0, integer_cursor);
// Allocate new string as return value.
char* result = NewArray<char>(fraction_cursor - integer_cursor);
- memcpy(result, buffer + integer_cursor,
- fraction_cursor - integer_cursor);
+ memcpy(result, buffer + integer_cursor, fraction_cursor - integer_cursor);
return result;
}
diff --git a/src/third_party/v8/src/objects/backing-store.cc b/src/third_party/v8/src/objects/backing-store.cc
index 53e3837..9f755f5 100644
--- a/src/third_party/v8/src/objects/backing-store.cc
+++ b/src/third_party/v8/src/objects/backing-store.cc
@@ -6,7 +6,6 @@
#include <cstring>
-#include "src/base/platform/wrappers.h"
#include "src/execution/isolate.h"
#include "src/handles/global-handles.h"
#include "src/logging/counters.h"
@@ -465,8 +464,7 @@
// If the allocation was successful, then the new buffer must be at least
// as big as the old one.
DCHECK_GE(new_pages * wasm::kWasmPageSize, byte_length_);
- memcpy(new_backing_store->buffer_start(), buffer_start_,
- byte_length_);
+ memcpy(new_backing_store->buffer_start(), buffer_start_, byte_length_);
}
return new_backing_store;
diff --git a/src/third_party/v8/src/objects/bigint.cc b/src/third_party/v8/src/objects/bigint.cc
index f2cd964..129bb14 100644
--- a/src/third_party/v8/src/objects/bigint.cc
+++ b/src/third_party/v8/src/objects/bigint.cc
@@ -240,7 +240,6 @@
OBJECT_CONSTRUCTORS_IMPL(MutableBigInt, FreshlyAllocatedBigInt)
NEVER_READ_ONLY_SPACE_IMPL(MutableBigInt)
-#include "src/base/platform/wrappers.h"
#include "src/objects/object-macros-undef.h"
template <typename T, typename Isolate>
@@ -362,10 +361,9 @@
int length = source->length();
// Allocating a BigInt of the same length as an existing BigInt cannot throw.
Handle<MutableBigInt> result = New(isolate, length).ToHandleChecked();
- memcpy(
- reinterpret_cast<void*>(result->address() + BigIntBase::kHeaderSize),
- reinterpret_cast<void*>(source->address() + BigIntBase::kHeaderSize),
- BigInt::SizeFor(length) - BigIntBase::kHeaderSize);
+ memcpy(reinterpret_cast<void*>(result->address() + BigIntBase::kHeaderSize),
+ reinterpret_cast<void*>(source->address() + BigIntBase::kHeaderSize),
+ BigInt::SizeFor(length) - BigIntBase::kHeaderSize);
return result;
}
diff --git a/src/third_party/v8/src/objects/fixed-array-inl.h b/src/third_party/v8/src/objects/fixed-array-inl.h
index c4eafe1..547e4dc 100644
--- a/src/third_party/v8/src/objects/fixed-array-inl.h
+++ b/src/third_party/v8/src/objects/fixed-array-inl.h
@@ -632,7 +632,6 @@
} // namespace internal
} // namespace v8
-#include "src/base/platform/wrappers.h"
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_FIXED_ARRAY_INL_H_
diff --git a/src/third_party/v8/src/objects/js-array-buffer.cc b/src/third_party/v8/src/objects/js-array-buffer.cc
index 15477ac..728791c 100644
--- a/src/third_party/v8/src/objects/js-array-buffer.cc
+++ b/src/third_party/v8/src/objects/js-array-buffer.cc
@@ -4,7 +4,6 @@
#include "src/objects/js-array-buffer.h"
-#include "src/base/platform/wrappers.h"
#include "src/execution/protectors-inl.h"
#include "src/logging/counters.h"
#include "src/objects/js-array-buffer-inl.h"
diff --git a/src/third_party/v8/src/objects/layout-descriptor.cc b/src/third_party/v8/src/objects/layout-descriptor.cc
index 680f8d3..034680e 100644
--- a/src/third_party/v8/src/objects/layout-descriptor.cc
+++ b/src/third_party/v8/src/objects/layout-descriptor.cc
@@ -7,7 +7,6 @@
#include <sstream>
#include "src/base/bits.h"
-#include "src/base/platform/wrappers.h"
#include "src/handles/handles-inl.h"
#include "src/objects/objects-inl.h"
@@ -103,8 +102,8 @@
if (layout_descriptor->IsSlowLayout()) {
memcpy(new_layout_descriptor->GetDataStartAddress(),
- layout_descriptor->GetDataStartAddress(),
- layout_descriptor->DataSize());
+ layout_descriptor->GetDataStartAddress(),
+ layout_descriptor->DataSize());
return new_layout_descriptor;
} else {
// Fast layout.
diff --git a/src/third_party/v8/src/objects/shared-function-info-inl.h b/src/third_party/v8/src/objects/shared-function-info-inl.h
index 70ef90d..caf14e8 100644
--- a/src/third_party/v8/src/objects/shared-function-info-inl.h
+++ b/src/third_party/v8/src/objects/shared-function-info-inl.h
@@ -791,7 +791,6 @@
} // namespace internal
} // namespace v8
-#include "src/base/platform/wrappers.h"
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_SHARED_FUNCTION_INFO_INL_H_
diff --git a/src/third_party/v8/src/parsing/parse-info.cc b/src/third_party/v8/src/parsing/parse-info.cc
index ff94d6c..1c2b1b9 100644
--- a/src/third_party/v8/src/parsing/parse-info.cc
+++ b/src/third_party/v8/src/parsing/parse-info.cc
@@ -17,10 +17,6 @@
#include "src/objects/scope-info.h"
#include "src/zone/zone.h"
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/parsing/preparse-data.cc b/src/third_party/v8/src/parsing/preparse-data.cc
index 0ce29fa..b18788b 100644
--- a/src/third_party/v8/src/parsing/preparse-data.cc
+++ b/src/third_party/v8/src/parsing/preparse-data.cc
@@ -8,7 +8,6 @@
#include "src/ast/scopes.h"
#include "src/ast/variables.h"
-#include "src/base/platform/wrappers.h"
#include "src/handles/handles.h"
#include "src/objects/objects-inl.h"
#include "src/objects/shared-function-info.h"
diff --git a/src/third_party/v8/src/parsing/scanner.cc b/src/third_party/v8/src/parsing/scanner.cc
index 7c0838f..9a04bdc 100644
--- a/src/third_party/v8/src/parsing/scanner.cc
+++ b/src/third_party/v8/src/parsing/scanner.cc
@@ -11,7 +11,6 @@
#include <cmath>
#include "src/ast/ast-value-factory.h"
-#include "src/base/platform/wrappers.h"
#include "src/numbers/conversions-inl.h"
#include "src/objects/bigint.h"
#include "src/parsing/parse-info.h"
diff --git a/src/third_party/v8/src/poems.h b/src/third_party/v8/src/poems.h
index 4ac3cae..b8ac836 100644
--- a/src/third_party/v8/src/poems.h
+++ b/src/third_party/v8/src/poems.h
@@ -1,14 +1,3 @@
-// Copyright 2018 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.
@@ -23,6 +12,11 @@
#error "Including V8 poems without V8_OS_STARBOARD defined."
#endif
+// This file is deprecated, stop using poems and use wrapper functions in
+// base/platform/wrappers.h instead.
+// Currently only tracing-controller.cc has trouble removing poems.h
+// dependencies.
+
#include "starboard/memory.h"
#include "starboard/string.h"
#include "starboard/common/log.h"
@@ -56,3 +50,4 @@
#define fflush(x)
#endif // V8_SRC_POEMS_H_
+
diff --git a/src/third_party/v8/src/profiler/allocation-tracker.cc b/src/third_party/v8/src/profiler/allocation-tracker.cc
index cb40e6e..5900438 100644
--- a/src/third_party/v8/src/profiler/allocation-tracker.cc
+++ b/src/third_party/v8/src/profiler/allocation-tracker.cc
@@ -9,10 +9,6 @@
#include "src/objects/objects-inl.h"
#include "src/profiler/heap-snapshot-generator-inl.h"
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/profiler/heap-snapshot-generator.cc b/src/third_party/v8/src/profiler/heap-snapshot-generator.cc
index 4c057eb..2907a21 100644
--- a/src/third_party/v8/src/profiler/heap-snapshot-generator.cc
+++ b/src/third_party/v8/src/profiler/heap-snapshot-generator.cc
@@ -40,10 +40,6 @@
#include "src/profiler/heap-snapshot-generator-inl.h"
#include "src/utils/vector.h"
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/profiler/profile-generator.cc b/src/third_party/v8/src/profiler/profile-generator.cc
index 2b7030e..f3344c5 100644
--- a/src/third_party/v8/src/profiler/profile-generator.cc
+++ b/src/third_party/v8/src/profiler/profile-generator.cc
@@ -14,10 +14,6 @@
#include "src/tracing/trace-event.h"
#include "src/tracing/traced-value.h"
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/regexp/regexp-interpreter.cc b/src/third_party/v8/src/regexp/regexp-interpreter.cc
index 8607f34..a73a9d3 100644
--- a/src/third_party/v8/src/regexp/regexp-interpreter.cc
+++ b/src/third_party/v8/src/regexp/regexp-interpreter.cc
@@ -22,10 +22,6 @@
#include "unicode/uchar.h"
#endif // V8_INTL_SUPPORT
-#if defined(V8_OS_STARBOARD)
-#include "src/poems.h"
-#endif
-
// Use token threaded dispatch iff the compiler supports computed gotos and the
// build argument v8_enable_regexp_interpreter_threaded_dispatch was set.
#if V8_HAS_COMPUTED_GOTO && \
diff --git a/src/third_party/v8/src/runtime/runtime-test.cc b/src/third_party/v8/src/runtime/runtime-test.cc
index f85cddb..c6df042 100644
--- a/src/third_party/v8/src/runtime/runtime-test.cc
+++ b/src/third_party/v8/src/runtime/runtime-test.cc
@@ -40,10 +40,6 @@
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-serialization.h"
-#if defined(V8_OS_STARBOARD)
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/runtime/runtime.cc b/src/third_party/v8/src/runtime/runtime.cc
index e2e7ab4..4c5360f 100644
--- a/src/third_party/v8/src/runtime/runtime.cc
+++ b/src/third_party/v8/src/runtime/runtime.cc
@@ -5,7 +5,6 @@
#include "src/runtime/runtime.h"
#include "src/base/hashmap.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/reloc-info.h"
#include "src/execution/isolate.h"
#include "src/handles/handles-inl.h"
diff --git a/src/third_party/v8/src/snapshot/deserializer.cc b/src/third_party/v8/src/snapshot/deserializer.cc
index 8f4b8a8..5a729b3 100644
--- a/src/third_party/v8/src/snapshot/deserializer.cc
+++ b/src/third_party/v8/src/snapshot/deserializer.cc
@@ -5,7 +5,6 @@
#include "src/snapshot/deserializer.h"
#include "src/base/logging.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/assembler-inl.h"
#include "src/common/assert-scope.h"
#include "src/common/external-pointer.h"
diff --git a/src/third_party/v8/src/snapshot/snapshot-source-sink.h b/src/third_party/v8/src/snapshot/snapshot-source-sink.h
index 964b049..f0686af 100644
--- a/src/third_party/v8/src/snapshot/snapshot-source-sink.h
+++ b/src/third_party/v8/src/snapshot/snapshot-source-sink.h
@@ -9,7 +9,6 @@
#include "src/base/atomicops.h"
#include "src/base/logging.h"
-#include "src/base/platform/wrappers.h"
#include "src/common/globals.h"
#include "src/snapshot/snapshot-utils.h"
#include "src/utils/utils.h"
diff --git a/src/third_party/v8/src/trap-handler/handler-outside.cc b/src/third_party/v8/src/trap-handler/handler-outside.cc
index 65e8f75..22d94ea 100644
--- a/src/third_party/v8/src/trap-handler/handler-outside.cc
+++ b/src/third_party/v8/src/trap-handler/handler-outside.cc
@@ -30,10 +30,6 @@
#include "src/trap-handler/trap-handler-internal.h"
#include "src/trap-handler/trap-handler.h"
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
namespace {
size_t gNextCodeObject = 0;
diff --git a/src/third_party/v8/src/utils/allocation.cc b/src/third_party/v8/src/utils/allocation.cc
index e7aa682..79c2790 100644
--- a/src/third_party/v8/src/utils/allocation.cc
+++ b/src/third_party/v8/src/utils/allocation.cc
@@ -10,6 +10,7 @@
#include "src/base/logging.h"
#include "src/base/page-allocator.h"
#include "src/base/platform/platform.h"
+#include "src/base/platform/wrappers.h"
#include "src/flags/flags.h"
#include "src/init/v8.h"
#include "src/sanitizer/lsan-page-allocator.h"
@@ -18,12 +19,6 @@
#if V8_LIBC_BIONIC
#include <malloc.h> // NOLINT
-
-#include "src/base/platform/wrappers.h"
-#endif
-
-#if defined(V8_OS_STARBOARD)
-#include "src/poems.h"
#endif
namespace v8 {
diff --git a/src/third_party/v8/src/utils/detachable-vector.h b/src/third_party/v8/src/utils/detachable-vector.h
index e921ea7..232e89f 100644
--- a/src/third_party/v8/src/utils/detachable-vector.h
+++ b/src/third_party/v8/src/utils/detachable-vector.h
@@ -11,7 +11,6 @@
#include "src/base/logging.h"
#include "src/base/macros.h"
-#include "src/base/platform/wrappers.h"
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/utils/memcopy.h b/src/third_party/v8/src/utils/memcopy.h
index b3648ed..b940a4a 100644
--- a/src/third_party/v8/src/utils/memcopy.h
+++ b/src/third_party/v8/src/utils/memcopy.h
@@ -8,12 +8,10 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-
#include <algorithm>
#include "src/base/logging.h"
#include "src/base/macros.h"
-#include "src/base/platform/wrappers.h"
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/utils/ostreams.cc b/src/third_party/v8/src/utils/ostreams.cc
index 61a2c7c..d58357c 100644
--- a/src/third_party/v8/src/utils/ostreams.cc
+++ b/src/third_party/v8/src/utils/ostreams.cc
@@ -17,10 +17,6 @@
#endif
#endif
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
#define LOG_TAG "v8"
#include <android/log.h> // NOLINT
diff --git a/src/third_party/v8/src/utils/ostreams.h b/src/third_party/v8/src/utils/ostreams.h
index 5a91d1e..82c2923 100644
--- a/src/third_party/v8/src/utils/ostreams.h
+++ b/src/third_party/v8/src/utils/ostreams.h
@@ -166,9 +166,6 @@
// Print any collection which can be iterated via std::begin and std::end.
// {Iterator} is the common type of {std::begin} and {std::end} called on a
// {const T&}. This function is only instantiable if that type exists.
-// template <typename T, typename Iterator = typename std::common_type<
-// decltype(std::begin(std::declval<const T&>())),
-// decltype(std::end(std::declval<const T&>()))>::type>
template <typename T, typename Iterator = decltype(std::begin(std::declval<const T&>()))>
PrintIteratorRange<Iterator> PrintCollection(const T& collection) {
return {std::begin(collection), std::end(collection)};
diff --git a/src/third_party/v8/src/utils/utils.cc b/src/third_party/v8/src/utils/utils.cc
index 1c2b8cc..4957f9e 100644
--- a/src/third_party/v8/src/utils/utils.cc
+++ b/src/third_party/v8/src/utils/utils.cc
@@ -15,10 +15,6 @@
#include "src/base/platform/wrappers.h"
#include "src/utils/memcopy.h"
-#if defined(V8_OS_STARBOARD)
-#include "v8/src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/wasm/baseline/arm/liftoff-assembler-arm.h b/src/third_party/v8/src/wasm/baseline/arm/liftoff-assembler-arm.h
index 2f450f7..af969f3 100644
--- a/src/third_party/v8/src/wasm/baseline/arm/liftoff-assembler-arm.h
+++ b/src/third_party/v8/src/wasm/baseline/arm/liftoff-assembler-arm.h
@@ -5,7 +5,6 @@
#ifndef V8_WASM_BASELINE_ARM_LIFTOFF_ASSEMBLER_ARM_H_
#define V8_WASM_BASELINE_ARM_LIFTOFF_ASSEMBLER_ARM_H_
-#include "src/base/platform/wrappers.h"
#include "src/heap/memory-chunk.h"
#include "src/wasm/baseline/liftoff-assembler.h"
#include "src/wasm/baseline/liftoff-register.h"
diff --git a/src/third_party/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32.h b/src/third_party/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32.h
index 86ded4d..5e64009 100644
--- a/src/third_party/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32.h
+++ b/src/third_party/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32.h
@@ -5,7 +5,6 @@
#ifndef V8_WASM_BASELINE_IA32_LIFTOFF_ASSEMBLER_IA32_H_
#define V8_WASM_BASELINE_IA32_LIFTOFF_ASSEMBLER_IA32_H_
-#include "src/base/platform/wrappers.h"
#include "src/codegen/assembler.h"
#include "src/heap/memory-chunk.h"
#include "src/wasm/baseline/liftoff-assembler.h"
diff --git a/src/third_party/v8/src/wasm/baseline/liftoff-assembler.cc b/src/third_party/v8/src/wasm/baseline/liftoff-assembler.cc
index 28f0458..956291f 100644
--- a/src/third_party/v8/src/wasm/baseline/liftoff-assembler.cc
+++ b/src/third_party/v8/src/wasm/baseline/liftoff-assembler.cc
@@ -18,10 +18,6 @@
#include "src/wasm/wasm-linkage.h"
#include "src/wasm/wasm-opcodes.h"
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
namespace wasm {
diff --git a/src/third_party/v8/src/wasm/baseline/liftoff-assembler.h b/src/third_party/v8/src/wasm/baseline/liftoff-assembler.h
index 20e972e..895abbb 100644
--- a/src/third_party/v8/src/wasm/baseline/liftoff-assembler.h
+++ b/src/third_party/v8/src/wasm/baseline/liftoff-assembler.h
@@ -20,10 +20,6 @@
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-value.h"
-#if defined(V8_OS_STARBOARD)
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/v8/src/wasm/baseline/liftoff-compiler.cc b/src/third_party/v8/src/wasm/baseline/liftoff-compiler.cc
index 39b2956..5066468 100644
--- a/src/third_party/v8/src/wasm/baseline/liftoff-compiler.cc
+++ b/src/third_party/v8/src/wasm/baseline/liftoff-compiler.cc
@@ -5,7 +5,6 @@
#include "src/wasm/baseline/liftoff-compiler.h"
#include "src/base/optional.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/assembler-inl.h"
// TODO(clemensb): Remove dependences on compiler stuff.
#include "src/codegen/external-reference.h"
diff --git a/src/third_party/v8/src/wasm/baseline/mips64/liftoff-assembler-mips64.h b/src/third_party/v8/src/wasm/baseline/mips64/liftoff-assembler-mips64.h
index 3eb2d28..b97c494 100644
--- a/src/third_party/v8/src/wasm/baseline/mips64/liftoff-assembler-mips64.h
+++ b/src/third_party/v8/src/wasm/baseline/mips64/liftoff-assembler-mips64.h
@@ -5,7 +5,6 @@
#ifndef V8_WASM_BASELINE_MIPS64_LIFTOFF_ASSEMBLER_MIPS64_H_
#define V8_WASM_BASELINE_MIPS64_LIFTOFF_ASSEMBLER_MIPS64_H_
-#include "src/base/platform/wrappers.h"
#include "src/heap/memory-chunk.h"
#include "src/wasm/baseline/liftoff-assembler.h"
diff --git a/src/third_party/v8/src/wasm/function-body-decoder-impl.h b/src/third_party/v8/src/wasm/function-body-decoder-impl.h
index d67f1e3..b319965 100644
--- a/src/third_party/v8/src/wasm/function-body-decoder-impl.h
+++ b/src/third_party/v8/src/wasm/function-body-decoder-impl.h
@@ -11,7 +11,6 @@
#include <inttypes.h>
#include "src/base/platform/elapsed-timer.h"
-#include "src/base/platform/wrappers.h"
#include "src/base/small-vector.h"
#include "src/utils/bit-vector.h"
#include "src/wasm/decoder.h"
@@ -3157,8 +3156,13 @@
#undef DECODE_IMPL2
OpcodeHandler GetOpcodeHandler(uint8_t opcode) {
+#ifndef V8_OS_STARBOARD
+ static constexpr std::array<OpcodeHandler, 256> kOpcodeHandlers =
+ base::make_array<256>(GetOpcodeHandlerTableEntry);
+#else
DCHECK(false);
static constexpr std::array<OpcodeHandler, 256> kOpcodeHandlers{};
+#endif
return kOpcodeHandlers[opcode];
}
diff --git a/src/third_party/v8/src/wasm/local-decl-encoder.cc b/src/third_party/v8/src/wasm/local-decl-encoder.cc
index a396194..5a2681c 100644
--- a/src/third_party/v8/src/wasm/local-decl-encoder.cc
+++ b/src/third_party/v8/src/wasm/local-decl-encoder.cc
@@ -4,7 +4,6 @@
#include "src/wasm/local-decl-encoder.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/signature.h"
#include "src/wasm/leb-helper.h"
diff --git a/src/third_party/v8/src/wasm/memory-tracing.cc b/src/third_party/v8/src/wasm/memory-tracing.cc
index 58ed547..0d88c4b 100644
--- a/src/third_party/v8/src/wasm/memory-tracing.cc
+++ b/src/third_party/v8/src/wasm/memory-tracing.cc
@@ -10,10 +10,6 @@
#include "src/utils/utils.h"
#include "src/utils/vector.h"
-#if V8_OS_STARBOARD
-#include "starboard/common/log.h"
-#endif // V8_OS_STARBOARD
-
namespace v8 {
namespace internal {
namespace wasm {
diff --git a/src/third_party/v8/src/wasm/module-compiler.cc b/src/third_party/v8/src/wasm/module-compiler.cc
index a7d69a8..e5cd5eb 100644
--- a/src/third_party/v8/src/wasm/module-compiler.cc
+++ b/src/third_party/v8/src/wasm/module-compiler.cc
@@ -36,10 +36,6 @@
#include "src/wasm/wasm-result.h"
#include "src/wasm/wasm-serialization.h"
-#if defined(V8_OS_STARBOARD)
-#include "src/poems.h"
-#endif
-
#define TRACE_COMPILE(...) \
do { \
if (FLAG_trace_wasm_compiler) PrintF(__VA_ARGS__); \
diff --git a/src/third_party/v8/src/wasm/module-instantiate.cc b/src/third_party/v8/src/wasm/module-instantiate.cc
index 361d481..9169a31 100644
--- a/src/third_party/v8/src/wasm/module-instantiate.cc
+++ b/src/third_party/v8/src/wasm/module-instantiate.cc
@@ -6,7 +6,6 @@
#include "src/api/api.h"
#include "src/asmjs/asm-js.h"
-#include "src/base/platform/wrappers.h"
#include "src/logging/counters.h"
#include "src/logging/metrics.h"
#include "src/numbers/conversions-inl.h"
diff --git a/src/third_party/v8/src/wasm/streaming-decoder.cc b/src/third_party/v8/src/wasm/streaming-decoder.cc
index f25dd0e..e9b987f 100644
--- a/src/third_party/v8/src/wasm/streaming-decoder.cc
+++ b/src/third_party/v8/src/wasm/streaming-decoder.cc
@@ -4,7 +4,6 @@
#include "src/wasm/streaming-decoder.h"
-#include "src/base/platform/wrappers.h"
#include "src/handles/handles.h"
#include "src/objects/descriptor-array.h"
#include "src/objects/dictionary.h"
diff --git a/src/third_party/v8/src/wasm/wasm-code-manager.cc b/src/third_party/v8/src/wasm/wasm-code-manager.cc
index 83be91d..0e1b953 100644
--- a/src/third_party/v8/src/wasm/wasm-code-manager.cc
+++ b/src/third_party/v8/src/wasm/wasm-code-manager.cc
@@ -35,14 +35,9 @@
#include "src/wasm/wasm-objects.h"
#if defined(V8_OS_WIN64)
-#include "src/base/platform/wrappers.h"
#include "src/diagnostics/unwinding-info-win64.h"
#endif // V8_OS_WIN64
-#if defined(V8_OS_STARBOARD)
-#include "src/poems.h"
-#endif
-
#define TRACE_HEAP(...) \
do { \
if (FLAG_trace_wasm_native_heap) PrintF(__VA_ARGS__); \
diff --git a/src/third_party/v8/src/wasm/wasm-debug-evaluate.cc b/src/third_party/v8/src/wasm/wasm-debug-evaluate.cc
index f4a4deb..bbd75f6 100644
--- a/src/third_party/v8/src/wasm/wasm-debug-evaluate.cc
+++ b/src/third_party/v8/src/wasm/wasm-debug-evaluate.cc
@@ -8,7 +8,6 @@
#include <limits>
#include "src/api/api-inl.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/machine-type.h"
#include "src/compiler/wasm-compiler.h"
#include "src/execution/frames-inl.h"
diff --git a/src/third_party/v8/src/wasm/wasm-debug.cc b/src/third_party/v8/src/wasm/wasm-debug.cc
index 36ced71..5da5525 100644
--- a/src/third_party/v8/src/wasm/wasm-debug.cc
+++ b/src/third_party/v8/src/wasm/wasm-debug.cc
@@ -8,7 +8,6 @@
#include <unordered_map>
#include "src/base/optional.h"
-#include "src/base/platform/wrappers.h"
#include "src/codegen/assembler-inl.h"
#include "src/common/assert-scope.h"
#include "src/compiler/wasm-compiler.h"
diff --git a/src/third_party/v8/src/wasm/wasm-engine.cc b/src/third_party/v8/src/wasm/wasm-engine.cc
index 9649789..9f962f7 100644
--- a/src/third_party/v8/src/wasm/wasm-engine.cc
+++ b/src/third_party/v8/src/wasm/wasm-engine.cc
@@ -27,7 +27,6 @@
#include "src/wasm/wasm-objects-inl.h"
#ifdef V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING
-#include "src/base/platform/wrappers.h"
#include "src/debug/wasm/gdb-server/gdb-server.h"
#endif // V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING
diff --git a/src/third_party/v8/src/wasm/wasm-js.cc b/src/third_party/v8/src/wasm/wasm-js.cc
index 91a49ee..8bc82f2 100644
--- a/src/third_party/v8/src/wasm/wasm-js.cc
+++ b/src/third_party/v8/src/wasm/wasm-js.cc
@@ -12,7 +12,6 @@
#include "src/ast/ast.h"
#include "src/base/logging.h"
#include "src/base/overflowing-math.h"
-#include "src/base/platform/wrappers.h"
#include "src/common/assert-scope.h"
#include "src/execution/execution.h"
#include "src/execution/frames-inl.h"
diff --git a/src/third_party/v8/src/wasm/wasm-module.h b/src/third_party/v8/src/wasm/wasm-module.h
index e86b3de..9c54f17 100644
--- a/src/third_party/v8/src/wasm/wasm-module.h
+++ b/src/third_party/v8/src/wasm/wasm-module.h
@@ -8,7 +8,6 @@
#include <memory>
#include "src/base/optional.h"
-#include "src/base/platform/wrappers.h"
#include "src/common/globals.h"
#include "src/handles/handles.h"
#include "src/utils/vector.h"
diff --git a/src/third_party/v8/src/wasm/wasm-objects.cc b/src/third_party/v8/src/wasm/wasm-objects.cc
index 15a70cc..e0579d1 100644
--- a/src/third_party/v8/src/wasm/wasm-objects.cc
+++ b/src/third_party/v8/src/wasm/wasm-objects.cc
@@ -30,10 +30,6 @@
#include "src/wasm/wasm-subtyping.h"
#include "src/wasm/wasm-value.h"
-#if defined(V8_OS_STARBOARD)
-#include "src/poems.h"
-#endif
-
#define TRACE_IFT(...) \
do { \
if (false) PrintF(__VA_ARGS__); \
diff --git a/src/third_party/v8/src/wasm/wasm-text.cc b/src/third_party/v8/src/wasm/wasm-text.cc
deleted file mode 100644
index 5690295..0000000
--- a/src/third_party/v8/src/wasm/wasm-text.cc
+++ /dev/null
@@ -1,400 +0,0 @@
-// Copyright 2016 the V8 project 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 "src/wasm/wasm-text.h"
-
-#include "src/debug/interface-types.h"
-#include "src/utils/ostreams.h"
-#include "src/utils/vector.h"
-#include "src/objects/objects-inl.h"
-#include "src/wasm/function-body-decoder-impl.h"
-#include "src/wasm/function-body-decoder.h"
-#include "src/wasm/wasm-module.h"
-#include "src/wasm/wasm-opcodes.h"
-#include "src/zone/zone.h"
-
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
-namespace v8 {
-namespace internal {
-namespace wasm {
-
-namespace {
-bool IsValidFunctionName(const Vector<const char> &name) {
- if (name.empty()) return false;
- const char *special_chars = "_.+-*/\\^~=<>!?@#$%&|:'`";
- for (char c : name) {
- bool valid_char = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') || strchr(special_chars, c);
- if (!valid_char) return false;
- }
- return true;
-}
-
-} // namespace
-
-void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes,
- uint32_t func_index, std::ostream& os,
- debug::WasmDisassembly::OffsetTable* offset_table) {
- DCHECK_NOT_NULL(module);
- DCHECK_GT(module->functions.size(), func_index);
- const WasmFunction *fun = &module->functions[func_index];
-
- AccountingAllocator allocator;
- Zone zone(&allocator, ZONE_NAME);
- int line_nr = 0;
- int control_depth = 1;
-
- // Print the function signature.
- os << "func";
- WasmName fun_name = wire_bytes.GetNameOrNull(fun, module);
- if (IsValidFunctionName(fun_name)) {
- os << " $";
- os.write(fun_name.begin(), fun_name.length());
- }
- if (fun->sig->parameter_count()) {
- os << " (param";
- for (auto param : fun->sig->parameters())
- os << ' ' << ValueTypes::TypeName(param);
- os << ')';
- }
- if (fun->sig->return_count()) {
- os << " (result";
- for (auto ret : fun->sig->returns()) os << ' ' << ValueTypes::TypeName(ret);
- os << ')';
- }
- os << "\n";
- ++line_nr;
-
- // Print the local declarations.
- BodyLocalDecls decls(&zone);
- Vector<const byte> func_bytes = wire_bytes.GetFunctionBytes(fun);
- BytecodeIterator i(func_bytes.begin(), func_bytes.end(), &decls);
- DCHECK_LT(func_bytes.begin(), i.pc());
- if (!decls.type_list.empty()) {
- os << "(local";
- for (const ValueType &v : decls.type_list) {
- os << ' ' << ValueTypes::TypeName(v);
- }
- os << ")\n";
- ++line_nr;
- }
-
- for (; i.has_next(); i.next()) {
- WasmOpcode opcode = i.current();
- if (opcode == kExprElse || opcode == kExprCatch || opcode == kExprEnd) {
- --control_depth;
- }
-
- DCHECK_LE(0, control_depth);
- const int kMaxIndentation = 64;
- int indentation = std::min(kMaxIndentation, 2 * control_depth);
- if (offset_table) {
- offset_table->emplace_back(i.pc_offset(), line_nr, indentation);
- }
-
- // 64 whitespaces
- const char padding[kMaxIndentation + 1] =
- " ";
- os.write(padding, indentation);
-
- switch (opcode) {
- case kExprLoop:
- case kExprIf:
- case kExprBlock:
- case kExprTry: {
- BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i,
- i.pc());
- os << WasmOpcodes::OpcodeName(opcode);
- if (imm.type == kWasmBottom) {
- os << " (type " << imm.sig_index << ")";
- } else if (imm.out_arity() > 0) {
- os << " " << ValueTypes::TypeName(imm.out_type(0));
- }
- control_depth++;
- break;
- }
- case kExprBr:
- case kExprBrIf: {
- BranchDepthImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.depth;
- break;
- }
- case kExprBrOnExn: {
- BranchOnExceptionImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.depth.depth << ' '
- << imm.index.index;
- break;
- }
- case kExprElse:
- case kExprCatch:
- os << WasmOpcodes::OpcodeName(opcode);
- control_depth++;
- break;
- case kExprEnd:
- os << "end";
- break;
- case kExprBrTable: {
- BranchTableImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- BranchTableIterator<Decoder::kNoValidate> iterator(&i, imm);
- os << "br_table";
- while (iterator.has_next()) os << ' ' << iterator.next();
- break;
- }
- case kExprCallIndirect:
- case kExprReturnCallIndirect: {
- CallIndirectImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i,
- i.pc());
- DCHECK_EQ(0, imm.table_index);
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.sig_index;
- break;
- }
- case kExprCallFunction:
- case kExprReturnCall: {
- CallFunctionImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.index;
- break;
- }
- case kExprGetLocal:
- case kExprSetLocal:
- case kExprTeeLocal: {
- LocalIndexImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.index;
- break;
- }
- case kExprThrow: {
- ExceptionIndexImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.index;
- break;
- }
- case kExprGetGlobal:
- case kExprSetGlobal: {
- GlobalIndexImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.index;
- break;
- }
- case kExprTableGet:
- case kExprTableSet: {
- TableIndexImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.index;
- break;
- }
- case kExprSelectWithType: {
- SelectTypeImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' '
- << ValueTypes::TypeName(imm.type);
- break;
- }
-#define CASE_CONST(type, str, cast_type) \
- case kExpr##type##Const: { \
- Imm##type##Immediate<Decoder::kNoValidate> imm(&i, i.pc()); \
- os << #str ".const " << static_cast<cast_type>(imm.value); \
- break; \
- }
- CASE_CONST(I32, i32, int32_t)
- CASE_CONST(I64, i64, int64_t)
- CASE_CONST(F32, f32, float)
- CASE_CONST(F64, f64, double)
-#undef CASE_CONST
-
- case kExprRefFunc: {
- FunctionIndexImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.index;
- break;
- }
-
-#define CASE_OPCODE(opcode, _, __) case kExpr##opcode:
- FOREACH_LOAD_MEM_OPCODE(CASE_OPCODE)
- FOREACH_STORE_MEM_OPCODE(CASE_OPCODE) {
- MemoryAccessImmediate<Decoder::kNoValidate> imm(&i, i.pc(),
- kMaxUInt32);
- os << WasmOpcodes::OpcodeName(opcode) << " offset=" << imm.offset
- << " align=" << (1ULL << imm.alignment);
- break;
- }
-
- FOREACH_SIMPLE_OPCODE(CASE_OPCODE)
- FOREACH_SIMPLE_PROTOTYPE_OPCODE(CASE_OPCODE)
- case kExprUnreachable:
- case kExprNop:
- case kExprReturn:
- case kExprMemorySize:
- case kExprMemoryGrow:
- case kExprDrop:
- case kExprSelect:
- case kExprRethrow:
- case kExprRefNull:
- os << WasmOpcodes::OpcodeName(opcode);
- break;
-
- case kNumericPrefix: {
- WasmOpcode numeric_opcode = i.prefixed_opcode();
- switch (numeric_opcode) {
- case kExprI32SConvertSatF32:
- case kExprI32UConvertSatF32:
- case kExprI32SConvertSatF64:
- case kExprI32UConvertSatF64:
- case kExprI64SConvertSatF32:
- case kExprI64UConvertSatF32:
- case kExprI64SConvertSatF64:
- case kExprI64UConvertSatF64:
- case kExprMemoryCopy:
- case kExprMemoryFill:
- os << WasmOpcodes::OpcodeName(opcode);
- break;
- case kExprMemoryInit: {
- MemoryInitImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' '
- << imm.data_segment_index;
- break;
- }
- case kExprDataDrop: {
- DataDropImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.index;
- break;
- }
- case kExprTableInit: {
- TableInitImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' '
- << imm.elem_segment_index << ' ' << imm.table.index;
- break;
- }
- case kExprElemDrop: {
- ElemDropImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.index;
- break;
- }
- case kExprTableCopy: {
- TableCopyImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.table_src.index
- << ' ' << imm.table_dst.index;
- break;
- }
- case kExprTableGrow:
- case kExprTableSize:
- case kExprTableFill: {
- TableIndexImmediate<Decoder::kNoValidate> imm(&i, i.pc() + 1);
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.index;
- break;
- }
- default:
- UNREACHABLE();
- break;
- }
- break;
- }
-
- case kSimdPrefix: {
- WasmOpcode simd_opcode = i.prefixed_opcode();
- switch (simd_opcode) {
- case kExprS128LoadMem:
- case kExprS128StoreMem: {
- MemoryAccessImmediate<Decoder::kNoValidate> imm(&i, i.pc(),
- kMaxUInt32);
- os << WasmOpcodes::OpcodeName(opcode) << " offset=" << imm.offset
- << " align=" << (1ULL << imm.alignment);
- break;
- }
-
- case kExprS8x16Shuffle: {
- Simd8x16ShuffleImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode);
- for (uint8_t v : imm.shuffle) {
- os << ' ' << v;
- }
- break;
- }
-
- case kExprI8x16ExtractLane:
- case kExprI16x8ExtractLane:
- case kExprI32x4ExtractLane:
- case kExprI64x2ExtractLane:
- case kExprF32x4ExtractLane:
- case kExprF64x2ExtractLane:
- case kExprI8x16ReplaceLane:
- case kExprI16x8ReplaceLane:
- case kExprI32x4ReplaceLane:
- case kExprI64x2ReplaceLane:
- case kExprF32x4ReplaceLane:
- case kExprF64x2ReplaceLane: {
- SimdLaneImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.lane;
- break;
- }
-
- case kExprI8x16Shl:
- case kExprI8x16ShrS:
- case kExprI8x16ShrU:
- case kExprI16x8Shl:
- case kExprI16x8ShrS:
- case kExprI16x8ShrU:
- case kExprI32x4Shl:
- case kExprI32x4ShrS:
- case kExprI32x4ShrU:
- case kExprI64x2Shl:
- case kExprI64x2ShrS:
- case kExprI64x2ShrU: {
- SimdShiftImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.shift;
- break;
- }
-
- FOREACH_SIMD_0_OPERAND_OPCODE(CASE_OPCODE) {
- os << WasmOpcodes::OpcodeName(opcode);
- break;
- }
-
- default:
- UNREACHABLE();
- break;
- }
- break;
- }
-
- case kAtomicPrefix: {
- WasmOpcode atomic_opcode = i.prefixed_opcode();
- switch (atomic_opcode) {
- FOREACH_ATOMIC_OPCODE(CASE_OPCODE) {
- MemoryAccessImmediate<Decoder::kNoValidate> imm(&i, i.pc() + 1,
- kMaxUInt32);
- os << WasmOpcodes::OpcodeName(atomic_opcode)
- << " offset=" << imm.offset
- << " align=" << (1ULL << imm.alignment);
- break;
- }
- FOREACH_ATOMIC_0_OPERAND_OPCODE(CASE_OPCODE) {
- os << WasmOpcodes::OpcodeName(atomic_opcode);
- break;
- }
- default:
- UNREACHABLE();
- break;
- }
- break;
- }
-
- // This group is just printed by their internal opcode name, as they
- // should never be shown to end-users.
- FOREACH_ASMJS_COMPAT_OPCODE(CASE_OPCODE) {
- os << WasmOpcodes::OpcodeName(opcode);
- }
- break;
-#undef CASE_OPCODE
-
- default:
- UNREACHABLE();
- break;
- }
- os << '\n';
- ++line_nr;
- }
- DCHECK_EQ(0, control_depth);
- DCHECK(i.ok());
-}
-
-} // namespace wasm
-} // namespace internal
-} // namespace v8
diff --git a/src/third_party/v8/src/zone/accounting-allocator.cc b/src/third_party/v8/src/zone/accounting-allocator.cc
index 8808a67..baa7016 100644
--- a/src/third_party/v8/src/zone/accounting-allocator.cc
+++ b/src/third_party/v8/src/zone/accounting-allocator.cc
@@ -14,10 +14,6 @@
#include "src/zone/zone-compression.h"
#include "src/zone/zone-segment.h"
-#if V8_OS_STARBOARD
-#include "src/poems.h"
-#endif
-
namespace v8 {
namespace internal {
diff --git a/src/third_party/web_platform_tests/FileAPI/idlharness.html b/src/third_party/web_platform_tests/FileAPI/idlharness.html
index 0ef3700..1795112 100644
--- a/src/third_party/web_platform_tests/FileAPI/idlharness.html
+++ b/src/third_party/web_platform_tests/FileAPI/idlharness.html
@@ -30,7 +30,7 @@
request.onload = function() {
var idls = request.responseText;
- idl_array.add_untested_idls("[PrimaryGlobal] interface Window { };");
+ idl_array.add_untested_idls("[Global] interface Window { };");
idl_array.add_untested_idls("interface ArrayBuffer {};");
idl_array.add_untested_idls("interface ArrayBufferView {};");
diff --git a/src/third_party/web_platform_tests/IndexedDB/interfaces.html b/src/third_party/web_platform_tests/IndexedDB/interfaces.html
index cc4e7f2..447e4da 100644
--- a/src/third_party/web_platform_tests/IndexedDB/interfaces.html
+++ b/src/third_party/web_platform_tests/IndexedDB/interfaces.html
@@ -20,7 +20,7 @@
request.onload = function() {
var idls = request.responseText;
- idlArray.add_untested_idls("[PrimaryGlobal] interface Window { };");
+ idlArray.add_untested_idls("[Global] interface Window { };");
idlArray.add_untested_idls("interface Event { };");
idlArray.add_untested_idls("interface EventTarget { };");
diff --git a/src/third_party/web_platform_tests/ambient-light/idlharness.html b/src/third_party/web_platform_tests/ambient-light/idlharness.html
index bcf2228..bf79159 100644
--- a/src/third_party/web_platform_tests/ambient-light/idlharness.html
+++ b/src/third_party/web_platform_tests/ambient-light/idlharness.html
@@ -15,7 +15,7 @@
<div id="log"></div>
<pre id="untested_idl">
-[PrimaryGlobal]
+[Global]
interface Window {
};
diff --git a/src/third_party/web_platform_tests/html/dom/interfaces.html b/src/third_party/web_platform_tests/html/dom/interfaces.html
index 69d81cc..bf9650e 100644
--- a/src/third_party/web_platform_tests/html/dom/interfaces.html
+++ b/src/third_party/web_platform_tests/html/dom/interfaces.html
@@ -2252,7 +2252,7 @@
// Window.
typedef Window WindowProxy;
-[PrimaryGlobal]
+[Global]
/*sealed*/ interface Window : EventTarget {
// the current browsing context
[Unforgeable] readonly attribute WindowProxy window;
diff --git a/src/third_party/web_platform_tests/html/webappapis/animation-frames/idlharness.html b/src/third_party/web_platform_tests/html/webappapis/animation-frames/idlharness.html
index acc6657..fb16e95 100644
--- a/src/third_party/web_platform_tests/html/webappapis/animation-frames/idlharness.html
+++ b/src/third_party/web_platform_tests/html/webappapis/animation-frames/idlharness.html
@@ -15,7 +15,7 @@
<p>This test validates the WebIDL included in the Timing control for script-based animations specification.</p>
<pre id='untested_idl' style='display:none'>
-[PrimaryGlobal]
+[Global]
interface Window {
};
</pre>
diff --git a/src/third_party/web_platform_tests/mediasession/idlharness.html b/src/third_party/web_platform_tests/mediasession/idlharness.html
index a90c83e..58f7556 100644
--- a/src/third_party/web_platform_tests/mediasession/idlharness.html
+++ b/src/third_party/web_platform_tests/mediasession/idlharness.html
@@ -13,7 +13,7 @@
<h1>Media Session IDL tests</h1>
<pre id='untested_idl' style='display:none'>
-[PrimaryGlobal]
+[Global]
interface Window {
};
diff --git a/src/third_party/web_platform_tests/navigation-timing/idlharness.html b/src/third_party/web_platform_tests/navigation-timing/idlharness.html
index 65a8778..c3b8735 100644
--- a/src/third_party/web_platform_tests/navigation-timing/idlharness.html
+++ b/src/third_party/web_platform_tests/navigation-timing/idlharness.html
@@ -18,7 +18,7 @@
<pre id='untested_idl' style='display:none'>
-[PrimaryGlobal]
+[Global]
interface Window {
};
diff --git a/src/third_party/web_platform_tests/proximity/idlharness.html b/src/third_party/web_platform_tests/proximity/idlharness.html
index 817aa5c..607251c 100644
--- a/src/third_party/web_platform_tests/proximity/idlharness.html
+++ b/src/third_party/web_platform_tests/proximity/idlharness.html
@@ -15,7 +15,7 @@
<div id="log"></div>
<pre id="untested_idl">
-[PrimaryGlobal]
+[Global]
interface Window {
};
diff --git a/src/third_party/web_platform_tests/webstorage/idlharness.html b/src/third_party/web_platform_tests/webstorage/idlharness.html
index 454e441..bd6b746 100644
--- a/src/third_party/web_platform_tests/webstorage/idlharness.html
+++ b/src/third_party/web_platform_tests/webstorage/idlharness.html
@@ -15,7 +15,7 @@
<div id="log"></div>
<pre id='untested_idl' style='display:none'>
-[PrimaryGlobal]
+[Global]
interface Window {
};
diff --git a/src/tools/format_ninja.py b/src/tools/format_ninja.py
index b0d1ba0..acff046 100644
--- a/src/tools/format_ninja.py
+++ b/src/tools/format_ninja.py
@@ -33,7 +33,7 @@
from typing import List, Tuple
_ACTION_COMPONENTS = ['directory', 'command', 'file', 'output']
-
+STRIP = 0
def make_path_absolute(path: str, directory: str) -> str:
if os.path.isabs(path):
@@ -43,6 +43,8 @@
def remove_directory_path(path: str, directory: str) -> str:
+ dirsplit = directory.split(os.path.sep)
+ directory = os.path.sep.join(dirsplit[:-STRIP])
if os.path.commonpath([path, directory]) != directory:
return path
@@ -113,7 +115,10 @@
parser = argparse.ArgumentParser()
parser.add_argument('json_filename', type=str)
parser.add_argument('-o', '--output', type=str)
+ parser.add_argument('-p', '--strip', type=int)
args = parser.parse_args()
+ if args.strip:
+ STRIP = int(args.strip)
output = args.output if args.output else 'normalized_' + os.path.basename(
args.json_filename)
main(args.json_filename, output)
diff --git a/src/tools/gyp/pylib/gyp/MSVSVersion.py b/src/tools/gyp/pylib/gyp/MSVSVersion.py
index f51c3a9..6478510 100644
--- a/src/tools/gyp/pylib/gyp/MSVSVersion.py
+++ b/src/tools/gyp/pylib/gyp/MSVSVersion.py
@@ -324,10 +324,13 @@
if not os.path.exists(path):
path = r'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE'
path = _ConvertToCygpath(path)
- full_path = os.path.join(path, 'devenv.exe')
- if os.path.exists(full_path) and version in version_to_year:
+ devenv_path = os.path.join(path, 'devenv.exe')
+ devenv_ini_path = os.path.join(path, 'devenv.isolation.ini')
+ if (os.path.exists(devenv_path) or os.path.exists(devenv_ini_path)) and version in version_to_year:
versions.append(_CreateVersion(version_to_year[version],
os.path.join(path, '..', '..')))
+ else:
+ print('_DetectVisualStudioVersion() did not find Visual Studio 2017 (v15.0)')
continue
# Old method of searching for which VS version is installed
# We don't use the 2010-encouraged-way because we also want to get the
diff --git a/src/tools/protoc_wrapper/gn_protoc_wrapper.py b/src/tools/protoc_wrapper/gn_protoc_wrapper.py
new file mode 100644
index 0000000..dc8a3f1
--- /dev/null
+++ b/src/tools/protoc_wrapper/gn_protoc_wrapper.py
@@ -0,0 +1,212 @@
+#!/usr/bin/env python3
+# Copyright (c) 2012 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.
+
+"""
+A simple wrapper for protoc.
+Script for //third_party/protobuf/proto_library.gni .
+Features:
+- Inserts #include for extra header automatically.
+- Prevents bad proto names.
+- Works around protoc's bad descriptor file generation.
+ Ninja expects the format:
+ target: deps
+ But protoc just outputs:
+ deps
+ This script adds the "target:" part.
+"""
+
+from __future__ import print_function
+import argparse
+import os.path
+import subprocess
+import sys
+import tempfile
+
+PROTOC_INCLUDE_POINT = "// @@protoc_insertion_point(includes)"
+
+
+def FormatGeneratorOptions(options):
+ if not options:
+ return ""
+ if options.endswith(":"):
+ return options
+ return options + ":"
+
+
+def VerifyProtoNames(protos):
+ for filename in protos:
+ if "-" in filename:
+ raise RuntimeError("Proto file names must not contain hyphens "
+ "(see http://crbug.com/386125 for more information).")
+
+
+def StripProtoExtension(filename):
+ if not filename.endswith(".proto"):
+ raise RuntimeError("Invalid proto filename extension: "
+ "{0} .".format(filename))
+ return filename.rsplit(".", 1)[0]
+
+
+def WriteIncludes(headers, include):
+ for filename in headers:
+ include_point_found = False
+ contents = []
+ with open(filename) as f:
+ for line in f:
+ stripped_line = line.strip()
+ contents.append(stripped_line)
+ if stripped_line == PROTOC_INCLUDE_POINT:
+ if include_point_found:
+ raise RuntimeError("Multiple include points found.")
+ include_point_found = True
+ extra_statement = "#include \"{0}\"".format(include)
+ contents.append(extra_statement)
+
+ if not include_point_found:
+ raise RuntimeError("Include point not found in header: "
+ "{0} .".format(filename))
+
+ with open(filename, "w") as f:
+ for line in contents:
+ print(line, file=f)
+
+
+def main(argv):
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--protoc", required=True,
+ help="Relative path to compiler.")
+
+ parser.add_argument("--proto-in-dir", required=True,
+ help="Base directory with source protos.")
+ parser.add_argument("--cc-out-dir",
+ help="Output directory for standard C++ generator.")
+ parser.add_argument("--py-out-dir",
+ help="Output directory for standard Python generator.")
+ parser.add_argument("--js-out-dir",
+ help="Output directory for standard JS generator.")
+ parser.add_argument("--plugin-out-dir",
+ help="Output directory for custom generator plugin.")
+
+ parser.add_argument('--enable-kythe-annotations', action='store_true',
+ help='Enable generation of Kythe kzip, used for '
+ 'codesearch.')
+ parser.add_argument("--plugin",
+ help="Relative path to custom generator plugin.")
+ parser.add_argument("--plugin-options",
+ help="Custom generator plugin options.")
+ parser.add_argument("--cc-options",
+ help="Standard C++ generator options.")
+ parser.add_argument("--include",
+ help="Name of include to insert into generated headers.")
+ parser.add_argument("--import-dir", action="append", default=[],
+ help="Extra import directory for protos, can be repeated."
+ )
+ parser.add_argument("--descriptor-set-out",
+ help="Path to write a descriptor.")
+ parser.add_argument(
+ "--descriptor-set-dependency-file",
+ help="Path to write the dependency file for descriptor set.")
+ # The meaning of this flag is flipped compared to the corresponding protoc
+ # flag due to this script previously passing --include_imports. Removing the
+ # --include_imports is likely to have unintended consequences.
+ parser.add_argument(
+ "--exclude-imports",
+ help="Do not include imported files into generated descriptor.",
+ action="store_true",
+ default=False)
+ parser.add_argument("protos", nargs="+",
+ help="Input protobuf definition file(s).")
+
+ options = parser.parse_args(argv)
+
+ proto_dir = os.path.relpath(options.proto_in_dir)
+ protoc_cmd = [os.path.realpath(options.protoc)]
+
+ protos = options.protos
+ headers = []
+ VerifyProtoNames(protos)
+
+ if options.py_out_dir:
+ protoc_cmd += ["--python_out", options.py_out_dir]
+
+ if options.js_out_dir:
+ protoc_cmd += [
+ "--js_out",
+ "one_output_file_per_input_file,binary:" + options.js_out_dir
+ ]
+
+ if options.cc_out_dir:
+ cc_out_dir = options.cc_out_dir
+ cc_options_list = []
+ if options.enable_kythe_annotations:
+ cc_options_list.extend([
+ 'annotate_headers', 'annotation_pragma_name=kythe_metadata',
+ 'annotation_guard_name=KYTHE_IS_RUNNING'
+ ])
+
+ # cc_options will likely have trailing colon so needs to be inserted at the
+ # end.
+ if options.cc_options:
+ cc_options_list.append(options.cc_options)
+
+ cc_options = FormatGeneratorOptions(','.join(cc_options_list))
+ protoc_cmd += ["--cpp_out", cc_options + cc_out_dir]
+ for filename in protos:
+ stripped_name = StripProtoExtension(filename)
+ headers.append(os.path.join(cc_out_dir, stripped_name + ".pb.h"))
+
+ if options.plugin_out_dir:
+ plugin_options = FormatGeneratorOptions(options.plugin_options)
+ protoc_cmd += [
+ "--plugin", "protoc-gen-plugin=" + os.path.relpath(options.plugin),
+ "--plugin_out", plugin_options + options.plugin_out_dir
+ ]
+
+ protoc_cmd += ["--proto_path", proto_dir]
+ for path in options.import_dir:
+ protoc_cmd += ["--proto_path", path]
+
+ protoc_cmd += [os.path.join(proto_dir, name) for name in protos]
+
+ if options.descriptor_set_out:
+ protoc_cmd += ["--descriptor_set_out", options.descriptor_set_out]
+ if not options.exclude_imports:
+ protoc_cmd += ["--include_imports"]
+
+ dependency_file_data = None
+ if options.descriptor_set_out and options.descriptor_set_dependency_file:
+ protoc_cmd += ['--dependency_out', options.descriptor_set_dependency_file]
+ ret = subprocess.call(protoc_cmd)
+
+ with open(options.descriptor_set_dependency_file, 'rb') as f:
+ dependency_file_data = f.read().decode('utf-8')
+
+ ret = subprocess.call(protoc_cmd)
+ if ret != 0:
+ if ret <= -100:
+ # Windows error codes such as 0xC0000005 and 0xC0000409 are much easier to
+ # recognize and differentiate in hex. In order to print them as unsigned
+ # hex we need to add 4 Gig to them.
+ error_number = "0x%08X" % (ret + (1 << 32))
+ else:
+ error_number = "%d" % ret
+ raise RuntimeError("Protoc has returned non-zero status: "
+ "{0}".format(error_number))
+
+ if dependency_file_data:
+ with open(options.descriptor_set_dependency_file, 'w') as f:
+ f.write(options.descriptor_set_out + ":")
+ f.write(dependency_file_data)
+
+ if options.include:
+ WriteIncludes(headers, options.include)
+
+
+if __name__ == "__main__":
+ try:
+ main(sys.argv[1:])
+ except RuntimeError as e:
+ print(e, file=sys.stderr)
+ sys.exit(1)