Import Cobalt 24.lts.5.1032616
diff --git a/.github/config/linux-modular.json b/.github/config/linux-modular.json
index ee3f9b1..c4e25d4 100644
--- a/.github/config/linux-modular.json
+++ b/.github/config/linux-modular.json
@@ -10,7 +10,7 @@
"name":"modular",
"platform":"linux-x64x11-modular",
"target_platform":"linux-x64x11",
- "extra_gn_arguments":"build_with_separate_cobalt_toolchain=true"
+ "extra_gn_arguments":"build_with_separate_cobalt_toolchain=true use_contrib_cast=true"
}
]
}
diff --git a/base/i18n/base_i18n_export.h b/base/i18n/base_i18n_export.h
index e8a2add..ef498e9 100644
--- a/base/i18n/base_i18n_export.h
+++ b/base/i18n/base_i18n_export.h
@@ -5,7 +5,11 @@
#ifndef BASE_I18N_BASE_I18N_EXPORT_H_
#define BASE_I18N_BASE_I18N_EXPORT_H_
-#if defined(COMPONENT_BUILD)
+#ifdef USE_COBALT_CUSTOMIZATIONS
+#include "starboard/configuration.h"
+#endif // USE_COBALT_CUSTOMIZATIONS
+
+#if defined(COMPONENT_BUILD) || SB_IS(MODULAR) && !SB_IS(EVERGREEN)
#if defined(WIN32)
#if defined(BASE_I18N_IMPLEMENTATION)
@@ -22,7 +26,7 @@
#endif
#endif
-#else // defined(COMPONENT_BUILD)
+#else // defined(COMPONENT_BUILD) || SB_IS(MODULAR) && !SB_IS(EVERGREEN)
#define BASE_I18N_EXPORT
#endif
diff --git a/build/config/win/visual_studio_version.gni b/build/config/win/visual_studio_version.gni
index 63b9a97..22ec3af 100644
--- a/build/config/win/visual_studio_version.gni
+++ b/build/config/win/visual_studio_version.gni
@@ -39,6 +39,8 @@
declare_args() {
msvc_path = "$visual_studio_path/VC/Tools/MSVC/$visual_studio_version"
+
+ llvm_clang_path = "$visual_studio_path/VC/Tools/Llvm/x64/bin"
}
} else {
declare_args() {
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni
index 89b26d3..2a2cc3c 100644
--- a/build/toolchain/gcc_toolchain.gni
+++ b/build/toolchain/gcc_toolchain.gni
@@ -117,7 +117,7 @@
template("gcc_toolchain") {
toolchain(target_name) {
is_starboard_toolchain = target_name == "starboard"
- if (!build_with_separate_cobalt_toolchain) {
+ if (!sb_is_modular || sb_is_evergreen) {
not_needed(["is_starboard_toolchain"])
}
assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value")
@@ -391,7 +391,7 @@
# TODO(b/206642994): see if we can remove this condition. It's needed for
# now to add cflags for evergreen platforms but we haven't yet decided
# whether cflags should be added here for all platforms.
- if (is_starboard && sb_is_evergreen && !is_starboard_toolchain) {
+ if (!is_starboard_toolchain && is_starboard && sb_is_modular) {
command = "$asm -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{asmflags}}${extra_asmflags} -c {{source}} -o {{output}}"
} else {
command = "$asm -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}}${extra_asmflags} -c {{source}} -o {{output}}"
diff --git a/cobalt/BUILD.gn b/cobalt/BUILD.gn
index 53c4bc3..92fe9dc 100644
--- a/cobalt/BUILD.gn
+++ b/cobalt/BUILD.gn
@@ -81,8 +81,5 @@
"//components/update_client",
]
}
- if (!build_with_separate_cobalt_toolchain) {
- deps += [ "//third_party/llvm-project/libunwind:unwind_evergreen" ]
- }
}
}
diff --git a/cobalt/browser/BUILD.gn b/cobalt/browser/BUILD.gn
index 3228260..25e387a 100644
--- a/cobalt/browser/BUILD.gn
+++ b/cobalt/browser/BUILD.gn
@@ -55,6 +55,7 @@
":browser",
":browser_switches",
"//cobalt/base",
+ "//cobalt/css_parser",
"//net",
]
data_deps = [
@@ -414,3 +415,10 @@
cache_templates("cached_jinja_templates") {
output_dir = _bindings_scripts_output_dir
}
+
+group("test_dependencies_on_browser") {
+ testonly = true
+
+ # TODO: 297087147 - Depend on smaller targets than browser.
+ deps = [ "//cobalt/browser" ]
+}
diff --git a/cobalt/browser/browser_module.cc b/cobalt/browser/browser_module.cc
index d83200f..c6f7f18 100644
--- a/cobalt/browser/browser_module.cc
+++ b/cobalt/browser/browser_module.cc
@@ -492,33 +492,51 @@
// First try any registered handlers. If one of these handles the URL, we
// don't use the web module.
- if (TryURLHandlers(url)) {
+ if (NavigateTryURLHandlers(url)) {
return;
}
// Clear error handling once we're told to navigate, either because it's the
// retry from the error or something decided we should navigate elsewhere.
- on_error_retry_timer_.Stop();
- waiting_for_error_retry_ = false;
+ NavigateResetErrorHandling();
// Navigations aren't allowed if the app is frozen. If this is the case,
// simply set the pending navigate url, which will cause the navigation to
// occur when Cobalt resumes, and return.
- if (application_state_ == base::kApplicationStateFrozen) {
- pending_navigate_url_ = url;
+ if (NavigateHandleStateFrozen(url)) {
return;
}
- // Now that we know the navigation is occurring, clear out
- // |pending_navigate_url_|.
- pending_navigate_url_ = GURL::EmptyGURL();
+ // Destroys the old WebModule, increments the navigation generation
+ // number, and resets the main WebModule layer
+ NavigateResetWebModule();
+ // checks whether a service worker should be started for the given URL
+ auto service_worker_started_event = std::make_unique<base::WaitableEvent>();
+ bool can_start_service_worker =
+ NavigateServiceWorkerSetups(url, service_worker_started_event.get());
+
+ // Wait until after the old WebModule is destroyed before setting the navigate
+ // time so that it won't be included in the time taken to load the URL.
+ navigate_time_ = base::TimeTicks::Now().ToInternalValue();
+
+ const ViewportSize viewport_size = GetViewportSize();
+
+ // Show a splash screen while we're waiting for the web page to load.
+ NavigateSetupSplashScreen(url, viewport_size);
+
+ NavigateSetupScrollEngine();
+
+ NavigateCreateWebModule(url, can_start_service_worker,
+ service_worker_started_event.get(), viewport_size);
+}
+
+void BrowserModule::NavigateResetWebModule() {
#if defined(ENABLE_DEBUGGER)
if (web_module_) {
web_module_->FreezeDebugger(&debugger_state_);
}
#endif // defined(ENABLE_DEBUGGER)
-
// Destroy old WebModule first, so we don't get a memory high-watermark after
// the second WebModule's constructor runs, but before
// std::unique_ptr::reset() is run.
@@ -534,23 +552,56 @@
current_main_web_module_timeline_id_ = next_timeline_id_++;
main_web_module_layer_->Reset();
+}
+void BrowserModule::NavigateResetErrorHandling() {
+ on_error_retry_timer_.Stop();
+ waiting_for_error_retry_ = false;
+}
+
+bool BrowserModule::NavigateHandleStateFrozen(const GURL& url) {
+ if (application_state_ == base::kApplicationStateFrozen) {
+ pending_navigate_url_ = url;
+ return true;
+ }
+
+ // Now that we know the navigation is occurring, clear out
+ // |pending_navigate_url_|.
+ pending_navigate_url_ = GURL::EmptyGURL();
+ return false;
+}
+
+bool BrowserModule::NavigateServiceWorkerSetups(
+ const GURL& url, base::WaitableEvent* service_worker_started_event) {
// Service worker should only start for HTTP or HTTPS fetches.
// https://fetch.spec.whatwg.org/commit-snapshots/8f8ab504da6ca9681db5c7f8aa3d1f4b6bf8840c/#http-fetch
bool can_start_service_worker = url.SchemeIsHTTPOrHTTPS();
- auto service_worker_started_event = std::make_unique<base::WaitableEvent>();
+ watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance();
+ if (watchdog) {
+ std::vector<std::string> service_worker_clients = {
+ worker::WorkerConsts::kServiceWorkerRegistryName,
+ worker::WorkerConsts::kServiceWorkerName};
+ std::string violation_json =
+ watchdog->GetWatchdogViolations(service_worker_clients);
+ {
+ if (violation_json != "") {
+ LOG(WARNING) << "Service Worker watchdog violation detected: "
+ << violation_json;
+ LOG(WARNING) << "Erase Service Worker registration map.";
+ can_start_service_worker = false;
+ service_worker_registry_->EraseRegistrationMap();
+ }
+ }
+ }
if (can_start_service_worker) {
service_worker_registry_->EnsureServiceWorkerStarted(
- url::Origin::Create(url), url, service_worker_started_event.get());
+ url::Origin::Create(url), url, service_worker_started_event);
}
+ return can_start_service_worker;
+}
- // Wait until after the old WebModule is destroyed before setting the navigate
- // time so that it won't be included in the time taken to load the URL.
- navigate_time_ = base::TimeTicks::Now().ToInternalValue();
-
- // Show a splash screen while we're waiting for the web page to load.
- const ViewportSize viewport_size = GetViewportSize();
-
+void BrowserModule::NavigateSetupSplashScreen(
+ const GURL& url, const ViewportSize viewport_size) {
DestroySplashScreen();
if (options_.enable_splash_screen_on_reloads ||
main_web_module_generation_ == 1) {
@@ -571,10 +622,17 @@
lifecycle_observers_.AddObserver(splash_screen_.get());
}
}
+}
+void BrowserModule::NavigateSetupScrollEngine() {
scroll_engine_.reset(new ui_navigation::scroll_engine::ScrollEngine());
scroll_engine_->thread()->Start();
+}
+void BrowserModule::NavigateCreateWebModule(
+ const GURL& url, bool can_start_service_worker,
+ base::WaitableEvent* service_worker_started_event,
+ const ViewportSize viewport_size) {
// Create new WebModule.
#if !defined(COBALT_FORCE_CSP)
options_.web_module_options.csp_insecure_allowed_token =
@@ -1345,7 +1403,7 @@
}
}
-bool BrowserModule::TryURLHandlers(const GURL& url) {
+bool BrowserModule::NavigateTryURLHandlers(const GURL& url) {
for (URLHandlerCollection::const_iterator iter = url_handlers_.begin();
iter != url_handlers_.end(); ++iter) {
if (iter->Run(url)) {
diff --git a/cobalt/browser/browser_module.h b/cobalt/browser/browser_module.h
index 00fd5ce..2011577 100644
--- a/cobalt/browser/browser_module.h
+++ b/cobalt/browser/browser_module.h
@@ -139,6 +139,7 @@
// |pending_navigate_url_| to the specified url, which will trigger a
// navigation when Cobalt resumes.
void Navigate(const GURL& url_reference);
+
// Reloads web module.
void Reload();
@@ -334,9 +335,28 @@
bool FilterKeyEventForHotkeys(base::Token type,
const dom::KeyboardEventInit& event);
+ void NavigateResetErrorHandling();
+
+ bool NavigateHandleStateFrozen(const GURL& url);
+
+ void NavigateResetWebModule();
+
+ bool NavigateServiceWorkerSetups(
+ const GURL& url, base::WaitableEvent* service_worker_started_event);
+
+ void NavigateSetupSplashScreen(const GURL& url,
+ const cssom::ViewportSize viewport_size);
+
+ void NavigateSetupScrollEngine();
+
+ void NavigateCreateWebModule(
+ const GURL& url, bool can_start_service_worker,
+ base::WaitableEvent* service_worker_started_event,
+ const cssom::ViewportSize viewport_size);
+
// Tries all registered URL handlers for a URL. Returns true if one of the
// handlers handled the URL, false if otherwise.
- bool TryURLHandlers(const GURL& url);
+ bool NavigateTryURLHandlers(const GURL& url);
// Destroys the splash screen, if currently displayed.
void DestroySplashScreen(base::TimeDelta close_time = base::TimeDelta());
diff --git a/cobalt/browser/main.cc b/cobalt/browser/main.cc
index 7d0d0a0..ff13b37 100644
--- a/cobalt/browser/main.cc
+++ b/cobalt/browser/main.cc
@@ -18,6 +18,7 @@
#include "cobalt/base/wrap_main.h"
#include "cobalt/browser/application.h"
#include "cobalt/browser/switches.h"
+#include "cobalt/css_parser/switches.h"
#include "cobalt/version.h"
namespace {
@@ -41,6 +42,7 @@
cobalt::browser::switches::kHelp)) {
SbLogRaw("Options: \n");
SbLogRaw(cobalt::browser::switches::HelpMessage().c_str());
+ SbLogRaw(cobalt::css_parser::switches::HelpMessage().c_str());
return true;
}
return false;
diff --git a/cobalt/browser/metrics/BUILD.gn b/cobalt/browser/metrics/BUILD.gn
index 3f25f1a..62c85fa 100644
--- a/cobalt/browser/metrics/BUILD.gn
+++ b/cobalt/browser/metrics/BUILD.gn
@@ -51,6 +51,7 @@
deps = [
":metrics",
"//base",
+ "//cobalt//browser:test_dependencies_on_browser",
"//cobalt/browser:generated_types",
"//cobalt/h5vcc",
"//cobalt/h5vcc:metric_event_handler_wrapper",
diff --git a/cobalt/browser/service_worker_registry.cc b/cobalt/browser/service_worker_registry.cc
index bbfdf0f..89b9395 100644
--- a/cobalt/browser/service_worker_registry.cc
+++ b/cobalt/browser/service_worker_registry.cc
@@ -31,8 +31,6 @@
// Signals the given WaitableEvent.
void SignalWaitableEvent(base::WaitableEvent* event) { event->Signal(); }
-// The watchdog client name used to represent service worker registry thread.
-const char kWatchdogName[] = "service worker registry";
// The watchdog time interval in microseconds allowed between pings before
// triggering violations.
const int64_t kWatchdogTimeInterval = 15000000;
@@ -61,7 +59,8 @@
// Registers service worker thread as a watchdog client.
if (watchdog) {
watchdog_registered_ = true;
- watchdog->Register(kWatchdogName, kWatchdogName,
+ watchdog->Register(worker::WorkerConsts::kServiceWorkerRegistryName,
+ worker::WorkerConsts::kServiceWorkerRegistryName,
base::kApplicationStateStarted, kWatchdogTimeInterval,
kWatchdogTimeWait, watchdog::PING);
message_loop()->task_runner()->PostDelayedTask(
@@ -101,7 +100,7 @@
watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance();
if (watchdog) {
watchdog_registered_ = false;
- watchdog->Unregister(kWatchdogName);
+ watchdog->Unregister(worker::WorkerConsts::kServiceWorkerRegistryName);
}
// Ensure that the destruction observer got added before stopping the thread.
@@ -120,7 +119,7 @@
// If watchdog is already unregistered or shut down, stop ping watchdog.
if (!watchdog_registered_ || !watchdog) return;
- watchdog->Ping(kWatchdogName);
+ watchdog->Ping(worker::WorkerConsts::kServiceWorkerRegistryName);
message_loop()->task_runner()->PostDelayedTask(
FROM_HERE,
base::Bind(&ServiceWorkerRegistry::PingWatchdog, base::Unretained(this)),
@@ -134,6 +133,10 @@
done_event);
}
+void ServiceWorkerRegistry::EraseRegistrationMap() {
+ service_worker_context()->EraseRegistrationMap();
+}
+
worker::ServiceWorkerContext* ServiceWorkerRegistry::service_worker_context() {
// Ensure that the thread had a chance to allocate the object.
destruction_observer_added_.Wait();
diff --git a/cobalt/browser/service_worker_registry.h b/cobalt/browser/service_worker_registry.h
index 4880d6a..f0e934e 100644
--- a/cobalt/browser/service_worker_registry.h
+++ b/cobalt/browser/service_worker_registry.h
@@ -49,6 +49,8 @@
const GURL& client_url,
base::WaitableEvent* done_event);
+ void EraseRegistrationMap();
+
worker::ServiceWorkerContext* service_worker_context();
private:
diff --git a/cobalt/build/build_info.py b/cobalt/build/build_info.py
index aed2646..52f4494 100755
--- a/cobalt/build/build_info.py
+++ b/cobalt/build/build_info.py
@@ -57,7 +57,7 @@
output = subprocess.check_output(['git', 'rev-list', '--count', 'HEAD'],
cwd=cwd)
build_id = int(output.strip().decode()) + COMMIT_COUNT_BUILD_ID_OFFSET
- return build_id
+ return str(build_id)
def _get_last_commit_with_format(placeholder, cwd):
diff --git a/cobalt/build/get_build_id_test.py b/cobalt/build/get_build_id_test.py
index 562179f..26e7b2b 100644
--- a/cobalt/build/get_build_id_test.py
+++ b/cobalt/build/get_build_id_test.py
@@ -87,8 +87,9 @@
self.make_commit()
build_number = build_info.get_build_id_from_commit_count(
cwd=self.test_dir.name)
- self.assertEqual(build_number,
- num_commits + build_info.COMMIT_COUNT_BUILD_ID_OFFSET)
+ self.assertEqual(
+ int(build_number),
+ num_commits + build_info.COMMIT_COUNT_BUILD_ID_OFFSET)
def testCommitsOutrankCommitCount(self):
self.make_commit()
@@ -102,8 +103,9 @@
for _ in range(num_commits):
self.make_commit()
build_number = get_build_id.main(cwd=self.test_dir.name)
- self.assertEqual(build_number,
- num_commits + build_info.COMMIT_COUNT_BUILD_ID_OFFSET)
+ self.assertEqual(
+ int(build_number),
+ num_commits + build_info.COMMIT_COUNT_BUILD_ID_OFFSET)
if __name__ == '__main__':
diff --git a/cobalt/build/gn.py b/cobalt/build/gn.py
index 7ff3bc4..e8c4472 100755
--- a/cobalt/build/gn.py
+++ b/cobalt/build/gn.py
@@ -68,7 +68,7 @@
parser.add_argument(
'-p',
'--platform',
- required=True,
+ default='linux-x64x11',
choices=list(PLATFORMS),
help='The platform to build.')
parser.add_argument(
diff --git a/cobalt/css_parser/BUILD.gn b/cobalt/css_parser/BUILD.gn
index d6a668c..8cbc194 100644
--- a/cobalt/css_parser/BUILD.gn
+++ b/cobalt/css_parser/BUILD.gn
@@ -76,6 +76,8 @@
"shadow_property_parse_structures.cc",
"shadow_property_parse_structures.h",
"string_pool.h",
+ "switches.cc",
+ "switches.h",
"text_decoration_shorthand_property_parse_structures.cc",
"text_decoration_shorthand_property_parse_structures.h",
"transition_shorthand_property_parse_structures.cc",
@@ -92,6 +94,7 @@
deps = [
":css_grammar",
+ "//base",
"//cobalt/base",
"//cobalt/cssom",
"//nb",
@@ -119,7 +122,9 @@
":css_grammar",
":css_parser",
"//base",
+ "//cobalt/browser:test_dependencies_on_browser",
"//cobalt/cssom",
+ "//cobalt/dom",
"//cobalt/test:run_all_unittests",
"//testing/gmock",
"//testing/gtest",
diff --git a/cobalt/css_parser/parser.cc b/cobalt/css_parser/parser.cc
index ccc9b42..aaaf474 100644
--- a/cobalt/css_parser/parser.cc
+++ b/cobalt/css_parser/parser.cc
@@ -23,6 +23,7 @@
#include <string>
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/containers/hash_tables.h"
#include "base/lazy_instance.h"
#include "base/optional.h"
@@ -39,6 +40,7 @@
#include "cobalt/css_parser/ref_counted_util.h"
#include "cobalt/css_parser/scanner.h"
#include "cobalt/css_parser/string_pool.h"
+#include "cobalt/css_parser/switches.h"
#include "cobalt/css_parser/trivial_string_piece.h"
#include "cobalt/css_parser/trivial_type_pairs.h"
#include "cobalt/cssom/active_pseudo_class.h"
@@ -539,11 +541,19 @@
void LogWarningCallback(const ::base::DebuggerHooks* debugger_hooks,
const std::string& message) {
CLOG(WARNING, *debugger_hooks) << message;
+ ::base::CommandLine* command_line = ::base::CommandLine::ForCurrentProcess();
+ if (command_line->GetSwitchValueASCII(switches::kOnCssWarning) == "crash") {
+ IMMEDIATE_CRASH() << message;
+ }
}
void LogErrorCallback(const ::base::DebuggerHooks* debugger_hooks,
const std::string& message) {
CLOG(ERROR, *debugger_hooks) << message;
+ ::base::CommandLine* command_line = ::base::CommandLine::ForCurrentProcess();
+ if (command_line->GetSwitchValueASCII(switches::kOnCssError) == "crash") {
+ IMMEDIATE_CRASH() << message;
+ }
}
} // namespace
diff --git a/cobalt/css_parser/switches.cc b/cobalt/css_parser/switches.cc
new file mode 100644
index 0000000..bb4e085
--- /dev/null
+++ b/cobalt/css_parser/switches.cc
@@ -0,0 +1,50 @@
+// Copyright 2023 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/css_parser/switches.h"
+
+#include <map>
+
+namespace cobalt {
+namespace css_parser {
+namespace switches {
+
+const char kOnCssError[] = "on_css_error";
+const char kOnCssErrorHelp[] =
+ "If set to \"crash\", crashes on CSS error even when recoverable.";
+
+const char kOnCssWarning[] = "on_css_warning";
+const char kOnCssWarningHelp[] = "If set to \"crash\", crashes on CSS warning.";
+
+std::string HelpMessage() {
+ std::string help_message;
+ std::map<std::string, const char*> help_map{
+ {kOnCssError, kOnCssErrorHelp},
+ {kOnCssWarning, kOnCssWarningHelp},
+ };
+
+ for (const auto& switch_message : help_map) {
+ help_message.append(" --")
+ .append(switch_message.first)
+ .append("\n")
+ .append(" ")
+ .append(switch_message.second)
+ .append("\n\n");
+ }
+ return help_message;
+}
+
+} // namespace switches
+} // namespace css_parser
+} // namespace cobalt
diff --git a/cobalt/css_parser/switches.h b/cobalt/css_parser/switches.h
new file mode 100644
index 0000000..cd3943f
--- /dev/null
+++ b/cobalt/css_parser/switches.h
@@ -0,0 +1,35 @@
+// Copyright 2023 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 COBALT_CSS_PARSER_SWITCHES_H_
+#define COBALT_CSS_PARSER_SWITCHES_H_
+
+#include <string>
+
+namespace cobalt {
+namespace css_parser {
+namespace switches {
+
+extern const char kOnCssError[];
+extern const char kOnCssErrorHelp[];
+extern const char kOnCssWarning[];
+extern const char kOnCssWarningHelp[];
+
+std::string HelpMessage();
+
+} // namespace switches
+} // namespace css_parser
+} // namespace cobalt
+
+#endif // COBALT_CSS_PARSER_SWITCHES_H_
diff --git a/cobalt/cssom/BUILD.gn b/cobalt/cssom/BUILD.gn
index b313c59..04dae86 100644
--- a/cobalt/cssom/BUILD.gn
+++ b/cobalt/cssom/BUILD.gn
@@ -319,8 +319,10 @@
deps = [
"//cobalt/base",
+ "//cobalt/browser:test_dependencies_on_browser",
"//cobalt/css_parser",
"//cobalt/cssom",
+ "//cobalt/dom",
"//cobalt/math",
"//cobalt/test:run_all_unittests",
"//testing/gmock",
diff --git a/cobalt/h5vcc/BUILD.gn b/cobalt/h5vcc/BUILD.gn
index f081ce4..901f668 100644
--- a/cobalt/h5vcc/BUILD.gn
+++ b/cobalt/h5vcc/BUILD.gn
@@ -28,12 +28,6 @@
has_pedantic_warnings = true
sources = [
- "dial/dial_http_request.cc",
- "dial/dial_http_request.h",
- "dial/dial_http_response.cc",
- "dial/dial_http_response.h",
- "dial/dial_server.cc",
- "dial/dial_server.h",
"h5vcc.cc",
"h5vcc.h",
"h5vcc_accessibility.cc",
@@ -91,10 +85,23 @@
"//cobalt/web:dom_exception",
"//cobalt/worker",
"//net",
- "//net:http_server",
"//starboard",
"//third_party/protobuf:protobuf_lite",
]
+ if (enable_in_app_dial) {
+ sources += [
+ "dial/dial_http_request.cc",
+ "dial/dial_http_request.h",
+ "dial/dial_http_response.cc",
+ "dial/dial_http_response.h",
+ "dial/dial_server.cc",
+ "dial/dial_server.h",
+ ]
+ deps += [
+ "//net:cobalt_dial_server",
+ "//net:http_server",
+ ]
+ }
if (enable_account_manager) {
sources += [
diff --git a/cobalt/h5vcc/h5vcc_crash_log.cc b/cobalt/h5vcc/h5vcc_crash_log.cc
index b3e76e7..39c545c 100644
--- a/cobalt/h5vcc/h5vcc_crash_log.cc
+++ b/cobalt/h5vcc/h5vcc_crash_log.cc
@@ -191,6 +191,19 @@
return "";
}
+script::Sequence<std::string> H5vccCrashLog::GetWatchdogViolationClients() {
+ watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance();
+ script::Sequence<std::string> client_names;
+ if (watchdog) {
+ std::vector<std::string> client_string_names =
+ watchdog->GetWatchdogViolationClientNames();
+ for (std::size_t i = 0; i < client_string_names.size(); ++i) {
+ client_names.push_back(client_string_names[i]);
+ }
+ }
+ return client_names;
+}
+
bool H5vccCrashLog::GetPersistentSettingWatchdogEnable() {
watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance();
if (watchdog) return watchdog->GetPersistentSettingWatchdogEnable();
diff --git a/cobalt/h5vcc/h5vcc_crash_log.h b/cobalt/h5vcc/h5vcc_crash_log.h
index ea06c88..e01d23e 100644
--- a/cobalt/h5vcc/h5vcc_crash_log.h
+++ b/cobalt/h5vcc/h5vcc_crash_log.h
@@ -81,6 +81,8 @@
std::string GetWatchdogViolations(
const script::Sequence<std::string>& clients = {});
+ script::Sequence<std::string> GetWatchdogViolationClients();
+
bool GetPersistentSettingWatchdogEnable();
void SetPersistentSettingWatchdogEnable(bool enable_watchdog);
diff --git a/cobalt/h5vcc/h5vcc_crash_log.idl b/cobalt/h5vcc/h5vcc_crash_log.idl
index 8d4a3ba..e60e0ab 100644
--- a/cobalt/h5vcc/h5vcc_crash_log.idl
+++ b/cobalt/h5vcc/h5vcc_crash_log.idl
@@ -86,6 +86,9 @@
// }
DOMString getWatchdogViolations(optional sequence<DOMString> clients);
+ // Returns a sequence of the client names that have watchdog violations.
+ sequence<DOMString> getWatchdogViolationClients();
+
// Gets a persistent Watchdog setting that determines whether or not Watchdog
// is enabled. When disabled, Watchdog behaves like a stub except that
// persistent settings can still be get/set. Requires a restart to take
diff --git a/cobalt/h5vcc/h5vcc_storage.cc b/cobalt/h5vcc/h5vcc_storage.cc
index f059e8e..dac5b5c 100644
--- a/cobalt/h5vcc/h5vcc_storage.cc
+++ b/cobalt/h5vcc/h5vcc_storage.cc
@@ -25,7 +25,7 @@
#include "cobalt/cache/cache.h"
#include "cobalt/persistent_storage/persistent_settings.h"
#include "cobalt/storage/storage_manager.h"
-#include "cobalt/worker/service_worker_consts.h"
+#include "cobalt/worker/worker_consts.h"
#include "net/base/completion_once_callback.h"
#include "net/disk_cache/cobalt/cobalt_backend_impl.h"
#include "net/disk_cache/cobalt/resource_type.h"
@@ -419,7 +419,7 @@
kSbFileMaxPath);
base::FilePath service_worker_file_path =
base::FilePath(storage_dir.data())
- .Append(worker::ServiceWorkerConsts::kSettingsJson);
+ .Append(worker::WorkerConsts::kSettingsJson);
base::DeleteFile(service_worker_file_path, /*recursive=*/false);
}
diff --git a/cobalt/layout/BUILD.gn b/cobalt/layout/BUILD.gn
index 7966365..36c0181 100644
--- a/cobalt/layout/BUILD.gn
+++ b/cobalt/layout/BUILD.gn
@@ -140,6 +140,7 @@
deps = [
":layout",
"//base",
+ "//cobalt//browser:test_dependencies_on_browser",
"//cobalt/base",
"//cobalt/css_parser",
"//cobalt/cssom",
diff --git a/cobalt/loader/BUILD.gn b/cobalt/loader/BUILD.gn
index 2db902d..9b808f9 100644
--- a/cobalt/loader/BUILD.gn
+++ b/cobalt/loader/BUILD.gn
@@ -195,6 +195,7 @@
deps = [
":loader",
"//cobalt/base:base",
+ "//cobalt/browser:test_dependencies_on_browser",
"//cobalt/dom",
"//cobalt/dom_parser",
"//cobalt/math:math",
diff --git a/cobalt/loader/image/sandbox/BUILD.gn b/cobalt/loader/image/sandbox/BUILD.gn
index adf6ab1..dbfc6a2 100644
--- a/cobalt/loader/image/sandbox/BUILD.gn
+++ b/cobalt/loader/image/sandbox/BUILD.gn
@@ -18,10 +18,12 @@
# This target will build a sandbox application that allows for easy
# experimentation with the ImageDecoder on any platform.
target(final_executable_type, "image_decoder_sandbox") {
+ testonly = true
sources = [ "image_decoder_sandbox.cc" ]
deps = [
"//cobalt/base",
+ "//cobalt/browser:test_dependencies_on_browser",
"//cobalt/loader",
"//cobalt/loader:copy_loader_test_data",
"//cobalt/math",
diff --git a/cobalt/media/BUILD.gn b/cobalt/media/BUILD.gn
index 813baa2..0e7c06d 100644
--- a/cobalt/media/BUILD.gn
+++ b/cobalt/media/BUILD.gn
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import("//starboard/build/config/os_definitions.gni")
+
config("media_config") {
if (!is_win) {
cflags_cc = [
@@ -129,6 +131,7 @@
deps = [
":media",
"//base/test:test_support",
+ "//cobalt//browser:test_dependencies_on_browser",
"//cobalt/base",
"//cobalt/test:run_all_unittests",
"//testing/gmock",
@@ -137,4 +140,9 @@
]
data_deps = [ "//cobalt/media/testing:cobalt_media_download_test_data" ]
+
+ # TODO: b/296715826 - Fix symbol resolution in cval_stats_test.cc.
+ if (sb_is_modular && is_host_win) {
+ sources -= [ "base/cval_stats_test.cc" ]
+ }
}
diff --git a/cobalt/media/sandbox/BUILD.gn b/cobalt/media/sandbox/BUILD.gn
index 19be835..84d2620 100644
--- a/cobalt/media/sandbox/BUILD.gn
+++ b/cobalt/media/sandbox/BUILD.gn
@@ -16,9 +16,11 @@
# media/renderer interface.
target(final_executable_type, "media_sandbox") {
+ testonly = true
sources = [ "media2_sandbox.cc" ]
deps = [
+ "//cobalt//browser:test_dependencies_on_browser",
"//cobalt/base",
"//cobalt/math",
"//cobalt/media",
@@ -28,6 +30,7 @@
}
target(final_executable_type, "web_media_player_sandbox") {
+ testonly = true
sources = [
"format_guesstimator.cc",
"format_guesstimator.h",
@@ -42,6 +45,7 @@
"//cobalt/base",
# Use test data from demos to avoid keeping two copies of video files.
+ "//cobalt/browser:test_dependencies_on_browser",
"//cobalt/demos/content:demos_testdata",
"//cobalt/loader",
"//cobalt/math",
diff --git a/cobalt/network/BUILD.gn b/cobalt/network/BUILD.gn
index 1a4fd75..73e33ca 100644
--- a/cobalt/network/BUILD.gn
+++ b/cobalt/network/BUILD.gn
@@ -63,10 +63,7 @@
}
if (enable_in_app_dial) {
- deps += [
- # DialService depends on http server.
- "//net:http_server",
- ]
+ deps += [ "//net:cobalt_dial_server" ]
}
# Enable network logging on all but gold builds.
diff --git a/cobalt/renderer/BUILD.gn b/cobalt/renderer/BUILD.gn
index 2b4ac9d..54d2187 100644
--- a/cobalt/renderer/BUILD.gn
+++ b/cobalt/renderer/BUILD.gn
@@ -128,6 +128,7 @@
":renderer",
":renderer_headers_only",
"//base:i18n",
+ "//cobalt//browser:test_dependencies_on_browser",
"//cobalt/base",
"//cobalt/loader",
"//cobalt/math",
diff --git a/cobalt/renderer/sandbox/BUILD.gn b/cobalt/renderer/sandbox/BUILD.gn
index 30d7def..bf1b00b 100644
--- a/cobalt/renderer/sandbox/BUILD.gn
+++ b/cobalt/renderer/sandbox/BUILD.gn
@@ -20,10 +20,12 @@
# also be useful for visually inspecting the output that the Cobalt
# renderer is producing.
target(final_executable_type, "renderer_sandbox") {
+ testonly = true
sources = [ "renderer_sandbox_main.cc" ]
deps = [
"//cobalt/base",
+ "//cobalt/browser:test_dependencies_on_browser",
"//cobalt/math",
"//cobalt/renderer",
"//cobalt/renderer/test/scenes",
@@ -39,10 +41,12 @@
# is constantly animating, which for many implementations can be a
# performance problem.
target(final_executable_type, "scaling_text_sandbox") {
+ testonly = true
sources = [ "scaling_text_sandbox_main.cc" ]
deps = [
"//cobalt/base",
+ "//cobalt/browser:test_dependencies_on_browser",
"//cobalt/math",
"//cobalt/renderer",
"//cobalt/renderer/test/scenes",
diff --git a/cobalt/script/v8c/v8c_exception_state.cc b/cobalt/script/v8c/v8c_exception_state.cc
index ee9fbe0..ee47099 100644
--- a/cobalt/script/v8c/v8c_exception_state.cc
+++ b/cobalt/script/v8c/v8c_exception_state.cc
@@ -70,6 +70,7 @@
V8cGlobalEnvironment* global_environment =
V8cGlobalEnvironment::GetFromIsolate(isolate_);
+ if (!global_environment) return;
v8::Local<v8::Object> wrapper =
global_environment->wrapper_factory()->GetWrapper(exception);
diff --git a/cobalt/script/v8c/v8c_global_environment.cc b/cobalt/script/v8c/v8c_global_environment.cc
index 9ec5c07..04e94d1 100644
--- a/cobalt/script/v8c/v8c_global_environment.cc
+++ b/cobalt/script/v8c/v8c_global_environment.cc
@@ -378,7 +378,7 @@
V8cGlobalEnvironment* global_environment =
V8cGlobalEnvironment::GetFromIsolate(context->GetIsolate());
DCHECK(global_environment);
- if (!global_environment->report_eval_.is_null()) {
+ if (global_environment && !global_environment->report_eval_.is_null()) {
global_environment->report_eval_.Run();
}
// This callback should only be called while code generation from strings is
@@ -396,7 +396,8 @@
v8::Isolate* isolate = v8::Isolate::GetCurrent();
V8cGlobalEnvironment* global_environment =
V8cGlobalEnvironment::GetFromIsolate(isolate);
- if (isolate->GetEnteredOrMicrotaskContext().IsEmpty()) {
+ if (!global_environment ||
+ isolate->GetEnteredOrMicrotaskContext().IsEmpty()) {
return;
}
if (message->ErrorLevel() != v8::Isolate::kMessageError) {
diff --git a/cobalt/site/docs/development/setup-android.md b/cobalt/site/docs/development/setup-android.md
index 2a5f0b1..82e26aa 100644
--- a/cobalt/site/docs/development/setup-android.md
+++ b/cobalt/site/docs/development/setup-android.md
@@ -26,12 +26,16 @@
Where 4 is the number of parallel threads. You can adjust the number of
parallel threads according to how your workstation performs.
-1. Run `cobalt/build/gn.py -p android-x86` to configure the Cobalt build,
- which also installs the SDK and NDK. (This step will have to be repeated
- with 'android-arm' or 'android-arm64' to target those architectures.) The
- SDK and NDK will be downloaded and installed into a `starboard-toolchains`
- directory as needed. If prompted, read and accept the license agreement to
- proceed forward.
+1. Run `starboard/android/shared/download_sdk.sh` to download the SDK and NDK.
+ The SDK and NDK will be downloaded and installed into
+ `~/starboard-toolchains`. If you wish to customize the download location
+ you must set the relevant environment variables accordingly.
+
+ If prompted, read and accept the license agreement.
+
+1. Run `cobalt/build/gn.py -p android-x86` to configure the Cobalt build.
+ (This step will have to be repeated with 'android-arm' or 'android-arm64'
+ to target those architectures.)
**Note:** If you have trouble building with an error referencing the
`debug.keystore` you may need to set one up on your system:
diff --git a/cobalt/site/docs/development/setup-windows.md b/cobalt/site/docs/development/setup-windows.md
index 65b9496..47a98cc 100644
--- a/cobalt/site/docs/development/setup-windows.md
+++ b/cobalt/site/docs/development/setup-windows.md
@@ -27,10 +27,10 @@
<aside class="note">
<b>Note:</b> By default, Cobalt's build system will check
- C:\Program Files (x86)\ for the Visual Studio install directory. If you
- installed it elsewhere, you can set the `VSINSTALLDIR` environment
+ <code>C:\Program Files (x86)\</code> for the Visual Studio install directory. If you
+ installed it elsewhere, you can set the <code>VSINSTALLDIR</code> environment
variable to point to the correct location. For example
- `C:/Program Files/Microsoft Visual Studio/2022/Professional`
+ <code>C:/Program Files/Microsoft Visual Studio/2022/Professional</code>
</aside>
1. Install GN, which we use for our build system code. There are a few ways to
@@ -63,12 +63,12 @@
```
<aside class="note">
- If you plan to contribute to the Cobalt codebase it is recommended that
- you create your own
- [fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/about-forks)
- of the [Cobalt repository](https://github.com/youtube/cobalt), apply
- changes to the fork, and then
- [create a pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork)
+ <b>Note:</b> If you plan to contribute to the Cobalt codebase it is
+ recommended that you create your own
+ <a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/about-forks">fork</a>
+ of the <a href="https://github.com/youtube/cobalt">Cobalt repository</a>,
+ apply changes to the fork, and then
+ <a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork">create a pull request</a>
to merge those changes into the Cobalt repository.
</aside>
@@ -141,7 +141,8 @@
configuration](/starboard/porting.html#1-enumerate-and-name-your-platform-configurations)
that identifies the platform. As described in the Starboard porting
guide, it contains a `family name` (like `linux`) and a
- `binary variant` (like `x64x11`), separated by a hyphen.
+ `binary variant` (like `x64x11`), separated by a hyphen. For Windows
+ builds use win-win32.
1. `<build_type>` is the build you are compiling. Possible values are
`debug`, `devel`, `qa`, and `gold`.
1. `<target_name>` is the name assigned to the compiled code and it is
@@ -222,10 +223,10 @@
but they should work for local testing.
<aside class="note">
- <b>Note:</b> if you change the value of `PUBLISHER` in
- `appx_product_settings.py` you <b>must</b> regenerate a pfx file in order for
- the packaging step below to work correctly. Follow the instructions in
- `starboard/xb1/cert/README.md` to generate your own pfx.
+ <b>Note:</b> if you change the value of <code>PUBLISHER</code> in
+ <code>appx_product_settings.py</code> you <b>must</b> regenerate a pfx file in
+ order for the packaging step below to work correctly. Follow the instructions
+ in <code>starboard/xb1/cert/README.md</code> to generate your own pfx.
</aside>
### Build Cobalt
diff --git a/cobalt/storage/BUILD.gn b/cobalt/storage/BUILD.gn
index 9c575bd..0bab5d9 100644
--- a/cobalt/storage/BUILD.gn
+++ b/cobalt/storage/BUILD.gn
@@ -55,7 +55,6 @@
":storage",
"//cobalt/base",
"//cobalt/test:run_all_unittests",
- "//net",
"//testing/gmock",
"//testing/gtest",
"//url",
diff --git a/cobalt/ui_navigation/scroll_engine/BUILD.gn b/cobalt/ui_navigation/scroll_engine/BUILD.gn
index 980b3fd..25dc91b 100644
--- a/cobalt/ui_navigation/scroll_engine/BUILD.gn
+++ b/cobalt/ui_navigation/scroll_engine/BUILD.gn
@@ -34,6 +34,7 @@
sources = [ "free_scrolling_nav_item_test.cc" ]
deps = [
":scroll_engine",
+ "//cobalt//browser:test_dependencies_on_browser",
"//cobalt/base",
"//cobalt/test:run_all_unittests",
"//testing/gmock",
diff --git a/cobalt/version.h b/cobalt/version.h
index 9d152df..517e7d5 100644
--- a/cobalt/version.h
+++ b/cobalt/version.h
@@ -35,6 +35,6 @@
// release is cut.
//.
-#define COBALT_VERSION "24.lts.4"
+#define COBALT_VERSION "24.lts.5"
#endif // COBALT_VERSION_H_
diff --git a/cobalt/watchdog/watchdog.cc b/cobalt/watchdog/watchdog.cc
index 5e2a599..1e43688 100644
--- a/cobalt/watchdog/watchdog.cc
+++ b/cobalt/watchdog/watchdog.cc
@@ -109,6 +109,7 @@
// Starts monitor thread.
is_monitoring_.store(true);
+ InitializeViolationsMap(this);
SB_DCHECK(!SbThreadIsValid(watchdog_thread_));
watchdog_thread_ = SbThreadCreate(0, kSbThreadNoPriority, kSbThreadNoAffinity,
true, "Watchdog", &Watchdog::Monitor, this);
@@ -146,10 +147,17 @@
return watchdog_file_path_;
}
-std::vector<std::string> Watchdog::GetWatchdogClientNames() {
+std::vector<std::string> Watchdog::GetWatchdogViolationClientNames() {
+ if (pending_write_) WriteWatchdogViolations();
+
+ std::string watchdog_json = ReadViolationFile(GetWatchdogFilePath().c_str());
std::vector<std::string> names;
- for (auto& it : client_map_) {
- names.push_back(it.first);
+ if (watchdog_json != "") {
+ std::unique_ptr<base::Value> violations_map =
+ base::JSONReader::Read(watchdog_json);
+ for (const auto& it : violations_map->DictItems()) {
+ names.push_back(it.first);
+ }
}
return names;
}
@@ -228,8 +236,6 @@
void Watchdog::UpdateViolationsMap(void* context, Client* client,
SbTimeMonotonic time_delta) {
// Gets violation dictionary with key client name from violations_map_.
- if (static_cast<Watchdog*>(context)->violations_map_ == nullptr)
- InitializeViolationsMap(context);
base::Value* violation_dict =
(static_cast<Watchdog*>(context)->violations_map_)->FindKey(client->name);
@@ -317,19 +323,26 @@
static_cast<Watchdog*>(context)->pending_write_ = true;
}
+std::string Watchdog::ReadViolationFile(const char* file_path) {
+ starboard::ScopedFile read_file(file_path, kSbFileOpenOnly | kSbFileRead);
+ if (read_file.IsValid()) {
+ int64_t kFileSize = read_file.GetSize();
+ std::vector<char> buffer(kFileSize + 1, 0);
+ read_file.ReadAll(buffer.data(), kFileSize);
+ return std::string(buffer.data());
+ }
+ return "";
+}
+
void Watchdog::InitializeViolationsMap(void* context) {
// Loads the previous Watchdog violations file containing violations before
// app start, if it exists, to populate violations_map_.
static_cast<Watchdog*>(context)->violations_count_ = 0;
- starboard::ScopedFile read_file(
- (static_cast<Watchdog*>(context)->GetWatchdogFilePath()).c_str(),
- kSbFileOpenOnly | kSbFileRead);
- if (read_file.IsValid()) {
- int64_t kFileSize = read_file.GetSize();
- std::vector<char> buffer(kFileSize + 1, 0);
- read_file.ReadAll(buffer.data(), kFileSize);
- std::string watchdog_json = std::string(buffer.data());
+ std::string watchdog_json =
+ static_cast<Watchdog*>(context)->ReadViolationFile(
+ (static_cast<Watchdog*>(context)->GetWatchdogFilePath()).c_str());
+ if (watchdog_json != "") {
static_cast<Watchdog*>(context)->violations_map_ =
base::JSONReader::Read(watchdog_json);
}
@@ -538,48 +551,37 @@
if (pending_write_) WriteWatchdogViolations();
- starboard::ScopedFile file(GetWatchdogFilePath().c_str(),
- kSbFileOpenOnly | kSbFileRead | kSbFileWrite);
- if (file.IsValid()) {
- int64_t kFileSize = file.GetSize();
- std::vector<char> buffer(kFileSize + 1, 0);
- file.ReadAll(buffer.data(), kFileSize);
- watchdog_json = std::string(buffer.data());
-
- // If clients is empty we will fetch all clients.
+ if (!static_cast<base::DictionaryValue*>(violations_map_.get())->empty()) {
+ // Get all Watchdog violations if clients is given.
if (clients.empty()) {
+ // Removes all Watchdog violations.
+ base::JSONWriter::Write(*violations_map_, &watchdog_json_fetched);
if (clear) {
- if (violations_map_) {
- static_cast<base::DictionaryValue*>(violations_map_.get())->Clear();
- violations_count_ = 0;
- }
+ static_cast<base::DictionaryValue*>(violations_map_.get())->Clear();
+ violations_count_ = 0;
starboard::SbFileDeleteRecursive(GetWatchdogFilePath().c_str(), true);
}
- watchdog_json_fetched = watchdog_json;
} else {
- std::string watchdog_json_not_read = "";
- std::unique_ptr<base::Value> violations_map =
- base::JSONReader::Read(watchdog_json);
base::Value filtered_client_data(base::Value::Type::DICTIONARY);
for (int i = 0; i < clients.size(); i++) {
- base::Value* violation_dict = violations_map->FindKey(clients[i]);
+ base::Value* violation_dict =
+ static_cast<base::DictionaryValue*>(violations_map_.get())
+ ->FindKey(clients[i]);
if (violation_dict != nullptr) {
filtered_client_data.SetKey(clients[i], (*violation_dict).Clone());
if (clear) {
base::Value* violations = violation_dict->FindKey("violations");
int violations_count = violations->GetList().size();
- violations_map->RemoveKey(clients[i]);
- if (violations_map_) {
- bool result =
- static_cast<base::DictionaryValue*>(violations_map_.get())
- ->RemoveKey(clients[i]);
- if (result) {
- violations_count_ -= violations_count;
- }
- if (violations_count_ == 0) {
- static_cast<base::DictionaryValue*>(violations_map_.get())
- ->Clear();
- }
+
+ static_cast<base::DictionaryValue*>(violations_map_.get())
+ ->RemoveKey(clients[i]);
+ violations_count_ -= violations_count;
+ if (!static_cast<base::DictionaryValue*>(violations_map_.get())
+ ->empty()) {
+ WriteWatchdogViolations();
+ } else {
+ starboard::SbFileDeleteRecursive(GetWatchdogFilePath().c_str(),
+ true);
}
}
}
@@ -587,19 +589,6 @@
if (!filtered_client_data.DictEmpty()) {
base::JSONWriter::Write(filtered_client_data, &watchdog_json_fetched);
}
- if (clear) {
- // If all data is fetched, delete the violation file.
- if (violations_map->DictEmpty()) {
- starboard::SbFileDeleteRecursive(GetWatchdogFilePath().c_str(), true);
- } else {
- base::JSONWriter::Write(*violations_map, &watchdog_json_not_read);
- file.Seek(kSbFileFromBegin, 0);
- file.WriteAll(watchdog_json_not_read.c_str(),
- static_cast<int>(watchdog_json_not_read.size()));
- file.Truncate(static_cast<int>(watchdog_json_not_read.size()));
- time_last_written_microseconds_ = SbTimeGetMonotonicNow();
- }
- }
}
SB_LOG(INFO) << "[Watchdog] Reading violations:\n" << watchdog_json_fetched;
} else {
diff --git a/cobalt/watchdog/watchdog.h b/cobalt/watchdog/watchdog.h
index fde3b4b..8aa9a7c 100644
--- a/cobalt/watchdog/watchdog.h
+++ b/cobalt/watchdog/watchdog.h
@@ -82,7 +82,7 @@
bool InitializeStub();
void Uninitialize();
std::string GetWatchdogFilePath();
- std::vector<std::string> GetWatchdogClientNames();
+ std::vector<std::string> GetWatchdogViolationClientNames();
void UpdateState(base::ApplicationState state);
bool Register(std::string name, std::string description,
base::ApplicationState monitor_state,
@@ -105,6 +105,7 @@
private:
void WriteWatchdogViolations();
+ std::string ReadViolationFile(const char* file_path);
static void* Monitor(void* context);
static void UpdateViolationsMap(void* context, Client* client,
SbTimeMonotonic time_delta);
diff --git a/cobalt/watchdog/watchdog_test.cc b/cobalt/watchdog/watchdog_test.cc
index 0681ce0..1cafc43 100644
--- a/cobalt/watchdog/watchdog_test.cc
+++ b/cobalt/watchdog/watchdog_test.cc
@@ -325,7 +325,10 @@
starboard::ScopedFile file(watchdog_->GetWatchdogFilePath().c_str(),
kSbFileCreateAlways | kSbFileWrite);
file.WriteAll(json.c_str(), static_cast<int>(json.size()));
-
+ TearDown();
+ watchdog_ = new watchdog::Watchdog();
+ watchdog_->InitializeCustom(nullptr, std::string(kWatchdogViolationsJson),
+ kWatchdogMonitorFrequency);
ASSERT_TRUE(watchdog_->Register("test-name-3", "test-desc-3",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
@@ -489,23 +492,26 @@
ASSERT_NE(write_json, json);
}
-TEST_F(WatchdogTest, GetRegisteredClientNames) {
+TEST_F(WatchdogTest, GetViolationClientNames) {
ASSERT_TRUE(watchdog_->Register("test-name-1", "test-desc-1",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
ASSERT_TRUE(watchdog_->Register("test-name-2", "test-desc-2",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
- std::vector<std::string> names = watchdog_->GetWatchdogClientNames();
+ SbThreadSleep(kWatchdogSleepDuration);
+ ASSERT_TRUE(watchdog_->Unregister("test-name-1"));
+ ASSERT_TRUE(watchdog_->Unregister("test-name-2"));
+ std::vector<std::string> names = watchdog_->GetWatchdogViolationClientNames();
+ ASSERT_EQ(names.size(), 2);
std::set<std::string> expected_names = {"test-name-1", "test-name-2"};
for (std::vector<std::string>::const_iterator it = names.begin();
it != names.end(); ++it) {
const std::string name = *it;
ASSERT_TRUE((expected_names.find(name) != expected_names.end()));
}
- ASSERT_TRUE(watchdog_->Unregister("test-name-1"));
- ASSERT_TRUE(watchdog_->Unregister("test-name-2"));
- names = watchdog_->GetWatchdogClientNames();
+ watchdog_->GetWatchdogViolations();
+ names = watchdog_->GetWatchdogViolationClientNames();
ASSERT_EQ(names.size(), 0);
}
diff --git a/cobalt/web/agent.cc b/cobalt/web/agent.cc
index a2f8901..e9f51e4 100644
--- a/cobalt/web/agent.cc
+++ b/cobalt/web/agent.cc
@@ -43,6 +43,7 @@
#include "cobalt/worker/service_worker_object.h"
#include "cobalt/worker/service_worker_registration.h"
#include "cobalt/worker/service_worker_registration_object.h"
+#include "cobalt/worker/worker_consts.h"
namespace cobalt {
namespace web {
@@ -547,7 +548,7 @@
}
watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance();
- if (watchdog) {
+ if (watchdog && watchdog_registered_) {
watchdog_registered_ = false;
watchdog->Unregister(watchdog_name_);
}
@@ -577,12 +578,15 @@
if (!thread_.StartWithOptions(thread_options)) return;
DCHECK(message_loop());
+ // Registers service worker thread as a watchdog client.
watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance();
- // Registers service worker thread as a watchdog client.
if (watchdog) {
- watchdog_name_ =
- thread_.thread_name() + std::to_string(thread_.GetThreadId());
+ watchdog_name_ = thread_.thread_name();
+ if (watchdog_name_ == worker::WorkerConsts::kServiceWorkerName ||
+ watchdog_name_ == worker::WorkerConsts::kDedicatedWorkerName) {
+ watchdog_name_ += std::to_string(thread_.GetThreadId());
+ }
watchdog_registered_ = true;
watchdog->Register(watchdog_name_, watchdog_name_,
base::kApplicationStateStarted, kWatchdogTimeInterval,
diff --git a/cobalt/web/cache.cc b/cobalt/web/cache.cc
index a47a3c6..29e3372 100644
--- a/cobalt/web/cache.cc
+++ b/cobalt/web/cache.cc
@@ -198,13 +198,13 @@
script::EnvironmentSettings* environment_settings,
std::unique_ptr<script::ValueHandleHolder::Reference> request_reference,
std::unique_ptr<script::ValuePromiseVoid::Reference> promise_reference) {
+ base::AutoLock auto_lock(fetcher_lock_);
auto* global_environment = get_global_environment(environment_settings);
auto* isolate = global_environment->isolate();
script::v8c::EntryScope entry_scope(isolate);
uint32_t key = cache_utils::GetKey(environment_settings->base_url(),
request_reference->referenced_value());
if (fetchers_.find(key) != fetchers_.end()) {
- base::AutoLock auto_lock(*(fetchers_[key]->lock()));
auto* promises = &(fetch_contexts_[key].first);
promises->push_back(std::move(promise_reference));
return;
@@ -402,6 +402,7 @@
}
void Cache::OnFetchCompleted(uint32_t key, bool success) {
+ base::AutoLock auto_lock(fetcher_lock_);
auto* environment_settings = fetch_contexts_[key].second;
auto* context = get_context(environment_settings);
context->message_loop()->task_runner()->PostTask(
@@ -410,17 +411,15 @@
}
void Cache::OnFetchCompletedMainThread(uint32_t key, bool success) {
+ base::AutoLock auto_lock(fetcher_lock_);
auto* fetcher = fetchers_[key].get();
auto* promises = &(fetch_contexts_[key].first);
int status = fetcher->response_code();
// |status| of 200-299 excluding 206 "Partial Content" should be cached.
if (!success || status == 206 || status < 200 || status > 299) {
- {
- base::AutoLock auto_lock(*fetcher->lock());
- while (promises->size() > 0) {
- promises->back()->value().Reject();
- promises->pop_back();
- }
+ while (promises->size() > 0) {
+ promises->back()->value().Reject();
+ promises->pop_back();
}
fetchers_.erase(key);
fetch_contexts_.erase(key);
@@ -447,12 +446,9 @@
global_environment->Compile(script::SourceCode::CreateSourceCode(
fetcher->BufferToString(), base::SourceLocation(__FILE__, 1, 1)));
}
- {
- base::AutoLock auto_lock(*fetcher->lock());
- while (promises->size() > 0) {
- promises->back()->value().Resolve();
- promises->pop_back();
- }
+ while (promises->size() > 0) {
+ promises->back()->value().Resolve();
+ promises->pop_back();
}
fetchers_.erase(key);
fetch_contexts_.erase(key);
diff --git a/cobalt/web/cache.h b/cobalt/web/cache.h
index 02e5c88..88e0855 100644
--- a/cobalt/web/cache.h
+++ b/cobalt/web/cache.h
@@ -75,7 +75,6 @@
int response_code() const { return response_code_; }
const std::string& status_text() const { return status_text_; }
base::ListValue headers() { return std::move(headers_); }
- base::Lock* lock() const { return &lock_; }
std::vector<uint8_t> BufferToVector() const;
std::string BufferToString() const;
@@ -95,7 +94,6 @@
int response_code_;
base::ListValue headers_;
std::string status_text_;
- mutable base::Lock lock_;
};
void PerformAdd(
@@ -106,6 +104,7 @@
void OnFetchCompletedMainThread(uint32_t key, bool success);
std::map<uint32_t, std::unique_ptr<Fetcher>> fetchers_;
+ mutable base::Lock fetcher_lock_;
std::map<uint32_t, std::pair<std::vector<std::unique_ptr<
script::ValuePromiseVoid::Reference>>,
script::EnvironmentSettings*>>
diff --git a/cobalt/web_animations/BUILD.gn b/cobalt/web_animations/BUILD.gn
index 81ee087..6d4f09f 100644
--- a/cobalt/web_animations/BUILD.gn
+++ b/cobalt/web_animations/BUILD.gn
@@ -53,8 +53,10 @@
deps = [
":web_animations",
+ "//cobalt/browser:test_dependencies_on_browser",
"//cobalt/css_parser",
"//cobalt/cssom",
+ "//cobalt/dom",
"//cobalt/test:run_all_unittests",
"//testing/gmock",
"//testing/gtest",
diff --git a/cobalt/worker/BUILD.gn b/cobalt/worker/BUILD.gn
index 23aeaa1..4b07e54 100644
--- a/cobalt/worker/BUILD.gn
+++ b/cobalt/worker/BUILD.gn
@@ -36,8 +36,6 @@
"navigation_preload_manager.h",
"service_worker.cc",
"service_worker.h",
- "service_worker_consts.cc",
- "service_worker_consts.h",
"service_worker_container.cc",
"service_worker_container.h",
"service_worker_context.cc",
@@ -60,6 +58,7 @@
"window_client.h",
"worker.cc",
"worker.h",
+ "worker_consts.h",
"worker_global_scope.cc",
"worker_global_scope.h",
"worker_location.h",
@@ -105,6 +104,7 @@
"//cobalt/browser:browser",
"//cobalt/browser:generated_bindings",
"//cobalt/browser:generated_types",
+ "//cobalt/browser:test_dependencies_on_browser",
"//cobalt/css_parser",
"//cobalt/cssom",
"//cobalt/dom/testing:dom_testing",
diff --git a/cobalt/worker/dedicated_worker.cc b/cobalt/worker/dedicated_worker.cc
index 489a987..783cead 100644
--- a/cobalt/worker/dedicated_worker.cc
+++ b/cobalt/worker/dedicated_worker.cc
@@ -28,10 +28,6 @@
namespace cobalt {
namespace worker {
-namespace {
-const char kDedicatedWorkerName[] = "DedicatedWorker";
-} // namespace
-
DedicatedWorker::DedicatedWorker(script::EnvironmentSettings* settings,
const std::string& scriptURL,
script::ExceptionState* exception_state)
@@ -111,7 +107,7 @@
options.construction_location.file_path =
environment_settings()->creation_url().spec();
}
- worker_.reset(new Worker(kDedicatedWorkerName, options));
+ worker_.reset(new Worker(WorkerConsts::kDedicatedWorkerName, options));
// 10. Return worker.
}
diff --git a/cobalt/worker/service_worker_consts.cc b/cobalt/worker/service_worker_consts.cc
deleted file mode 100644
index 4254b85..0000000
--- a/cobalt/worker/service_worker_consts.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2023 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/worker/service_worker_consts.h"
-
-namespace cobalt {
-namespace worker {
-const char ServiceWorkerConsts::kServiceWorkerRegisterBadMIMEError[] =
- "Service Worker Register failed: The script has an unsupported MIME type "
- "('%s').";
-
-const char ServiceWorkerConsts::kServiceWorkerRegisterNoMIMEError[] =
- "Service Worker Register failed: The script does not have a MIME type.";
-
-const char
- ServiceWorkerConsts::kServiceWorkerRegisterScriptOriginNotSameError[] =
- "Service Worker Register failed: Script URL ('%s') and referrer ('%s') "
- "origin are not the same.";
-
-const char
- ServiceWorkerConsts::kServiceWorkerRegisterScopeOriginNotSameError[] =
- "Service Worker Register failed: Scope URL ('%s') and referrer ('%s') "
- "origin are not the same.";
-
-const char ServiceWorkerConsts::kServiceWorkerRegisterBadScopeError[] =
- "Service Worker Register failed: Scope ('%s') is not allowed.";
-
-const char
- ServiceWorkerConsts::kServiceWorkerUnregisterScopeOriginNotSameError[] =
- "Service Worker Unregister failed: Scope origin does not match.";
-
-const char ServiceWorkerConsts::kServiceWorkerAllowed[] =
- "Service-Worker-Allowed";
-
-const char ServiceWorkerConsts::kSettingsJson[] =
- "service_worker_settings.json";
-
-const char* const ServiceWorkerConsts::kJavaScriptMimeTypes[16] = {
- "application/ecmascript",
- "application/javascript",
- "application/x-ecmascript",
- "application/x-javascript",
- "text/ecmascript",
- "text/javascript",
- "text/javascript1.0",
- "text/javascript1.1",
- "text/javascript1.2",
- "text/javascript1.3",
- "text/javascript1.4",
- "text/javascript1.5",
- "text/jscript",
- "text/livescript",
- "text/x-ecmascript",
- "text/x-javascript"};
-} // namespace worker
-} // namespace cobalt
diff --git a/cobalt/worker/service_worker_consts.h b/cobalt/worker/service_worker_consts.h
deleted file mode 100644
index 5bb8dd1..0000000
--- a/cobalt/worker/service_worker_consts.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2023 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 COBALT_WORKER_SERVICE_WORKER_CONSTS_H_
-#define COBALT_WORKER_SERVICE_WORKER_CONSTS_H_
-
-namespace cobalt {
-namespace worker {
-
-struct ServiceWorkerConsts {
- // Constants for error messages.
- static const char kServiceWorkerRegisterBadMIMEError[];
- static const char kServiceWorkerRegisterNoMIMEError[];
- static const char kServiceWorkerRegisterScriptOriginNotSameError[];
- static const char kServiceWorkerRegisterScopeOriginNotSameError[];
- static const char kServiceWorkerRegisterBadScopeError[];
- static const char kServiceWorkerUnregisterScopeOriginNotSameError[];
- static const char kServiceWorkerAllowed[];
-
- // Constants for ServiceWorkerPersistentSettings
- static const char kSettingsJson[];
-
- // Array of JavaScript mime types, according to the MIME Sniffinc spec:
- // https://mimesniff.spec.whatwg.org/#javascript-mime-type
- static const char* const kJavaScriptMimeTypes[16];
-};
-
-} // namespace worker
-} // namespace cobalt
-
-#endif // COBALT_WORKER_SERVICE_WORKER_CONSTS_H_
diff --git a/cobalt/worker/service_worker_context.cc b/cobalt/worker/service_worker_context.cc
index 5c39206..b4b4bac 100644
--- a/cobalt/worker/service_worker_context.cc
+++ b/cobalt/worker/service_worker_context.cc
@@ -376,6 +376,16 @@
service_worker_object->ObtainWebAgentAndWaitUntilDone();
}
+void ServiceWorkerContext::EraseRegistrationMap() {
+ if (message_loop() != base::MessageLoop::current()) {
+ message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&ServiceWorkerContext::EraseRegistrationMap,
+ base::Unretained(this)));
+ return;
+ }
+ scope_to_registration_map_->DeletePersistentSettings();
+}
+
std::string* ServiceWorkerContext::RunServiceWorker(ServiceWorkerObject* worker,
bool force_bypass_cache) {
TRACE_EVENT0("cobalt::worker", "ServiceWorkerContext::RunServiceWorker()");
diff --git a/cobalt/worker/service_worker_context.h b/cobalt/worker/service_worker_context.h
index 1446fe8..e51882d 100644
--- a/cobalt/worker/service_worker_context.h
+++ b/cobalt/worker/service_worker_context.h
@@ -150,6 +150,8 @@
const GURL& client_url,
base::WaitableEvent* done_event);
+ void EraseRegistrationMap();
+
ServiceWorkerJobs* jobs() { return jobs_.get(); }
ServiceWorkerRegistrationMap* registration_map() {
return scope_to_registration_map_.get();
diff --git a/cobalt/worker/service_worker_jobs.cc b/cobalt/worker/service_worker_jobs.cc
index 5c93575..fa0451b 100644
--- a/cobalt/worker/service_worker_jobs.cc
+++ b/cobalt/worker/service_worker_jobs.cc
@@ -325,8 +325,7 @@
PromiseErrorData(
web::DOMException::kSecurityErr,
base::StringPrintf(
- ServiceWorkerConsts::
- kServiceWorkerRegisterScriptOriginNotSameError,
+ WorkerConsts::kServiceWorkerRegisterScriptOriginNotSameError,
job->script_url.spec().c_str(), job->referrer.spec().c_str())));
// 2.2. Invoke Finish Job with job and abort these steps.
FinishJob(job);
@@ -343,8 +342,7 @@
PromiseErrorData(
web::DOMException::kSecurityErr,
base::StringPrintf(
- ServiceWorkerConsts::
- kServiceWorkerRegisterScopeOriginNotSameError,
+ WorkerConsts::kServiceWorkerRegisterScopeOriginNotSameError,
job->scope_url.spec().c_str(), job->referrer.spec().c_str())));
// 3.2. Invoke Finish Job with job and abort these steps.
@@ -491,12 +489,11 @@
if (content_type.empty()) {
RejectJobPromise(
state->job,
- PromiseErrorData(
- web::DOMException::kSecurityErr,
- ServiceWorkerConsts::kServiceWorkerRegisterNoMIMEError));
+ PromiseErrorData(web::DOMException::kSecurityErr,
+ WorkerConsts::kServiceWorkerRegisterNoMIMEError));
return true;
}
- for (auto mime_type : ServiceWorkerConsts::kJavaScriptMimeTypes) {
+ for (auto mime_type : WorkerConsts::kJavaScriptMimeTypes) {
if (net::MatchesMimeType(mime_type, content_type)) {
mime_type_is_javascript = true;
break;
@@ -511,16 +508,15 @@
state->job,
PromiseErrorData(
web::DOMException::kSecurityErr,
- base::StringPrintf(
- ServiceWorkerConsts::kServiceWorkerRegisterBadMIMEError,
- content_type.c_str())));
+ base::StringPrintf(WorkerConsts::kServiceWorkerRegisterBadMIMEError,
+ content_type.c_str())));
return true;
}
// 8.8. Let serviceWorkerAllowed be the result of extracting header list
// values given `Service-Worker-Allowed` and response’s header list.
std::string service_worker_allowed;
bool service_worker_allowed_exists = headers->GetNormalizedHeader(
- ServiceWorkerConsts::kServiceWorkerAllowed, &service_worker_allowed);
+ WorkerConsts::kServiceWorkerAllowed, &service_worker_allowed);
// 8.9. Set policyContainer to the result of creating a policy container
// from a fetch response given response.
state->script_headers = headers;
@@ -564,11 +560,10 @@
// 8.16.2. Asynchronously complete these steps with a network error.
RejectJobPromise(
state->job,
- PromiseErrorData(
- web::DOMException::kSecurityErr,
- base::StringPrintf(
- ServiceWorkerConsts::kServiceWorkerRegisterBadScopeError,
- scope_string.c_str())));
+ PromiseErrorData(web::DOMException::kSecurityErr,
+ base::StringPrintf(
+ WorkerConsts::kServiceWorkerRegisterBadScopeError,
+ scope_string.c_str())));
return true;
}
return true;
@@ -722,7 +717,7 @@
// 11. Let worker be a new service worker.
ServiceWorkerObject::Options options(
- "ServiceWorker", state->job->client->web_settings(),
+ WorkerConsts::kServiceWorkerName, state->job->client->web_settings(),
state->job->client->network_module(), state->registration);
options.web_options.platform_info = state->job->client->platform_info();
options.web_options.service_worker_context =
@@ -1014,9 +1009,9 @@
// 1.1. Invoke Reject Job Promise with job and "SecurityError" DOMException.
RejectJobPromise(
job,
- PromiseErrorData(web::DOMException::kSecurityErr,
- ServiceWorkerConsts::
- kServiceWorkerUnregisterScopeOriginNotSameError));
+ PromiseErrorData(
+ web::DOMException::kSecurityErr,
+ WorkerConsts::kServiceWorkerUnregisterScopeOriginNotSameError));
// 1.2. Invoke Finish Job with job and abort these steps.
FinishJob(job);
diff --git a/cobalt/worker/service_worker_persistent_settings.cc b/cobalt/worker/service_worker_persistent_settings.cc
index f74d63f..fc81821 100644
--- a/cobalt/worker/service_worker_persistent_settings.cc
+++ b/cobalt/worker/service_worker_persistent_settings.cc
@@ -30,11 +30,11 @@
#include "cobalt/script/promise.h"
#include "cobalt/script/script_value.h"
#include "cobalt/web/cache_utils.h"
-#include "cobalt/worker/service_worker_consts.h"
#include "cobalt/worker/service_worker_context.h"
#include "cobalt/worker/service_worker_jobs.h"
#include "cobalt/worker/service_worker_registration_object.h"
#include "cobalt/worker/service_worker_update_via_cache.h"
+#include "cobalt/worker/worker_consts.h"
#include "cobalt/worker/worker_global_scope.h"
#include "net/base/completion_once_callback.h"
#include "net/disk_cache/cobalt/resource_type.h"
@@ -88,7 +88,7 @@
const Options& options)
: options_(options) {
persistent_settings_.reset(new cobalt::persistent_storage::PersistentSettings(
- ServiceWorkerConsts::kSettingsJson));
+ WorkerConsts::kSettingsJson));
persistent_settings_->ValidatePersistentSettings();
DCHECK(persistent_settings_);
}
@@ -110,7 +110,7 @@
persistent_settings_->GetPersistentSettingAsDictionary(key_string);
if (dict.empty()) {
DLOG(INFO) << "Key: " << key_string << " does not exist in "
- << ServiceWorkerConsts::kSettingsJson;
+ << WorkerConsts::kSettingsJson;
continue;
}
if (!CheckPersistentValue(key_string, kSettingsStorageKeyKey, dict,
@@ -461,5 +461,9 @@
}
}
+void ServiceWorkerPersistentSettings::DeleteAll(base::OnceClosure closure) {
+ persistent_settings_->DeletePersistentSettings(std::move(closure));
+}
+
} // namespace worker
} // namespace cobalt
diff --git a/cobalt/worker/service_worker_persistent_settings.h b/cobalt/worker/service_worker_persistent_settings.h
index e595acb..f855895 100644
--- a/cobalt/worker/service_worker_persistent_settings.h
+++ b/cobalt/worker/service_worker_persistent_settings.h
@@ -87,6 +87,8 @@
void RemoveAll();
+ void DeleteAll(base::OnceClosure closure);
+
private:
Options options_;
diff --git a/cobalt/worker/service_worker_registration_map.cc b/cobalt/worker/service_worker_registration_map.cc
index 3532094..24bfd5d 100644
--- a/cobalt/worker/service_worker_registration_map.cc
+++ b/cobalt/worker/service_worker_registration_map.cc
@@ -61,8 +61,6 @@
new ServiceWorkerPersistentSettings(options));
DCHECK(service_worker_persistent_settings_);
- // TODO(b/259731731) For now do not read from persisted settings until
- // activation of persisted registrations works.
ReadPersistentSettings();
}
@@ -71,6 +69,15 @@
registration_map_);
}
+void ServiceWorkerRegistrationMap::DeletePersistentSettings() {
+ base::OnceClosure closure = base::BindOnce(
+ [](std::map<RegistrationMapKey,
+ scoped_refptr<ServiceWorkerRegistrationObject>>*
+ registration_map) { (*registration_map).clear(); },
+ ®istration_map_);
+ service_worker_persistent_settings_->DeleteAll(std::move(closure));
+}
+
scoped_refptr<ServiceWorkerRegistrationObject>
ServiceWorkerRegistrationMap::MatchServiceWorkerRegistration(
const url::Origin& storage_key, const GURL& client_url) {
diff --git a/cobalt/worker/service_worker_registration_map.h b/cobalt/worker/service_worker_registration_map.h
index 591f58f..421e6f8 100644
--- a/cobalt/worker/service_worker_registration_map.h
+++ b/cobalt/worker/service_worker_registration_map.h
@@ -81,6 +81,8 @@
void ReadPersistentSettings();
+ void DeletePersistentSettings();
+
private:
// ThreadChecker for use by the methods operating on the registration map.
THREAD_CHECKER(thread_checker_);
diff --git a/cobalt/worker/worker.cc b/cobalt/worker/worker.cc
index d01d252..28ee68e 100644
--- a/cobalt/worker/worker.cc
+++ b/cobalt/worker/worker.cc
@@ -174,9 +174,19 @@
// 1. Set request's reserved client to inside settings.
// 2. Fetch request, and asynchronously wait to run the remaining steps as
// part of fetch's process response for the response response.
+ DCHECK(web_context_);
+ DCHECK(web_context_->environment_settings());
const GURL& url = web_context_->environment_settings()->creation_url();
+ DCHECK(!url.is_empty());
loader::Origin origin = loader::Origin(url.GetOrigin());
+ DCHECK(options_.outside_context);
+
+ // Window thread may remove its global object before destroying worker.
+ if (!options_.outside_context->GetWindowOrWorkerGlobalScope()) {
+ return;
+ }
+
csp::SecurityCallback csp_callback = base::Bind(
&web::CspDelegate::CanLoad,
base::Unretained(options_.outside_context->GetWindowOrWorkerGlobalScope()
diff --git a/cobalt/worker/worker.h b/cobalt/worker/worker.h
index d37d462..364837a 100644
--- a/cobalt/worker/worker.h
+++ b/cobalt/worker/worker.h
@@ -63,13 +63,13 @@
base::SourceLocation construction_location;
// True if worker is a SharedWorker object, and false otherwise.
- bool is_shared;
+ bool is_shared = false;
// Parameters from 'Run a worker' step 9.1 in the spec.
// https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#dom-worker
GURL url;
web::Context* outside_context = nullptr;
- web::EventTarget* outside_event_target;
+ web::EventTarget* outside_event_target = nullptr;
web::MessagePort* outside_port = nullptr;
WorkerOptions options;
};
diff --git a/cobalt/worker/worker_consts.h b/cobalt/worker/worker_consts.h
new file mode 100644
index 0000000..9ee5c52
--- /dev/null
+++ b/cobalt/worker/worker_consts.h
@@ -0,0 +1,80 @@
+// Copyright 2023 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 COBALT_WORKER_WORKER_CONSTS_H_
+#define COBALT_WORKER_WORKER_CONSTS_H_
+
+namespace cobalt {
+namespace worker {
+
+namespace WorkerConsts {
+
+// Constants for error messages.
+constexpr const char kServiceWorkerRegisterBadMIMEError[] =
+ "Service Worker Register failed: The script has an unsupported MIME type "
+ "('%s').";
+constexpr const char kServiceWorkerRegisterNoMIMEError[] =
+ "Service Worker Register failed: The script does not have a MIME type.";
+constexpr const char kServiceWorkerRegisterScriptOriginNotSameError[] =
+ "Service Worker Register failed: Script URL ('%s') and referrer ('%s') "
+ "origin are not the same.";
+constexpr const char kServiceWorkerRegisterScopeOriginNotSameError[] =
+ "Service Worker Register failed: Scope URL ('%s') and referrer ('%s') "
+ "origin are not the same.";
+constexpr const char kServiceWorkerRegisterBadScopeError[] =
+ "Service Worker Register failed: Scope ('%s') is not allowed.";
+constexpr const char kServiceWorkerUnregisterScopeOriginNotSameError[] =
+ "Service Worker Unregister failed: Scope origin does not match.";
+
+constexpr const char kServiceWorkerAllowed[] = "Service-Worker-Allowed";
+
+// Constants for ServiceWorkerPersistentSettings
+constexpr const char kSettingsJson[] = "service_worker_settings.json";
+
+// Array of JavaScript mime types, according to the MIME Sniffinc spec:
+// https://mimesniff.spec.whatwg.org/#javascript-mime-type
+constexpr const char* const kJavaScriptMimeTypes[16] = {
+ "application/ecmascript",
+ "application/javascript",
+ "application/x-ecmascript",
+ "application/x-javascript",
+ "text/ecmascript",
+ "text/javascript",
+ "text/javascript1.0",
+ "text/javascript1.1",
+ "text/javascript1.2",
+ "text/javascript1.3",
+ "text/javascript1.4",
+ "text/javascript1.5",
+ "text/jscript",
+ "text/livescript",
+ "text/x-ecmascript",
+ "text/x-javascript"};
+
+// The name of a Service Worker thread.
+constexpr const char kServiceWorkerName[] = "ServiceWorker";
+
+// The name of a Service Worker Registry thread.
+constexpr const char kServiceWorkerRegistryName[] = "ServiceWorkerRegistry";
+
+// The name of a Dedicated Worker thread.
+constexpr const char kDedicatedWorkerName[] = "DedicatedWorker";
+
+}; // namespace WorkerConsts
+
+
+} // namespace worker
+} // namespace cobalt
+
+#endif // COBALT_WORKER_WORKER_CONSTS_H_
diff --git a/cobalt/worker/worker_global_scope.cc b/cobalt/worker/worker_global_scope.cc
index 0f2372b..7bf72c0 100644
--- a/cobalt/worker/worker_global_scope.cc
+++ b/cobalt/worker/worker_global_scope.cc
@@ -31,8 +31,8 @@
#include "cobalt/web/user_agent_platform_info.h"
#include "cobalt/web/window_or_worker_global_scope.h"
#include "cobalt/web/window_timers.h"
-#include "cobalt/worker/service_worker_consts.h"
#include "cobalt/worker/service_worker_object.h"
+#include "cobalt/worker/worker_consts.h"
#include "cobalt/worker/worker_location.h"
#include "cobalt/worker/worker_navigator.h"
#include "net/base/mime_util.h"
@@ -169,7 +169,7 @@
std::string content_type;
bool mime_type_is_javascript = false;
if (headers->GetNormalizedHeader("Content-type", &content_type)) {
- for (auto mime_type : ServiceWorkerConsts::kJavaScriptMimeTypes) {
+ for (auto mime_type : WorkerConsts::kJavaScriptMimeTypes) {
if (net::MatchesMimeType(mime_type, content_type)) {
mime_type_is_javascript = true;
break;
@@ -177,13 +177,12 @@
}
}
if (content_type.empty()) {
- error->reset(new std::string(base::StringPrintf(
- ServiceWorkerConsts::kServiceWorkerRegisterNoMIMEError,
- content_type.c_str())));
+ error->reset(new std::string(
+ base::StringPrintf(WorkerConsts::kServiceWorkerRegisterNoMIMEError)));
} else if (!mime_type_is_javascript) {
- error->reset(new std::string(base::StringPrintf(
- ServiceWorkerConsts::kServiceWorkerRegisterBadMIMEError,
- content_type.c_str())));
+ error->reset(new std::string(
+ base::StringPrintf(WorkerConsts::kServiceWorkerRegisterBadMIMEError,
+ content_type.c_str())));
}
return true;
}
diff --git a/cobalt/worker/worker_global_scope.h b/cobalt/worker/worker_global_scope.h
index 9c3468f..49ce6d7 100644
--- a/cobalt/worker/worker_global_scope.h
+++ b/cobalt/worker/worker_global_scope.h
@@ -35,7 +35,7 @@
#include "cobalt/web/user_agent_platform_info.h"
#include "cobalt/web/window_or_worker_global_scope.h"
#include "cobalt/web/window_timers.h"
-#include "cobalt/worker/service_worker_consts.h"
+#include "cobalt/worker/worker_consts.h"
#include "cobalt/worker/worker_location.h"
#include "cobalt/worker/worker_navigator.h"
#include "net/http/http_response_headers.h"
diff --git a/components/update_client/BUILD.gn b/components/update_client/BUILD.gn
index d83b2e6..08c7c4d 100644
--- a/components/update_client/BUILD.gn
+++ b/components/update_client/BUILD.gn
@@ -246,10 +246,7 @@
"//starboard/loader_app:installation_manager",
"//testing/gmock",
"//testing/gtest",
+ # TODO: b/296919440 - Make this a data dep
+ "//starboard/loader_app($starboard_toolchain)",
]
- if (build_with_separate_cobalt_toolchain) {
- data_deps = [ "//starboard/loader_app($starboard_toolchain)" ]
- } else {
- deps += [ "//starboard/loader_app" ]
- }
}
diff --git a/content/browser/speech/BUILD.gn b/content/browser/speech/BUILD.gn
index 6e5ae30..21ba4c7 100644
--- a/content/browser/speech/BUILD.gn
+++ b/content/browser/speech/BUILD.gn
@@ -39,6 +39,7 @@
]
deps = [
":speech",
+ "//cobalt//browser:test_dependencies_on_browser",
"//cobalt/media",
"//cobalt/test:run_all_unittests",
"//starboard",
diff --git a/docker/docsite/Dockerfile b/docker/docsite/Dockerfile
index 6b1bd9d..2e164c8 100644
--- a/docker/docsite/Dockerfile
+++ b/docker/docsite/Dockerfile
@@ -46,7 +46,10 @@
RUN mkdir /project_out_dir \
&& chown ${USER:-defaultuser}:defaultgroup /project_out_dir
+<<<<<<< HEAD
RUN git config --global --add safe.directory /code
+=======
+>>>>>>> 77f6a7c80d7 (Fix git config for /code in Linux containers (#611))
COPY Gemfile /app/Gemfile
# Note: This file was generated by running a working version of this Docker
diff --git a/docker/linux/base/build/Dockerfile b/docker/linux/base/build/Dockerfile
index 38fa8ce..4d0306d 100644
--- a/docker/linux/base/build/Dockerfile
+++ b/docker/linux/base/build/Dockerfile
@@ -110,5 +110,7 @@
&& echo ${CLANG_16_VER} >> ${CLANG_16_TC_HOME}/cr_build_revision \
&& rm clang-llvmorg-${CLANG_16_VER}.tgz
+RUN git config --global --add safe.directory /code
+
WORKDIR /code
CMD ["/usr/bin/python","--version"]
diff --git a/docker/windows/base/visualstudio2022/Dockerfile b/docker/windows/base/visualstudio2022/Dockerfile
index 780d9bf..a2722ff 100644
--- a/docker/windows/base/visualstudio2022/Dockerfile
+++ b/docker/windows/base/visualstudio2022/Dockerfile
@@ -31,13 +31,16 @@
-ArgumentList '--quiet --wait --norestart --nocache`
--installPath C:\BuildTools `
--add Microsoft.VisualStudio.Component.VC.CoreIde `
- --add Microsoft.VisualStudio.Component.VC.14.34.17.4.x86.x64 `
- --add Microsoft.VisualStudio.Component.VC.Llvm.Clang `
- --add Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset `
- --add Microsoft.VisualStudio.Component.Windows10SDK.18362';`
+ --add Microsoft.VisualStudio.Component.VC.14.34.17.4.x86.x64 `
+ --add Microsoft.VisualStudio.Component.VC.Llvm.Clang `
+ --add Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset `
+ --add Microsoft.VisualStudio.Component.Windows10SDK.18362'; `
Write-Host ('Cleaning up vs_buildtools.exe');`
Remove-Item -Force -Recurse ${env:ProgramFiles(x86)}\'Microsoft Visual Studio'\Installer;`
Remove-Item -Force -Recurse $env:TEMP\*;`
+ Remove-Item -Force -Recurse $env:ProgramData\'Package Cache'\;`
+ Remove-Item -Force -Recurse C:\BuildTools\VC\Tools\Llvm\ARM64;`
+ Remove-Item -Force -Recurse C:\BuildTools\Common7\IDE;`
Remove-Item C:\TEMP\vs_buildtools.exe
ENV VSINSTALLDIR "C:\BuildTools"
diff --git a/nb/BUILD.gn b/nb/BUILD.gn
index eb947a2..ff056c9 100644
--- a/nb/BUILD.gn
+++ b/nb/BUILD.gn
@@ -63,7 +63,9 @@
"//starboard/common",
]
- if (defined(has_nb_platform) && has_nb_platform) {
+ # TODO: b/295615064 Remove nb platform specific dependency.
+ if (defined(has_nb_platform) && has_nb_platform &&
+ current_toolchain == starboard_toolchain) {
deps += [ "//$starboard_path/nb:nb_platform" ]
}
}
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 0412e4d..e694523 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -198,7 +198,6 @@
"der/tag.cc",
"der/tag.h",
- # dial is a legacy Chromium component with heavy Cobalt modifications.
"base/arena.cc",
"base/arena.h",
"base/backoff_entry.cc",
@@ -344,18 +343,6 @@
"cookies/cookie_util.h",
"cookies/parsed_cookie.cc",
"cookies/parsed_cookie.h",
- "dial/dial_http_server.cc",
- "dial/dial_http_server.h",
- "dial/dial_service.cc",
- "dial/dial_service.h",
- "dial/dial_service_handler.h",
- "dial/dial_system_config.cc",
- "dial/dial_system_config.h",
- "dial/dial_system_config_starboard.cc",
- "dial/dial_udp_server.cc",
- "dial/dial_udp_server.h",
- "dial/dial_udp_socket_factory.cc",
- "dial/dial_udp_socket_factory.h",
"dns/address_sorter.h",
"dns/address_sorter.h",
"dns/address_sorter_starboard.cc",
@@ -3630,12 +3617,6 @@
"dns/record_rdata_unittest.cc",
"dns/serial_worker_unittest.cc",
- # dial is a legacy component we kept from old Chromium net.
- "dial/dial_http_server_unittest.cc",
- "dial/dial_service_unittest.cc",
- "dial/dial_test_helpers.h",
- "dial/dial_udp_server_unittests.cc",
-
# disk_cache component is disabled because only http cache depends on
# it and Cobalt does not support http cache yet.
# "disk_cache/backend_cleanup_tracker_unittest.cc",
@@ -4194,6 +4175,17 @@
]
}
+ if (enable_in_app_dial) {
+ sources += [
+ # DIAL server is Cobalt custom implementation. This is the wrong place for
+ # it and it should be moved to cobalt/network in the future.
+ "dial/dial_http_server_unittest.cc",
+ "dial/dial_service_unittest.cc",
+ "dial/dial_test_helpers.h",
+ "dial/dial_udp_server_unittests.cc",
+ ]
+ }
+
# Avoid compiler errors due to conversion from "0x00" to char.
if (is_win) {
if (!is_starboard) {
@@ -4234,6 +4226,9 @@
"//url",
"//url:url_features",
]
+ if (enable_in_app_dial) {
+ deps += [ ":cobalt_dial_server" ]
+ }
if (is_starboard) {
data_deps = [
@@ -4243,6 +4238,33 @@
"//third_party/icu:icudata",
]
}
+
+ if(use_cobalt_customizations) {
+ # TODO: b/296715826 - Fix unused symbols which cause linker errors for windows platform modular builds.
+ sources -= [
+ "http/http_stream_factory_job_controller_unittest.cc",
+ "http/http_stream_factory_unittest.cc",
+ "http/http_stream_parser_unittest.cc",
+ "quic/bidirectional_stream_quic_impl_unittest.cc",
+ "quic/crypto/proof_verifier_chromium_test.cc",
+ "quic/network_connection_unittest.cc",
+ "quic/properties_based_quic_server_info_test.cc",
+ "quic/quic_address_mismatch_test.cc",
+ "quic/quic_chromium_alarm_factory_test.cc",
+ "quic/quic_chromium_client_session_test.cc",
+ "quic/quic_chromium_client_stream_test.cc",
+ "quic/quic_chromium_connection_helper_test.cc",
+ "quic/quic_clock_skew_detector_test.cc",
+ "quic/quic_connectivity_probing_manager_test.cc",
+ "quic/quic_end_to_end_unittest.cc",
+ "quic/quic_http_stream_test.cc",
+ "quic/quic_network_transaction_unittest.cc",
+ "quic/quic_proxy_client_socket_unittest.cc",
+ "quic/quic_stream_factory_test.cc",
+ "quic/quic_utils_chromium_test.cc",
+ ]
+
+ }
}
static_library("test_support") {
@@ -4255,6 +4277,7 @@
# "disk_cache/disk_cache_test_util.cc",
# "disk_cache/disk_cache_test_util.h",
+ "base/directory_lister.h",
"base/test_data_stream.cc",
"base/test_data_stream.h",
"quic/quic_test_packet_maker.cc",
@@ -4421,6 +4444,16 @@
"//third_party/zlib",
"//url",
]
+
+ if(use_cobalt_customizations) {
+ # TODO: b/296715826 - Fix unused symbols which cause linker errors for windows platform modular builds.
+ sources -= [
+ "test/quic_simple_test_server.cc",
+ "test/quic_simple_test_server.h",
+ "quic/quic_test_packet_maker.cc",
+ "quic/quic_test_packet_maker.h",
+ ]
+ }
}
static_library("quic_test_tools") {
@@ -4659,3 +4692,28 @@
"//starboard/common",
]
}
+
+if (enable_in_app_dial) {
+static_library("cobalt_dial_server") {
+ sources = [
+ "dial/dial_http_server.cc",
+ "dial/dial_http_server.h",
+ "dial/dial_service.cc",
+ "dial/dial_service.h",
+ "dial/dial_service_handler.h",
+ "dial/dial_system_config.cc",
+ "dial/dial_system_config.h",
+ "dial/dial_system_config_starboard.cc",
+ "dial/dial_udp_server.cc",
+ "dial/dial_udp_server.h",
+ "dial/dial_udp_socket_factory.cc",
+ "dial/dial_udp_socket_factory.h",
+ ]
+ deps = [
+ ":http_server",
+ ":net",
+ "//base:base",
+ "//starboard/common",
+ ]
+ }
+}
diff --git a/net/base/directory_lister.h b/net/base/directory_lister.h
index 3f8b541..e5677e4 100644
--- a/net/base/directory_lister.h
+++ b/net/base/directory_lister.h
@@ -21,6 +21,7 @@
namespace net {
+#if !defined(USE_COBALT_CUSTOMIZATIONS)
// This class provides an API for asynchronously listing the contents of a
// directory on the filesystem. It runs a task on a background thread, and
// enumerates all files in the specified directory on that thread. Destroying
@@ -135,6 +136,37 @@
DISALLOW_COPY_AND_ASSIGN(DirectoryLister);
};
+#else
+
+// TODO b/296715826 Fix stubbed out class.
+class NET_EXPORT DirectoryLister {
+ public:
+ struct DirectoryListerData {
+ base::FileEnumerator::FileInfo info;
+ base::FilePath path;
+ base::FilePath absolute_path;
+ };
+ class DirectoryListerDelegate {
+ public:
+ virtual void OnListFile(const DirectoryListerData& data) = 0;
+
+ virtual void OnListDone(int error) = 0;
+
+ protected:
+ virtual ~DirectoryListerDelegate() {}
+ };
+ enum ListingType {};
+ DirectoryLister(const base::FilePath& dir,
+ DirectoryListerDelegate* delegate){};
+ DirectoryLister(const base::FilePath& dir,
+ ListingType type,
+ DirectoryListerDelegate* delegate){};
+ ~DirectoryLister(){};
+ void Start() {};
+ void Cancel() {};
+};
+
+#endif // !defined(USE_COBALT_CUSTOMIZATIONS)
} // namespace net
#endif // NET_BASE_DIRECTORY_LISTER_H_
diff --git a/net/base/net_export.h b/net/base/net_export.h
index 55cf986..29891cf 100644
--- a/net/base/net_export.h
+++ b/net/base/net_export.h
@@ -4,12 +4,16 @@
#ifndef NET_BASE_NET_EXPORT_H_
#define NET_BASE_NET_EXPORT_H_
-
// Defines NET_EXPORT so that functionality implemented by the net module can
// be exported to consumers, and NET_EXPORT_PRIVATE that allows unit tests to
// access features not intended to be used directly by real consumers.
-#if defined(COMPONENT_BUILD)
+#ifdef USE_COBALT_CUSTOMIZATIONS
+#include "starboard/configuration.h"
+#endif // USE_COBALT_CUSTOMIZATIONS
+
+#if defined(COMPONENT_BUILD) || SB_IS(MODULAR) && !SB_IS(EVERGREEN)
+
#if defined(WIN32)
#if defined(NET_IMPLEMENTATION)
@@ -30,7 +34,7 @@
#endif
#endif
-#else /// defined(COMPONENT_BUILD)
+#else // defined(COMPONENT_BUILD) || SB_IS(MODULAR) && !SB_IS(EVERGREEN)
#define NET_EXPORT
#define NET_EXPORT_PRIVATE
#endif
diff --git a/starboard/BUILD.gn b/starboard/BUILD.gn
index 630ec47..3ab468c 100644
--- a/starboard/BUILD.gn
+++ b/starboard/BUILD.gn
@@ -12,7 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import("//starboard/build/config/os_definitions.gni")
import("//starboard/build/config/starboard_target_type.gni")
+import("//starboard/contrib/cast/cast.gni")
group("gn_all") {
testonly = true
@@ -57,9 +59,8 @@
deps += [ "//starboard/benchmark" ]
}
- if (build_with_separate_cobalt_toolchain && is_cobalt_toolchain) {
- assert(sb_is_modular,
- "sb_is_modular should be set when building with cobalt_toolchain")
+ if (build_with_separate_cobalt_toolchain && use_contrib_cast) {
+ deps += [ "//starboard/contrib/cast/cast_starboard_api/samples:cast" ]
}
if (!sb_is_evergreen) {
@@ -68,7 +69,7 @@
if (sb_is_evergreen_compatible) {
deps += [ "//third_party/crashpad/client" ]
data_deps = [
- "//starboard/loader_app",
+ "//starboard/loader_app($starboard_toolchain)",
"//third_party/crashpad/handler:crashpad_handler(//$starboard_path/toolchain:native_target)",
]
}
@@ -89,7 +90,7 @@
"//starboard/client_porting/eztime",
]
- if (sb_is_modular) {
+ if (sb_is_modular && current_toolchain == cobalt_toolchain) {
public_deps += [
"//third_party/llvm-project/compiler-rt:compiler_rt",
"//third_party/llvm-project/libcxx:cxx",
@@ -98,11 +99,13 @@
]
if (sb_is_evergreen) {
public_deps += [ "//starboard/elf_loader:sabi_string" ]
- }
- if (build_with_separate_cobalt_toolchain) {
- data_deps = [ ":starboard_platform_group($starboard_toolchain)" ]
} else {
- public_deps += [ "//third_party/llvm-project/libunwind:unwind_evergreen" ]
+ data_deps = [ ":starboard_platform_group($starboard_toolchain)" ]
+ }
+
+ # TODO: b/295702296 Fix libunwind for modular builds.
+ if (sb_is_evergreen || is_host_win) {
+ public_deps += [ "//third_party/llvm-project/libunwind:unwind" ]
}
} else {
public_deps += [
@@ -110,7 +113,7 @@
"//starboard/common",
]
- if (!build_with_separate_cobalt_toolchain) {
+ if (!sb_is_modular || sb_is_evergreen) {
if (sb_is_evergreen_compatible) {
public_deps += [ "//third_party/crashpad/wrapper" ]
} else {
@@ -177,24 +180,8 @@
}
if (current_toolchain == starboard_toolchain) {
- target(starboard_target_type, "starboard_platform_group") {
- if (starboard_target_type == "shared_library") {
- build_loader = false
- }
- public_deps = [
- "//starboard/client_porting/cwrappers",
- "//starboard/client_porting/eztime",
- "//starboard/common",
- "//starboard/egl_and_gles",
- ]
- if (sb_is_evergreen_compatible) {
- public_deps += [ "//third_party/crashpad/wrapper" ]
- } else {
- public_deps += [ "//third_party/crashpad/wrapper:wrapper_stub" ]
- }
- if (!sb_is_modular) {
- public_deps += [ "//$starboard_path:starboard_platform" ]
- }
+ # This is the default 'starboard_platform_target'; use default properties
+ starboard_platform_target("starboard_platform_group") {
}
if (platform_tests_path == "") {
@@ -206,10 +193,17 @@
sources = [ "//starboard/common/test_main.cc" ]
public_deps = [
- ":starboard",
+ ":starboard_with_main",
"//testing/gmock",
"//testing/gtest",
]
}
}
+
+ group("starboard_with_main") {
+ public_deps = [ ":starboard" ]
+ if (sb_is_modular && !sb_is_evergreen) {
+ public_deps += [ "//$starboard_path:starboard_platform_with_main" ]
+ }
+ }
}
diff --git a/starboard/android/apk/app/CMakeLists.txt b/starboard/android/apk/app/CMakeLists.txt
index 8c7d129..d10920b 100644
--- a/starboard/android/apk/app/CMakeLists.txt
+++ b/starboard/android/apk/app/CMakeLists.txt
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Since libcoat.so is an "IMPORTED" library in CMake, in order to debug in
+# Since libcobalt.so is an "IMPORTED" library in CMake, in order to debug in
# Android Studio you have to manually set the debugger type so that LLDB will
# be started:
# Run -> Edit Configurations -> "app" -> Debugger -> Debug Type = Dual
@@ -65,18 +65,18 @@
set(skip_ninja_arg -n)
endif()
-# Run Cobalt ninja, and copy the result as our "IMPORTED" libcoat.so.
+# Run Cobalt ninja, and copy the result as our "IMPORTED" libcobalt.so.
# ("coat_lib" never gets created, so this runs every time.)
add_custom_command(OUTPUT coat_lib
COMMAND ${CMAKE_CURRENT_LIST_DIR}/cobalt-ninja.sh
${skip_ninja_arg} -C ${COBALT_PRODUCT_DIR} ${COBALT_TARGET}
COMMAND ${CMAKE_COMMAND} -E copy
${COBALT_LIBRARY_DIR}/lib${COBALT_TARGET}.so
- ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcoat.so
+ ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcobalt.so
)
if(EVERGREEN_COMPATIBLE)
- # Follow the pattern used to import libcoat.so, above.
+ # Follow the pattern used to import libcobalt.so, above.
add_custom_command(OUTPUT crashpad_handler_lib
COMMAND ${CMAKE_CURRENT_LIST_DIR}/cobalt-ninja.sh
${skip_ninja_arg} -C ${COBALT_PRODUCT_DIR} crashpad_handler
@@ -109,15 +109,15 @@
# We need a target (not a file) for the phony native dependency below.
add_custom_target(external_cobalt_build DEPENDS coat_lib cobalt_content)
-# Declare libcoat.so as a shared library that needs to be included in the APK.
+# Declare libcobalt.so as a shared library that needs to be included in the APK.
# However, Android Studio will build it as an "IMPORTED" library.
add_library(coat SHARED IMPORTED)
set_target_properties(coat PROPERTIES
- IMPORTED_LOCATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcoat.so
+ IMPORTED_LOCATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcobalt.so
)
if(EVERGREEN_COMPATIBLE)
- # Follow the pattern used to include libcoat.so, above.
+ # Follow the pattern used to include libcobalt.so, above.
add_library(crashpadhandler SHARED IMPORTED)
set_target_properties(crashpadhandler PROPERTIES
IMPORTED_LOCATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcrashpad_handler.so
diff --git a/starboard/android/apk/app/src/app/AndroidManifest.xml b/starboard/android/apk/app/src/app/AndroidManifest.xml
index 0bece9b..6b2602d 100644
--- a/starboard/android/apk/app/src/app/AndroidManifest.xml
+++ b/starboard/android/apk/app/src/app/AndroidManifest.xml
@@ -50,7 +50,7 @@
<meta-data android:name="cobalt.APP_URL" android:value="https://www.youtube.com/tv"/>
<meta-data android:name="cobalt.SPLASH_URL" android:value="h5vcc-embedded://cobalt_splash_screen.html"/>
<meta-data android:name="cobalt.EVERGREEN_LITE" android:value="false"/>
- <meta-data android:name="android.app.lib_name" android:value="coat"/>
+ <meta-data android:name="android.app.lib_name" android:value="cobalt"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltHttpHelper.java b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltHttpHelper.java
index 56a2ffd..e5f5df8 100644
--- a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltHttpHelper.java
+++ b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltHttpHelper.java
@@ -25,6 +25,7 @@
/** Helper class that implements an HTTP POST function used by DRM one-time provisioning. */
public class CobaltHttpHelper {
+ private static final int HTTP_TIMEOUT_MILLIS = 10000;
private static final int RETRY_SLEEP_MILLIS = 250;
private static final int MAX_ATTEMPTS = 3;
@@ -72,6 +73,8 @@
private byte[] internalPerformHttpPost(String url) throws IOException, TransientFailure {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
try {
+ conn.setConnectTimeout(HTTP_TIMEOUT_MILLIS);
+ conn.setReadTimeout(HTTP_TIMEOUT_MILLIS);
conn.setRequestMethod("POST");
conn.setDoOutput(false);
conn.setDoInput(true);
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
index 2d719ad..61f4bca 100644
--- a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
+++ b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
@@ -85,7 +85,11 @@
static {
// Even though NativeActivity already loads our library from C++,
// we still have to load it from Java to make JNI calls into it.
- System.loadLibrary("coat");
+
+ // GameActivity has code to load the libcobalt.so as well.
+ // It reads the library name from the meta data field "android.app.lib_name" in the
+ // AndroidManifest.xml
+ System.loadLibrary("cobalt");
}
private final Context appContext;
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java b/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java
index 23ab5f3..ffcea69 100644
--- a/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java
+++ b/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java
@@ -535,41 +535,10 @@
if (mMediaDrm == null) {
throw new IllegalStateException("Cannot create media crypto with null mMediaDrm.");
}
- if (mMediaCryptoSession != null) {
- throw new IllegalStateException(
- "Cannot create media crypto with non-null mMediaCryptoSession.");
- }
- // TODO: Cannot do this during provisioning pending.
-
- // Open media crypto session.
- try {
- mMediaCryptoSession = openSession();
- } catch (NotProvisionedException e) {
- Log.d(TAG, "Device not provisioned", e);
- if (!attemptProvisioning()) {
- Log.e(TAG, "Failed to provision device during MediaCrypto creation.");
- return false;
- }
- try {
- mMediaCryptoSession = openSession();
- } catch (NotProvisionedException e2) {
- Log.e(TAG, "Device still not provisioned after supposedly successful provisioning", e2);
- return false;
- }
- }
-
- if (mMediaCryptoSession == null) {
- Log.e(TAG, "Cannot create MediaCrypto Session.");
- return false;
- }
- Log.d(
- TAG,
- String.format("MediaCrypto Session created: %s", bytesToHexString(mMediaCryptoSession)));
-
// Create MediaCrypto object.
try {
if (MediaCrypto.isCryptoSchemeSupported(mSchemeUUID)) {
- MediaCrypto mediaCrypto = new MediaCrypto(mSchemeUUID, mMediaCryptoSession);
+ MediaCrypto mediaCrypto = new MediaCrypto(mSchemeUUID, new byte[0]);
Log.d(TAG, "MediaCrypto successfully created!");
mMediaCrypto = mediaCrypto;
return true;
@@ -580,14 +549,6 @@
Log.e(TAG, "Cannot create MediaCrypto", e);
}
- try {
- // Some implementations let this method throw exceptions.
- mMediaDrm.closeSession(mMediaCryptoSession);
- } catch (Exception e) {
- Log.e(TAG, "closeSession failed: ", e);
- }
- mMediaCryptoSession = null;
-
return false;
}
@@ -621,6 +582,59 @@
}
}
+ @UsedByNative
+ boolean createMediaCryptoSession() {
+ if (mMediaCryptoSession != null) {
+ return true;
+ }
+ Log.w(TAG, "MediaDrmBridge createMediaCryptoSession");
+ if (mMediaCrypto == null) {
+ throw new IllegalStateException("Cannot create media crypto session with null mMediaCrypto.");
+ }
+
+ // Open media crypto session.
+ try {
+ mMediaCryptoSession = openSession();
+ } catch (NotProvisionedException e) {
+ Log.w(TAG, "Device not provisioned", e);
+ if (!attemptProvisioning()) {
+ Log.e(TAG, "Failed to provision device during MediaCrypto creation.");
+ return false;
+ }
+ try {
+ mMediaCryptoSession = openSession();
+ } catch (NotProvisionedException e2) {
+ Log.e(TAG, "Device still not provisioned after supposedly successful provisioning", e2);
+ return false;
+ }
+ }
+
+ if (mMediaCryptoSession == null) {
+ Log.e(TAG, "Cannot create MediaCrypto Session.");
+ return false;
+ }
+
+ try {
+ mMediaCrypto.setMediaDrmSession(mMediaCryptoSession);
+ } catch (MediaCryptoException e3) {
+ Log.e(TAG, "Unable to set media drm session", e3);
+ try {
+ // Some implementations let this method throw exceptions.
+ mMediaDrm.closeSession(mMediaCryptoSession);
+ } catch (Exception e) {
+ Log.e(TAG, "closeSession failed: ", e);
+ }
+ mMediaCryptoSession = null;
+ return false;
+ }
+
+ Log.d(
+ TAG,
+ String.format("MediaCrypto Session created: %s", bytesToHexString(mMediaCryptoSession)));
+
+ return true;
+ }
+
/**
* Attempt to get the device that we are currently running on provisioned.
*
diff --git a/starboard/android/arm/toolchain/BUILD.gn b/starboard/android/arm/toolchain/BUILD.gn
index b49df51..6b167d1 100644
--- a/starboard/android/arm/toolchain/BUILD.gn
+++ b/starboard/android/arm/toolchain/BUILD.gn
@@ -21,7 +21,6 @@
cc = "$prefix/armv7a-linux-androideabi${android_ndk_api_level}-clang"
cxx = "$prefix/armv7a-linux-androideabi${android_ndk_api_level}-clang++"
ld = cxx
- ar = "$prefix/arm-linux-androideabi-readelf"
ar = "ar"
nm = "nm"
@@ -35,7 +34,6 @@
cc = "$prefix/armv7a-linux-androideabi${android_ndk_api_level}-clang"
cxx = "$prefix/armv7a-linux-androideabi${android_ndk_api_level}-clang++"
ld = cxx
- ar = "$prefix/arm-linux-androideabi-readelf"
ar = "ar"
nm = "nm"
diff --git a/starboard/android/shared/application_android.cc b/starboard/android/shared/application_android.cc
index 0334d1f..33b26ad 100644
--- a/starboard/android/shared/application_android.cc
+++ b/starboard/android/shared/application_android.cc
@@ -143,6 +143,7 @@
}
ApplicationAndroid::~ApplicationAndroid() {
+ // The application is exiting.
// Release the global reference.
if (resource_overlay_) {
JniEnvExt* env = JniEnvExt::Get();
@@ -156,6 +157,12 @@
ALooper_removeFd(looper_, keyboard_inject_readfd_);
close(keyboard_inject_readfd_);
close(keyboard_inject_writefd_);
+
+ {
+ // Signal for any potentially waiting window creation or destroy commands.
+ ScopedLock lock(android_command_mutex_);
+ android_command_condition_.Signal();
+ }
}
void ApplicationAndroid::Initialize() {
@@ -251,7 +258,10 @@
JniEnvExt* env = JniEnvExt::Get();
AndroidCommand cmd;
int err = read(android_command_readfd_, &cmd, sizeof(cmd));
- SB_DCHECK(err >= 0) << "Command read failed. errno=" << errno;
+ if (err < 0) {
+ SB_DCHECK(err >= 0) << "Command read failed. errno=" << errno;
+ return;
+ }
SB_LOG(INFO) << "Android command: " << AndroidCommandName(cmd.type);
@@ -394,7 +404,10 @@
SB_LOG(INFO) << "Send Android command: " << AndroidCommandName(type);
AndroidCommand cmd{type, data};
ScopedLock lock(android_command_mutex_);
- write(android_command_writefd_, &cmd, sizeof(cmd));
+ if (write(android_command_writefd_, &cmd, sizeof(cmd)) == -1) {
+ SB_LOG(ERROR) << "Writing Android command failed";
+ return;
+ }
// Synchronization only necessary when managing resources.
switch (type) {
case AndroidCommand::kNativeWindowCreated:
diff --git a/starboard/android/shared/application_android.h b/starboard/android/shared/application_android.h
index d023e74..e8917c1 100644
--- a/starboard/android/shared/application_android.h
+++ b/starboard/android/shared/application_android.h
@@ -56,8 +56,8 @@
kDeepLink,
} CommandType;
- CommandType type;
- void* data;
+ CommandType type = kUndefined;
+ void* data = nullptr;
};
#if SB_API_VERSION >= 15
diff --git a/starboard/android/shared/drm_system.cc b/starboard/android/shared/drm_system.cc
index 3b195e5..7897d3b 100644
--- a/starboard/android/shared/drm_system.cc
+++ b/starboard/android/shared/drm_system.cc
@@ -14,10 +14,15 @@
#include "starboard/android/shared/drm_system.h"
+#include <memory>
+#include <utility>
+
#include "starboard/android/shared/jni_env_ext.h"
#include "starboard/android/shared/jni_utils.h"
#include "starboard/android/shared/media_common.h"
+#include "starboard/common/atomic.h"
#include "starboard/common/instance_counter.h"
+#include "starboard/common/thread.h"
namespace {
@@ -177,7 +182,8 @@
SbDrmSessionUpdateRequestFunc update_request_callback,
SbDrmSessionUpdatedFunc session_updated_callback,
SbDrmSessionKeyStatusesChangedFunc key_statuses_changed_callback)
- : key_system_(key_system),
+ : Thread("DrmSystemThread"),
+ key_system_(key_system),
context_(context),
update_request_callback_(update_request_callback),
session_updated_callback_(session_updated_callback),
@@ -206,10 +212,35 @@
return;
}
j_media_crypto_ = env->ConvertLocalRefToGlobalRef(j_media_crypto_);
+
+ Start();
+}
+
+void DrmSystem::Run() {
+ JniEnvExt* env = JniEnvExt::Get();
+ bool result = env->CallBooleanMethodOrAbort(
+ j_media_drm_bridge_, "createMediaCryptoSession", "()Z");
+ if (result) {
+ created_media_crypto_session_.store(true);
+ }
+ if (!result && j_media_crypto_) {
+ env->DeleteGlobalRef(j_media_crypto_);
+ j_media_crypto_ = NULL;
+ return;
+ }
+
+ ScopedLock scoped_lock(mutex_);
+ if (!deferred_session_update_requests_.empty()) {
+ for (const auto& update_request : deferred_session_update_requests_) {
+ update_request->Generate(j_media_drm_bridge_);
+ }
+ deferred_session_update_requests_.clear();
+ }
}
DrmSystem::~DrmSystem() {
ON_INSTANCE_RELEASED(AndroidDrmSystem);
+ Join();
JniEnvExt* env = JniEnvExt::Get();
if (j_media_crypto_) {
@@ -223,17 +254,64 @@
}
}
+DrmSystem::SessionUpdateRequest::SessionUpdateRequest(
+ int ticket,
+ const char* type,
+ const void* initialization_data,
+ int initialization_data_size) {
+ JniEnvExt* env = JniEnvExt::Get();
+ j_ticket_ = static_cast<jint>(ticket);
+ j_init_data_ =
+ ByteArrayFromRaw(initialization_data, initialization_data_size);
+ j_mime_ = env->NewStringStandardUTFOrAbort(type);
+}
+
+void DrmSystem::SessionUpdateRequest::ConvertLocalRefToGlobalRef() {
+ if (!references_are_global_) {
+ JniEnvExt* env = JniEnvExt::Get();
+ j_init_data_ = env->ConvertLocalRefToGlobalRef(j_init_data_);
+ j_mime_ = env->ConvertLocalRefToGlobalRef(j_mime_);
+ references_are_global_ = true;
+ }
+}
+
+DrmSystem::SessionUpdateRequest::~SessionUpdateRequest() {
+ JniEnvExt* env = JniEnvExt::Get();
+ if (references_are_global_) {
+ env->DeleteGlobalRef(j_init_data_);
+ env->DeleteGlobalRef(j_mime_);
+ } else {
+ env->DeleteLocalRef(j_init_data_);
+ env->DeleteLocalRef(j_mime_);
+ }
+ j_init_data_ = nullptr;
+ j_mime_ = nullptr;
+}
+
+void DrmSystem::SessionUpdateRequest::Generate(
+ jobject j_media_drm_bridge) const {
+ JniEnvExt* env = JniEnvExt::Get();
+ env->CallVoidMethodOrAbort(j_media_drm_bridge, "createSession",
+ "(I[BLjava/lang/String;)V", j_ticket_,
+ j_init_data_, j_mime_);
+}
+
void DrmSystem::GenerateSessionUpdateRequest(int ticket,
const char* type,
const void* initialization_data,
int initialization_data_size) {
- ScopedLocalJavaRef<jbyteArray> j_init_data(
- ByteArrayFromRaw(initialization_data, initialization_data_size));
- JniEnvExt* env = JniEnvExt::Get();
- ScopedLocalJavaRef<jstring> j_mime(env->NewStringStandardUTFOrAbort(type));
- env->CallVoidMethodOrAbort(
- j_media_drm_bridge_, "createSession", "(I[BLjava/lang/String;)V",
- static_cast<jint>(ticket), j_init_data.Get(), j_mime.Get());
+ std::unique_ptr<SessionUpdateRequest> session_update_request(
+ new SessionUpdateRequest(ticket, type, initialization_data,
+ initialization_data_size));
+ if (created_media_crypto_session_.load()) {
+ session_update_request->Generate(j_media_drm_bridge_);
+ } else {
+ // Defer generating the update request.
+ session_update_request->ConvertLocalRefToGlobalRef();
+ ScopedLock scoped_lock(mutex_);
+ deferred_session_update_requests_.push_back(
+ std::move(session_update_request));
+ }
// |update_request_callback_| will be called by Java calling into
// |onSessionMessage|.
}
diff --git a/starboard/android/shared/drm_system.h b/starboard/android/shared/drm_system.h
index 48051c5..f60d25b 100644
--- a/starboard/android/shared/drm_system.h
+++ b/starboard/android/shared/drm_system.h
@@ -18,21 +18,25 @@
#include "starboard/shared/starboard/drm/drm_system_internal.h"
#include <jni.h>
+#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
+#include "starboard/android/shared/jni_utils.h"
#include "starboard/android/shared/media_common.h"
+#include "starboard/common/atomic.h"
#include "starboard/common/log.h"
#include "starboard/common/mutex.h"
+#include "starboard/common/thread.h"
#include "starboard/types.h"
namespace starboard {
namespace android {
namespace shared {
-class DrmSystem : public ::SbDrmSystemPrivate {
+class DrmSystem : public ::SbDrmSystemPrivate, private Thread {
public:
DrmSystem(const char* key_system,
void* context,
@@ -81,9 +85,33 @@
return IsWidevineL1(key_system_.c_str());
}
+ // Return true when the drm system is ready for secure input buffers.
+ bool IsReady() { return created_media_crypto_session_.load(); }
+
private:
+ class SessionUpdateRequest {
+ public:
+ SessionUpdateRequest(int ticket,
+ const char* type,
+ const void* initialization_data,
+ int initialization_data_size);
+ ~SessionUpdateRequest();
+
+ void ConvertLocalRefToGlobalRef();
+ void Generate(jobject j_media_drm_bridge) const;
+
+ private:
+ bool references_are_global_ = false;
+ jint j_ticket_;
+ jobject j_init_data_;
+ jobject j_mime_;
+ };
+
void CallKeyStatusesChangedCallbackWithKeyStatusRestricted_Locked();
+ // From Thread.
+ void Run() override;
+
const std::string key_system_;
void* context_;
SbDrmSessionUpdateRequestFunc update_request_callback_;
@@ -94,9 +122,13 @@
jobject j_media_drm_bridge_;
jobject j_media_crypto_;
+ std::vector<std::unique_ptr<SessionUpdateRequest>>
+ deferred_session_update_requests_;
+
Mutex mutex_;
- std::unordered_map<std::string, std::vector<SbDrmKeyId> > cached_drm_key_ids_;
+ std::unordered_map<std::string, std::vector<SbDrmKeyId>> cached_drm_key_ids_;
bool hdcp_lost_;
+ atomic_bool created_media_crypto_session_;
std::vector<uint8_t> metrics_;
};
diff --git a/starboard/android/shared/media_decoder.cc b/starboard/android/shared/media_decoder.cc
index 721680e..78425b7 100644
--- a/starboard/android/shared/media_decoder.cc
+++ b/starboard/android/shared/media_decoder.cc
@@ -35,6 +35,9 @@
const jint kNoSize = 0;
const jint kNoBufferFlags = 0;
+// Delay to use after a retryable error has been encountered.
+const SbTime kErrorRetryDelay = 50 * kSbTimeMillisecond;
+
const char* GetNameForMediaCodecStatus(jint status) {
switch (status) {
case MEDIA_CODEC_OK:
@@ -461,15 +464,23 @@
jint status;
if (event.type == Event::kWriteCodecConfig) {
- status = media_codec_bridge_->QueueInputBuffer(dequeue_input_result.index,
- kNoOffset, size, kNoPts,
- BUFFER_FLAG_CODEC_CONFIG);
+ if (!drm_system_ || (drm_system_ && drm_system_->IsReady())) {
+ status = media_codec_bridge_->QueueInputBuffer(dequeue_input_result.index,
+ kNoOffset, size, kNoPts,
+ BUFFER_FLAG_CODEC_CONFIG);
+ } else {
+ status = MEDIA_CODEC_NO_KEY;
+ }
} else if (event.type == Event::kWriteInputBuffer) {
jlong pts_us = input_buffer->timestamp();
if (drm_system_ && input_buffer->drm_info()) {
- status = media_codec_bridge_->QueueSecureInputBuffer(
- dequeue_input_result.index, kNoOffset, *input_buffer->drm_info(),
- pts_us);
+ if (drm_system_->IsReady()) {
+ status = media_codec_bridge_->QueueSecureInputBuffer(
+ dequeue_input_result.index, kNoOffset, *input_buffer->drm_info(),
+ pts_us);
+ } else {
+ status = MEDIA_CODEC_NO_KEY;
+ }
} else {
status = media_codec_bridge_->QueueInputBuffer(
dequeue_input_result.index, kNoOffset, size, pts_us, kNoBufferFlags);
@@ -534,6 +545,7 @@
SB_LOG(INFO) << "|" << action_name << "| failed with status: "
<< GetNameForMediaCodecStatus(status)
<< ", will try again after a delay.";
+ SbThreadYield();
} else {
SB_LOG(ERROR) << "|" << action_name << "| failed with status: "
<< GetNameForMediaCodecStatus(status) << ".";
diff --git a/starboard/android/shared/media_get_audio_configuration.cc b/starboard/android/shared/media_get_audio_configuration.cc
index dbd658f..6b645b6 100644
--- a/starboard/android/shared/media_get_audio_configuration.cc
+++ b/starboard/android/shared/media_get_audio_configuration.cc
@@ -17,6 +17,7 @@
#include "starboard/android/shared/jni_env_ext.h"
#include "starboard/android/shared/jni_utils.h"
#include "starboard/android/shared/media_capabilities_cache.h"
+#include "starboard/common/media.h"
// Constants for output types from
// https://developer.android.com/reference/android/media/AudioDeviceInfo.
@@ -129,11 +130,19 @@
bool SbMediaGetAudioConfiguration(
int output_index,
SbMediaAudioConfiguration* out_configuration) {
+ using starboard::GetMediaAudioConnectorName;
using starboard::android::shared::JniEnvExt;
using starboard::android::shared::MediaCapabilitiesCache;
using starboard::android::shared::ScopedLocalJavaRef;
- if (output_index < 0 || out_configuration == NULL) {
+ if (output_index < 0) {
+ SB_LOG(WARNING) << "output_index is " << output_index
+ << ", which cannot be negative.";
+ return false;
+ }
+
+ if (out_configuration == nullptr) {
+ SB_LOG(WARNING) << "out_configuration cannot be nullptr.";
return false;
}
@@ -152,6 +161,8 @@
output_index, j_output_device_info.Get());
if (!succeeded) {
+ SB_LOG(WARNING)
+ << "Call to AudioOutputManager.getOutputDeviceInfo() failed.";
return false;
}
@@ -171,9 +182,8 @@
int channels =
MediaCapabilitiesCache::GetInstance()->GetMaxAudioOutputChannels();
if (channels < 2) {
- SB_LOG(WARNING)
- << "The supported channels from output device is smaller than 2. "
- "Fallback to 2 channels";
+ SB_LOG(WARNING) << "The supported channels from output device is "
+ << channels << ", set to 2 channels instead.";
out_configuration->number_of_channels = 2;
} else {
out_configuration->number_of_channels = channels;
@@ -182,5 +192,10 @@
out_configuration->number_of_channels = 2;
}
+ SB_LOG(INFO) << "Audio connector type for index " << output_index << " is "
+ << GetMediaAudioConnectorName(out_configuration->connector)
+ << " and it has " << out_configuration->number_of_channels
+ << " channels.";
+
return true;
}
diff --git a/starboard/android/shared/media_get_audio_output_count.cc b/starboard/android/shared/media_get_audio_output_count.cc
index befefd3..0c4d473 100644
--- a/starboard/android/shared/media_get_audio_output_count.cc
+++ b/starboard/android/shared/media_get_audio_output_count.cc
@@ -15,6 +15,9 @@
#include "starboard/media.h"
int SbMediaGetAudioOutputCount() {
- // Only supports one HDMI output.
- return 1;
+ // TODO(b/284140486, b/297426689): Tentatively returns 16 to ensure that all
+ // audio output devices are checked in `IsAudioOutputSupported()`. We should
+ // revisit this, and probably remove `SbMediaGetAudioOutputCount()` completely
+ // from Starboard.
+ return 16;
}
diff --git a/starboard/build/config/BUILD.gn b/starboard/build/config/BUILD.gn
index 0c816e8..6a0290a 100644
--- a/starboard/build/config/BUILD.gn
+++ b/starboard/build/config/BUILD.gn
@@ -92,7 +92,7 @@
config("target") {
if (current_toolchain != host_toolchain) {
if (final_executable_type == "shared_library") {
- if (!build_with_separate_cobalt_toolchain) {
+ if (!sb_is_modular || sb_is_evergreen) {
# Rewrite main() functions into StarboardMain. TODO: This is a
# hack, it would be better to be more surgical, here.
defines = [ "main=StarboardMain" ]
@@ -229,7 +229,8 @@
# override flags specified in a platform's "platform_configuration" config,
# which is where these particular flags would otherwise naturally fit.
config("default_compiler_flags") {
- if (is_starboardized_toolchain && sb_is_modular && target_cpu == "arm") {
+ if (is_starboardized_toolchain && sb_is_modular &&
+ current_toolchain == cobalt_toolchain && target_cpu == "arm") {
cflags = [ "-mfpu=vfpv3" ]
asmflags = cflags
}
diff --git a/starboard/build/config/BUILDCONFIG.gn b/starboard/build/config/BUILDCONFIG.gn
index 6c7d409..4075ed3 100644
--- a/starboard/build/config/BUILDCONFIG.gn
+++ b/starboard/build/config/BUILDCONFIG.gn
@@ -99,13 +99,7 @@
host_toolchain = "//starboard/build/toolchain/$host_os:$_host_toolchain_cpu"
if (build_with_separate_cobalt_toolchain) {
- # TODO(b/294450490): decide a way to set cobalt_toolchain for modular builds for all platforms.
- # we'll need more conditionals for other platforms.
- if (host_os == "win") {
- cobalt_toolchain = "//$starboard_path/toolchain:cobalt"
- } else {
- cobalt_toolchain = "//starboard/build/toolchain:clang"
- }
+ cobalt_toolchain = "//starboard/build/toolchain:clang"
starboard_toolchain = "//$starboard_path/toolchain:starboard"
} else {
cobalt_toolchain = "//$starboard_path/toolchain:target"
@@ -117,6 +111,9 @@
import("//$starboard_path/platform_configuration/configuration.gni")
import("//starboard/build/config/build_assertions.gni")
+# TODO(b/295399926) Clean up flag by moving to modular/helper_var.gni
+sb_is_modular = sb_is_evergreen || build_with_separate_cobalt_toolchain
+
declare_args() {
use_tsan = getenv("USE_TSAN") == 1
}
diff --git a/starboard/build/config/os_definitions.gni b/starboard/build/config/os_definitions.gni
index 6a5747b..16c48ef 100644
--- a/starboard/build/config/os_definitions.gni
+++ b/starboard/build/config/os_definitions.gni
@@ -31,3 +31,5 @@
is_apple = is_ios || is_mac
is_posix = !is_win && !is_fuchsia
+
+is_host_win = host_os == "win" || host_os == "winuwp"
diff --git a/starboard/build/config/starboard_target_type.gni b/starboard/build/config/starboard_target_type.gni
index 0c3983a..c1ebc17 100644
--- a/starboard/build/config/starboard_target_type.gni
+++ b/starboard/build/config/starboard_target_type.gni
@@ -17,9 +17,36 @@
}
if (starboard_target_type == "") {
- if (build_with_separate_cobalt_toolchain) {
+ if (sb_is_modular && !sb_is_evergreen) {
starboard_target_type = "shared_library"
} else {
starboard_target_type = "group"
}
}
+
+template("starboard_platform_target") {
+ target(starboard_target_type, target_name) {
+ forward_variables_from(invoker, [ "extra_configs" ])
+
+ if (defined(invoker.extra_configs)) {
+ configs += extra_configs
+ }
+ if (starboard_target_type == "shared_library") {
+ build_loader = false
+ }
+ public_deps = [
+ "//starboard/client_porting/cwrappers",
+ "//starboard/client_porting/eztime",
+ "//starboard/common",
+ "//starboard/egl_and_gles",
+ ]
+ if (sb_is_evergreen_compatible) {
+ public_deps += [ "//third_party/crashpad/wrapper" ]
+ } else {
+ public_deps += [ "//third_party/crashpad/wrapper:wrapper_stub" ]
+ }
+ if (!sb_is_evergreen) {
+ public_deps += [ "//$starboard_path:starboard_platform" ]
+ }
+ }
+}
diff --git a/starboard/build/toolchain/BUILD.gn b/starboard/build/toolchain/BUILD.gn
index 2bfec6e..21a6a3c 100644
--- a/starboard/build/toolchain/BUILD.gn
+++ b/starboard/build/toolchain/BUILD.gn
@@ -13,8 +13,59 @@
# limitations under the License.
import("//build/config/clang/clang.gni")
+import("//build/config/win/visual_studio_version.gni")
import("//build/toolchain/gcc_toolchain.gni")
+import("//starboard/build/config/os_definitions.gni")
-clang_toolchain("clang") {
- clang_base_path = clang_base_path
+# Use this toolchain for linux-x64 platforms.
+if (is_linux && !using_old_compiler && target_cpu == "x64") {
+ clang_toolchain("clang") {
+ clang_base_path = clang_base_path
+ }
+} else {
+ import("//$starboard_path/toolchain/variables.gni")
+ assert(
+ defined(native_linker_path),
+ "native_linker_path should be defined in $starboard_path/toolchain/variables.gni")
+}
+
+# Use this toolchain for raspi platforms, old linux compiler platforms.
+if ((is_linux && target_cpu == "arm") || (using_old_compiler && !is_host_win)) {
+ gcc_toolchain("clang") {
+ prefix = rebase_path("$clang_base_path/bin", root_build_dir)
+ cc = "$prefix/clang"
+ cxx = "$prefix/clang++"
+ ld = native_linker_path
+ readelf = "readelf"
+ ar = "${prefix}/llvm-ar"
+ nm = "nm"
+ toolchain_args = {
+ is_clang = true
+ }
+ }
+}
+
+# Use this toolchain for Windows based platforms.
+if (is_host_win) {
+ gcc_toolchain("clang") {
+ prefix = llvm_clang_path
+ cc = "$prefix/clang.exe"
+ cxx = "$prefix/clang++.exe"
+ ld = native_linker_path
+ readelf = "$prefix/llvm-readobj.exe"
+ ar = "${prefix}/llvm-ar.exe"
+ nm = "${prefix}/llvm-nm.exe"
+ toolchain_args = {
+ is_clang = true
+ }
+
+ executable_extension = native_executable_extension
+ shlib_extension = native_shlib_extension
+ if (defined(native_snarl_linker)) {
+ using_snarl_linker = true
+ }
+ toolchain_args = {
+ is_clang = true
+ }
+ }
}
diff --git a/starboard/common/optional.h b/starboard/common/optional.h
index 6c65763..f67609c 100644
--- a/starboard/common/optional.h
+++ b/starboard/common/optional.h
@@ -21,7 +21,6 @@
#include "starboard/common/log.h"
#include "starboard/configuration.h"
-#include "starboard/export.h"
#include "starboard/memory.h"
namespace starboard {
@@ -89,7 +88,7 @@
extern const in_place_t in_place;
template <typename T>
-class SB_EXPORT optional {
+class optional {
public:
// Construction via the default constructor results in an optional that is
// not engaged.
diff --git a/starboard/contrib/cast/README.md b/starboard/contrib/cast/README.md
new file mode 100644
index 0000000..479ab3c
--- /dev/null
+++ b/starboard/contrib/cast/README.md
@@ -0,0 +1,53 @@
+## Cast Starboard API
+
+The Cast Starboard API is a shared library which contains the portion of
+Starboard required to run Cast.
+
+### Customizations
+
+As of Starboard 15, there are public methods required for Cast that are not
+already exposed by `libstarboard_platform_group.so`. As a result, the dedicated
+header `cast_starboard_api.h` is omitted from this release, though it may
+return in the future.
+
+Cast still requires additional behavior be implemented behind the existing
+Starboard APIs. Reference the `Cast TV Integration Guide` for details.
+
+### Reference Implementation
+
+The `cast_starboard_api/samples/` directory contains the reference target
+`cast_starboard_api` which can be built when both
+`build_with_separate_cobalt_toolchain=true` and `use_contrib_cast=true` are
+specified. To generate the target:
+
+```
+gn gen out/linux-x64x11_devel --args="target_platform=\"linux-x64x11\" build_with_separate_cobalt_toolchain=true use_contrib_cast=true build_type=\"devel\""
+```
+
+To build the target:
+
+```
+ninja -C out/linux-x64x11_devel/ cast_starboard_api
+```
+
+### Test Suite
+
+Tests for Cast-specific behaviors are not currently included in NPLB or YTS.
+
+A limited test suite, `cast_starboard_api_test`, is provided to ensure the
+standalone library can be initialized and a window surface can be created in the
+format required by Cast. To build the test suite:
+
+```
+ninja -C out/linux-x64x11_devel/ cast_starboard_api_test
+```
+
+To run the test suite:
+
+```
+./out/linux-x64x11_devel/cast_starboard_api_test_loader
+```
+
+### Known Issues
+
+- When `build_type=\"devel\"`, some systems may SB_DCHECK in `NetworkNotifier`.
diff --git a/starboard/contrib/cast/cast.gni b/starboard/contrib/cast/cast.gni
new file mode 100644
index 0000000..4a0cd3f
--- /dev/null
+++ b/starboard/contrib/cast/cast.gni
@@ -0,0 +1,5 @@
+declare_args() {
+ # Includes `//starboard/contrib/cast/cast_starboard_api/samples:cast` into
+ # `//starboard:gn_all`.
+ use_contrib_cast = false
+}
diff --git a/starboard/contrib/cast/cast_starboard_api/samples/BUILD.gn b/starboard/contrib/cast/cast_starboard_api/samples/BUILD.gn
new file mode 100644
index 0000000..a26bfa4
--- /dev/null
+++ b/starboard/contrib/cast/cast_starboard_api/samples/BUILD.gn
@@ -0,0 +1,57 @@
+# Copyright 2023 The Cobalt Authors. All rights reserved.
+import("//starboard/build/config/starboard_target_type.gni")
+import("//starboard/contrib/cast/cast.gni")
+
+assert(build_with_separate_cobalt_toolchain && use_contrib_cast)
+
+group("cast") {
+ public_deps = [ ":cast_starboard_api($starboard_toolchain)" ]
+}
+
+config("default") {
+ ldflags = [
+ # Hide unwanted symbols, which also shrinks the resulting binary.
+ "-Wl,--version-script=" +
+ rebase_path("./cast_starboard_api.lds", root_build_dir),
+ ]
+
+ if (!use_asan) {
+ ldflags += [
+ # Prevent unresolved symbols, which would require the consumer of
+ # `cast_starboard_api` to be aware of transitive dependences at runtime.
+ "-Wl,-z,defs",
+ ]
+ }
+}
+
+if (current_toolchain == starboard_toolchain) {
+ starboard_platform_target("cast_starboard_api") {
+ extra_configs = [ ":default" ]
+ }
+
+ copy("cast_starboard_api_test_data") {
+ install_content = true
+ sources = [ "$root_out_dir/libcast_starboard_api.so" ]
+
+ # This artifact is consumed by a test built outside of the
+ # starboard_toolchain; move from `starboard/content/` to `content/`.
+ outputs = [
+ "$sb_static_contents_output_data_dir/../../content/{{source_file_part}}",
+ ]
+ deps = [ ":cast_starboard_api" ]
+ }
+}
+
+target(gtest_target_type, "cast_starboard_api_test") {
+ testonly = true
+ sources = [
+ "//starboard/common/test_main.cc",
+ "cast_starboard_api_test.cc",
+ ]
+ data_deps = [ ":cast_starboard_api_test_data($starboard_toolchain)" ]
+ deps = [
+ "//starboard",
+ "//starboard/nplb/testdata/file_tests:nplb_file_tests_data",
+ "//testing/gtest",
+ ]
+}
diff --git a/starboard/contrib/cast/cast_starboard_api/samples/cast_starboard_api.lds b/starboard/contrib/cast/cast_starboard_api/samples/cast_starboard_api.lds
new file mode 100644
index 0000000..b686799
--- /dev/null
+++ b/starboard/contrib/cast/cast_starboard_api/samples/cast_starboard_api.lds
@@ -0,0 +1,9 @@
+# Copyright 2023 The Cobalt Authors. All rights reserved.
+LIBCAST_STARBOARD_API {
+ global:
+ CastStarboardApi*;
+ kSb*;
+ Sb*;
+ local:
+ *;
+};
diff --git a/starboard/contrib/cast/cast_starboard_api/samples/cast_starboard_api_test.cc b/starboard/contrib/cast/cast_starboard_api/samples/cast_starboard_api_test.cc
new file mode 100644
index 0000000..cc6ff4d
--- /dev/null
+++ b/starboard/contrib/cast/cast_starboard_api/samples/cast_starboard_api_test.cc
@@ -0,0 +1,271 @@
+// Copyright 2023 The Cobalt Authors. All rights reserved.
+
+#include <dlfcn.h>
+
+#include "starboard/common/condition_variable.h"
+#include "starboard/common/log.h"
+#include "starboard/common/mutex.h"
+#include "starboard/common/thread.h"
+#include "starboard/egl.h"
+#include "starboard/event.h"
+#include "starboard/file.h"
+#include "starboard/gles.h"
+#include "starboard/system.h"
+#include "starboard/window.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class CastStarboardApiTest : public ::testing::Test {
+ public:
+ // This acts as a proxy to the Starboard implementation provided by
+ // `libcast_starboard_api.so`.
+ struct CastStarboardApi {
+ decltype(SbRunStarboardMain)* SbRunStarboardMain;
+ decltype(SbEventSchedule)* SbEventSchedule;
+ decltype(SbGetEglInterface)* SbGetEglInterface;
+ decltype(SbGetGlesInterface)* SbGetGlesInterface;
+ decltype(SbWindowCreate)* SbWindowCreate;
+ decltype(SbWindowDestroy)* SbWindowDestroy;
+ decltype(SbWindowGetPlatformHandle)* SbWindowGetPlatformHandle;
+ decltype(SbSystemRequestStop)* SbSystemRequestStop;
+ };
+
+ CastStarboardApiTest();
+ ~CastStarboardApiTest();
+
+ // Receives events from the static |EventHandle|. If |event| is non-null,
+ // add its type to |received_| so tests can see it. If |event| is null,
+ // then it was a manually scheduled event and we signal |received_cond_|.
+ void EventHandleInternal(const SbEvent* event);
+
+ // Waits until |received_cond_| has been signalled; used to ensure the event
+ // loop is running.
+ void WaitForEventCallback();
+
+ // Signals |received_cond_|.
+ void EventCallbackInternal();
+
+ CastStarboardApi& api() { return api_; }
+ const std::vector<SbEventType>& events() { return received_; }
+
+ private:
+ class CastStarboardApiThread : public starboard::Thread {
+ public:
+ explicit CastStarboardApiThread(CastStarboardApi* api)
+ : starboard::Thread("cast_thread"), api_(api) {}
+
+ void Run() override;
+
+ private:
+ CastStarboardApi* api_;
+ };
+
+ template <class FuncType>
+ void DlSym(void* lib, const char* func_name, FuncType* func) {
+ *func = (FuncType)(dlsym(lib, func_name));
+ EXPECT_NE(func, nullptr) << func_name << " could not be loaded";
+ }
+
+ CastStarboardApi api_;
+
+ // These properties are used to initialize the main Starboard thread.
+ std::unique_ptr<CastStarboardApiThread> sb_thread_;
+ std::unique_ptr<starboard::ConditionVariable> started_cond_;
+ starboard::Mutex started_mutex_;
+
+ // These properties are used to track event dispatch during tests.
+ std::vector<SbEventType> received_;
+ starboard::Mutex received_mutex_;
+ std::unique_ptr<starboard::ConditionVariable> received_cond_;
+};
+
+// A behavior in the default implementation prevents dlclose from being used on
+// this library, so we must only open it once.
+void* g_lib = nullptr;
+
+// |EventHandleStatic| must be able to operate on the |g_test_instance|, so it's
+// tracked here.
+CastStarboardApiTest* g_test_instance = nullptr;
+
+// Static callback for SbEvent(s); forwards to |EventHandleInternal|.
+void EventHandleStatic(const SbEvent* event) {
+ g_test_instance->EventHandleInternal(event);
+}
+
+// Static callback for manually scheduled events; forwards to
+// |EventHandleInternal|.
+void EventCallbackStatic(void* context) {
+ static_cast<CastStarboardApiTest*>(context)->EventCallbackInternal();
+}
+
+CastStarboardApiTest::CastStarboardApiTest() {
+ g_test_instance = this;
+ started_cond_ =
+ std::make_unique<starboard::ConditionVariable>(started_mutex_);
+ received_cond_ =
+ std::make_unique<starboard::ConditionVariable>(received_mutex_);
+
+ // Ensure libcast_starboard_api.so has been opened.
+ if (!g_lib) {
+ std::vector<char> content_path(kSbFileMaxPath + 1);
+ EXPECT_TRUE(SbSystemGetPath(kSbSystemPathContentDirectory,
+ content_path.data(), kSbFileMaxPath + 1));
+ const std::string lib_path = std::string(content_path.data()) +
+ kSbFileSepChar + "libcast_starboard_api.so";
+ g_lib = dlopen(lib_path.c_str(), RTLD_LAZY);
+ EXPECT_NE(g_lib, nullptr)
+ << lib_path << " could not be loaded: " << dlerror();
+ }
+
+ // Assign the |api_| methods.
+ DlSym(g_lib, "SbRunStarboardMain", &api_.SbRunStarboardMain);
+ DlSym(g_lib, "SbEventSchedule", &api_.SbEventSchedule);
+ DlSym(g_lib, "SbGetEglInterface", &api_.SbGetEglInterface);
+ DlSym(g_lib, "SbGetGlesInterface", &api_.SbGetGlesInterface);
+ DlSym(g_lib, "SbWindowCreate", &api_.SbWindowCreate);
+ DlSym(g_lib, "SbWindowDestroy", &api_.SbWindowDestroy);
+ DlSym(g_lib, "SbWindowGetPlatformHandle", &api_.SbWindowGetPlatformHandle);
+ DlSym(g_lib, "SbSystemRequestStop", &api_.SbSystemRequestStop);
+
+ // Start the Starboard thread and wait for kSbEventTypeStart to propagate.
+ sb_thread_ = std::make_unique<CastStarboardApiThread>(&api_);
+ sb_thread_->Start();
+
+ // Watch event for initialation completion.
+ started_mutex_.Acquire();
+ started_cond_->Wait();
+ started_mutex_.Release();
+}
+
+CastStarboardApiTest::~CastStarboardApiTest() {
+ api().SbSystemRequestStop(0);
+ sb_thread_->Join();
+ sb_thread_.reset();
+ started_cond_.reset();
+ g_test_instance = nullptr;
+}
+
+void CastStarboardApiTest::EventHandleInternal(const SbEvent* event) {
+ switch (event->type) {
+ case kSbEventTypeStart:
+ started_cond_->Signal();
+ break;
+ default:
+ break;
+ }
+
+ received_.push_back(event->type);
+}
+
+void CastStarboardApiTest::EventCallbackInternal() {
+ received_cond_->Signal();
+}
+
+void CastStarboardApiTest::WaitForEventCallback() {
+ received_mutex_.Acquire();
+ received_cond_->Wait();
+ received_mutex_.Release();
+}
+
+void CastStarboardApiTest::CastStarboardApiThread::Run() {
+ api_->SbRunStarboardMain(0, nullptr, &EventHandleStatic);
+}
+
+// The default Application only be started once in the lifetime of the
+// executable. To simplify and avoid race conditions in the test framework, both
+// test scenarios are implemented in a single test case.
+TEST_F(CastStarboardApiTest, EventLoop_CastWindowSurface) {
+ // Test 1:
+ // Ensure the event loop is running after initialization, and that SbEvent(s)
+ // are being received. Effectively tests |SbRunStarboardMain|.
+ api().SbEventSchedule(&EventCallbackStatic, this, 0);
+ WaitForEventCallback();
+ EXPECT_FALSE(events().empty());
+ EXPECT_EQ(events().front(), kSbEventTypeStart);
+
+ // Test 2:
+ // Ensure that a window surface can be created which supports the config
+ // required by Cast.
+ const SbEglInterface* egl = api().SbGetEglInterface();
+
+ // Cast expects `SB_EGL_DEFAULT_DISPLAY` to refer to the correct display.
+ SbEglDisplay display = egl->eglGetDisplay(SB_EGL_DEFAULT_DISPLAY);
+ EXPECT_TRUE(egl->eglInitialize(display, nullptr, nullptr))
+ << "Failed eglInitialize for display: " << egl->eglGetError();
+
+ SbWindow window = api().SbWindowCreate(nullptr);
+ SbEglNativeWindowType window_type = reinterpret_cast<SbEglNativeWindowType>(
+ api().SbWindowGetPlatformHandle(window));
+
+ SbEglInt32 config_attribs[] = {SB_EGL_BUFFER_SIZE,
+ 32,
+ SB_EGL_ALPHA_SIZE,
+ 8,
+ SB_EGL_BLUE_SIZE,
+ 8,
+ SB_EGL_GREEN_SIZE,
+ 8,
+ SB_EGL_RED_SIZE,
+ 8,
+ SB_EGL_RENDERABLE_TYPE,
+ SB_EGL_OPENGL_ES2_BIT,
+ SB_EGL_SURFACE_TYPE,
+ SB_EGL_WINDOW_BIT,
+ SB_EGL_NONE};
+
+ int32_t num_configs;
+ EXPECT_TRUE(
+ egl->eglChooseConfig(display, config_attribs, nullptr, 0, &num_configs))
+ << "Failed eglChooseConfig for the specified config_attribs: "
+ << egl->eglGetError();
+ EXPECT_NE(num_configs, 0) << "No suitable EGL configs found.";
+
+ std::unique_ptr<SbEglConfig[]> configs(new SbEglConfig[num_configs]);
+ EXPECT_TRUE(egl->eglChooseConfig(display, config_attribs, configs.get(),
+ num_configs, &num_configs))
+ << "Failed eglChooseConfig: " << egl->eglGetError();
+
+ SbEglSurface surface = nullptr;
+ SbEglConfig config;
+ for (int i = 0; i < num_configs; i++) {
+ surface =
+ egl->eglCreateWindowSurface(display, configs[i], window_type, NULL);
+ if (surface) {
+ config = configs[i];
+ egl->eglDestroySurface(display, surface);
+ break;
+ }
+ }
+
+ EXPECT_NE(surface, nullptr)
+ << "Failed eglCreateWindowSurface for all configs: "
+ << egl->eglGetError();
+ const SbGlesInterface* gles = api().SbGetGlesInterface();
+
+ const SbEglInt32 context_attribs[] = {SB_EGL_CONTEXT_CLIENT_VERSION, 2,
+ SB_EGL_NONE};
+
+ SbEglContext context =
+ egl->eglCreateContext(display, config, NULL, context_attribs);
+ egl->eglMakeCurrent(display, SB_EGL_NO_SURFACE, SB_EGL_NO_SURFACE, context);
+ std::string version(
+ reinterpret_cast<const char*>(gles->glGetString(SB_GL_VERSION)));
+ const std::string prefix = "OpenGL ES ";
+ EXPECT_TRUE(version.find(prefix, 0) == 0);
+ EXPECT_GT(version.length(), prefix.length() + 1);
+
+ char actual_version = version.at(prefix.length());
+ if (!(actual_version == '2' || actual_version == '3')) {
+ // Normally we could check whether gles->glGetStringi (or other OpenGL 3+
+ // functions) are non-null, but various Starboard implementations actually
+ // report the underlying version even if OpenGL 3+ functions are not
+ // exposed. Cast will automatically treat any valid OpenGL 2+ version as
+ // OpenGL ES 2.0.
+ FAIL() << "Expected OpenGL ES 2 or 3.";
+ }
+
+ api().SbWindowDestroy(window);
+}
+
+} // namespace
diff --git a/starboard/evergreen/shared/platform_configuration/BUILD.gn b/starboard/evergreen/shared/platform_configuration/BUILD.gn
index 01ac96f..2340c86 100644
--- a/starboard/evergreen/shared/platform_configuration/BUILD.gn
+++ b/starboard/evergreen/shared/platform_configuration/BUILD.gn
@@ -28,7 +28,7 @@
"-Wl,-u GetEvergreenSabiString",
]
- if (!build_with_separate_cobalt_toolchain) {
+ if (sb_is_evergreen) {
ldflags += [ "-nostdlib" ]
}
cflags = [
diff --git a/starboard/evergreen/shared/platform_configuration/configuration.gni b/starboard/evergreen/shared/platform_configuration/configuration.gni
index c76baea..4327e1d 100644
--- a/starboard/evergreen/shared/platform_configuration/configuration.gni
+++ b/starboard/evergreen/shared/platform_configuration/configuration.gni
@@ -14,9 +14,7 @@
import("//starboard/build/config/base_configuration.gni")
-sb_is_modular = true
-
-sb_is_evergreen = true
+sb_is_evergreen = !build_with_separate_cobalt_toolchain
cobalt_font_package = "empty"
diff --git a/starboard/extension/BUILD.gn b/starboard/extension/BUILD.gn
index 5212664..57b95b1 100644
--- a/starboard/extension/BUILD.gn
+++ b/starboard/extension/BUILD.gn
@@ -26,7 +26,7 @@
"//testing/gmock",
"//testing/gtest",
]
- if (sb_is_modular) {
+ if (sb_is_modular && current_toolchain == cobalt_toolchain) {
deps += cobalt_platform_dependencies
}
}
diff --git a/starboard/linux/shared/BUILD.gn b/starboard/linux/shared/BUILD.gn
index 065f2c4..57b7908 100644
--- a/starboard/linux/shared/BUILD.gn
+++ b/starboard/linux/shared/BUILD.gn
@@ -428,13 +428,15 @@
build_loader = false
testonly = true
- sources = media_tests_sources + player_tests_sources +
- [ "//starboard/common/test_main.cc" ]
+ sources = media_tests_sources + player_tests_sources + [
+ "//starboard/common/test_main.cc",
+ "//starboard/shared/ffmpeg/ffmpeg_audio_decoder_test.cc",
+ ]
configs += [ "//starboard/build/config:starboard_implementation" ]
deps = [
- "//starboard",
+ "//starboard:starboard_with_main",
"//starboard/shared/starboard/player/filter/testing:test_util",
"//testing/gmock",
"//testing/gtest",
diff --git a/starboard/linux/shared/launcher.py b/starboard/linux/shared/launcher.py
index 022073a..10cdbde 100644
--- a/starboard/linux/shared/launcher.py
+++ b/starboard/linux/shared/launcher.py
@@ -31,8 +31,6 @@
# This file is still executed with Python2 in CI.
# pylint:disable=consider-using-f-string,super-with-arguments
-IS_MODULAR_BUILD = os.getenv("MODULAR_BUILD", "0") == "1"
-
def GetProcessStatus(pid):
"""Returns process running status given its pid, or empty string if not found.
@@ -63,7 +61,7 @@
self.device_ip = socket.gethostbyname(socket.gethostname())
self.executable = self.GetTargetPath()
- if IS_MODULAR_BUILD:
+ if abstract_launcher.IS_MODULAR_BUILD:
self.executable += "_loader"
if not os.path.exists(self.executable):
self.executable = os.path.abspath(
diff --git a/starboard/linux/shared/media_is_audio_supported.cc b/starboard/linux/shared/media_is_audio_supported.cc
index 8d2e637..d857bd5 100644
--- a/starboard/linux/shared/media_is_audio_supported.cc
+++ b/starboard/linux/shared/media_is_audio_supported.cc
@@ -49,6 +49,12 @@
if (audio_codec == kSbMediaAudioCodecMp3) {
return bitrate <= kSbMediaMaxAudioBitrateInBitsPerSecond;
}
+ if (audio_codec == kSbMediaAudioCodecPcm) {
+ return bitrate <= kSbMediaMaxAudioBitrateInBitsPerSecond;
+ }
+ if (audio_codec == kSbMediaAudioCodecFlac) {
+ return bitrate <= kSbMediaMaxAudioBitrateInBitsPerSecond;
+ }
#endif // SB_API_VERSION >= 14
return false;
diff --git a/starboard/linux/shared/platform_configuration/BUILD.gn b/starboard/linux/shared/platform_configuration/BUILD.gn
index 87ea329..4e7334a 100644
--- a/starboard/linux/shared/platform_configuration/BUILD.gn
+++ b/starboard/linux/shared/platform_configuration/BUILD.gn
@@ -63,8 +63,8 @@
# Do not warn about unused function params.
"-Wno-unused-parameter",
]
- if (build_with_separate_cobalt_toolchain) {
- # If we're building modularly, we need visibility.
+ if (sb_is_modular && !sb_is_evergreen) {
+ # If we're building with cobalt toolchain and native linker, we need visibility.
cflags += [ "-fvisibility=default" ]
} else {
# Default visibility to hidden, to enable dead stripping.
@@ -143,7 +143,7 @@
"rt",
]
- if (!sb_is_modular) {
+ if (!sb_is_modular || current_toolchain != cobalt_toolchain) {
ldflags += [ "-static-libstdc++" ]
}
diff --git a/starboard/linux/x64x11/BUILD.gn b/starboard/linux/x64x11/BUILD.gn
index ad6b13a..3666f36 100644
--- a/starboard/linux/x64x11/BUILD.gn
+++ b/starboard/linux/x64x11/BUILD.gn
@@ -15,7 +15,10 @@
static_library("starboard_platform") {
check_includes = false
- sources = [ "//starboard/linux/x64x11/main.cc" ]
+ sources = [ "//starboard/linux/x64x11/run_starboard_main.cc" ]
+ if (!sb_is_modular || sb_is_evergreen) {
+ sources += [ "//starboard/linux/x64x11/main.cc" ]
+ }
public_deps = [
"//starboard/linux/x64x11/shared:starboard_platform",
@@ -24,3 +27,12 @@
configs += [ "//starboard/build/config:starboard_implementation" ]
}
+
+if (sb_is_modular && !sb_is_evergreen) {
+ static_library("starboard_platform_with_main") {
+ check_includes = false
+ sources = [ "//starboard/linux/x64x11/main.cc" ]
+ configs += [ "//starboard/build/config:starboard_implementation" ]
+ public_deps = [ ":starboard_platform" ]
+ }
+}
diff --git a/starboard/linux/x64x11/clang/3.9/BUILD.gn b/starboard/linux/x64x11/clang/3.9/BUILD.gn
index ba56f59..f947b50 100644
--- a/starboard/linux/x64x11/clang/3.9/BUILD.gn
+++ b/starboard/linux/x64x11/clang/3.9/BUILD.gn
@@ -15,7 +15,10 @@
static_library("starboard_platform") {
check_includes = false
- sources = [ "//starboard/linux/x64x11/main.cc" ]
+ sources = [ "//starboard/linux/x64x11/run_starboard_main.cc" ]
+ if (!sb_is_modular || sb_is_evergreen) {
+ sources += [ "//starboard/linux/x64x11/main.cc" ]
+ }
public_deps = [
"//starboard/linux/x64x11/shared:starboard_platform",
diff --git a/starboard/linux/x64x11/egl/BUILD.gn b/starboard/linux/x64x11/egl/BUILD.gn
index ad6b13a..91ed007 100644
--- a/starboard/linux/x64x11/egl/BUILD.gn
+++ b/starboard/linux/x64x11/egl/BUILD.gn
@@ -15,7 +15,10 @@
static_library("starboard_platform") {
check_includes = false
- sources = [ "//starboard/linux/x64x11/main.cc" ]
+ sources = [ "//starboard/linux/x64x11/run_starboard_main.cc" ]
+ if (!sb_is_modular || sb_is_evergreen) {
+ sources += [ "//starboard/linux/x64x11/main.cc" ]
+ }
public_deps = [
"//starboard/linux/x64x11/shared:starboard_platform",
diff --git a/starboard/linux/x64x11/gcc/6.3/BUILD.gn b/starboard/linux/x64x11/gcc/6.3/BUILD.gn
index ba56f59..f947b50 100644
--- a/starboard/linux/x64x11/gcc/6.3/BUILD.gn
+++ b/starboard/linux/x64x11/gcc/6.3/BUILD.gn
@@ -15,7 +15,10 @@
static_library("starboard_platform") {
check_includes = false
- sources = [ "//starboard/linux/x64x11/main.cc" ]
+ sources = [ "//starboard/linux/x64x11/run_starboard_main.cc" ]
+ if (!sb_is_modular || sb_is_evergreen) {
+ sources += [ "//starboard/linux/x64x11/main.cc" ]
+ }
public_deps = [
"//starboard/linux/x64x11/shared:starboard_platform",
diff --git a/starboard/linux/x64x11/main.cc b/starboard/linux/x64x11/main.cc
index 82046a0..5cfd197 100644
--- a/starboard/linux/x64x11/main.cc
+++ b/starboard/linux/x64x11/main.cc
@@ -53,6 +53,7 @@
return 1;
}
+#if !SB_IS(MODULAR)
bool start_handler_at_crash =
command_line.HasSwitch(
starboard::shared::starboard::kStartHandlerAtCrash) ||
@@ -60,6 +61,7 @@
starboard::shared::starboard::kStartHandlerAtLaunch);
third_party::crashpad::wrapper::InstallCrashpadHandler(start_handler_at_crash,
ca_certificates_path);
+#endif // !SB_IS(MODULAR)
#endif
#if SB_HAS_QUIRK(BACKTRACE_DLOPEN_BUG)
@@ -83,15 +85,3 @@
starboard::shared::signal::UninstallCrashSignalHandlers();
return result;
}
-
-#if SB_API_VERSION >= 15
-int SbRunStarboardMain(int argc, char** argv, SbEventHandleCallback callback) {
- starboard::shared::x11::ApplicationX11 application(callback);
- int result = 0;
- {
- starboard::shared::starboard::LinkReceiver receiver(&application);
- result = application.Run(argc, argv);
- }
- return result;
-}
-#endif // SB_API_VERSION >= 15
diff --git a/starboard/linux/x64x11/run_starboard_main.cc b/starboard/linux/x64x11/run_starboard_main.cc
new file mode 100644
index 0000000..813e1df
--- /dev/null
+++ b/starboard/linux/x64x11/run_starboard_main.cc
@@ -0,0 +1,30 @@
+// Copyright 2023 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/event.h"
+
+#include "starboard/shared/starboard/link_receiver.h"
+#include "starboard/shared/x11/application_x11.h"
+
+#if SB_API_VERSION >= 15
+int SbRunStarboardMain(int argc, char** argv, SbEventHandleCallback callback) {
+ starboard::shared::x11::ApplicationX11 application(callback);
+ int result = 0;
+ {
+ starboard::shared::starboard::LinkReceiver receiver(&application);
+ result = application.Run(argc, argv);
+ }
+ return result;
+}
+#endif // SB_API_VERSION >= 15
diff --git a/starboard/linux/x64x11/shared/BUILD.gn b/starboard/linux/x64x11/shared/BUILD.gn
index d58d764..2da6b40 100644
--- a/starboard/linux/x64x11/shared/BUILD.gn
+++ b/starboard/linux/x64x11/shared/BUILD.gn
@@ -45,7 +45,7 @@
"//starboard/shared/x11/window_internal.cc",
]
- if (!build_with_separate_cobalt_toolchain) {
+ if (!sb_is_modular || sb_is_evergreen) {
sources += [ "//starboard/linux/x64x11/sanitizer_options.cc" ]
}
diff --git a/starboard/linux/x64x11/shared/platform_configuration/BUILD.gn b/starboard/linux/x64x11/shared/platform_configuration/BUILD.gn
index 32c24f6..ab9cf36 100644
--- a/starboard/linux/x64x11/shared/platform_configuration/BUILD.gn
+++ b/starboard/linux/x64x11/shared/platform_configuration/BUILD.gn
@@ -13,8 +13,8 @@
# limitations under the License.
config("platform_configuration") {
- if (current_toolchain == default_toolchain &&
- build_with_separate_cobalt_toolchain) {
+ if (current_toolchain == default_toolchain && sb_is_modular &&
+ !sb_is_evergreen) {
configs = [ "//starboard/evergreen/x64/platform_configuration" ]
} else {
configs = [
@@ -28,7 +28,7 @@
config("libraries") {
configs = [ "//starboard/linux/shared/platform_configuration:libraries" ]
- if (build_with_separate_cobalt_toolchain) {
+ if (sb_is_modular && !sb_is_evergreen) {
libs = [ "//third_party/libvpx/platforms/linux-x64/libvpx.so.6" ]
ldflags = [ "-Wl,-rpath=" + rebase_path("//") +
"/third_party/libvpx/platforms/linux-x64/" ]
diff --git a/starboard/linux/x64x11/skia/BUILD.gn b/starboard/linux/x64x11/skia/BUILD.gn
index 024e560..66917ea 100644
--- a/starboard/linux/x64x11/skia/BUILD.gn
+++ b/starboard/linux/x64x11/skia/BUILD.gn
@@ -16,11 +16,14 @@
check_includes = false
sources = [
- "//starboard/linux/x64x11/main.cc",
+ "//starboard/linux/x64x11/run_starboard_main.cc",
"//starboard/linux/x64x11/skia/configuration.cc",
"//starboard/linux/x64x11/skia/configuration.h",
"//starboard/linux/x64x11/skia/system_get_extensions.cc",
]
+ if (!sb_is_modular || sb_is_evergreen) {
+ sources += [ "//starboard/linux/x64x11/main.cc" ]
+ }
public_deps = [
"//starboard/linux/x64x11/shared:starboard_platform",
diff --git a/starboard/loader_app/BUILD.gn b/starboard/loader_app/BUILD.gn
index 4d38cce..e0384a1 100644
--- a/starboard/loader_app/BUILD.gn
+++ b/starboard/loader_app/BUILD.gn
@@ -106,6 +106,7 @@
deps = [
":common_loader_app_dependencies",
"//cobalt/content/fonts:copy_font_data",
+ "//starboard:starboard_with_main",
"//starboard/elf_loader",
]
if (sb_is_evergreen_compatible && sb_evergreen_compatible_package) {
diff --git a/starboard/nplb/BUILD.gn b/starboard/nplb/BUILD.gn
index 08e415a..664751b 100644
--- a/starboard/nplb/BUILD.gn
+++ b/starboard/nplb/BUILD.gn
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import("//starboard/build/config/os_definitions.gni")
+
target(gtest_target_type, "nplb") {
testonly = true
@@ -268,4 +270,31 @@
# signedness_and_size_of_enum_test.cc casts -1 to enum value
cflags = [ "-Wno-enum-constexpr-conversion" ]
}
+
+ # TODO b/296238576 Add these tests for windows based platform modular builds
+ if (sb_is_modular && !sb_is_evergreen && is_host_win) {
+ sources -= [
+ "maximum_player_configuration_explorer.cc",
+ "maximum_player_configuration_explorer.h",
+ "maximum_player_configuration_explorer_test.cc",
+ "media_buffer_test.cc",
+ "media_set_audio_write_duration_test.cc",
+ "player_create_test.cc",
+ "player_creation_param_helpers.cc",
+ "player_creation_param_helpers.h",
+ "player_get_audio_configuration_test.cc",
+ "player_get_preferred_output_mode_test.cc",
+ "player_test_fixture.cc",
+ "player_test_fixture.h",
+ "player_test_util.cc",
+ "player_test_util.h",
+ "player_write_sample_test.cc",
+ "vertical_video_test.cc",
+ ]
+
+ deps -= [
+ "//starboard/shared/starboard/media:media_util",
+ "//starboard/shared/starboard/player:video_dmp",
+ ]
+ }
}
diff --git a/starboard/nplb/media_can_play_mime_and_key_system_test.cc b/starboard/nplb/media_can_play_mime_and_key_system_test.cc
index 2a5594e..a77a4e9 100644
--- a/starboard/nplb/media_can_play_mime_and_key_system_test.cc
+++ b/starboard/nplb/media_can_play_mime_and_key_system_test.cc
@@ -72,6 +72,21 @@
return kDeviceTypeFHD;
}
+testing::AssertionResult IsMimeAndKeySystemSupported(std::string param,
+ std::string key_system) {
+ SbMediaSupportType support_type =
+ SbMediaCanPlayMimeAndKeySystem(param.c_str(), key_system.c_str());
+ if (support_type == kSbMediaSupportTypeProbably) {
+ return testing::AssertionSuccess();
+ }
+
+ return testing::AssertionFailure()
+ << "SbMediaCanPlayMimeAndKeySystem(\"" << param << "\", \""
+ << key_system << "\") returns " << support_type
+ << ". It should return kSbMediaSupportTypeProbably ("
+ << kSbMediaSupportTypeProbably << ").";
+}
+
TEST(SbMediaCanPlayMimeAndKeySystem, SunnyDay) {
// Vp9
SbMediaCanPlayMimeAndKeySystem(
@@ -292,20 +307,20 @@
mime_params = params_fhd;
}
+ const char* key_system = "";
for (auto& param : mime_params) {
- SbMediaSupportType support = SbMediaCanPlayMimeAndKeySystem(param, "");
- EXPECT_TRUE(support == kSbMediaSupportTypeProbably);
+ EXPECT_TRUE(IsMimeAndKeySystemSupported(param, key_system));
}
// AAC-LC
- SbMediaSupportType result = SbMediaCanPlayMimeAndKeySystem(
- "audio/mp4; codecs=\"mp4a.40.2\"; channels=2; bitrate=256000;", "");
- ASSERT_EQ(result, kSbMediaSupportTypeProbably);
+ ASSERT_TRUE(IsMimeAndKeySystemSupported(
+ "audio/mp4; codecs=\"mp4a.40.2\"; channels=2; bitrate=256000",
+ key_system));
// HE-AAC
- result = SbMediaCanPlayMimeAndKeySystem(
- "audio/mp4; codecs=\"mp4a.40.5\"; channels=2; bitrate=48000;", "");
- ASSERT_EQ(result, kSbMediaSupportTypeProbably);
+ ASSERT_TRUE(IsMimeAndKeySystemSupported(
+ "audio/mp4; codecs=\"mp4a.40.5\"; channels=2; bitrate=48000",
+ key_system));
}
TEST(SbMediaCanPlayMimeAndKeySystem, AnySupportedKeySystems) {
diff --git a/starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.cc b/starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.cc
index 17937fa..4cf444b 100644
--- a/starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.cc
+++ b/starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.cc
@@ -20,6 +20,7 @@
#include "starboard/audio_sink.h"
#include "starboard/common/log.h"
#include "starboard/common/string.h"
+#include "starboard/media.h"
#include "starboard/memory.h"
#include "starboard/shared/starboard/media/media_util.h"
@@ -36,7 +37,10 @@
return kSbMediaAudioSampleTypeInt16Deprecated;
}
-AVCodecID GetFfmpegCodecIdByMediaCodec(SbMediaAudioCodec audio_codec) {
+AVCodecID GetFfmpegCodecIdByMediaCodec(
+ starboard::media::AudioStreamInfo stream_info) {
+ SbMediaAudioCodec audio_codec = stream_info.codec;
+
switch (audio_codec) {
case kSbMediaAudioCodecAac:
return AV_CODEC_ID_AAC;
@@ -57,6 +61,24 @@
#if SB_API_VERSION >= 14
case kSbMediaAudioCodecMp3:
return AV_CODEC_ID_MP3;
+ case kSbMediaAudioCodecPcm:
+ if (stream_info.bits_per_sample == 16) {
+ return AV_CODEC_ID_PCM_S16LE;
+ } else {
+ SB_LOG(ERROR) << "PCM is only supported for 16-bit audio ("
+ << stream_info.bits_per_sample
+ << " bits per sample was requested)";
+ return AV_CODEC_ID_NONE;
+ }
+ case kSbMediaAudioCodecFlac:
+ if (stream_info.bits_per_sample == 16) {
+ return AV_CODEC_ID_FLAC;
+ } else {
+ SB_LOG(ERROR) << "FLAC is only supported for 16-bit audio ("
+ << stream_info.bits_per_sample
+ << " bits per sample was requested)";
+ return AV_CODEC_ID_NONE;
+ }
#endif // SB_API_VERSION >= 14
default:
return AV_CODEC_ID_NONE;
@@ -78,7 +100,7 @@
stream_ended_(false),
audio_stream_info_(audio_stream_info) {
SB_DCHECK(g_registered) << "Decoder Specialization registration failed.";
- SB_DCHECK(GetFfmpegCodecIdByMediaCodec(audio_stream_info_.codec) !=
+ SB_DCHECK(GetFfmpegCodecIdByMediaCodec(audio_stream_info_) !=
AV_CODEC_ID_NONE)
<< "Unsupported audio codec " << audio_stream_info_.codec;
ffmpeg_ = FFMPEGDispatch::GetInstance();
@@ -277,10 +299,16 @@
}
codec_context_->codec_type = AVMEDIA_TYPE_AUDIO;
- codec_context_->codec_id =
- GetFfmpegCodecIdByMediaCodec(audio_stream_info_.codec);
+ codec_context_->codec_id = GetFfmpegCodecIdByMediaCodec(audio_stream_info_);
// Request_sample_fmt is set by us, but sample_fmt is set by the decoder.
- if (GetSupportedSampleType() == kSbMediaAudioSampleTypeInt16Deprecated) {
+ if (GetSupportedSampleType() == kSbMediaAudioSampleTypeInt16Deprecated
+#if SB_API_VERSION >= 14
+ // If we request FLT for 16-bit FLAC, FFmpeg will pick S32 as the closest
+ // option. Since the rest of this pipeline doesn't support S32, we should
+ // use S16 as the desired format.
+ || audio_stream_info_.codec == kSbMediaAudioCodecFlac
+#endif // SB_API_VERSION >= 14
+ ) {
codec_context_->request_sample_fmt = AV_SAMPLE_FMT_S16;
} else {
codec_context_->request_sample_fmt = AV_SAMPLE_FMT_FLT;
diff --git a/starboard/shared/ffmpeg/ffmpeg_audio_decoder_test.cc b/starboard/shared/ffmpeg/ffmpeg_audio_decoder_test.cc
new file mode 100644
index 0000000..c009bb4
--- /dev/null
+++ b/starboard/shared/ffmpeg/ffmpeg_audio_decoder_test.cc
@@ -0,0 +1,84 @@
+// Copyright 2023 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/shared/ffmpeg/ffmpeg_audio_decoder.h"
+
+#include <memory>
+
+#include "starboard/media.h"
+#include "starboard/shared/starboard/media/media_util.h"
+#include "starboard/shared/starboard/player/job_queue.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace shared {
+namespace ffmpeg {
+namespace {
+
+// The codecs tested by these tests were introduced in SB_API_VERSION 14.
+#if SB_API_VERSION >= 14
+using ::starboard::shared::starboard::media::AudioStreamInfo;
+using ::testing::NotNull;
+
+AudioStreamInfo CreateStreamInfoForCodec(SbMediaAudioCodec codec) {
+ AudioStreamInfo stream_info;
+ stream_info.codec = codec;
+ stream_info.number_of_channels = 2;
+ stream_info.samples_per_second = 44100;
+ stream_info.bits_per_sample = 8;
+ return stream_info;
+}
+
+class FFmpegAudioDecoderTest
+ : public ::testing::Test,
+ public ::starboard::shared::starboard::player::JobQueue::JobOwner {
+ protected:
+ FFmpegAudioDecoderTest() : JobOwner(kDetached) { AttachToCurrentThread(); }
+
+ ~FFmpegAudioDecoderTest() override = default;
+
+ // Create a JobQueue for use on the current thread.
+ ::starboard::shared::starboard::player::JobQueue job_queue_;
+};
+
+TEST_F(FFmpegAudioDecoderTest, SupportsMp3Codec) {
+ AudioStreamInfo stream_info = CreateStreamInfoForCodec(kSbMediaAudioCodecMp3);
+ std::unique_ptr<AudioDecoder> decoder(AudioDecoder::Create(stream_info));
+ ASSERT_THAT(decoder, NotNull());
+ EXPECT_TRUE(decoder->is_valid());
+}
+
+TEST_F(FFmpegAudioDecoderTest, SupportsFlacCodecFor16BitAudio) {
+ AudioStreamInfo stream_info =
+ CreateStreamInfoForCodec(kSbMediaAudioCodecFlac);
+ stream_info.bits_per_sample = 16;
+ std::unique_ptr<AudioDecoder> decoder(AudioDecoder::Create(stream_info));
+ ASSERT_THAT(decoder, NotNull());
+ EXPECT_TRUE(decoder->is_valid());
+}
+
+TEST_F(FFmpegAudioDecoderTest, SupportsPcmCodecFor16BitAudio) {
+ AudioStreamInfo stream_info = CreateStreamInfoForCodec(kSbMediaAudioCodecPcm);
+ stream_info.bits_per_sample = 16;
+ std::unique_ptr<AudioDecoder> decoder(AudioDecoder::Create(stream_info));
+ ASSERT_THAT(decoder, NotNull());
+ EXPECT_TRUE(decoder->is_valid());
+}
+#endif // SB_API_VERSION >= 14
+
+} // namespace
+} // namespace ffmpeg
+} // namespace shared
+} // namespace starboard
diff --git a/starboard/shared/starboard/crash_handler.cc b/starboard/shared/starboard/crash_handler.cc
index a9c998f..e1fec16 100644
--- a/starboard/shared/starboard/crash_handler.cc
+++ b/starboard/shared/starboard/crash_handler.cc
@@ -29,7 +29,11 @@
}
bool SetString(const char* key, const char* value) {
+#if SB_IS(MODULAR)
+ return false;
+#else
return third_party::crashpad::wrapper::InsertCrashpadAnnotation(key, value);
+#endif // SB_IS(MODULAR)
}
const CobaltExtensionCrashHandlerApi kCrashHandlerApi = {
diff --git a/starboard/shared/starboard/media/codec_util.cc b/starboard/shared/starboard/media/codec_util.cc
index 291bee1..1c2c1b3 100644
--- a/starboard/shared/starboard/media/codec_util.cc
+++ b/starboard/shared/starboard/media/codec_util.cc
@@ -103,6 +103,11 @@
if (strcmp(codec, "flac") == 0) {
return kSbMediaAudioCodecFlac;
}
+ // For WAV, the "codecs" parameter of a MIME type refers to the WAVE format
+ // ID, where 1 represents PCM: https://datatracker.ietf.org/doc/html/rfc2361
+ if (strcmp(codec, "1") == 0) {
+ return kSbMediaAudioCodecPcm;
+ }
#endif // SB_API_VERSION >= 14
#if SB_API_VERSION >= 15
if (strncmp(codec, "iamf.", 5) == 0) {
diff --git a/starboard/shared/starboard/media/media_tests.gni b/starboard/shared/starboard/media/media_tests.gni
index a720a48..4777863 100644
--- a/starboard/shared/starboard/media/media_tests.gni
+++ b/starboard/shared/starboard/media/media_tests.gni
@@ -17,6 +17,7 @@
"//starboard/shared/starboard/media/codec_util_test.cc",
"//starboard/shared/starboard/media/media_util_test.cc",
"//starboard/shared/starboard/media/mime_type_test.cc",
+ "//starboard/shared/starboard/media/mime_util_test.cc",
"//starboard/shared/starboard/media/video_capabilities_test.cc",
"//starboard/shared/starboard/media/vp9_util_test.cc",
]
diff --git a/starboard/shared/starboard/media/mime_util.cc b/starboard/shared/starboard/media/mime_util.cc
index fe49830..0ef4b2d 100644
--- a/starboard/shared/starboard/media/mime_util.cc
+++ b/starboard/shared/starboard/media/mime_util.cc
@@ -37,12 +37,15 @@
// Use SbMediaGetAudioConfiguration() to check if the platform can support
// |channels|.
bool IsAudioOutputSupported(SbMediaAudioCodingType coding_type, int channels) {
+ // TODO(b/284140486, b/297426689): Consider removing the call to
+ // `SbMediaGetAudioOutputCount()` completely as the loop will be terminated
+ // once `SbMediaGetAudioConfiguration()` returns false.
int count = SbMediaGetAudioOutputCount();
for (int output_index = 0; output_index < count; ++output_index) {
SbMediaAudioConfiguration configuration;
if (!SbMediaGetAudioConfiguration(output_index, &configuration)) {
- continue;
+ break;
}
if (configuration.coding_type == coding_type &&
@@ -99,9 +102,20 @@
break;
#if SB_API_VERSION >= 14
case kSbMediaAudioCodecMp3:
+ if (mime_type.subtype() != "mpeg" && mime_type.subtype() != "mp3") {
+ return false;
+ }
+ break;
case kSbMediaAudioCodecFlac:
+ if (mime_type.subtype() != "ogg" && mime_type.subtype() != "flac") {
+ return false;
+ }
+ break;
case kSbMediaAudioCodecPcm:
- return false;
+ if (mime_type.subtype() != "wav") {
+ return false;
+ }
+ break;
#endif // SB_API_VERSION >= 14
#if SB_API_VERSION >= 15
case kSbMediaAudioCodecIamf:
diff --git a/starboard/shared/starboard/media/mime_util_test.cc b/starboard/shared/starboard/media/mime_util_test.cc
new file mode 100644
index 0000000..14784e6
--- /dev/null
+++ b/starboard/shared/starboard/media/mime_util_test.cc
@@ -0,0 +1,122 @@
+// Copyright 2023 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/shared/starboard/media/mime_util.h"
+
+#include "starboard/media.h"
+#include "starboard/shared/starboard/media/media_support_internal.h"
+#include "starboard/shared/starboard/media/mime_type.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace media {
+namespace {
+
+// The codecs tested by these tests were introduced in SB_API_VERSION 14.
+#if SB_API_VERSION >= 14
+constexpr char kEmptyKeySystem[] = "";
+constexpr int64_t kBitrate = 44100;
+
+TEST(MimeUtilTest, ChecksSupportedMp3Containers) {
+ const std::string valid_mp3_mime_str_1 =
+ "audio/mpeg; codecs=\"mp3\"; bitrate=44100";
+ const MimeType valid_mp3_mime_1(valid_mp3_mime_str_1);
+ EXPECT_EQ(
+ CanPlayMimeAndKeySystem(valid_mp3_mime_str_1.c_str(), kEmptyKeySystem),
+ SbMediaIsAudioSupported(kSbMediaAudioCodecMp3, &valid_mp3_mime_1,
+ kBitrate)
+ ? kSbMediaSupportTypeProbably
+ : kSbMediaSupportTypeNotSupported);
+
+ const std::string valid_mp3_mime_str_2 =
+ "audio/mp3; codecs=\"mp3\"; bitrate=44100";
+ const MimeType valid_mp3_mime_2(valid_mp3_mime_str_2);
+ EXPECT_EQ(
+ CanPlayMimeAndKeySystem(valid_mp3_mime_str_2.c_str(), kEmptyKeySystem),
+ SbMediaIsAudioSupported(kSbMediaAudioCodecMp3, &valid_mp3_mime_2,
+ kBitrate)
+ ? kSbMediaSupportTypeProbably
+ : kSbMediaSupportTypeNotSupported);
+}
+
+TEST(MimeUtilTest, ChecksUnsupportedMp3Containers) {
+ // Invalid container for MP3 codec.
+ const std::string invalid_mp3_mime_str =
+ "audio/mp4; codecs=\"mp3\"; bitrate=44100";
+ const MimeType invalid_mp3_mime(invalid_mp3_mime_str);
+ EXPECT_EQ(
+ CanPlayMimeAndKeySystem(invalid_mp3_mime_str.c_str(), kEmptyKeySystem),
+ kSbMediaSupportTypeNotSupported);
+}
+
+TEST(MimeUtilTest, ChecksSupportedFlacContainers) {
+ const std::string valid_flac_mime_str_1 =
+ "audio/ogg; codecs=\"flac\"; bitrate=44100";
+ const MimeType valid_flac_mime_1(valid_flac_mime_str_1);
+ EXPECT_EQ(
+ CanPlayMimeAndKeySystem(valid_flac_mime_str_1.c_str(), kEmptyKeySystem),
+ SbMediaIsAudioSupported(kSbMediaAudioCodecMp3, &valid_flac_mime_1,
+ kBitrate)
+ ? kSbMediaSupportTypeProbably
+ : kSbMediaSupportTypeNotSupported);
+
+ const std::string valid_flac_mime_str_2 =
+ "audio/flac; codecs=\"flac\"; bitrate=44100";
+ const MimeType valid_flac_mime_2(valid_flac_mime_str_2);
+ EXPECT_EQ(
+ CanPlayMimeAndKeySystem(valid_flac_mime_str_2.c_str(), kEmptyKeySystem),
+ SbMediaIsAudioSupported(kSbMediaAudioCodecMp3, &valid_flac_mime_2,
+ kBitrate)
+ ? kSbMediaSupportTypeProbably
+ : kSbMediaSupportTypeNotSupported);
+}
+
+TEST(MimeUtilTest, ChecksUnsupportedFlacContainers) {
+ // Invalid container for FLAC codec.
+ const std::string invalid_flac_mime_str =
+ "audio/mp4; codecs=\"flac\"; bitrate=44100";
+ const MimeType invalid_flac_mime(invalid_flac_mime_str);
+ EXPECT_EQ(
+ CanPlayMimeAndKeySystem(invalid_flac_mime_str.c_str(), kEmptyKeySystem),
+ kSbMediaSupportTypeNotSupported);
+}
+
+TEST(MimeUtilTest, ChecksSupportedPcmContainers) {
+ const std::string valid_pcm_mime_str =
+ "audio/wav; codecs=\"1\"; bitrate=44100";
+ const MimeType valid_pcm_mime(valid_pcm_mime_str);
+ EXPECT_EQ(
+ CanPlayMimeAndKeySystem(valid_pcm_mime_str.c_str(), kEmptyKeySystem),
+ SbMediaIsAudioSupported(kSbMediaAudioCodecPcm, &valid_pcm_mime, kBitrate)
+ ? kSbMediaSupportTypeProbably
+ : kSbMediaSupportTypeNotSupported);
+}
+
+TEST(MimeUtilTest, ChecksUnsupportedWavCodecs) {
+ const std::string invalid_wav_mime_str =
+ "audio/wav; codecs=\"aac\"; bitrate=44100";
+ const MimeType invalid_wav_mime(invalid_wav_mime_str);
+ EXPECT_EQ(
+ CanPlayMimeAndKeySystem(invalid_wav_mime_str.c_str(), kEmptyKeySystem),
+ kSbMediaSupportTypeNotSupported);
+}
+#endif // SB_API_VERSION >= 14
+
+} // namespace
+} // namespace media
+} // namespace starboard
+} // namespace shared
+} // namespace starboard
diff --git a/starboard/shared/starboard/player/filter/audio_resampler_impl.cc b/starboard/shared/starboard/player/filter/audio_resampler_impl.cc
index c07f29e..b0fa874 100644
--- a/starboard/shared/starboard/player/filter/audio_resampler_impl.cc
+++ b/starboard/shared/starboard/player/filter/audio_resampler_impl.cc
@@ -12,9 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "starboard/shared/starboard/player/filter/audio_resampler.h"
+
+#include <deque>
+
#include "starboard/common/log.h"
#include "starboard/configuration.h"
-#include "starboard/shared/starboard/player/filter/audio_resampler.h"
#include "starboard/shared/starboard/player/filter/interleaved_sinc_resampler.h"
namespace starboard {
@@ -58,8 +61,11 @@
SbMediaAudioSampleType destination_sample_type_;
SbMediaAudioFrameStorageType destination_storage_type_;
+ std::deque<scoped_refptr<DecodedAudio>> audio_inputs_;
+
size_t frames_to_resample_ = 0;
size_t frames_resampled_ = 0;
+ size_t frames_outputted_ = 0;
};
} // namespace
@@ -82,69 +88,84 @@
scoped_refptr<DecodedAudio> AudioResamplerImpl::WriteEndOfStream() {
double sample_rate_ratio = interleaved_resampler_.GetSampleRateRatio();
int out_num_of_frames =
- round(frames_to_resample_ / sample_rate_ratio) - frames_resampled_;
+ round(frames_to_resample_ / sample_rate_ratio) - frames_outputted_;
if (out_num_of_frames > 0) {
- interleaved_resampler_.QueueBuffer(nullptr, 0);
- int channels = interleaved_resampler_.channels();
- int resampled_audio_size = out_num_of_frames * channels * sizeof(float);
- scoped_refptr<DecodedAudio> resampled_audio = new DecodedAudio(
- channels, kSbMediaAudioSampleTypeFloat32,
- kSbMediaAudioFrameStorageTypeInterleaved, 0, resampled_audio_size);
+ SB_DCHECK(!audio_inputs_.empty());
+ // If there're frames left in |interleaved_resampler_|, |audio_inputs_|
+ // should not be empty. To be cautious in production, we add a check here.
+ if (!audio_inputs_.empty()) {
+ interleaved_resampler_.QueueBuffer(nullptr, 0);
+ int channels = interleaved_resampler_.channels();
+ int resampled_audio_size = out_num_of_frames * channels * sizeof(float);
+ scoped_refptr<DecodedAudio> resampled_audio = new DecodedAudio(
+ channels, kSbMediaAudioSampleTypeFloat32,
+ kSbMediaAudioFrameStorageTypeInterleaved,
+ audio_inputs_.front()->timestamp(), resampled_audio_size);
- float* dst = reinterpret_cast<float*>(resampled_audio->data());
- interleaved_resampler_.Resample(dst, out_num_of_frames);
+ float* dst = reinterpret_cast<float*>(resampled_audio->data());
+ interleaved_resampler_.Resample(dst, out_num_of_frames);
- if (!resampled_audio->IsFormat(destination_sample_type_,
- destination_storage_type_)) {
- resampled_audio = resampled_audio->SwitchFormatTo(
- destination_sample_type_, destination_storage_type_);
+ if (!resampled_audio->IsFormat(destination_sample_type_,
+ destination_storage_type_)) {
+ resampled_audio = resampled_audio->SwitchFormatTo(
+ destination_sample_type_, destination_storage_type_);
+ }
+ return resampled_audio;
}
- return resampled_audio;
}
return new DecodedAudio;
}
scoped_refptr<DecodedAudio> AudioResamplerImpl::Resample(
- scoped_refptr<DecodedAudio> audio_data) {
- SB_DCHECK(audio_data->channels() == interleaved_resampler_.channels());
+ scoped_refptr<DecodedAudio> audio_input) {
+ SB_DCHECK(audio_input->channels() == interleaved_resampler_.channels());
+
+ audio_inputs_.push_back(audio_input);
// It does nothing if source sample type is float and source storage type is
// interleaved.
- if (!audio_data->IsFormat(kSbMediaAudioSampleTypeFloat32,
- kSbMediaAudioFrameStorageTypeInterleaved)) {
- audio_data =
- audio_data->SwitchFormatTo(kSbMediaAudioSampleTypeFloat32,
- kSbMediaAudioFrameStorageTypeInterleaved);
+ if (!audio_input->IsFormat(kSbMediaAudioSampleTypeFloat32,
+ kSbMediaAudioFrameStorageTypeInterleaved)) {
+ audio_input =
+ audio_input->SwitchFormatTo(kSbMediaAudioSampleTypeFloat32,
+ kSbMediaAudioFrameStorageTypeInterleaved);
}
- int num_of_frames = audio_data->frames();
- frames_to_resample_ += num_of_frames;
- int channels = audio_data->channels();
- int out_num_of_frames = static_cast<int>(
- ceil(num_of_frames / interleaved_resampler_.GetSampleRateRatio()));
+ // Enqueue the input.
+ int num_of_input_frames = audio_input->frames();
+ frames_to_resample_ += num_of_input_frames;
+ float* input_samples = reinterpret_cast<float*>(audio_input->data());
+ interleaved_resampler_.QueueBuffer(input_samples, num_of_input_frames);
- int resampled_audio_size = out_num_of_frames * channels * sizeof(float);
+ // Check if we have enough frames to output.
+ scoped_refptr<DecodedAudio>& next_audio_to_output = audio_inputs_.front();
+ int num_of_output_frames =
+ static_cast<int>(
+ ceil((frames_resampled_ + next_audio_to_output->frames()) /
+ interleaved_resampler_.GetSampleRateRatio())) -
+ frames_outputted_;
+ int channels = next_audio_to_output->channels();
scoped_refptr<DecodedAudio> resampled_audio = nullptr;
-
- float* samples = reinterpret_cast<float*>(audio_data->data());
- interleaved_resampler_.QueueBuffer(samples, num_of_frames);
-
- if (interleaved_resampler_.HasEnoughData(out_num_of_frames)) {
+ if (interleaved_resampler_.HasEnoughData(num_of_output_frames)) {
+ int output_audio_size = num_of_output_frames * channels * sizeof(float);
resampled_audio =
new DecodedAudio(channels, kSbMediaAudioSampleTypeFloat32,
kSbMediaAudioFrameStorageTypeInterleaved,
- audio_data->timestamp(), resampled_audio_size);
+ next_audio_to_output->timestamp(), output_audio_size);
float* dst = reinterpret_cast<float*>(resampled_audio->data());
- interleaved_resampler_.Resample(dst, out_num_of_frames);
- frames_resampled_ += out_num_of_frames;
+ interleaved_resampler_.Resample(dst, num_of_output_frames);
+ frames_resampled_ += next_audio_to_output->frames();
+ frames_outputted_ += num_of_output_frames;
if (!resampled_audio->IsFormat(destination_sample_type_,
destination_storage_type_)) {
resampled_audio = resampled_audio->SwitchFormatTo(
destination_sample_type_, destination_storage_type_);
}
+
+ audio_inputs_.pop_front();
}
return resampled_audio;
diff --git a/starboard/shared/starboard/player/filter/testing/BUILD.gn b/starboard/shared/starboard/player/filter/testing/BUILD.gn
index 80f2765..9d6f6b9 100644
--- a/starboard/shared/starboard/player/filter/testing/BUILD.gn
+++ b/starboard/shared/starboard/player/filter/testing/BUILD.gn
@@ -26,6 +26,7 @@
"audio_decoder_test.cc",
"audio_frame_discarder_test.cc",
"audio_renderer_internal_test.cc",
+ "audio_resampler_test.cc",
"file_cache_reader_test.cc",
"media_time_provider_impl_test.cc",
"player_components_test.cc",
@@ -38,6 +39,7 @@
public_deps = [
":test_util",
+ "//starboard:starboard_with_main",
"//starboard/shared/starboard/media:media_util",
"//testing/gmock",
]
diff --git a/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc b/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
index 7a2b8fe..5d6f6e0 100644
--- a/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
+++ b/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
@@ -43,6 +43,7 @@
namespace testing {
namespace {
+using std::deque;
using std::string;
using std::vector;
using ::testing::Bool;
@@ -112,9 +113,11 @@
ASSERT_LT(buffer_index, dmp_reader->number_of_audio_buffers());
can_accept_more_input_ = false;
+ scoped_refptr<InputBuffer> input =
+ GetAudioInputBuffer(dmp_reader, buffer_index);
+ written_inputs_.push_back(input);
audio_decoder_->Decode(
- {GetAudioInputBuffer(dmp_reader, buffer_index)},
- std::bind(&AdaptiveAudioDecoderTest::OnConsumed, this));
+ {input}, std::bind(&AdaptiveAudioDecoderTest::OnConsumed, this));
}
void WriteMultipleInputs(VideoDmpReader* dmp_reader,
@@ -191,6 +194,7 @@
vector<std::unique_ptr<VideoDmpReader>> dmp_readers_;
scoped_refptr<DecodedAudio> last_decoded_audio_;
+ deque<scoped_refptr<InputBuffer>> written_inputs_;
int num_of_output_frames_ = 0;
int output_sample_rate_;
bool first_output_received_ = false;
@@ -244,11 +248,23 @@
last_decoded_audio_ = decoded_audio;
return;
}
- // TODO: fix resampler timestamp issue.
- // if (last_decoded_audio_) {
- // ASSERT_LT(last_decoded_audio_->timestamp(),
- // decoded_audio->timestamp());
- // }
+
+ // Stub decoder doesn't produce outputs with right timestamp.
+ if (!using_stub_decoder_) {
+ ASSERT_NEAR(decoded_audio->timestamp(),
+ written_inputs_.front()->timestamp(), 5);
+ written_inputs_.pop_front();
+
+ // TODO: The timestamps of inputs are not monotonic increasing, so
+ // that we can't get monotonic increasing output timestamps here. We
+ // can enable the check below once we make the input timestamps monotonic
+ // increasing.
+ if (last_decoded_audio_) {
+ // ASSERT_LE(last_decoded_audio_->timestamp(),
+ // decoded_audio->timestamp());
+ }
+ }
+
last_decoded_audio_ = decoded_audio;
num_of_output_frames_ += last_decoded_audio_->frames();
}
diff --git a/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc b/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
index 43fbff5..b9500df 100644
--- a/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
+++ b/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
@@ -224,10 +224,7 @@
ASSERT_EQ(decoded_audio_sample_type_, local_decoded_audio->sample_type());
ASSERT_EQ(decoded_audio_sample_rate_, decoded_sample_rate);
- // TODO: Adaptive audio decoder may set output timestamp to 0, so we don't
- // verify audio timestamp if it's 0. Consider enabling it after we
- // fix timestamp issues.
- if (local_decoded_audio->timestamp() != 0 && !decoded_audios_.empty()) {
+ if (!decoded_audios_.empty()) {
ASSERT_LT(decoded_audios_.back()->timestamp(),
local_decoded_audio->timestamp());
}
diff --git a/starboard/shared/starboard/player/filter/testing/audio_resampler_test.cc b/starboard/shared/starboard/player/filter/testing/audio_resampler_test.cc
new file mode 100644
index 0000000..ad88fa6
--- /dev/null
+++ b/starboard/shared/starboard/player/filter/testing/audio_resampler_test.cc
@@ -0,0 +1,195 @@
+// Copyright 2023 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 <tuple>
+#include <vector>
+
+#include "starboard/common/string.h"
+#include "starboard/shared/starboard/player/filter/audio_resampler.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace player {
+namespace filter {
+namespace testing {
+namespace {
+
+using ::testing::Combine;
+using ::testing::ValuesIn;
+
+typedef ::testing::tuple<SbMediaAudioSampleType,
+ SbMediaAudioFrameStorageType,
+ int,
+ SbMediaAudioSampleType,
+ SbMediaAudioFrameStorageType,
+ int,
+ int>
+ AudioResamplerTestParam;
+
+SbMediaAudioSampleType kSampleTypesToTest[] = {
+ kSbMediaAudioSampleTypeInt16Deprecated,
+ kSbMediaAudioSampleTypeFloat32,
+};
+SbMediaAudioFrameStorageType kStorageTypesToTest[] = {
+ kSbMediaAudioFrameStorageTypeInterleaved,
+ kSbMediaAudioFrameStorageTypePlanar,
+};
+int kSampleRatesToTest[] = {22050, 44100, 48000};
+int kChannelsToTest[] = {1, 2, 6};
+
+const char* ConvertSampleTypeToString(SbMediaAudioSampleType sample_type) {
+ if (sample_type == kSbMediaAudioSampleTypeInt16Deprecated) {
+ return "int16";
+ } else if (sample_type == kSbMediaAudioSampleTypeFloat32) {
+ return "float32";
+ }
+ SB_NOTREACHED();
+ return "";
+}
+
+const char* ConvertStorageTypeToString(
+ SbMediaAudioFrameStorageType storage_type) {
+ if (storage_type == kSbMediaAudioFrameStorageTypeInterleaved) {
+ return "interleaved";
+ } else if (storage_type == kSbMediaAudioFrameStorageTypePlanar) {
+ return "planar";
+ }
+ SB_NOTREACHED();
+ return "";
+}
+
+class AudioResamplerTest
+ : public ::testing::TestWithParam<AudioResamplerTestParam> {
+ protected:
+ AudioResamplerTest() {
+ const AudioResamplerTestParam& param = GetParam();
+ source_sample_type_ = std::get<0>(param);
+ source_storage_type_ = std::get<1>(param);
+ source_sample_rate_ = std::get<2>(param);
+ destination_sample_type_ = std::get<3>(param);
+ destination_storage_type_ = std::get<4>(param);
+ destination_sample_rate_ = std::get<5>(param);
+ channels_ = std::get<6>(param);
+
+ GenerateAudioInputs();
+ }
+
+ void GenerateAudioInputs() {
+ const int kNumberOfInputs = 40;
+ const int kSamplesPerInput = 1024;
+
+ int total_frames = 0;
+ for (int i = 0; i < kNumberOfInputs; i++) {
+ int sample_size =
+ source_sample_type_ == kSbMediaAudioSampleTypeInt16Deprecated
+ ? sizeof(int16_t)
+ : sizeof(float);
+ int audio_size = kSamplesPerInput * channels_ * sample_size;
+ scoped_refptr<DecodedAudio> input = new DecodedAudio(
+ channels_, source_sample_type_, source_storage_type_,
+ kSbTimeSecond * total_frames / source_sample_rate_, audio_size);
+ total_frames += kSamplesPerInput;
+ inputs_.push_back(input);
+ }
+ }
+
+ SbMediaAudioSampleType source_sample_type_;
+ SbMediaAudioFrameStorageType source_storage_type_;
+ int source_sample_rate_;
+ SbMediaAudioSampleType destination_sample_type_;
+ SbMediaAudioFrameStorageType destination_storage_type_;
+ int destination_sample_rate_;
+ int channels_;
+
+ std::vector<scoped_refptr<DecodedAudio>> inputs_;
+};
+
+TEST_P(AudioResamplerTest, SunnyDay) {
+ scoped_ptr<AudioResampler> resampler = AudioResampler::Create(
+ source_sample_type_, source_storage_type_, source_sample_rate_,
+ destination_sample_type_, destination_storage_type_,
+ destination_sample_rate_, channels_);
+
+ int total_input_frames = 0;
+ std::vector<scoped_refptr<DecodedAudio>> outputs;
+ for (auto input : inputs_) {
+ scoped_refptr<DecodedAudio> output = resampler->Resample(input);
+ total_input_frames += input->frames();
+ if (output) {
+ outputs.push_back(output);
+ }
+ }
+ scoped_refptr<DecodedAudio> output = resampler->WriteEndOfStream();
+ if (output) {
+ outputs.push_back(output);
+ }
+
+ // Theoretically, if the input is too small, the last output could consist
+ // of multiple inputs. But as our audio unit is always larger than resampler
+ // block size. The amount of outputs should be always same as the inputs, and
+ // they should have same timestamp.
+ EXPECT_EQ(inputs_.size(), outputs.size());
+ int total_output_frames = 0;
+ for (int i = 0; i < outputs.size(); i++) {
+ EXPECT_EQ(inputs_[i]->timestamp(), outputs[i]->timestamp());
+ total_output_frames += outputs[i]->frames();
+ EXPECT_NEAR(
+ inputs_[i]->frames() * destination_sample_rate_ / source_sample_rate_,
+ outputs[i]->frames(), 5);
+ }
+ EXPECT_NEAR(
+ total_input_frames * destination_sample_rate_ / source_sample_rate_,
+ total_output_frames, 5);
+}
+
+std::string GetTestConfigName(
+ ::testing::TestParamInfo<AudioResamplerTestParam> info) {
+ const AudioResamplerTestParam& param = info.param;
+ SbMediaAudioSampleType source_sample_type = std::get<0>(param);
+ SbMediaAudioFrameStorageType source_storage_type = std::get<1>(param);
+ int source_sample_rate = std::get<2>(param);
+ SbMediaAudioSampleType destination_sample_type = std::get<3>(param);
+ SbMediaAudioFrameStorageType destination_storage_type = std::get<4>(param);
+ int destination_sample_rate = std::get<5>(param);
+ int channels = std::get<6>(param);
+ std::string name = FormatString(
+ "%s_%s_%d_to_%s_%s_%d_channels_%d",
+ ConvertSampleTypeToString(source_sample_type),
+ ConvertStorageTypeToString(source_storage_type), source_sample_rate,
+ ConvertSampleTypeToString(destination_sample_type),
+ ConvertStorageTypeToString(destination_storage_type),
+ destination_sample_rate, channels);
+ return name;
+}
+
+INSTANTIATE_TEST_CASE_P(AudioResamplerTests,
+ AudioResamplerTest,
+ Combine(ValuesIn(kSampleTypesToTest),
+ ValuesIn(kStorageTypesToTest),
+ ValuesIn(kSampleRatesToTest),
+ ValuesIn(kSampleTypesToTest),
+ ValuesIn(kStorageTypesToTest),
+ ValuesIn(kSampleRatesToTest),
+ ValuesIn(kChannelsToTest)),
+ GetTestConfigName);
+
+} // namespace
+} // namespace testing
+} // namespace filter
+} // namespace player
+} // namespace starboard
+} // namespace shared
+} // namespace starboard
diff --git a/starboard/shared/starboard/player/filter/tools/BUILD.gn b/starboard/shared/starboard/player/filter/tools/BUILD.gn
index b2d0a78..f1842ff 100644
--- a/starboard/shared/starboard/player/filter/tools/BUILD.gn
+++ b/starboard/shared/starboard/player/filter/tools/BUILD.gn
@@ -18,7 +18,7 @@
sources = [ "audio_dmp_player.cc" ]
configs += [ "//starboard/build/config:starboard_implementation" ]
public_deps = [
- "//starboard",
+ "//starboard:starboard_with_main",
"//starboard/shared/starboard/media:media_util",
"//starboard/shared/starboard/player:player_download_test_data",
"//starboard/shared/starboard/player:video_dmp",
diff --git a/starboard/shared/uwp/media_is_video_supported.cc b/starboard/shared/uwp/media_is_video_supported.cc
index 5316a98..eab4c87 100644
--- a/starboard/shared/uwp/media_is_video_supported.cc
+++ b/starboard/shared/uwp/media_is_video_supported.cc
@@ -112,11 +112,7 @@
case starboard::shared::uwp::kXboxOneX:
// Horizontal video resolutions
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 3840, 2160,
- 30);
- hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 2560, 1440,
60);
- // Until we can resolve b/170881040, we should cap Xbox One X to 2K for
- // HDR 60 FPS.
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 3840, 2160,
30);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 2560, 1440,
@@ -124,7 +120,7 @@
// Vertical video resolutions
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 2160, 3840,
30);
- hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 1440, 2560,
+ hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 2160, 3840,
60);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 2160, 3840,
30);
diff --git a/starboard/shared/x11/application_x11.cc b/starboard/shared/x11/application_x11.cc
index d2b4f12..7efa103 100644
--- a/starboard/shared/x11/application_x11.cc
+++ b/starboard/shared/x11/application_x11.cc
@@ -919,7 +919,12 @@
return pending_event;
}
- SB_DCHECK(dev_input_);
+ // In modular builds, |CreateWindow| is not always called before the event
+ // loop is running.
+ if (!dev_input_) {
+ return nullptr;
+ }
+
shared::starboard::Application::Event* evdev_event =
dev_input_->WaitForSystemEventWithTimeout(time);
diff --git a/starboard/tools/abstract_launcher.py b/starboard/tools/abstract_launcher.py
index ff0ad61..9928039 100644
--- a/starboard/tools/abstract_launcher.py
+++ b/starboard/tools/abstract_launcher.py
@@ -26,6 +26,8 @@
ARG_SYSTOOLS = "systools"
ARG_DRYRUN = "dryrun"
+IS_MODULAR_BUILD = os.getenv("MODULAR_BUILD", "0") == "1"
+
def _GetLauncherForPlatform(platform_name):
"""Gets the module containing a platform's concrete launcher implementation.
diff --git a/starboard/xb1/args.gn b/starboard/xb1/args.gn
index 5101b33..2bf8065 100644
--- a/starboard/xb1/args.gn
+++ b/starboard/xb1/args.gn
@@ -16,4 +16,3 @@
target_os = "winuwp"
target_cpu = "x64"
is_clang = false
-is_internal_build = false
diff --git a/starboard/xb1/platform_configuration/BUILD.gn b/starboard/xb1/platform_configuration/BUILD.gn
index 5c493ae..68b7862 100644
--- a/starboard/xb1/platform_configuration/BUILD.gn
+++ b/starboard/xb1/platform_configuration/BUILD.gn
@@ -57,9 +57,10 @@
"vcruntime.lib",
"ucrt.lib",
]
- ldflags += [ "/DEBUG:FASTLINK" ]
}
+ ldflags += [ "/DEBUG:FASTLINK" ]
+
ldflags += [ "/NODEFAULTLIB" ]
arflags += [ "/NODEFAULTLIB" ]
libs += [
diff --git a/third_party/boringssl/BUILD.gn b/third_party/boringssl/BUILD.gn
index f90940c..51f71e4 100644
--- a/third_party/boringssl/BUILD.gn
+++ b/third_party/boringssl/BUILD.gn
@@ -176,26 +176,3 @@
configs += [ "//starboard/build/config:speed" ]
}
}
-
-target(final_executable_type, "crypto_tool") {
- sources = [
- "src/tool/args.cc",
- "src/tool/ciphers.cc",
- "src/tool/const.cc",
- "src/tool/digest.cc",
- "src/tool/file.cc",
- "src/tool/generate_ed25519.cc",
- "src/tool/genrsa.cc",
- "src/tool/pkcs12.cc",
- "src/tool/rand.cc",
- "src/tool/sign.cc",
- "src/tool/speed.cc",
- "src/tool/tool.cc",
- ]
- include_dirs = [ "src/include" ]
- defines = [ "OPENSSL_NO_SOCK" ]
- deps = [ ":crypto" ]
- if (is_starboard) {
- deps += [ "//starboard" ]
- }
-}
diff --git a/third_party/inspector_protocol/crdtp/json_platform.cc b/third_party/inspector_protocol/crdtp/json_platform.cc
index facc7c8..968df8e 100644
--- a/third_party/inspector_protocol/crdtp/json_platform.cc
+++ b/third_party/inspector_protocol/crdtp/json_platform.cc
@@ -26,7 +26,6 @@
}
std::string DToStr(double value) {
- //Ask Kaido/Yavor if this is needed.
#if SB_IS(MODULAR)
#error "The std::locale::classic() is not supported for Evergreen. Please use base::NumberToString()."
#endif
diff --git a/third_party/llvm-project/libcxx/BUILD.gn b/third_party/llvm-project/libcxx/BUILD.gn
index 1d47c23..0c80cac 100644
--- a/third_party/llvm-project/libcxx/BUILD.gn
+++ b/third_party/llvm-project/libcxx/BUILD.gn
@@ -119,7 +119,4 @@
"//third_party/llvm-project/libcxxabi:cxxabi",
"//third_party/musl:c",
]
- if (!build_with_separate_cobalt_toolchain) {
- deps += [ "//third_party/llvm-project/libunwind:unwind_evergreen" ]
- }
}
diff --git a/third_party/llvm-project/libcxxabi/BUILD.gn b/third_party/llvm-project/libcxxabi/BUILD.gn
index 0ed1b42..9142fa4 100644
--- a/third_party/llvm-project/libcxxabi/BUILD.gn
+++ b/third_party/llvm-project/libcxxabi/BUILD.gn
@@ -90,7 +90,4 @@
all_dependent_configs = [ ":cxxabi_dependents_config" ]
deps = [ "//third_party/musl:c" ]
- if (!build_with_separate_cobalt_toolchain) {
- deps += [ "//third_party/llvm-project/libunwind:unwind_evergreen" ]
- }
}
diff --git a/third_party/llvm-project/libunwind/BUILD.gn b/third_party/llvm-project/libunwind/BUILD.gn
index 44d7882..cedc13b 100644
--- a/third_party/llvm-project/libunwind/BUILD.gn
+++ b/third_party/llvm-project/libunwind/BUILD.gn
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import("//starboard/build/config/os_definitions.gni")
+
common_sources = [
"src/AddressSpace.hpp",
"src/CompactUnwinder.hpp",
@@ -55,8 +57,9 @@
# dependencies from spilling over to gn check when run for non-evergreen
# platforms (e.g., raspi-2_gn_devel). It can and should be removed once the gn
# check errors have been resolved for evergreen.
-if (sb_is_evergreen) {
- config("unwind_evergreen_config") {
+# TODO: b/295702296 Fix libunwind for modular builds.
+if (sb_is_evergreen || (sb_is_modular && is_host_win)) {
+ config("unwind_config") {
configs = [ ":common_unwind_dependents_config" ]
cflags = [
@@ -90,10 +93,10 @@
]
}
- static_library("unwind_evergreen") {
+ static_library("unwind") {
sources = common_sources
- configs += [ ":unwind_evergreen_config" ]
+ configs += [ ":unwind_config" ]
all_dependent_configs = [ ":common_unwind_dependents_config" ]
deps = [
diff --git a/third_party/musl/BUILD.gn b/third_party/musl/BUILD.gn
index 740216a..8d00e30 100644
--- a/third_party/musl/BUILD.gn
+++ b/third_party/musl/BUILD.gn
@@ -520,9 +520,7 @@
]
}
-target(gtest_target_type, "musl_unittests") {
- build_loader = false
- testonly = true
+static_library("musl_unittests") {
sources = [ "test/type_size_test.cc" ]
deps = [
":c",
diff --git a/third_party/musl/test/type_size_test.cc b/third_party/musl/test/type_size_test.cc
index f85a0ce..ae2e93f 100644
--- a/third_party/musl/test/type_size_test.cc
+++ b/third_party/musl/test/type_size_test.cc
@@ -190,8 +190,13 @@
// TODO: Decide if we should, and how, verify that __WCHAR_TYPE__ is the
// expected size.
#else // !SB_IS(ARCH_X86)
+#if SB_IS(WCHAR_T_UTF16)
+SB_COMPILE_ASSERT(sizeof(wchar_t) == 2,
+ SB_IS_WCHAR_T_UTF16_is_inconsistent_with_sizeof_wchar_t);
+#else
SB_COMPILE_ASSERT(sizeof(wchar_t) == SB_SIZE_OF_INT,
SB_SIZE_OF_INT_is_inconsistent_with_sizeof_wchar_t);
+#endif // SB_IS(WCHAR_T_UTF16)
#endif // SB_IS(ARCH_X86)
#endif // SB_IS(MODULAR)
diff --git a/third_party/opus/starboard/config.h b/third_party/opus/starboard/config.h
index 7c67f29..4a9f5e1 100644
--- a/third_party/opus/starboard/config.h
+++ b/third_party/opus/starboard/config.h
@@ -35,6 +35,9 @@
#define OPUS_BUILD 1
+/* Don't let EXPORT to be redefined by later config code. */
+#define OPUS_EXPORT
+
#if defined(_M_IX86) || defined(_M_X64)
/* Can always compile SSE intrinsics (no special compiler flags necessary) */
#define OPUS_X86_MAY_HAVE_SSE