Import Cobalt 12.88774
Change-Id: Id685e20e1b1f8fec13607b39f552fad3cc76ebae
diff --git a/src/starboard/BUILD.gn b/src/starboard/BUILD.gn
new file mode 100644
index 0000000..8adaf0c
--- /dev/null
+++ b/src/starboard/BUILD.gn
@@ -0,0 +1,97 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+group("all") {
+ testonly = true
+ deps = [
+ # TODO: uncomment as each of these are implemented
+ # "//starboard/client_porting/eztime:all",
+ # "//starboard/client_porting/icu_init:all",
+ # "//starboard/client_porting/poem:all",
+ "//starboard/examples",
+ # "//starboard/nplb/blitter_pixel_tests:all",
+ "//starboard/nplb:all",
+ ":starboard",
+ ]
+
+ has_platform_tests =
+ exec_script("//build/dir_exists.py",
+ [ rebase_path("//$starboard_path/tests", root_build_dir) ],
+ "string") == "True"
+ if (has_platform_tests) {
+ deps += [ "//$starboard_path/tests" ]
+ }
+}
+
+source_set("starboard") {
+ sources = [
+ "atomic.h",
+ "audio_sink.h",
+ "blitter.h",
+ "byte_swap.h",
+ "character.h",
+ "condition_variable.h",
+ "configuration.h",
+ "decode_target.h",
+ "directory.h",
+ "double.h",
+ "drm.h",
+ "event.h",
+ "export.h",
+ "file.h",
+ "input.h",
+ "key.h",
+ "log.h",
+ "media.h",
+ "memory.h",
+ "microphone.h",
+ "mutex.h",
+ "once.h",
+ "player.h",
+ "queue.h",
+ "socket.h",
+ "socket_waiter.h",
+ "spin_lock.h",
+ "storage.h",
+ "string.h",
+ "system.h",
+ "thread.h",
+ "thread_types.h",
+ "time.h",
+ "time_zone.h",
+ "types.h",
+ "user.h",
+ "window.h",
+ "//starboard/shared/media_session/playback_state.h",
+ ]
+
+ private_sources = exec_script("tools/find_private_files.py",
+ [
+ rebase_path("//", root_build_dir),
+ "*.h",
+ ],
+ "list lines",
+ [ "//starboard/private" ])
+ sources += rebase_path(private_sources, ".", root_build_dir)
+
+ deps = [
+ "//starboard/common",
+ ]
+
+ public_deps = [
+ "//$starboard_path:starboard_platform",
+ ]
+
+ # TODO: handle shared_main_adapter.cc
+}
diff --git a/src/starboard/CHANGELOG.md b/src/starboard/CHANGELOG.md
index acbe7b4..6bcc0d7 100644
--- a/src/starboard/CHANGELOG.md
+++ b/src/starboard/CHANGELOG.md
@@ -8,12 +8,18 @@
## Version 6
-### Introduce pointer (mouse) input support.
+### Named `SbStorageRecord`s
+
+This extends the `SbStorage` interface with the ability to open named
+`SbStorageRecord`s. Calling `SbStorageOpenRecord` and `SbStorageDeleteRecord`
+with a `NULL` `name` parameter provides access to the old "default" record.
+
+### Introduce pointer (mouse) input support
This extends the `SbInput` interface with some enum values and data members to
allow mouse, wheel, and more generic pointer input.
-### Flexible audio specific config.
+### Flexible audio specific config
`SbMediaAudioHeader::audio_specific_config` will be a pointer instead of an
array.
@@ -26,7 +32,7 @@
Changes `SbTimeZoneGetName()` to be more flexible in what it is allowed to
return.
-### SbDecodeTargetNumberOfPlanesForFormat
+### `SbDecodeTargetNumberOfPlanesForFormat`
Adds the convenience inline function, SbDecodeTargetNumberOfPlanesForFormat() to
`starboard/decode_target.h`.
@@ -40,7 +46,7 @@
Removes `SbSystemPlatformErrorType` values specific to user status.
-### SbDecodeTarget support for the UYVY (i.e. YUV 422) format
+### `SbDecodeTarget` support for the UYVY (i.e. YUV 422) format
Add support for UYVY decode targets (e.g. YUV 422) via the
`kSbDecodeTargetFormat1PlaneUYVY` enum.
@@ -50,15 +56,19 @@
This adds SbKey codes for the colored keys found on most contemporary TV
remotes.
-### kSbEventTypeLowMemory
+### `kSbEventTypeLowMemory`
Adds a new event type -- `kSbEventTypeLowMemory` -- to allow a platform to
signal that the application may soon be terminated due to low memory
availability.
-### Interface change to SbPlayerWriteSample()
+### Interface change to `SbPlayerWriteSample()`
`const` is added to `sample_buffers` and `sample_buffer_sizes` parameters.
+### Support key status change
+Add `key_statuses_changed_callback` parameter to `SbDrmCreateSystem()` to
+support MediaKeySession::keyStatuses and MediaKeySession::onkeystatuseschange.
+
## Version 5
### Add Speech Recognizer API
diff --git a/src/starboard/README.md b/src/starboard/README.md
index 1487a1d..9f2d47f 100644
--- a/src/starboard/README.md
+++ b/src/starboard/README.md
@@ -5,6 +5,15 @@
that it does not.
+## GN Migration Notice
+
+Cobalt and Starboard are currently migrating from the GYP build system to the GN
+build system. This readme contains instructions for both systems. As of now, GN
+is not ready for general use for Cobalt/Starboard. If you are not a core Cobalt
+developer, you should probably ignore the sections titled "GN Instructions" for
+now.
+
+
## Interesting Source Locations
All source locations are specified relative to `src/starboard/` (this directory).
@@ -23,17 +32,6 @@
platforms that share some facet of their OS API.
-## Building with Starboard
-
-Follow the Cobalt instructions, except when invoking gyp:
-
- $ cobalt/build/gyp_cobalt -C debug linux-x64x11
-
-and when invoking ninja:
-
- $ ninja -C out/linux-x64x11_debug cobalt
-
-
## Quick Guide to Starting a Port
### I. Enumerate and Name Your Platform Configurations
@@ -113,6 +111,31 @@
And so on.
+#### GN Instructions
+
+Each `<binary-variant>/` directory must have at least `configuration_public.h`,
+`atomic_public.h`, `thread_types_public.h`, `BUILD.gn`, `configuration.gni`,
+and `buildconfig.gni`.
+
+In the BobCo's BobBox example, we would see a directory tree like:
+
+ * `src/third_party/starboard/bobbox/`
+ * `shared/`
+ * `mipseb/`
+ * `buildconfig.gni`
+ * `configuration.gni`
+ * `atomic_public.h`
+ * `BUILD.gn`
+ * `configuration_public.h`
+ * `thread_types_public.h`
+ * `mipsel/`
+ * `buildconfig.gni`
+ * `configuration.gni`
+ * `atomic_public.h`
+ * `BUILD.gn`
+ * `configuration_public.h`
+ * `thread_types_public.h`
+
### III. Base Your Port on a Reference Port
@@ -160,6 +183,26 @@
`src/third_party/starboard/bobbox/mipseb/gyp_configuration.py`, it would choose
the platform configuration name `bobbox-mipseb`.)
+#### GN Instructions
+
+Update `<binary-variant>/BUILD.gn` to point at all the source files that you
+want to build as your new Starboard implementation. The `//` expression in GN
+refers to the `src/` directory of your source tree. Otherwise, files are assumed
+to be relative to the directory the `BUILD.gn` or `.gni` file is in. The
+`BUILD.gn` file contains absolute paths, so the paths will still be valid if you
+copy it to a new directory. You can then incrementally replace files with new
+implementations as necessary.
+
+In order to use a new platform configuration in a build, you need to ensure that
+you have a `BUILD.gn`, `configuration.gni`, and `buildconfig.gni` in their
+own directory for each binary variant, plus the header files
+`configuration_public.h`, `atomic_public.h`, and `thread_types_public.h`. The GN
+build will scan your directories for these files, and then calculate a port name
+based on the directories between `src/third_party/starboard` and your
+`configuration.gni` files. (e.g. for
+`src/third_party/starboard/bobbox/mipseb/configuration.gni`, it would choose the
+platform configuration name `bobbox-mipseb`.)
+
### IV. A New Port, Step-by-Step
@@ -179,7 +222,7 @@
toolchain analogs for the toolchain for your platform.
1. In `gyp_configuration.gypi`
1. Update the names of the configurations and the default_configuration to
- be `<platform-configuation>_<build-type>` for your platform
+ be `<platform-configuration>_<build-type>` for your platform
configuration name, where `<build-type>` is one of `debug`, `devel`,
`qa`, `gold`.
1. Update your platform variables.
@@ -213,6 +256,46 @@
This will attempt to build the "No Platform Left Behind" test suite with your
new Starboard implementation, and you are ready to start porting!
+#### GN Instructions
+
+Follow the above list, except:
+
+ 1. Ignore the steps about `gyp_configuration.py` and `gyp_configuration.gypi`.
+ 1. Update `BUILD.gn` instead of `starboard_platform.gyp`.
+ 1. Also in `BUILD.gn`:
+ 1. Update your toolchain command-line flags and libraries, for all
+ configurations as well as for each individual configuration.
+ 1. Implement generic compiler configs such as `sb_pedantic_warnings`
+ and `rtti`.
+ 1. If you're not using a predefined toolchain, define one.
+ 1. In `buildconfig.gni`:
+ 1. If your platform is Linux-based, set `target_os_ = "linux"`.
+ 1. Set `target_cpu_` to your target architecture (e.g. `arm`, `ppc`,
+ `x64`, `x86`, `mips`).
+ 1. Set the target and host toolchains. If you defined a target
+ toolchain in `BUILD.gn`, you'll want to set it to that.
+ 1. In `configuration.gni`, set platform-specific defaults for any
+ variables that should be overriden for your Starboard platform. You
+ can find a list of such variables at `//cobalt/build/config/base.gni`
+ and `//starboard/build/config/base.gni`.
+
+
+You should now be able to run GN with your new port. From your `src/` directory:
+
+ $ gn args out/bobbox-mipseb_debug
+
+An editor will open up. Type into the editor:
+
+ cobalt_config = "debug"
+ target_platform = "bobbox-mipseb"
+
+Save and close the editor. Then run
+
+ $ ninja -C out/bobbox-mipseb_debug nplb
+
+This will attempt to build the "No Platform Left Behind" test suite with your
+new Starboard implementation, and you are ready to start porting!
+
## Suggested Implementation Order
diff --git a/src/starboard/build/config/BUILD.gn b/src/starboard/build/config/BUILD.gn
new file mode 100644
index 0000000..73454f9
--- /dev/null
+++ b/src/starboard/build/config/BUILD.gn
@@ -0,0 +1,91 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# TODO: change to //starboard eventually
+import("//cobalt/build/config/base.gni")
+import("//starboard/build/delegated_config.gni")
+
+# =============================================================================
+# COMPILER DEFAULTS
+# =============================================================================
+
+# TODO: only set these defines on the files that actually need them
+config("compiler_defaults") {
+ # The canonical way to detect Starboard is #if defined(STARBOARD). This
+ # should be defined both when building Starboard itself, and when building
+ # any other source file in a Starboard-based project.
+ defines = [ "STARBOARD" ]
+
+ if (gl_type == "none") {
+ defines += [ "SB_GYP_GL_TYPE_IS_NONE=1" ]
+ } else {
+ defines += [ "SB_GYP_GL_TYPE_IS_NONE=0" ]
+ }
+
+ if (abort_on_allocation_failure) {
+ defines += [ "SB_ABORT_ON_ALLOCATION_FAILURE" ]
+ }
+
+ if (sb_allow_memory_tracking) {
+ defines += [ "STARBOARD_ALLOWS_MEMORY_TRACKING" ]
+ }
+
+ if (sb_enable_lib) {
+ defines += [ "SB_IS_LIBRARY=1" ]
+ }
+
+ # There doesn't appear to be any way to use the C preprocessor to do
+ # string concatenation with the / character. This prevents us from using
+ # the preprocessor to assemble an include file path, so we have to do
+ # the concatenation here in GN.
+ # http://stackoverflow.com/questions/29601786/c-preprocessor-building-a-path-string
+ defines += [
+ "STARBOARD_ATOMIC_INCLUDE=\"$starboard_path/atomic_public.h\"",
+ "STARBOARD_CONFIGURATION_INCLUDE=\"$starboard_path/configuration_public.h\"",
+ "STARBOARD_THREAD_TYPES_INCLUDE=\"$starboard_path/thread_types_public.h\"",
+ ]
+
+ # TODO: find a way to remove this dependence on Cobalt
+ if (sb_media_platform == "starboard") {
+ defines += [ "SB_GYP_CAN_MEDIA_USE_STARBOARD_PIPELINE=1" ]
+ } else {
+ defines += [ "SB_GYP_CAN_MEDIA_USE_STARBOARD_PIPELINE=0" ]
+ }
+}
+
+# =============================================================================
+# DELEGATED CONFIGS
+# =============================================================================
+
+# Enables pedantic levels of warnings for the current toolchain.
+delegated_config("pedantic_warnings") {
+ path = "//$starboard_path"
+ generate_default = false
+}
+
+# Controls the optimization level
+delegated_config("optimizations") {
+ path = "//$starboard_path"
+ prefixes = [ "no", "debuggable", "full" ]
+}
+
+# Enables/disables rtti
+delegated_config("rtti") {
+ path = "//$starboard_path"
+}
+
+# Enables the exit-time-destructors warning.
+config("wexit_time_destructors") {
+ configs = [ "//$starboard_path:wexit_time_destructors" ]
+}
diff --git a/src/starboard/build/config/base.gni b/src/starboard/build/config/base.gni
new file mode 100644
index 0000000..7599e71
--- /dev/null
+++ b/src/starboard/build/config/base.gni
@@ -0,0 +1,81 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Import platform-specific defaults
+import("//$starboard_path/configuration.gni")
+
+# Starboard variables.
+
+# Enables embedding Starboard as a shared library within another app. This
+# requires a 'lib' starboard implementation for the corresponding platform.
+if (!defined(sb_enable_lib)) {
+ sb_enable_lib = false
+}
+
+# Directory path to static contents.
+if (!defined(sb_static_contents_output_base_dir)) {
+ sb_static_contents_output_base_dir = "$root_out_dir/content"
+}
+
+# Directory path to static contents' data.
+if (!defined(sb_static_contents_output_data_dir)) {
+ sb_static_contents_output_data_dir = "$root_out_dir/content/data"
+}
+
+# Halt execution on failure to allocate memory.
+if (!defined(abort_on_allocation_failure)) {
+ abort_on_allocation_failure = true
+}
+
+# The source of EGL and GLES headers and libraries.
+# Valid values (case and everything sensitive!):
+# "none" - No EGL + GLES implementation is available on this platform.
+# "system_gles3" - Use the system implementation of EGL + GLES3. The
+# headers and libraries must be on the system include and
+# link paths.
+# "system_gles2" - Use the system implementation of EGL + GLES2. The
+# headers and libraries must be on the system include and
+# link paths.
+# "glimp" - Cobalt's own EGL + GLES2 implementation. This requires a
+# valid Glimp implementation for the platform.
+# "angle" - A DirectX-to-OpenGL adaptation layer. This requires a valid
+# ANGLE implementation for the platform.
+# Choosing an unsupported value will result in a GN error:
+# "Unresolved dependencies: //cobalt/renderer/egl_and_gles:<gl_type>"
+if (!defined(gl_type)) {
+ gl_type = "system_gles2"
+}
+
+# TODO: Temporary indicator for Tizen - should eventually move to feature defines.
+if (!defined(is_tizen_os)) {
+ is_tizen_os = false
+}
+
+# The event polling mechanism available on this platform to support libevent.
+# Platforms may redefine to "poll" if necessary.
+# Other mechanisms, e.g. devpoll, kqueue, select, are not yet supported.
+if (!defined(sb_libevent_method)) {
+ sb_libevent_method = "epoll"
+}
+
+# Whether to allow memory tracking
+if (!defined(sb_allow_memory_tracking)) {
+ sb_allow_memory_tracking = (cobalt_config != "gold" && !sb_enable_lib)
+}
+
+
+# The system root for cross-compiles. Default: none.
+if (!defined(sysroot)) {
+ sysroot = ""
+}
diff --git a/src/starboard/build/config/fastbuild.gni b/src/starboard/build/config/fastbuild.gni
new file mode 100644
index 0000000..b1fe040
--- /dev/null
+++ b/src/starboard/build/config/fastbuild.gni
@@ -0,0 +1,18 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+declare_args() {
+ # If set to true, omits the generation of debugging symbols
+ cobalt_use_fastbuild = false
+}
diff --git a/src/starboard/build/config/sanitizers.gni b/src/starboard/build/config/sanitizers.gni
new file mode 100644
index 0000000..a1e9817
--- /dev/null
+++ b/src/starboard/build/config/sanitizers.gni
@@ -0,0 +1,40 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Modifications Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Allow for platform-specific customization of use_asan_by_default
+import("//$starboard_path/configuration.gni")
+
+declare_args() {
+ # Compile for Thread Sanitizer to find threading bugs.
+ use_tsan = false
+}
+
+declare_args() {
+ # Compile for Address Sanitizer to find memory bugs.
+ use_asan =
+ !use_tsan && (cobalt_config == "debug" || cobalt_config == "devel") &&
+ (defined(use_asan_by_default) && use_asan_by_default)
+}
+
+assert(!(use_asan && use_tsan), "ASan and TSan are mutually exclusive")
+
+if (current_toolchain != default_toolchain) {
+ # Disable sanitizers for non-default toolchains.
+ use_asan = false
+ use_tsan = false
+}
diff --git a/src/starboard/build/delegated_config.gni b/src/starboard/build/delegated_config.gni
new file mode 100644
index 0000000..cc96a51
--- /dev/null
+++ b/src/starboard/build/delegated_config.gni
@@ -0,0 +1,111 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The delegated_config template defines a family of configs which delegate to
+# real implementations elsewhere. The most notable use of this template is to
+# define toolchain-independent compiler configs, such as
+# //starboard/build/config:rtti (and its sisters :no_rtti and :default_rtti).
+#
+# The simplest way to use delegated_config is to specify only a path:
+#
+# delegated_config("rtti") {
+# path = "//$starboard_path"
+# }
+#
+# The sample code above will expand to:
+#
+# config("rtti") {
+# configs = [ "//$starboard_path:rtti" ]
+# }
+#
+# config("no_rtti") {
+# configs = [ "//$starboard_path:no_rtti" ]
+# }
+#
+# config("default_rtti") {
+# configs = [ "//$starboard_path:default_rtti" ]
+# }
+#
+# The BUILD.gn file is then expected to define each of those three configs (or
+# further delegate them to e.g. a toolchain's implementation).
+#
+# To use a different list of prefixes, set the prefixes option:
+#
+# delegated_config("optimizations") {
+# path = "//$starboard_path"
+# prefixes = [ "no", "debuggable", "full" ]
+# }
+#
+# This will expand to:
+#
+# config("no_optimizations") {
+# configs = [ "//$starboard_path:no_optimizations" ]
+# }
+#
+# config("debuggable_optimizations") {
+# configs = [ "//$starboard_path:debuggable_optimizations" ]
+# }
+#
+# config("full_optimizations") {
+# configs = [ "//$starboard_path:full_optimizations" ]
+# }
+#
+# config("default_optimizations") {
+# configs = [ "//$starboard_path:default_optimizations" ]
+# }
+#
+# Note that the default_optimizations config is generated, even though it is
+# not in the list of prefixes. If you don't want the default_optimizations
+# config to be generated, set generate_default = false:
+#
+# delegated_config("optimizations") {
+# path = "//$starboard_path"
+# prefixes = [ "no", "debuggable", "full" ]
+# generate_default = false
+# }
+#
+# Now only the no_, debuggable_, and full_ configs will be generated.
+
+template("delegated_config") {
+ assert(defined(invoker.path),
+ "You need to specify a path to the implementation")
+
+ if (defined(invoker.prefixes)) {
+ prefixes = invoker.prefixes
+ } else {
+ prefixes = [ "", "no" ]
+ }
+
+ foreach(prefix, prefixes) {
+ assert(prefix != "default",
+ "You shouldn't include \"default\" in the list of prefixes " +
+ "because it's separately generated.")
+
+ if (prefix == "") {
+ prefix_ = prefix
+ } else {
+ prefix_ = "${prefix}_"
+ }
+
+ config("$prefix_$target_name") {
+ configs = [ "${invoker.path}:$prefix_$target_name" ]
+ }
+ }
+
+ if (!(defined(invoker.generate_default) && !invoker.generate_default)) {
+ config("default_$target_name") {
+ configs = [ "${invoker.path}:default_$target_name" ]
+ }
+ }
+}
diff --git a/src/starboard/build/deploy.gni b/src/starboard/build/deploy.gni
new file mode 100644
index 0000000..0cd9369
--- /dev/null
+++ b/src/starboard/build/deploy.gni
@@ -0,0 +1,52 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This header file is meant to be included to provide a rule to deploy
+# a target on a target platform.
+#
+# Platforms needing such a deploy rule should define a template called
+# "deploy", which defines an action target which performs the necessary
+# actions (such as copying per-executable metadata files to the output
+# directory). This template should preferably be defined in
+# //$starboard_path/deploy.gni.
+#
+# To use this, at the top of the BUILD.gn file, import
+# //starboard/build/deploy.gni. Then, define a deploy target:
+#
+# deploy("deploy") {
+# executable_name = "the_primary_targets_name"
+# }
+#
+# See //starboard/nplb/BUILD.gn for an example.
+
+import("//$starboard_path/configuration.gni")
+
+if (defined(include_path_platform_deploy_gni)) {
+ import(include_path_platform_deploy_gni)
+} else {
+ # The default deploy action is to do nothing.
+ template("deploy") {
+ not_needed(invoker, "*")
+
+ # Create an empty target so we can still depend on it. Honor the testonly
+ # and visibility settings.
+ group(target_name) {
+ forward_variables_from(invoker,
+ [
+ "testonly",
+ "visibility",
+ ])
+ }
+ }
+}
diff --git a/src/starboard/build/toolchain/BUILD.gn b/src/starboard/build/toolchain/BUILD.gn
new file mode 100644
index 0000000..daf2fb3
--- /dev/null
+++ b/src/starboard/build/toolchain/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//starboard/build/toolchain/concurrent_links.gni")
+
+if (current_toolchain == default_toolchain) {
+ pool("link_pool") {
+ depth = concurrent_links
+ }
+}
diff --git a/src/starboard/build/toolchain/asan_symbolizer_path.gni b/src/starboard/build/toolchain/asan_symbolizer_path.gni
new file mode 100644
index 0000000..8ca146d
--- /dev/null
+++ b/src/starboard/build/toolchain/asan_symbolizer_path.gni
@@ -0,0 +1,23 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//starboard/build/config/sanitizers.gni")
+import("//starboard/build/toolchain/clang.gni")
+
+# TODO: is it really necessary to check whether ASAN is on here?
+if (use_asan) {
+ asan_symbolizer_path = "$clang_base_path/bin/llvm-symbolizer"
+} else {
+ asan_symbolizer_path = ""
+}
diff --git a/src/starboard/build/toolchain/clang.gni b/src/starboard/build/toolchain/clang.gni
new file mode 100644
index 0000000..6ef471a
--- /dev/null
+++ b/src/starboard/build/toolchain/clang.gni
@@ -0,0 +1,23 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+declare_args() {
+ clang_base_path = ""
+}
+
+if (clang_base_path == "") {
+ # clang_base_path depends on gyp_utils.py for its _CLANG_VERSION variable
+ clang_base_path = exec_script("get_clang_base_path.py", [], "trim string",
+ [ "//cobalt/build/gyp_utils.py" ])
+}
diff --git a/src/starboard/build/toolchain/concurrent_links.gni b/src/starboard/build/toolchain/concurrent_links.gni
new file mode 100644
index 0000000..22ac7e9
--- /dev/null
+++ b/src/starboard/build/toolchain/concurrent_links.gni
@@ -0,0 +1,45 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Modifications Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This file should only be imported from files that define toolchains.
+# There's no way to enforce this exactly, but all toolchains are processed
+# in the context of the default_toolchain, so we can at least check for that.
+assert(current_toolchain == default_toolchain)
+
+declare_args() {
+ # Limit the number of concurrent links; we often want to run fewer
+ # links at once than we do compiles, because linking is memory-intensive.
+ # The default to use varies by platform and by the amount of memory
+ # available, so we call out to a script to get the right value.
+ concurrent_links = -1
+}
+
+if (concurrent_links == -1) {
+ if (host_os == "win") {
+ _args = [ "--mem_per_link_gb=5" ]
+ } else if (host_os == "mac") {
+ _args = [ "--mem_per_link_gb=4" ]
+ }
+ else {
+ _args = []
+ }
+
+ # TODO(crbug.com/617429) Pass more build configuration info to the script
+ # so that we can compute better values.
+ concurrent_links = exec_script("get_concurrent_links.py", _args, "value")
+}
diff --git a/src/starboard/build/toolchain/gcc_ar_wrapper.py b/src/starboard/build/toolchain/gcc_ar_wrapper.py
new file mode 100755
index 0000000..4663f98
--- /dev/null
+++ b/src/starboard/build/toolchain/gcc_ar_wrapper.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Runs the 'ar' command after removing its output file first.
+
+This script is invoked like:
+ python gcc_ar_wrapper.py --ar=$AR --output=$OUT $OP $INPUTS
+to do the equivalent of:
+ rm -f $OUT && $AR $OP $OUT $INPUTS
+"""
+
+import argparse
+import os
+import subprocess
+import sys
+
+import wrapper_utils
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--ar',
+ required=True,
+ help='The ar binary to run',
+ metavar='PATH')
+ parser.add_argument('--output',
+ required=True,
+ help='Output archive file',
+ metavar='ARCHIVE')
+ parser.add_argument('--plugin',
+ help='Load plugin')
+ parser.add_argument('operation',
+ help='Operation on the archive')
+ parser.add_argument('inputs', nargs='+',
+ help='Input files')
+ args = parser.parse_args()
+
+ command = [args.ar, args.operation]
+ if args.plugin is not None:
+ command += ['--plugin', args.plugin]
+ command.append(args.output)
+ command += args.inputs
+
+ # Remove the output file first.
+ try:
+ os.remove(args.output)
+ except OSError as e:
+ if e.errno != os.errno.ENOENT:
+ raise
+
+ # Now just run the ar command.
+ return subprocess.call(wrapper_utils.CommandToRun(command))
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/src/starboard/build/toolchain/gcc_link_wrapper.py b/src/starboard/build/toolchain/gcc_link_wrapper.py
new file mode 100755
index 0000000..b964347
--- /dev/null
+++ b/src/starboard/build/toolchain/gcc_link_wrapper.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Runs a linking command and optionally a strip command.
+
+This script exists to avoid using complex shell commands in
+gcc_toolchain.gni's tool("link"), in case the host running the compiler
+does not have a POSIX-like shell (e.g. Windows).
+"""
+
+import argparse
+import os
+import subprocess
+import sys
+
+import wrapper_utils
+
+
+# When running on a Windows host and using a toolchain whose tools are
+# actually wrapper scripts (i.e. .bat files on Windows) rather than binary
+# executables, the "command" to run has to be prefixed with this magic.
+# The GN toolchain definitions take care of that for when GN/Ninja is
+# running the tool directly. When that command is passed in to this
+# script, it appears as a unitary string but needs to be split up so that
+# just 'cmd' is the actual command given to Python's subprocess module.
+BAT_PREFIX = 'cmd /c call '
+
+
+def CommandToRun(command):
+ if command[0].startswith(BAT_PREFIX):
+ command = command[0].split(None, 3) + command[1:]
+ return command
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--strip',
+ help='The strip binary to run',
+ metavar='PATH')
+ parser.add_argument('--unstripped-file',
+ help='Executable file produced by linking command',
+ metavar='FILE')
+ parser.add_argument('--map-file',
+ help=('Use --Wl,-Map to generate a map file. Will be '
+ 'gzipped if extension ends with .gz'),
+ metavar='FILE')
+ parser.add_argument('--output',
+ required=True,
+ help='Final output executable file',
+ metavar='FILE')
+ parser.add_argument('command', nargs='+',
+ help='Linking command')
+ args = parser.parse_args()
+
+ # Work-around for gold being slow-by-default. http://crbug.com/632230
+ fast_env = dict(os.environ)
+ fast_env['LC_ALL'] = 'C'
+ result = wrapper_utils.RunLinkWithOptionalMapFile(args.command, env=fast_env,
+ map_file=args.map_file)
+ if result != 0:
+ return result
+
+ # Finally, strip the linked executable (if desired).
+ if args.strip:
+ result = subprocess.call(CommandToRun([
+ args.strip, '--strip-unneeded', '-o', args.output, args.unstripped_file
+ ]))
+
+ return result
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/src/starboard/build/toolchain/gcc_solink_wrapper.py b/src/starboard/build/toolchain/gcc_solink_wrapper.py
new file mode 100755
index 0000000..71af5e3
--- /dev/null
+++ b/src/starboard/build/toolchain/gcc_solink_wrapper.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Runs 'ld -shared' and generates a .TOC file that's untouched when unchanged.
+
+This script exists to avoid using complex shell commands in
+gcc_toolchain.gni's tool("solink"), in case the host running the compiler
+does not have a POSIX-like shell (e.g. Windows).
+"""
+
+import argparse
+import os
+import subprocess
+import sys
+
+import wrapper_utils
+
+
+def CollectSONAME(args):
+ """Replaces: readelf -d $sofile | grep SONAME.
+
+ Args:
+ args: the args to pass to the subprocess
+
+ Returns:
+ A tuple of (return code, output)
+ """
+ toc = ''
+ readelf = subprocess.Popen(wrapper_utils.CommandToRun(
+ [args.readelf, '-d', args.sofile]), stdout=subprocess.PIPE, bufsize=-1)
+ for line in readelf.stdout:
+ if 'SONAME' in line:
+ toc += line
+ return readelf.wait(), toc
+
+
+def CollectDynSym(args):
+ """Replaces: nm --format=posix -g -D $sofile | cut -f1-2 -d' '.
+
+ Args:
+ args: the args to pass to the subprocess
+
+ Returns:
+ A tuple of (return code, output)
+ """
+ toc = ''
+ nm = subprocess.Popen(wrapper_utils.CommandToRun([
+ args.nm, '--format=posix', '-g', '-D', args.sofile]),
+ stdout=subprocess.PIPE, bufsize=-1)
+ for line in nm.stdout:
+ toc += ' '.join(line.split(' ', 2)[:2]) + '\n'
+ return nm.wait(), toc
+
+
+def CollectTOC(args):
+ result, toc = CollectSONAME(args)
+ if result == 0:
+ result, dynsym = CollectDynSym(args)
+ toc += dynsym
+ return result, toc
+
+
+def UpdateTOC(tocfile, toc):
+ if os.path.exists(tocfile):
+ old_toc = open(tocfile, 'r').read()
+ else:
+ old_toc = None
+ if toc != old_toc:
+ open(tocfile, 'w').write(toc)
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--readelf',
+ required=True,
+ help='The readelf binary to run',
+ metavar='PATH')
+ parser.add_argument('--nm',
+ required=True,
+ help='The nm binary to run',
+ metavar='PATH')
+ parser.add_argument('--strip',
+ help='The strip binary to run',
+ metavar='PATH')
+ parser.add_argument('--sofile',
+ required=True,
+ help='Shared object file produced by linking command',
+ metavar='FILE')
+ parser.add_argument('--tocfile',
+ required=True,
+ help='Output table-of-contents file',
+ metavar='FILE')
+ parser.add_argument('--map-file',
+ help=('Use --Wl,-Map to generate a map file. Will be '
+ 'gzipped if extension ends with .gz'),
+ metavar='FILE')
+ parser.add_argument('--output',
+ required=True,
+ help='Final output shared object file',
+ metavar='FILE')
+ parser.add_argument('--resource-whitelist',
+ help='Merge all resource whitelists into a single file.',
+ metavar='PATH')
+ parser.add_argument('command', nargs='+',
+ help='Linking command')
+ args = parser.parse_args()
+
+ # Work-around for gold being slow-by-default. http://crbug.com/632230
+ fast_env = dict(os.environ)
+ fast_env['LC_ALL'] = 'C'
+
+ if args.resource_whitelist:
+ whitelist_candidates = wrapper_utils.ResolveRspLinks(args.command)
+ wrapper_utils.CombineResourceWhitelists(
+ whitelist_candidates, args.resource_whitelist)
+
+ # First, run the actual link.
+ command = wrapper_utils.CommandToRun(args.command)
+ result = wrapper_utils.RunLinkWithOptionalMapFile(command, env=fast_env,
+ map_file=args.map_file)
+
+ if result != 0:
+ return result
+
+ # Next, generate the contents of the TOC file.
+ result, toc = CollectTOC(args)
+ if result != 0:
+ return result
+
+ # If there is an existing TOC file with identical contents, leave it alone.
+ # Otherwise, write out the TOC file.
+ UpdateTOC(args.tocfile, toc)
+
+ # Finally, strip the linked shared object file (if desired).
+ if args.strip:
+ result = subprocess.call(wrapper_utils.CommandToRun(
+ [args.strip, '--strip-unneeded', '-o', args.output, args.sofile]))
+
+ return result
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/src/starboard/build/toolchain/gcc_toolchain.gni b/src/starboard/build/toolchain/gcc_toolchain.gni
new file mode 100644
index 0000000..94c52f4
--- /dev/null
+++ b/src/starboard/build/toolchain/gcc_toolchain.gni
@@ -0,0 +1,487 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Modifications Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//starboard/build/toolchain/clang.gni")
+import("//starboard/build/toolchain/goma.gni")
+
+# This template defines a toolchain for something that works like gcc
+# (including clang).
+#
+# It requires the following variables specifying the executables to run:
+# - ar
+# - cc
+# - cxx
+# - ld
+#
+# Optional parameters that control the tools:
+#
+# - extra_cflags
+# Extra flags to be appended when compiling C files (but not C++ files).
+# - extra_cppflags
+# Extra flags to be appended when compiling both C and C++ files. "CPP"
+# stands for "C PreProcessor" in this context, although it can be
+# used for non-preprocessor flags as well. Not to be confused with
+# "CXX" (which follows).
+# - extra_cxxflags
+# Extra flags to be appended when compiling C++ files (but not C files).
+# - extra_ldflags
+# Extra flags to be appended when linking
+#
+# - libs_section_prefix
+# - libs_section_postfix
+# The contents of these strings, if specified, will be placed around
+# the libs section of the linker line. It allows one to inject libraries
+# at the beginning and end for all targets in a toolchain.
+# - solink_libs_section_prefix
+# - solink_libs_section_postfix
+# Same as libs_section_{pre,post}fix except used for solink instead of link.
+# - link_outputs
+# The content of this array, if specified, will be added to the list of
+# outputs from the link command. This can be useful in conjunction with
+# the post_link parameter.
+# - post_link
+# The content of this string, if specified, will be run as a separate
+# command following the the link command.
+# - deps
+# Just forwarded to the toolchain definition.
+# - executable_extension
+# If this string is specified it will be used for the file extension
+# for an executable, rather than using no extension; targets will
+# still be able to override the extension using the output_extension
+# variable.
+# - rebuild_define
+# The contents of this string, if specified, will be passed as a #define
+# to the toolchain. It can be used to force recompiles whenever a
+# toolchain is updated.
+# - shlib_extension
+# If this string is specified it will be used for the file extension
+# for a shared library, rather than default value specified in
+# toolchain.gni
+# - strip
+# Location of the strip executable. When specified, strip will be run on
+# all shared libraries and executables as they are built. The pre-stripped
+# artifacts will be put in lib.unstripped/ and exe.unstripped/.
+template("gcc_toolchain") {
+ toolchain(target_name) {
+ assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value")
+ assert(defined(invoker.cc), "gcc_toolchain() must specify a \"cc\" value")
+ assert(defined(invoker.cxx), "gcc_toolchain() must specify a \"cxx\" value")
+ assert(defined(invoker.ld), "gcc_toolchain() must specify a \"ld\" value")
+ assert(defined(invoker.shlib_extension),
+ "gcc_toolchain() must specify a \"shlib_extension\" value")
+
+ # This define changes when the toolchain changes, forcing a rebuild.
+ # Nothing should ever use this define.
+ if (defined(invoker.rebuild_define)) {
+ rebuild_string = "-D" + invoker.rebuild_define + " "
+ } else {
+ rebuild_string = ""
+ }
+
+ # GN's syntax can't handle more than one scope dereference at once, like
+ # "invoker.toolchain_args.foo", so make a temporary to hold the toolchain
+ # args so we can do "invoker_toolchain_args.foo".
+ assert(defined(invoker.toolchain_args),
+ "Toolchains must specify toolchain_args")
+ invoker_toolchain_args = invoker.toolchain_args
+ assert(defined(invoker_toolchain_args.current_cpu),
+ "toolchain_args must specify a current_cpu")
+ assert(defined(invoker_toolchain_args.current_os),
+ "toolchain_args must specify a current_os")
+
+ # When invoking this toolchain not as the default one, these args will be
+ # passed to the build. They are ignored when this is the default toolchain.
+ toolchain_args = {
+ # Populate toolchain args from the invoker.
+ forward_variables_from(invoker_toolchain_args, "*")
+ }
+
+ # When the invoker has explicitly overridden use_goma or cc_wrapper in the
+ # toolchain args, use those values, otherwise default to the global one.
+ # This works because the only reasonable override that toolchains might
+ # supply for these values are to force-disable them.
+ if (defined(toolchain_args.use_goma)) {
+ toolchain_uses_goma = toolchain_args.use_goma
+ } else {
+ toolchain_uses_goma = use_goma
+ }
+
+ # When the invoker has explicitly overridden use_goma in the
+ # toolchain args, use those values, otherwise default to the global one.
+ # This works because the only reasonable override that toolchains might
+ # supply for these values are to force-disable them.
+ if (toolchain_uses_goma) {
+ goma_path = "$goma_dir/gomacc"
+ compiler_prefix = "${goma_path} "
+ } else {
+ compiler_prefix = ""
+ }
+
+ cc = compiler_prefix + invoker.cc
+ cxx = compiler_prefix + invoker.cxx
+ ar = invoker.ar
+ ld = invoker.ld
+ if (!defined(asm)) {
+ asm = cc
+ }
+ if (defined(invoker.readelf)) {
+ readelf = invoker.readelf
+ } else {
+ readelf = "readelf"
+ }
+ if (defined(invoker.nm)) {
+ nm = invoker.nm
+ } else {
+ nm = "nm"
+ }
+ if (defined(invoker.stamp_command)) {
+ stamp_command = invoker.stamp_command
+ } else {
+ stamp_command = "touch {{output}}"
+ }
+ if (defined(invoker.copy_command)) {
+ copy_command = invoker.copy_command
+ } else {
+ copy_command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})"
+ }
+
+ default_shlib_extension = invoker.shlib_extension
+
+ if (defined(invoker.executable_extension)) {
+ default_executable_extension = invoker.executable_extension
+ } else {
+ default_executable_extension = ""
+ }
+
+ # Bring these into our scope for string interpolation with default values.
+ if (defined(invoker.libs_section_prefix)) {
+ libs_section_prefix = invoker.libs_section_prefix
+ } else {
+ libs_section_prefix = ""
+ }
+
+ if (defined(invoker.libs_section_postfix)) {
+ libs_section_postfix = invoker.libs_section_postfix
+ } else {
+ libs_section_postfix = ""
+ }
+
+ if (defined(invoker.solink_libs_section_prefix)) {
+ solink_libs_section_prefix = invoker.solink_libs_section_prefix
+ } else {
+ solink_libs_section_prefix = ""
+ }
+
+ if (defined(invoker.solink_libs_section_postfix)) {
+ solink_libs_section_postfix = invoker.solink_libs_section_postfix
+ } else {
+ solink_libs_section_postfix = ""
+ }
+
+ if (defined(invoker.extra_cflags) && invoker.extra_cflags != "") {
+ extra_cflags = " " + invoker.extra_cflags
+ } else {
+ extra_cflags = ""
+ }
+
+ if (defined(invoker.extra_cppflags) && invoker.extra_cppflags != "") {
+ extra_cppflags = " " + invoker.extra_cppflags
+ } else {
+ extra_cppflags = ""
+ }
+
+ if (defined(invoker.extra_cxxflags) && invoker.extra_cxxflags != "") {
+ extra_cxxflags = " " + invoker.extra_cxxflags
+ } else {
+ extra_cxxflags = ""
+ }
+
+ if (defined(invoker.extra_ldflags) && invoker.extra_ldflags != "") {
+ extra_ldflags = " " + invoker.extra_ldflags
+ } else {
+ extra_ldflags = ""
+ }
+
+ # These library switches can apply to all tools below.
+ lib_switch = "-l"
+ lib_dir_switch = "-L"
+
+ # Object files go in this directory.
+ object_subdir = "{{target_out_dir}}/{{label_name}}"
+
+ tool("cc") {
+ depfile = "{{output}}.d"
+ command = "$cc -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}${extra_cppflags}${extra_cflags} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ description = "CC {{output}}"
+ outputs = [
+ "$object_subdir/{{source_name_part}}.o",
+ ]
+ }
+
+ tool("cxx") {
+ depfile = "{{output}}.d"
+ command = "$cxx -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}${extra_cppflags}${extra_cxxflags} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ description = "CXX {{output}}"
+ outputs = [
+ "$object_subdir/{{source_name_part}}.o",
+ ]
+ }
+
+ tool("asm") {
+ # For GCC we can just use the C compiler to compile assembly.
+ depfile = "{{output}}.d"
+ command = "$asm -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ description = "ASM {{output}}"
+ outputs = [
+ "$object_subdir/{{source_name_part}}.o",
+ ]
+ }
+
+ tool("alink") {
+ rspfile = "{{output}}.rsp"
+
+ # This needs a Python script to avoid using simple sh features in this
+ # command, in case the host does not use a POSIX shell (e.g. compiling
+ # POSIX-like toolchains such as NaCl on Windows).
+ ar_wrapper = rebase_path("//starboard/build/toolchain/gcc_ar_wrapper.py",
+ root_build_dir)
+ extra_arflags = "rcsD"
+ command = "$python_path \"$ar_wrapper\" --output={{output}} --ar=\"$ar\" {{arflags}} $extra_arflags @\"$rspfile\""
+ description = "AR {{output}}"
+ rspfile_content = "{{inputs}}"
+ outputs = [
+ "{{output_dir}}/{{target_output_name}}{{output_extension}}",
+ ]
+
+ # Shared libraries go in the target out directory by default so we can
+ # generate different targets with the same name and not have them collide.
+ default_output_dir = "{{target_out_dir}}"
+ default_output_extension = ".a"
+ output_prefix = "lib"
+ }
+
+ tool("solink") {
+ soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so".
+ sofile = "{{output_dir}}/$soname" # Possibly including toolchain dir.
+ rspfile = sofile + ".rsp"
+ pool = "//starboard/build/toolchain:link_pool($default_toolchain)"
+
+ if (defined(invoker.strip)) {
+ unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname"
+ } else {
+ unstripped_sofile = sofile
+ }
+
+ # These variables are not built into GN but are helpers that
+ # implement (1) linking to produce a .so, (2) extracting the symbols
+ # from that file (3) if the extracted list differs from the existing
+ # .TOC file, overwrite it, otherwise, don't change it.
+ tocfile = sofile + ".TOC"
+
+ link_command = "$ld -shared {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\""
+
+ assert(defined(readelf), "to solink you must have a readelf")
+ assert(defined(nm), "to solink you must have an nm")
+ strip_switch = ""
+ if (defined(invoker.strip)) {
+ strip_switch = "--strip=${invoker.strip} "
+ }
+
+ # This needs a Python script to avoid using a complex shell command
+ # requiring sh control structures, pipelines, and POSIX utilities.
+ # The host might not have a POSIX shell and utilities (e.g. Windows).
+ solink_wrapper =
+ rebase_path("//starboard/build/toolchain/gcc_solink_wrapper.py",
+ root_build_dir)
+ command = "$python_path \"$solink_wrapper\" --readelf=\"$readelf\" --nm=\"$nm\" $strip_switch--sofile=\"$unstripped_sofile\" --tocfile=\"$tocfile\" --output=\"$sofile\" -- $link_command"
+
+ rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix"
+
+ description = "SOLINK $sofile"
+
+ # Use this for {{output_extension}} expansions unless a target manually
+ # overrides it (in which case {{output_extension}} will be what the target
+ # specifies).
+ default_output_extension = default_shlib_extension
+
+ default_output_dir = "{{root_out_dir}}"
+
+ output_prefix = "lib"
+
+ # Since the above commands only updates the .TOC file when it changes, ask
+ # Ninja to check if the timestamp actually changed to know if downstream
+ # dependencies should be recompiled.
+ restat = true
+
+ # Tell GN about the output files. It will link to the sofile but use the
+ # tocfile for dependency management.
+ outputs = [
+ sofile,
+ tocfile,
+ ]
+ if (sofile != unstripped_sofile) {
+ outputs += [ unstripped_sofile ]
+ }
+ link_output = sofile
+ depend_output = tocfile
+ }
+
+ tool("solink_module") {
+ soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so".
+ sofile = "{{output_dir}}/$soname"
+ rspfile = sofile + ".rsp"
+ pool = "//starboard/build/toolchain:link_pool($default_toolchain)"
+
+ if (defined(invoker.strip)) {
+ unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname"
+ } else {
+ unstripped_sofile = sofile
+ }
+
+ command = "$ld -shared {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\""
+
+ if (defined(invoker.strip)) {
+ strip_command = "${invoker.strip} --strip-unneeded -o \"$sofile\" \"$unstripped_sofile\""
+ command += " && " + strip_command
+ }
+ rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix"
+
+ description = "SOLINK_MODULE $sofile"
+
+ # Use this for {{output_extension}} expansions unless a target manually
+ # overrides it (in which case {{output_extension}} will be what the target
+ # specifies).
+ if (defined(invoker.loadable_module_extension)) {
+ default_output_extension = invoker.loadable_module_extension
+ } else {
+ default_output_extension = default_shlib_extension
+ }
+
+ default_output_dir = "{{root_out_dir}}"
+
+ output_prefix = "lib"
+
+ outputs = [
+ sofile,
+ ]
+ if (sofile != unstripped_sofile) {
+ outputs += [ unstripped_sofile ]
+ }
+ }
+
+ tool("link") {
+ exename = "{{target_output_name}}{{output_extension}}"
+ outfile = "{{output_dir}}/$exename"
+ rspfile = "$outfile.rsp"
+ unstripped_outfile = outfile
+ pool = "//starboard/build/toolchain:link_pool($default_toolchain)"
+
+ # Use this for {{output_extension}} expansions unless a target manually
+ # overrides it (in which case {{output_extension}} will be what the target
+ # specifies).
+ default_output_extension = default_executable_extension
+
+ default_output_dir = "{{root_out_dir}}"
+
+ if (defined(invoker.strip)) {
+ unstripped_outfile = "{{root_out_dir}}/exe.unstripped/$exename"
+ }
+
+ start_group_flag = "-Wl,--start-group"
+ end_group_flag = "-Wl,--end-group "
+ link_command = "$ld {{ldflags}}${extra_ldflags} -o \"$unstripped_outfile\" $start_group_flag @\"$rspfile\" {{solibs}} $end_group_flag $libs_section_prefix {{libs}} $libs_section_postfix"
+
+ strip_switch = ""
+
+ if (defined(invoker.strip)) {
+ strip_switch = " --strip=\"${invoker.strip}\" --unstripped-file=\"$unstripped_outfile\""
+ }
+
+ link_wrapper =
+ rebase_path("//starboard/build/toolchain/gcc_link_wrapper.py",
+ root_build_dir)
+ command = "$python_path \"$link_wrapper\" --output=\"$outfile\"$strip_switch -- $link_command"
+ description = "LINK $outfile"
+ rspfile_content = "{{inputs}}"
+ outputs = [
+ outfile,
+ ]
+ if (outfile != unstripped_outfile) {
+ outputs += [ unstripped_outfile ]
+ }
+ if (defined(invoker.link_outputs)) {
+ outputs += invoker.link_outputs
+ }
+ }
+
+ # These two are really entirely generic, but have to be repeated in
+ # each toolchain because GN doesn't allow a template to be used here.
+ # See //build/toolchain/toolchain.gni for details.
+ tool("stamp") {
+ command = stamp_command
+ description = "STAMP {{output}}"
+ }
+ tool("copy") {
+ command = copy_command
+ description = "COPY {{source}} {{output}}"
+ }
+
+ forward_variables_from(invoker, [ "deps" ])
+ }
+}
+
+# This is a shorthand for gcc_toolchain instances based on the Chromium-built
+# version of Clang. Only the toolchain_cpu and toolchain_os variables need to
+# be specified by the invoker, and optionally toolprefix if it's a
+# cross-compile case. Note that for a cross-compile case this toolchain
+# requires a config to pass the appropriate -target option, or else it will
+# actually just be doing a native compile. The invoker can optionally override
+# use_gold too.
+template("clang_toolchain") {
+ if (defined(invoker.toolprefix)) {
+ toolprefix = invoker.toolprefix
+ } else {
+ toolprefix = ""
+ }
+
+ gcc_toolchain(target_name) {
+ prefix = rebase_path("$clang_base_path/bin", root_build_dir)
+ cc = "$prefix/clang"
+ cxx = "$prefix/clang++"
+ ld = cxx
+ readelf = "${toolprefix}readelf"
+ ar = "${prefix}/llvm-ar"
+ nm = "${toolprefix}nm"
+
+ forward_variables_from(invoker,
+ [
+ "strip",
+ "is_clang_analysis_supported",
+ "shlib_extension",
+ ])
+
+ toolchain_args = {
+ if (defined(invoker.toolchain_args)) {
+ forward_variables_from(invoker.toolchain_args, "*")
+ }
+ }
+ }
+}
diff --git a/src/starboard/build/toolchain/get_clang_base_path.py b/src/starboard/build/toolchain/get_clang_base_path.py
new file mode 100755
index 0000000..d6fc75a
--- /dev/null
+++ b/src/starboard/build/toolchain/get_clang_base_path.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Finds and prints the Clang base path.
+
+If Clang is not present, it will be downloaded.
+"""
+
+import os.path
+import sys
+
+sys.path.append(
+ os.path.realpath(
+ os.path.join(
+ os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)))
+from cobalt.build.gyp_utils import EnsureClangAvailable # pylint: disable=g-import-not-at-top
+from cobalt.build.gyp_utils import GetClangBasePath
+from cobalt.build.gyp_utils import GetClangBinPath
+
+
+def main():
+ base_dir = GetClangBasePath()
+ bin_path = GetClangBinPath()
+ EnsureClangAvailable(base_dir, bin_path)
+ print os.path.join(base_dir, 'llvm-build', 'Release+Asserts')
+
+if __name__ == '__main__':
+ main()
diff --git a/src/starboard/build/toolchain/get_concurrent_links.py b/src/starboard/build/toolchain/get_concurrent_links.py
new file mode 100644
index 0000000..be5640a
--- /dev/null
+++ b/src/starboard/build/toolchain/get_concurrent_links.py
@@ -0,0 +1,86 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Computes and prints the default number of concurrent links.
+
+Computes the number of concurrent links to be run in the build, as a function
+of machine spec. Based on GetDefaultConcurrentLinks in GYP.
+"""
+
+import ctypes
+import optparse
+import os
+import re
+import subprocess
+import sys
+
+
+def _GetTotalMemoryInBytes():
+ """Gets the total amount of virtual memory in bytes.
+
+ Returns:
+ See above
+ """
+ if sys.platform in ('win32', 'cygwin'):
+
+ class MEMORYSTATUSEX(ctypes.Structure):
+ _fields_ = [
+ ('dwLength', ctypes.c_ulong),
+ ('dwMemoryLoad', ctypes.c_ulong),
+ ('ullTotalPhys', ctypes.c_ulonglong),
+ ('ullAvailPhys', ctypes.c_ulonglong),
+ ('ullTotalPageFile', ctypes.c_ulonglong),
+ ('ullAvailPageFile', ctypes.c_ulonglong),
+ ('ullTotalVirtual', ctypes.c_ulonglong),
+ ('ullAvailVirtual', ctypes.c_ulonglong),
+ ('sullAvailExtendedVirtual', ctypes.c_ulonglong),
+ ]
+
+ stat = MEMORYSTATUSEX(dwLength=ctypes.sizeof(MEMORYSTATUSEX))
+ ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat))
+ return stat.ullTotalPhys
+ elif sys.platform.startswith('linux'):
+ if os.path.exists('/proc/meminfo'):
+ with open('/proc/meminfo') as meminfo:
+ memtotal_re = re.compile(r'^MemTotal:\s*(\d*)\s*kB')
+ for line in meminfo:
+ match = memtotal_re.match(line)
+ if not match:
+ continue
+ return float(match.group(1)) * 2**10
+ elif sys.platform == 'darwin':
+ try:
+ return int(subprocess.check_output(['sysctl', '-n', 'hw.memsize']))
+ except subprocess.CalledProcessError:
+ return 0
+ # TODO: Implement this for other platforms.
+ return 0
+
+
+def _GetDefaultConcurrentLinks(mem_per_link_gb, reserve_mem_gb):
+ # Inherit the legacy environment variable for people that have set it in GYP.
+ pool_size = int(os.getenv('GYP_LINK_CONCURRENCY', 0))
+ if pool_size:
+ return pool_size
+
+ mem_total_bytes = _GetTotalMemoryInBytes()
+ mem_total_bytes = max(0, mem_total_bytes - reserve_mem_gb * 2**30)
+ num_concurrent_links = int(max(1, mem_total_bytes / mem_per_link_gb / 2**30))
+ hard_cap = max(1, int(os.getenv('GYP_LINK_CONCURRENCY_MAX', 2**32)))
+ return min(num_concurrent_links, hard_cap)
+
+
+def main():
+ parser = optparse.OptionParser()
+ parser.add_option('--mem_per_link_gb', action='store', type='int', default=6)
+ parser.add_option('--reserve_mem_gb', action='store', type='int', default=0)
+ parser.disable_interspersed_args()
+ options, _ = parser.parse_args()
+
+ print _GetDefaultConcurrentLinks(options.mem_per_link_gb,
+ options.reserve_mem_gb)
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/src/starboard/build/toolchain/goma.gni b/src/starboard/build/toolchain/goma.gni
new file mode 100644
index 0000000..dd72cefe
--- /dev/null
+++ b/src/starboard/build/toolchain/goma.gni
@@ -0,0 +1,40 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Modifications Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Defines the configuration of Goma.
+
+# Allow ports to set an alternate default for use_goma
+import("//$starboard_path/configuration.gni")
+
+declare_args() {
+ if (!defined(use_goma)) {
+ # Set to true to enable distributed compilation using Goma. By default we
+ # use Goma for stub and linux.
+ use_goma = false
+ }
+
+ # Set the default value based on the platform.
+ if (host_os == "win" || host_os == "winrt_81" ||
+ host_os == "winrt_81_phone" || host_os == "winrt_10") {
+ # Absolute directory containing the gomacc.exe binary.
+ goma_dir = "C:\goma\goma-win64"
+ } else {
+ # Absolute directory containing the gomacc binary.
+ goma_dir = getenv("HOME") + "/goma"
+ }
+}
diff --git a/src/starboard/build/toolchain/linux/BUILD.gn b/src/starboard/build/toolchain/linux/BUILD.gn
new file mode 100644
index 0000000..962109a
--- /dev/null
+++ b/src/starboard/build/toolchain/linux/BUILD.gn
@@ -0,0 +1,217 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Modifications Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//starboard/build/toolchain/gcc_toolchain.gni")
+
+clang_toolchain("clang_arm") {
+ toolprefix = "arm-linux-gnueabihf-"
+ shlib_extension = ".so"
+ toolchain_args = {
+ current_cpu = "arm"
+ current_os = "linux"
+ }
+}
+
+clang_toolchain("clang_arm64") {
+ toolprefix = "aarch64-linux-gnu-"
+ shlib_extension = ".so"
+ toolchain_args = {
+ current_cpu = "arm64"
+ current_os = "linux"
+ }
+}
+
+gcc_toolchain("arm64") {
+ toolprefix = "aarch64-linux-gnu-"
+ shlib_extension = ".so"
+
+ cc = "${toolprefix}gcc"
+ cxx = "${toolprefix}g++"
+
+ ar = "${toolprefix}ar"
+ ld = cxx
+ readelf = "${toolprefix}readelf"
+ nm = "${toolprefix}nm"
+
+ toolchain_args = {
+ current_cpu = "arm64"
+ current_os = "linux"
+ }
+}
+
+gcc_toolchain("arm") {
+ toolprefix = "arm-linux-gnueabihf-"
+ shlib_extension = ".so"
+
+ cc = "${toolprefix}gcc"
+ cxx = "${toolprefix}g++"
+
+ ar = "${toolprefix}ar"
+ ld = cxx
+ readelf = "${toolprefix}readelf"
+ nm = "${toolprefix}nm"
+
+ toolchain_args = {
+ current_cpu = "arm"
+ current_os = "linux"
+ }
+}
+
+clang_toolchain("clang_x86") {
+ shlib_extension = ".so"
+
+ toolchain_args = {
+ current_cpu = "x86"
+ current_os = "linux"
+ }
+}
+
+gcc_toolchain("x86") {
+ shlib_extension = ".so"
+
+ cc = "gcc"
+ cxx = "g++"
+
+ readelf = "readelf"
+ nm = "nm"
+ ar = "ar"
+ ld = cxx
+
+ toolchain_args = {
+ current_cpu = "x86"
+ current_os = "linux"
+ }
+}
+
+clang_toolchain("clang_x64") {
+ shlib_extension = ".so"
+
+ toolchain_args = {
+ current_cpu = "x64"
+ current_os = "linux"
+ }
+}
+
+gcc_toolchain("x64") {
+ shlib_extension = ".so"
+
+ cc = "gcc"
+ cxx = "g++"
+
+ readelf = "readelf"
+ nm = "nm"
+ ar = "ar"
+ ld = cxx
+
+ toolchain_args = {
+ current_cpu = "x64"
+ current_os = "linux"
+ }
+}
+
+clang_toolchain("clang_mipsel") {
+ shlib_extension = ".so"
+ toolchain_args = {
+ current_cpu = "mipsel"
+ current_os = "linux"
+ }
+}
+
+gcc_toolchain("mipsel") {
+ shlib_extension = ".so"
+
+ cc = "mipsel-linux-gnu-gcc"
+ cxx = "mipsel-linux-gnu-g++"
+ ar = "mipsel-linux-gnu-ar"
+ ld = cxx
+ readelf = "mipsel-linux-gnu-readelf"
+ nm = "mipsel-linux-gnu-nm"
+
+ toolchain_args = {
+ current_cpu = "mipsel"
+ current_os = "linux"
+ }
+}
+
+gcc_toolchain("s390x") {
+ shlib_extension = ".so"
+
+ cc = "gcc"
+ cxx = "g++"
+
+ readelf = "readelf"
+ nm = "nm"
+ ar = "ar"
+ ld = cxx
+
+ toolchain_args = {
+ current_cpu = "s390x"
+ current_os = "linux"
+ }
+}
+
+gcc_toolchain("ppc64") {
+ shlib_extension = ".so"
+
+ cc = "gcc"
+ cxx = "g++"
+
+ readelf = "readelf"
+ nm = "nm"
+ ar = "ar"
+ ld = cxx
+
+ toolchain_args = {
+ current_cpu = "ppc64"
+ current_os = "linux"
+ }
+}
+
+gcc_toolchain("mips") {
+ shlib_extension = ".so"
+
+ cc = "gcc"
+ cxx = "g++"
+
+ readelf = "readelf"
+ nm = "nm"
+ ar = "ar"
+ ld = cxx
+
+ toolchain_args = {
+ current_cpu = "mips"
+ current_os = "linux"
+ }
+}
+
+gcc_toolchain("mips64") {
+ shlib_extension = ".so"
+
+ cc = "gcc"
+ cxx = "g++"
+
+ readelf = "readelf"
+ nm = "nm"
+ ar = "ar"
+ ld = cxx
+
+ toolchain_args = {
+ current_cpu = "mips64"
+ current_os = "linux"
+ }
+}
diff --git a/src/starboard/build/toolchain/linux/config/BUILD.gn b/src/starboard/build/toolchain/linux/config/BUILD.gn
new file mode 100644
index 0000000..63f8da6
--- /dev/null
+++ b/src/starboard/build/toolchain/linux/config/BUILD.gn
@@ -0,0 +1,42 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Sets the optimization level
+config("no_optimizations") {
+ cflags = [ "-O0" ]
+}
+
+config("debuggable_optimizations") {
+ cflags = [ "-O2" ]
+}
+
+config("full_optimizations") {
+ cflags = [ "-O3" ]
+}
+
+
+# Enables/disables RTTI
+config("rtti") {
+ cflags_cc = [ "-frtti" ]
+}
+
+config("no_rtti") {
+ cflags_cc = [ "-fno-rtti" ]
+}
+
+
+# Enables -Wexit-time-destructors. Only usable for Clang.
+config("wexit_time_destructors") {
+ cflags = [ "-Wexit-time-destructors" ]
+}
diff --git a/src/starboard/build/toolchain/wrapper_utils.py b/src/starboard/build/toolchain/wrapper_utils.py
new file mode 100644
index 0000000..d01933d
--- /dev/null
+++ b/src/starboard/build/toolchain/wrapper_utils.py
@@ -0,0 +1,150 @@
+# Copyright (c) 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Helper functions for gcc_toolchain.gni wrappers."""
+
+import gzip
+import os
+import re
+import shlex
+import shutil
+import subprocess
+import threading
+
+_BAT_PREFIX = 'cmd /c call '
+_WHITELIST_RE = re.compile('whitelisted_resource_(?P<resource_id>[0-9]+)')
+
+
+def _GzipThenDelete(src_path, dest_path):
+ # Results for Android map file with GCC on a z620:
+ # Uncompressed: 207MB
+ # gzip -9: 16.4MB, takes 8.7 seconds.
+ # gzip -1: 21.8MB, takes 2.0 seconds.
+ # Piping directly from the linker via -print-map (or via -Map with a fifo)
+ # adds a whopping 30-45 seconds!
+ with open(src_path, 'rb') as f_in, gzip.GzipFile(dest_path, 'wb', 1) as f_out:
+ shutil.copyfileobj(f_in, f_out)
+ os.unlink(src_path)
+
+
+def CommandToRun(command):
+ """Generates commands compatible with Windows.
+
+ When running on a Windows host and using a toolchain whose tools are
+ actually wrapper scripts (i.e. .bat files on Windows) rather than binary
+ executables, the |command| to run has to be prefixed with this magic.
+ The GN toolchain definitions take care of that for when GN/Ninja is
+ running the tool directly. When that command is passed in to this
+ script, it appears as a unitary string but needs to be split up so that
+ just 'cmd' is the actual command given to Python's subprocess module.
+
+ Args:
+ command: List containing the UNIX style |command|.
+
+ Returns:
+ A list containing the Windows version of the |command|.
+ """
+ if command[0].startswith(_BAT_PREFIX):
+ command = command[0].split(None, 3) + command[1:]
+ return command
+
+
+def RunLinkWithOptionalMapFile(command, env=None, map_file=None):
+ """Runs the given command, adding in -Wl,-Map when |map_file| is given.
+
+ Also takes care of gzipping when |map_file| ends with .gz.
+
+ Args:
+ command: List of arguments comprising the command.
+ env: Environment variables.
+ map_file: Path to output map_file.
+
+ Returns:
+ The exit code of running |command|.
+ """
+ tmp_map_path = None
+ if map_file and map_file.endswith('.gz'):
+ tmp_map_path = map_file + '.tmp'
+ command.append('-Wl,-Map,' + tmp_map_path)
+ elif map_file:
+ command.append('-Wl,-Map,' + map_file)
+
+ result = subprocess.call(command, env=env)
+
+ if tmp_map_path and result == 0:
+ threading.Thread(
+ target=lambda: _GzipThenDelete(tmp_map_path, map_file)).start()
+ elif tmp_map_path and os.path.exists(tmp_map_path):
+ os.unlink(tmp_map_path)
+
+ return result
+
+
+def ResolveRspLinks(inputs):
+ """Return a list of files contained in a response file.
+
+ Args:
+ inputs: A command containing rsp files.
+
+ Returns:
+ A set containing the rsp file content.
+ """
+ rspfiles = [a[1:] for a in inputs if a.startswith('@')]
+ resolved = set()
+ for rspfile in rspfiles:
+ with open(rspfile, 'r') as f:
+ resolved.update(shlex.split(f.read()))
+
+ return resolved
+
+
+def CombineResourceWhitelists(whitelist_candidates, outfile):
+ """Combines all whitelists for a resource file into a single whitelist.
+
+ Args:
+ whitelist_candidates: List of paths to rsp files containing all targets.
+ outfile: Path to save the combined whitelist.
+ """
+ whitelists = ('%s.whitelist' % candidate for candidate in whitelist_candidates
+ if os.path.exists('%s.whitelist' % candidate))
+
+ resources = set()
+ for whitelist in whitelists:
+ with open(whitelist, 'r') as f:
+ resources.update(f.readlines())
+
+ with open(outfile, 'w') as f:
+ f.writelines(resources)
+
+
+def ExtractResourceIdsFromPragmaWarnings(text):
+ """Returns set of resource IDs that are inside unknown pragma warnings.
+
+ Args:
+ text: The text that will be scanned for unknown pragma warnings.
+
+ Returns:
+ A set containing integers representing resource IDs.
+ """
+ used_resources = set()
+ lines = text.splitlines()
+ for ln in lines:
+ match = _WHITELIST_RE.search(ln)
+ if match:
+ resource_id = int(match.group('resource_id'))
+ used_resources.add(resource_id)
+
+ return used_resources
+
+
+def CaptureCommandStderr(command, env=None):
+ """Returns the stderr of a command.
+
+ Args:
+ command: A list containing the command and arguments.
+ env: Environment variables for the new process.
+ """
+ child = subprocess.Popen(command, stderr=subprocess.PIPE, env=env)
+ _, stderr = child.communicate()
+ return child.returncode, stderr
diff --git a/src/starboard/byte_swap.h b/src/starboard/byte_swap.h
index 9fbd1fa..2347bd2 100644
--- a/src/starboard/byte_swap.h
+++ b/src/starboard/byte_swap.h
@@ -82,4 +82,47 @@
} // extern "C"
#endif
+#ifdef __cplusplus
+
+#include <algorithm>
+
+template <typename T>
+T SbByteSwap(T value) {
+ std::reverse(reinterpret_cast<uint8_t*>(&value),
+ reinterpret_cast<uint8_t*>(&value + 1));
+ return value;
+}
+
+template <>
+inline int16_t SbByteSwap(int16_t value) {
+ return SbByteSwapS16(value);
+}
+
+template <>
+inline uint16_t SbByteSwap(uint16_t value) {
+ return SbByteSwapU16(value);
+}
+
+template <>
+inline int32_t SbByteSwap(int32_t value) {
+ return SbByteSwapS32(value);
+}
+
+template <>
+inline uint32_t SbByteSwap(uint32_t value) {
+ return SbByteSwapU32(value);
+}
+
+template <>
+inline int64_t SbByteSwap(int64_t value) {
+ return SbByteSwapS64(value);
+}
+
+template <>
+inline uint64_t SbByteSwap(uint64_t value) {
+ return SbByteSwapU64(value);
+}
+
+#endif
+
#endif // STARBOARD_BYTE_SWAP_H_
diff --git a/src/starboard/common/BUILD.gn b/src/starboard/common/BUILD.gn
new file mode 100644
index 0000000..6d9fcbd
--- /dev/null
+++ b/src/starboard/common/BUILD.gn
@@ -0,0 +1,46 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# TODO: change to //starboard eventually
+import("//cobalt/build/config/base.gni")
+
+static_library("common") {
+ sources = [
+ "common.cc",
+ "flat_map.h",
+ "memory.cc",
+ "move.h",
+ "new.cc",
+ "optional.cc",
+ "ref_counted.cc",
+ "ref_counted.h",
+ "reset_and_return.h",
+ "rwlock.h",
+ "semaphore.h",
+ "scoped_ptr.h",
+ "state_machine.cc",
+ "state_machine.h",
+ "thread_collision_warner.cc",
+ "thread_collision_warner.h",
+ ]
+
+ # TODO: get rid of dependence on Cobalt
+ if (!enable_custom_media_session_client) {
+ sources += [ "//starboard/shared/media_session/stub_playback_state.cc" ]
+ }
+
+ # This must be defined when building Starboard, and must not when building
+ # Starboard client code.
+ defines = [ "STARBOARD_IMPLEMENTATION" ]
+}
diff --git a/src/starboard/common/common.gyp b/src/starboard/common/common.gyp
index bf285ef..f85fbb5 100644
--- a/src/starboard/common/common.gyp
+++ b/src/starboard/common/common.gyp
@@ -29,12 +29,15 @@
'memory.cc',
'move.h',
'new.cc',
+ 'optional.cc',
'ref_counted.cc',
'ref_counted.h',
'reset_and_return.h',
'rwlock.h',
'semaphore.h',
'scoped_ptr.h',
+ 'state_machine.cc',
+ 'state_machine.h',
'thread_collision_warner.cc',
'thread_collision_warner.h',
],
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/common/optional.cc
similarity index 69%
copy from src/starboard/win/lib/atomic_public.h
copy to src/starboard/common/optional.cc
index be4e805..f9618d1 100644
--- a/src/starboard/win/lib/atomic_public.h
+++ b/src/starboard/common/optional.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
+// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
-#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
+#include "starboard/common/optional.h"
-#include "starboard/shared/win32/atomic_public.h"
-
-#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
+namespace starboard {
+const nullopt_t nullopt;
+const in_place_t in_place;
+} // namespace starboard
diff --git a/src/starboard/common/optional.h b/src/starboard/common/optional.h
new file mode 100644
index 0000000..8e8fc00
--- /dev/null
+++ b/src/starboard/common/optional.h
@@ -0,0 +1,428 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_COMMON_OPTIONAL_H_
+#define STARBOARD_COMMON_OPTIONAL_H_
+
+#include <algorithm>
+#include <iosfwd>
+
+#include "starboard/configuration.h"
+#include "starboard/export.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+
+namespace starboard {
+
+// This class is based off of std::experimental::optional:
+// http://en.cppreference.com/w/cpp/experimental/optional
+//
+// It is a template class where instances parameterized by type T contain
+// memory for an instance of type T, but it may or may not be constructed.
+// If it is not constructed, it cannot be accessed, and if it is, it can
+// be accessed. This allows one to check if the inner object exists or not
+// before using it, and is useful for functions that may or may not return
+// a value. Note that the memory for the object is stored internally, so
+// no heap allocations are made over the course of construction and destruction
+// of the internal object (unless the internal object allocates memory within
+// its constructor).
+//
+// Some functionality is left out. For example, most C++11 functionality
+// is not implemented, since we would like this to be friendly to non-C++11
+// compilers.
+//
+// In the future, if C++11 functionality is needed, it can be implemented
+// and surrounded by preprocessor guards to maintain compatibility with non
+// C++11 compilers.
+//
+
+// The nullopt_t type is used as a signal for an empty optional. If any
+// optional is assigned the value of nullopt, it will be disengaged.
+// For example,
+// starboard::optional<int> my_int_optional(5);
+// EXPECT_FALSE(!my_int_optional);
+// my_int_optional = starboard::nullopt;
+// EXPECT_TRUE(!my_int_optional);
+//
+struct nullopt_t {
+ nullopt_t() {}
+};
+extern const nullopt_t nullopt;
+
+// The in_place_t type is used to signal in-place construction of the internal
+// object. This is used by the in place constructor of optional, which forwards
+// its parameters to the internal object's constructor.
+// For example,
+// class Foo {
+// public:
+// Foo(int x, int y) { x_ = x; y_ = y; }
+// int x() const { return x_; }
+// int y() const { return y_; }
+//
+// private:
+// int x_;
+// int y_;
+// };
+//
+// ...
+//
+// base::optional<Foo> my_foo(base::in_place, 2, 3);
+// EXPECT_FALSE(!my_foo);
+// EXPECT_EQ(2, my_foo->x());
+// EXPECT_EQ(3, my_foo->y());
+//
+struct in_place_t {
+ in_place_t() {}
+};
+extern const in_place_t in_place;
+
+template <typename T>
+class SB_EXPORT optional {
+ public:
+ // Construction via the default constructor results in an optional that is
+ // not engaged.
+ optional() { InitializeAsDisengaged(); }
+
+ optional(nullopt_t) { InitializeAsDisengaged(); } // NOLINT(runtime/explicit)
+
+ // This non-explicit singleton constructor is provided so users can pass in a
+ // T wherever a optional<T> is expected.
+ optional(const T& value) { SetValue(value); } // NOLINT(runtime/explicit)
+
+ optional(const optional<T>& other) { // NOLINT(runtime/explicit)
+ if (other.engaged_) {
+ SetValue(other.value());
+ } else {
+ InitializeAsDisengaged();
+ }
+ }
+
+ // Move constructor.
+ // NOLINTNEXTLINE(runtime/explicit)
+ optional(optional&& other) { // NOLINT(build/c++11)
+ if (other.engaged_) {
+ SetValue(std::move(other.value()));
+ } else {
+ InitializeAsDisengaged();
+ }
+ }
+
+ // Move value constructor.
+ // NOLINTNEXTLINE(runtime/explicit)
+ optional(T&& other) { // NOLINT(build/c++11)
+ SetValue(std::move(other));
+ }
+
+ // Destruct contained object upon optional's destruction.
+ ~optional() { EnsureDisengaged(); }
+
+ // Disengages the optional, calling the destructor of the contained object
+ // if it is engaged.
+ optional<T>& operator=(nullopt_t) {
+ EnsureDisengaged();
+ return *this;
+ }
+
+ // Reassigns the underlying optional to value passed in on the right hand
+ // side. This will destruct the lhs contained object first if it exists.
+ template <typename U>
+ optional<T>& operator=(const U& other) {
+ if (engaged_) {
+ value() = other;
+ } else {
+ SetValue(other);
+ }
+ return *this;
+ }
+
+ // Copy assignment.
+ optional<T>& operator=(const optional<T>& other) {
+ if (engaged_ && other.engaged_) {
+ value() = other.value();
+ } else if (!engaged_ && other.engaged_) {
+ SetValue(other.value());
+ } else if (engaged_ && !other.engaged_) {
+ EnsureDisengaged();
+ }
+ // Do nothing if lhs and rhs are both not engaged.
+ return *this;
+ }
+
+ // Move value assignment.
+ optional<T>& operator=(T&& other) { // NOLINT(build/c++11)
+ if (engaged_) {
+ value() = std::move(other);
+ } else {
+ SetValue(std::move(other));
+ }
+ return *this;
+ }
+
+ // Move optional assignment.
+ optional<T>& operator=(optional&& other) { // NOLINT(build/c++11)
+ if (engaged_ && other.engaged_) {
+ value() = std::move(other.value());
+ } else if (!engaged_ && other.engaged_) {
+ SetValue(std::move(other.value()));
+ } else if (engaged_ && !other.engaged_) {
+ EnsureDisengaged();
+ }
+ // Do nothing if lhs and rhs are both not engaged.
+ return *this;
+ }
+
+// Overloaded conversion to bool operator for determining whether the optional
+// is engaged or not. It returns true if the optional is engaged, and false
+// otherwise.
+#if (defined(_MSC_VER) && (_MSC_VER < 1800)) || \
+ (defined(__GNUC__) && \
+ (__GNUC__ < 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ < 5))))
+ // MSVC 2012 does not support explicit cast operators.
+ // http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx
+
+ // For any compiler that doesn't support explicit bool operators, we instead
+ // use the Safe Bool Idiom: http://www.artima.com/cppsource/safebool.html
+ private:
+ // The type of SafeBoolIdiomType (pointer to data member of a private type) is
+ // limited in functionality so much that the only thing a user can do with it
+ // is test for null, or apply to operator==/operator!=. Since both operators
+ // == and != are already overloaded for optional, this leaves null tests,
+ // which we use for boolean testing.
+ class PrivateSafeBoolIdiomFakeMemberType;
+ typedef PrivateSafeBoolIdiomFakeMemberType optional::*SafeBoolIdiomType;
+
+ public:
+ operator const SafeBoolIdiomType() const {
+ // If we wish to return true, we cast engaged_ to our private type giving
+ // a non-null pointer to data member. Otherwise, we return NULL. The
+ // only thing the user can do with the return type is test for NULL.
+ return engaged_
+ ? reinterpret_cast<const SafeBoolIdiomType>(&optional::engaged_)
+ : NULL;
+ }
+#else
+ explicit operator bool() const { return engaged_; }
+#endif
+
+ // Dereferences the internal object.
+ const T* operator->() const { return &(value()); }
+
+ T* operator->() { return &(value()); }
+
+ const T& operator*() const { return value(); }
+
+ T& operator*() { return value(); }
+
+ // Dereferences and returns the internal object.
+ const T& value() const {
+ SB_DCHECK(engaged_)
+ << "Attempted to access object in a disengaged optional.";
+ return *static_cast<const T*>(void_value());
+ }
+
+ T& value() {
+ SB_DCHECK(engaged_)
+ << "Attempted to access object in a disengaged optional.";
+ return *static_cast<T*>(void_value());
+ }
+
+ template <typename U>
+ T value_or(const U& value) const {
+ if (engaged_) {
+ return this->value();
+ } else {
+ return value;
+ }
+ }
+
+ // Swaps the values of two optionals.
+ void swap(optional<T>& other) {
+ if (engaged_ && other.engaged_) {
+ // Swap the value contents with each other.
+ std::swap(value(), other.value());
+ } else if (engaged_) {
+ other.SetValue(std::move(value()));
+ EnsureDisengaged();
+ } else if (other.engaged_) {
+ SetValue(std::move(other.value()));
+ other.EnsureDisengaged();
+ }
+ // If both the lhs and rhs are not engaged, we do nothing.
+ }
+
+// Include the pump.py-generated declaration and implementation for the
+// forwarding constructor and emplace.
+#include "starboard/common/optional_internal.h"
+
+ private:
+ // Sets a non-engaged optional to a specified value, and marks it as engaged.
+ void SetValue(T&& value) { // NOLINT(build/c++11)
+ new (void_value()) T(std::move(value));
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+
+ // Sets a non-engaged optional to a specified value, and marks it as engaged.
+ template <typename U>
+ void SetValue(const U& value) {
+ new (void_value()) T(value);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+
+ // If an optional is engaged, it destructs the wrapped value and marks the
+ // optional as disengaged. Does nothing to a disengaged optional.
+ void EnsureDisengaged() {
+ if (engaged_) {
+ static_cast<T*>(void_value())->~T();
+ engaged_ = false;
+#if !defined(NDEBUG)
+ value_ptr_ = NULL;
+#endif
+ }
+ }
+
+ // Called upon object construction to initialize the object into a disengaged
+ // state.
+ void InitializeAsDisengaged() {
+ engaged_ = false;
+#if !defined(NDEBUG)
+ value_ptr_ = NULL;
+#endif
+ }
+
+ const void* void_value() const {
+ return reinterpret_cast<const void*>(value_memory_);
+ }
+ void* void_value() { return reinterpret_cast<void*>(value_memory_); }
+
+ // The actual memory reserved for the object that may or may not exist.
+ SB_ALIGNAS(SB_ALIGNOF(T)) uint8_t value_memory_[sizeof(T)];
+ // This boolean tracks whether or not the object is constructed yet or not.
+ bool engaged_;
+#if !defined(NDEBUG)
+ // In debug builds, this member makes it easy to inspect the value contained
+ // in the optional via a debugger.
+ const T* value_ptr_;
+#endif
+};
+
+// Comparison between 2 optionals
+template <typename T>
+inline bool operator==(const optional<T>& lhs, const optional<T>& rhs) {
+ if (!lhs) {
+ return !rhs;
+ }
+
+ return rhs == lhs.value();
+}
+
+template <typename T>
+inline bool operator<(const optional<T>& lhs, const optional<T>& rhs) {
+ if (lhs && rhs) {
+ return lhs.value() < rhs.value();
+ } else {
+ // Handle all other cases simply in terms of whether the optionals are
+ // engaged or not.
+ return static_cast<bool>(lhs) < static_cast<bool>(rhs);
+ }
+}
+
+// Comparison with nullopt_t
+template <typename T>
+inline bool operator==(nullopt_t, const optional<T>& rhs) {
+ return !rhs;
+}
+
+template <typename T>
+inline bool operator==(const optional<T>& lhs, nullopt_t rhs) {
+ return rhs == lhs;
+}
+
+template <typename T>
+inline bool operator<(const optional<T>& /* lhs */, nullopt_t) {
+ return false;
+}
+
+template <typename T>
+inline bool operator<(nullopt_t, const optional<T>& rhs) {
+ return static_cast<bool>(rhs);
+}
+
+// Comparison between an optional and a value
+template <typename T>
+inline bool operator==(const optional<T>& lhs, const T& rhs) {
+ return (!lhs ? false : lhs.value() == rhs);
+}
+
+template <typename T>
+inline bool operator==(const T& lhs, const optional<T>& rhs) {
+ return rhs == lhs;
+}
+
+template <typename T>
+inline bool operator<(const T& lhs, const optional<T>& rhs) {
+ return rhs && lhs < rhs.value();
+}
+
+template <typename T>
+inline bool operator<(const optional<T>& lhs, const T& rhs) {
+ return !lhs || lhs.value() < rhs;
+}
+
+// This is a convenient but non-standard method, do not rely on it if you expect
+// the compatibility with upcoming C++ versions.
+template <typename T>
+inline std::ostream& operator<<(std::ostream& stream,
+ const optional<T>& maybe_value) {
+ if (maybe_value) {
+ stream << *maybe_value;
+ } else {
+ stream << "nullopt";
+ }
+ return stream;
+}
+
+template <typename T>
+optional<T> make_optional(const T& value) {
+ return optional<T>(value);
+}
+
+} // namespace starboard
+
+namespace std {
+
+template <typename T>
+struct hash<::starboard::optional<T> > {
+ public:
+ size_t operator()(const ::starboard::optional<T>& value) const {
+ return (value ? value_hash_(value.value()) : 0);
+ }
+
+ private:
+ hash<T> value_hash_;
+};
+
+template <typename T>
+void swap(::starboard::optional<T>& lhs, ::starboard::optional<T>& rhs) {
+ lhs.swap(rhs);
+}
+
+} // namespace std
+
+#endif // STARBOARD_COMMON_OPTIONAL_H_
diff --git a/src/starboard/common/optional_internal.h b/src/starboard/common/optional_internal.h
new file mode 100644
index 0000000..355e1db
--- /dev/null
+++ b/src/starboard/common/optional_internal.h
@@ -0,0 +1,180 @@
+// This file was GENERATED by command:
+// pump.py optional_internal.h.pump
+// DO NOT EDIT BY HAND!!!
+
+//
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// clang-format off
+// Begin forwarding constructor definitions ////////////////////////////////////
+ explicit optional(in_place_t) {
+ InitializeAsDisengaged();
+ new (void_value()) T();
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1>
+ explicit optional(in_place_t, const P1& p1) {
+ InitializeAsDisengaged();
+ new (void_value()) T(p1);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1, typename P2>
+ explicit optional(in_place_t, const P1& p1, const P2& p2) {
+ InitializeAsDisengaged();
+ new (void_value()) T(p1, p2);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1, typename P2, typename P3>
+ explicit optional(in_place_t, const P1& p1, const P2& p2, const P3& p3) {
+ InitializeAsDisengaged();
+ new (void_value()) T(p1, p2, p3);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1, typename P2, typename P3, typename P4>
+ explicit optional(in_place_t, const P1& p1, const P2& p2, const P3& p3,
+ const P4& p4) {
+ InitializeAsDisengaged();
+ new (void_value()) T(p1, p2, p3, p4);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1, typename P2, typename P3, typename P4, typename P5>
+ explicit optional(in_place_t, const P1& p1, const P2& p2, const P3& p3,
+ const P4& p4, const P5& p5) {
+ InitializeAsDisengaged();
+ new (void_value()) T(p1, p2, p3, p4, p5);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1, typename P2, typename P3, typename P4, typename P5,
+ typename P6>
+ explicit optional(in_place_t, const P1& p1, const P2& p2, const P3& p3,
+ const P4& p4, const P5& p5, const P6& p6) {
+ InitializeAsDisengaged();
+ new (void_value()) T(p1, p2, p3, p4, p5, p6);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1, typename P2, typename P3, typename P4, typename P5,
+ typename P6, typename P7>
+ explicit optional(in_place_t, const P1& p1, const P2& p2, const P3& p3,
+ const P4& p4, const P5& p5, const P6& p6, const P7& p7) {
+ InitializeAsDisengaged();
+ new (void_value()) T(p1, p2, p3, p4, p5, p6, p7);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+// End forwarding constructor definitions //////////////////////////////////////
+
+// Begin emplace(...) definitions //////////////////////////////////////////////
+ void emplace() {
+ EnsureDisengaged();
+ new (void_value()) T();
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1>
+ void emplace(const P1& p1) {
+ EnsureDisengaged();
+ new (void_value()) T(p1);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1, typename P2>
+ void emplace(const P1& p1, const P2& p2) {
+ EnsureDisengaged();
+ new (void_value()) T(p1, p2);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1, typename P2, typename P3>
+ void emplace(const P1& p1, const P2& p2, const P3& p3) {
+ EnsureDisengaged();
+ new (void_value()) T(p1, p2, p3);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1, typename P2, typename P3, typename P4>
+ void emplace(const P1& p1, const P2& p2, const P3& p3, const P4& p4) {
+ EnsureDisengaged();
+ new (void_value()) T(p1, p2, p3, p4);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1, typename P2, typename P3, typename P4, typename P5>
+ void emplace(const P1& p1, const P2& p2, const P3& p3, const P4& p4,
+ const P5& p5) {
+ EnsureDisengaged();
+ new (void_value()) T(p1, p2, p3, p4, p5);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1, typename P2, typename P3, typename P4, typename P5,
+ typename P6>
+ void emplace(const P1& p1, const P2& p2, const P3& p3, const P4& p4,
+ const P5& p5, const P6& p6) {
+ EnsureDisengaged();
+ new (void_value()) T(p1, p2, p3, p4, p5, p6);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+ template <typename P1, typename P2, typename P3, typename P4, typename P5,
+ typename P6, typename P7>
+ void emplace(const P1& p1, const P2& p2, const P3& p3, const P4& p4,
+ const P5& p5, const P6& p6, const P7& p7) {
+ EnsureDisengaged();
+ new (void_value()) T(p1, p2, p3, p4, p5, p6, p7);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+// End emplace(...) definitions ////////////////////////////////////////////////
+// clang-format on
diff --git a/src/starboard/common/optional_internal.h.pump b/src/starboard/common/optional_internal.h.pump
new file mode 100644
index 0000000..aaf152a
--- /dev/null
+++ b/src/starboard/common/optional_internal.h.pump
@@ -0,0 +1,74 @@
+//
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+$$ This is a pump file for generating the interface and implementation of
+$$ optional's forwarding constructor and emplace() method. Pump is a python
+$$ script that is part of the Google Test suite of utilities. Description
+$$ can be found here:
+$$
+$$ http://code.google.com/p/googletest/wiki/PumpManual
+$$
+
+$var MAX_ARITY = 7
+
+$range ARITY 0..MAX_ARITY
+
+// clang-format off
+// Begin forwarding constructor definitions ////////////////////////////////////
+
+$for ARITY [[
+
+$range ARG 1..ARITY
+
+$if ARITY > 0 [[
+ template <$for ARG , [[typename P$(ARG)]]>
+
+]]
+ explicit optional(in_place_t$if ARITY > 0 [[, ]]
+ $for ARG , [[const P$(ARG)& p$(ARG)]]) {
+ InitializeAsDisengaged();
+ new (void_value()) T($for ARG , [[p$(ARG)]]);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+
+]]
+// End forwarding constructor definitions //////////////////////////////////////
+
+// Begin emplace(...) definitions //////////////////////////////////////////////
+
+$for ARITY [[
+
+$range ARG 1..ARITY
+
+$if ARITY > 0 [[
+ template <$for ARG , [[typename P$(ARG)]]>
+
+]]
+ void emplace($for ARG , [[const P$(ARG)& p$(ARG)]]) {
+ EnsureDisengaged();
+ new (void_value()) T($for ARG , [[p$(ARG)]]);
+ engaged_ = true;
+#if !defined(NDEBUG)
+ value_ptr_ = static_cast<const T*>(void_value());
+#endif
+ }
+
+]]
+// End emplace(...) definitions ////////////////////////////////////////////////
+// clang-format on
\ No newline at end of file
diff --git a/src/starboard/common/state_machine.cc b/src/starboard/common/state_machine.cc
new file mode 100644
index 0000000..a87e0c7
--- /dev/null
+++ b/src/starboard/common/state_machine.cc
@@ -0,0 +1,296 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "starboard/common/state_machine.h"
+
+#include <algorithm>
+
+#include "starboard/log.h"
+
+// --- Macros for common logging idioms ---
+
+#define SM_STATE(s) GetStateString(s) << "(" << s << ")"
+#define SM_STATEN(s) GetStateString(s) << "(" << s.value_or(0) << ")"
+#define SM_EVENT(e) GetEventString(e) << "(" << e << ")"
+#define SM_PREFIX name_ << "-" << SM_STATEN(state_) << "v" << version_ << ": "
+#define SM_DLOG(level) SB_DLOG(level) << SM_PREFIX
+
+namespace starboard {
+
+StateMachineBase::StateMachineBase(const std::string& name)
+ : name_(name),
+ version_(0),
+ is_handling_(false),
+ is_initialized_(false),
+ should_log_(false) {}
+
+void StateMachineBase::Initialize() {
+ if (is_initialized_) {
+ return;
+ }
+
+ if (should_log_) {
+ SM_DLOG(INFO) << "INITIALIZING";
+ }
+ SB_DCHECK(!state_) << SM_PREFIX;
+ SB_DCHECK(!GetParentState(GetUserInitialState())) << SM_PREFIX;
+ is_initialized_ = true;
+ FollowInitialSubstates();
+}
+
+bool StateMachineBase::IsIn(State state) const {
+ optional<State> currentState = state_;
+ while (currentState) {
+ if (state == currentState.value()) {
+ return true;
+ }
+
+ currentState = GetParentState(currentState);
+ }
+
+ return false;
+}
+
+const char* StateMachineBase::GetStateString(optional<State> state) const {
+ if (!state) {
+ return "<none>";
+ }
+
+ const char* user = GetUserStateString(state.value());
+ if (user) {
+ return user;
+ }
+
+ return "UNKNOWN_STATE";
+}
+
+const char* StateMachineBase::GetEventString(optional<Event> event) const {
+ if (!event) {
+ return "<none>";
+ }
+
+ const char* user = GetUserEventString(event.value());
+ if (user) {
+ return user;
+ }
+
+ return "UNKNOWN_EVENT";
+}
+
+void StateMachineBase::Handle(Event event, void* data) {
+ Initialize();
+
+ if (is_handling_) {
+ if (should_log_) {
+ SM_DLOG(INFO) << "QUEUEING " << SM_EVENT(event);
+ }
+
+ event_queue_.push(EventWithData(event, data));
+ return;
+ }
+
+ HandleOneEvent(event, data);
+ HandleQueuedEvents();
+}
+
+optional<StateMachineBase::State> StateMachineBase::GetParentState(
+ optional<State> state) const {
+ if (!state) {
+ return optional<State>();
+ }
+
+ return GetUserParentState(state.value());
+}
+
+optional<StateMachineBase::State> StateMachineBase::GetInitialSubstate(
+ optional<State> state) const {
+ if (!state) {
+ return optional<State>();
+ }
+
+ return GetUserInitialSubstate(state.value());
+}
+
+void StateMachineBase::HandleQueuedEvents() {
+ while (!event_queue_.empty()) {
+ EventWithData& event = event_queue_.front();
+ HandleOneEvent(event.event, event.data);
+ event_queue_.pop();
+ }
+}
+
+void StateMachineBase::HandleOneEvent(Event event, void* data) {
+ if (should_log_) {
+ SM_DLOG(INFO) << "HANDLING " << SM_EVENT(event);
+ }
+
+ SB_DCHECK(!is_handling_) << SM_PREFIX;
+ is_handling_ = true;
+
+ // Walk up the hierarchy from the simplest current state, looking for event
+ // handlers, stopping at the first state that decides to handle the event.
+ optional<State> source = state_;
+ Result result;
+ while (source) {
+ result = HandleUserStateEvent(source.value(), event, data);
+ if (!result.is_handled) {
+ // Result was not handled, so we continue up the state chain.
+ source = GetParentState(source);
+ continue;
+ }
+
+ break;
+ }
+
+ // Log that the event was completely unhandled, because that's kinda weird.
+ // It's better if the state machine handler explicitly consumes and ignores
+ // events that should be ignored.
+ if (!result.is_handled && should_log_) {
+ SM_DLOG(WARNING) << "Event " << SM_EVENT(event) << " was unhandled.";
+ }
+
+ // If a transition was triggered, execute it.
+ if (result.is_transition) {
+ Transition(event, source.value(), result.target.value(),
+ result.is_external);
+ }
+
+ is_handling_ = false;
+}
+
+// Returns the index of |state| in |path|, or -1 if not found in |path_length|
+// elements. If |state| is null, then it will always return -1.
+static int IndexOf(optional<StateMachineBase::State> state,
+ const StateMachineBase::State* path,
+ size_t path_length) {
+ if (!state) {
+ return -1;
+ }
+
+ int i;
+ for (i = 0; !(path[i] == state) && i < path_length; ++i) {
+ }
+ return (i == path_length ? -1 : i);
+}
+
+// Finds the least common ancestor between the two state paths. If there is no
+// common ancestor, returns null.
+static optional<StateMachineBase::State> FindLeastCommonAncestor(
+ const StateMachineBase::State* path_a,
+ size_t length_a,
+ const StateMachineBase::State* path_b,
+ size_t length_b) {
+ size_t max = std::min(length_a, length_b);
+ size_t i;
+ for (i = 0; path_a[i] == path_b[i] && i < max; ++i) {
+ }
+ return (i == 0 ? optional<StateMachineBase::State>() : path_a[i - 1]);
+}
+
+void StateMachineBase::GetPath(State state,
+ size_t max_depth,
+ State* out_path,
+ size_t* out_depth) const {
+ if (max_depth == 0) {
+ SM_DLOG(FATAL) << "max_depth must be > 0";
+ if (out_depth) {
+ *out_depth = 0;
+ }
+ return;
+ }
+
+ size_t depth = 0;
+ optional<State> currentState = state;
+ while (currentState && depth < max_depth) {
+ out_path[depth] = currentState.value();
+ ++depth;
+ currentState = GetParentState(currentState);
+ }
+
+ // Reverse so the path is in ascending depth order.
+ std::reverse(out_path, out_path + depth);
+ if (out_depth) {
+ *out_depth = depth;
+ }
+}
+
+void StateMachineBase::Transition(Event event,
+ State source,
+ State target,
+ bool is_external) {
+ if (should_log_) {
+ SM_DLOG(INFO) << SM_EVENT(event) << " caused " << SM_STATE(source) << " -> "
+ << SM_STATE(target) << (is_external ? " (external)" : "");
+ }
+
+ // Define a reasonable max depth so we don't have to heap allocate. I've never
+ // seen an HSM as deep as whatever arbitrary value this is defined to be at
+ // the moment.
+ static const size_t kMaxDepth = 16;
+ State source_path[kMaxDepth];
+ size_t source_depth;
+ GetPath(source, kMaxDepth, source_path, &source_depth);
+ State target_path[kMaxDepth];
+ size_t target_depth;
+ GetPath(target, kMaxDepth, target_path, &target_depth);
+ optional<State> least_common_ancestor = FindLeastCommonAncestor(
+ source_path, source_depth, target_path, target_depth);
+
+ // External transitions must exit the source state and enter the target
+ // state, so if the LCA is one of the two, we need to go one level up.
+ if (is_external &&
+ (least_common_ancestor == source || least_common_ancestor == target)) {
+ least_common_ancestor = GetParentState(least_common_ancestor);
+ }
+
+ // Unwind (exit) states up to the closest common ancestor.
+ while (state_ && !(state_ == least_common_ancestor)) {
+ ExitCurrentState();
+ }
+
+ // Update version before we wind down to the target.
+ ++version_;
+
+ // Wind (enter) states down to the target state.
+ size_t next_depth = IndexOf(state_, target_path, target_depth) + 1;
+ SB_DCHECK(next_depth <= target_depth);
+ while (next_depth < target_depth) {
+ EnterState(target_path[next_depth]);
+ ++next_depth;
+ }
+
+ FollowInitialSubstates();
+}
+
+void StateMachineBase::FollowInitialSubstates() {
+ while (true) {
+ optional<State> substate =
+ (state_ ? GetInitialSubstate(state_) : GetUserInitialState());
+ if (!substate) {
+ break;
+ }
+ EnterState(substate.value());
+ }
+}
+
+void StateMachineBase::EnterState(State state) {
+ state_ = state;
+
+ if (should_log_) {
+ SM_DLOG(INFO) << "ENTER";
+ }
+
+ HandleUserStateEnter(state);
+}
+
+void StateMachineBase::ExitCurrentState() {
+ if (should_log_) {
+ SM_DLOG(INFO) << "EXIT";
+ }
+
+ HandleUserStateExit(state_.value());
+ state_ = GetParentState(state_);
+}
+
+} // namespace starboard
diff --git a/src/starboard/common/state_machine.h b/src/starboard/common/state_machine.h
new file mode 100644
index 0000000..017c06d
--- /dev/null
+++ b/src/starboard/common/state_machine.h
@@ -0,0 +1,517 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef STARBOARD_COMMON_STATE_MACHINE_H_
+#define STARBOARD_COMMON_STATE_MACHINE_H_
+
+#include <queue>
+#include <string>
+
+#include "starboard/common/optional.h"
+#include "starboard/configuration.h"
+#include "starboard/export.h"
+
+#ifdef __cplusplus
+namespace starboard {
+
+// An approximate implementation of a run-to-completion (RTC) Hierarchical State
+// Machine (HSM), supporting most UML Statechart semantics.
+//
+// Some good background information on UML Statecharts, mostly written by Miro
+// Samek:
+// http://en.wikipedia.org/wiki/UML_state_machine
+//
+// And Miro Samek's 3-part article on practical UML Statecharts:
+// http://www.embedded.com/design/prototyping-and-development/4008247/A-crash-course-in-UML-state-machines-Part-1
+//
+// This class does not provide any intrinsic support for "orthogonal regions,"
+// "extended state," or "deferred events." "Guard conditions" are easily
+// implemented by the client directly in the event handler. It also minorly
+// deviates from the UML Statechart specification by calling transition handlers
+// before exiting the current states. This is because this implementation uses a
+// simplification which combines the transition handlers and the
+// state-event-transition map into a single function (HandleUserStateEvent).
+//
+// This class is not thread-safe. It is the user's responsibility to synchronize
+// calls into the state machine, either with locks or by simply using from a
+// single thread.
+//
+// Terse suggestions for using this class:
+// * Use the templated StateMachine wrapper class instead of this class
+// directly.
+// * Define two enums, one for your states, and one for your events.
+// * Subclass to define your state machine and event handlers.
+// * Avoid directly exposing or passing around state machines (wrap instead).
+// Handle() is not a great public interface.
+// * Include your state machine in another class as a private by-value member.
+// * Synchronize access to the state machine.
+// * Prefer writing state machine event handlers over checking if the machine
+// IsIn() a particular state.
+// * Convert public methods into events, get into the state machine as quickly
+// as possible.
+// * You only need to define a state when you are going to leave the state
+// machine in a particular condition where events can occur.
+// * Create a superstate when you have an event you want to handle the same
+// way for a collection of states.
+// * When managing resources, create a state or superstate that represents the
+// acquisition of that resource, and release the resource in the Exit
+// handler.
+//
+// Some Definitions:
+// Simple State - A State with no substates. The state machine is always
+// left in exactly one Simple State.
+// Composite State - A State with at least one substate.
+// Guard Condition - An external condition on which an event handler
+// branches.
+// Run-To-Completion - A property specifying that the state machine handles
+// one event at a time, and no events are handled until
+// the previous event is done being handled.
+//
+// See the unittests for this class for a contrived example state machine
+// implementation.
+class StateMachineBase {
+ public:
+ // --- Nested Types and Constants ---
+
+ typedef uint32_t State;
+ typedef uint32_t Event;
+
+ // --- Public Methods ---
+
+ // Constructor with name. The name is helpful for debugging.
+ explicit StateMachineBase(const std::string& name);
+ virtual ~StateMachineBase() {}
+
+ // Enters the initial state, as specified by |GetUserInitialState()| and
+ // follows the initial substates down to the first simple (childless) state
+ // found. Idempotent. Will happen automatically on the first |Handle()| call,
+ // if not done explicitly.
+ void Initialize();
+
+ // Gets the name of this state machine, for logging purposes.
+ const char* name() const { return name_.c_str(); }
+
+ // Gets a version number that increases monotonically with each state
+ // transition (unless it overflows |uint64_t|). This can be useful for timers
+ // and asynchronous events that only want to do their action if the state has
+ // not changed since they were queued.
+ //
+ // The state version changes exactly once per transition. In other words, it
+ // doesn't change for every Enter and Exit for a transition.
+ uint64_t version() const { return version_; }
+
+ // Gets the simplest current state that this state machine is in. To check if
+ // the state machine is in a particular composite state, use |IsIn()|. Returns
+ // null if uninitialized.
+ optional<State> state() const { return state_; }
+
+ // Reports whether the state machine is currently in the given state. A state
+ // machine is considered to be "in" the current simple state, but also "in"
+ // all superstates of the current simple state.
+ bool IsIn(State state) const;
+
+ // Gets a printable string for the given state.
+ const char* GetStateString(optional<State> state) const;
+
+ // Gets a printable string for the given event.
+ const char* GetEventString(optional<Event> event) const;
+
+ // Handles the given event in the context of the state machine's current
+ // state, executing the appropriate event handlers and performing any
+ // precipitate state transitions. If called reentrantly, the event will be
+ // queued until the current event has run to completion.
+ //
+ // |data| is a way to pass auxiliary data to the event handler. No retention
+ // or ref-counting is done on that data, it is simply passed through to the
+ // event handler. Since |Handle()| will queue the event if (and only if)
+ // called from an event handler, it is up to the caller to ensure the lifetime
+ // of whatever is passed in here.
+ void Handle(Event event, void* data = NULL);
+
+ protected:
+ // --- Protected Nested Types ---
+
+ // A type that can be returned from a state-event handler, which will be
+ // coerced into the appropriate Result structure.
+ enum HandledState {
+ // The event handler returns this to say that the handler consume the event,
+ // but caused no state transition.
+ kHandled,
+
+ // The event handler returns this to say that the handler did not consume
+ // the event, and it should bubble up to the parent state, if any.
+ kNotHandled,
+ };
+
+ // Structure that handlers return, allowing them to cause state transitions or
+ // prevent the event from bubbling. State-event handlers may just return a
+ // HandledState or a state to transition to, and it will be coerced into this
+ // structure.
+ struct Result {
+ // Default constructor is unhandled.
+ Result() : is_transition(false), is_external(false), is_handled(false) {}
+
+ // The no-transition constructor. Non-explicit so that the implementor of
+ // |HandleUserStateEvent()| just needs to return a |HandledState| and it
+ // does the right thing.
+ Result(HandledState handled) // NOLINT(runtime/explicit)
+ : is_transition(false),
+ is_external(false),
+ is_handled(handled == kHandled) {}
+
+ // The state transition constructor. This implies that the event was
+ // handled. Non-explicit so that the implementor of |HandleUserStateEvent()|
+ // just needs to return a State and it does a non-external transition.
+ Result(State transition_target,
+ bool external = false) // NOLINT(runtime/explicit)
+ : target(transition_target),
+ is_transition(true),
+ is_external(external),
+ is_handled(true) {}
+
+ Result& operator=(HandledState rhs) {
+ target = nullopt;
+ is_transition = false;
+ is_external = false;
+ is_handled = (rhs == kHandled);
+ return *this;
+ }
+
+ Result& operator=(State transition_target) {
+ target = transition_target;
+ is_transition = true;
+ is_external = false;
+ is_handled = true;
+ return *this;
+ }
+
+ // State to transition to. Only valid if is_transition is true.
+ optional<State> target;
+
+ // Whether this result indicates a state transition.
+ bool is_transition;
+
+ // Whether the specified transition is external. Only meaningful if
+ // is_transition is true.
+ //
+ // For more on state transitions, see:
+ // http://en.wikipedia.org/wiki/UML_state_machine#Transition_execution_sequence
+ bool is_external;
+
+ // Whether the event was handled by the handler. If true, consumes the
+ // event, and prevents bubbling up to superstates. False propagates the
+ // event to superstates.
+ bool is_handled;
+ };
+
+ struct EventWithData {
+ EventWithData(Event event, void* data) : event(event), data(data) {}
+ Event event;
+ void* data;
+ };
+
+ // --- Implementation Interface for Subclasses ---
+
+ // Abstract method for subclasses to define the state hierarchy. It is
+ // recommended that all user-defined states be descendents of a single "top"
+ // state.
+ virtual optional<State> GetUserParentState(State state) const = 0;
+
+ // Abstract method for subclasses to define the initial substate of their
+ // states, which is required for all complex states. If a state is a simple
+ // state (no substates), returns null.
+ virtual optional<State> GetUserInitialSubstate(State state) const = 0;
+
+ // Abstract method for subclasses to define the initial (top) state of their
+ // state machine. This must be a state that has no parent. This state will be
+ // entered upon calling |Initialize()|.
+ virtual State GetUserInitialState() const = 0;
+
+ // Optional method for subclasses to define strings for their states, solely
+ // used for debugging purposes.
+ virtual const char* GetUserStateString(State state) const { return NULL; }
+
+ // Optional method for subclasses to define strings for their events, solely
+ // used for debugging purposes.
+ virtual const char* GetUserEventString(Event event) const { return NULL; }
+
+ // Abstract method for subclasses to define handlers for events in given
+ // states. This method must return either:
+ // a) a state to transition to, meaning the event was handled and caused
+ // a transition
+ // b) |kHandled| meaning the event was handled but no transition occurred
+ // c) |kNotHandled|, meaning the event should bubble up to the parent state
+ // d) an explicit Result structure, mainly for external transitions.
+ //
+ // Implementations wishing to catch all unhandled events may do so in their
+ // top state.
+ //
+ // This method is generally implemented as a nested switch statement, with the
+ // outer switch on |state| and the inner switch on |event|. You may want to
+ // break this apart into per-state or per-state-event functions for
+ // readability and maintainability.
+ virtual Result HandleUserStateEvent(State state, Event event, void* data) = 0;
+
+ // Abstract method for subclasses to define state entry behaviors.
+ virtual void HandleUserStateEnter(State state) = 0;
+
+ // Abstract method for subclasses to define state exit behaviors.
+ virtual void HandleUserStateExit(State state) = 0;
+
+ // --- Helper Methods for Subclasses ---
+
+ // Subclasses can call this method to turn on logging. Logging is opt-in,
+ // because it can be very verbose, and is likely only useful during
+ // development of a particular state machine.
+ void EnableLogging() { should_log_ = true; }
+
+ private:
+ // --- Private Helper Methods ---
+
+ // Gets the parent state of the given state.
+ optional<State> GetParentState(optional<State> state) const;
+
+ // Gets the initial substate of given state.
+ optional<State> GetInitialSubstate(optional<State> state) const;
+
+ // Handles all queued events until there are no more to run. Event handlers
+ // may queue more events by calling |Handle()|, and this method will also
+ // process all precipitate events.
+ void HandleQueuedEvents();
+
+ // Workhorse method for handling a single event.
+ void HandleOneEvent(Event event, void* data);
+
+ // Gets the path from the Top state to the given |state|, storing it in the
+ // given |out_path| array, up to |max_depth| entries. If specified,
+ // |out_depth| will be set to the number of valid states that fit in the given
+ // array.
+ void GetPath(State state,
+ size_t max_depth,
+ State* out_path,
+ size_t* out_depth) const;
+
+ // Transitions between the given source and target states, assuming that the
+ // source state is in the current state path to the Top state. The source
+ // state is the state whose handler generated the transition.
+ //
+ // See:
+ // http://en.wikipedia.org/wiki/UML_state_machine#Transition_execution_sequence
+ void Transition(Event event, State source, State target, bool is_external);
+
+ // Follows the initial substates from the current state until it reaches a
+ // simple state.
+ void FollowInitialSubstates();
+
+ // Enters the given state.
+ void EnterState(State state);
+
+ // Exits the current state to its parent.
+ void ExitCurrentState();
+
+ // --- Members ---
+
+ // The name of this state machine, for debugging purposes.
+ const std::string name_;
+
+ // The current state of this state machine. Null until initialized.
+ optional<State> state_;
+
+ // The unique version of this state machine's state, updated on every
+ // transition.
+ uint64_t version_;
+
+ // Queue of events to handle once the current event is done being
+ // handled. Should always be empty unless |is_handling_| is true.
+ std::queue<EventWithData> event_queue_;
+
+ // Whether this state machine is actively handling an event. Used to detect
+ // reentrant calls to |Handle()|.
+ bool is_handling_;
+
+ // Whether the state machine has been initialized into its initial state
+ // yet. Used to make |Initialize()| idempotent.
+ bool is_initialized_;
+
+ // Whether the state machine should log information about state transitions.
+ bool should_log_;
+};
+
+// A convenience template wrapper for StateMachineBase. See the above class
+// for complete documentation. Basically, you define your states and events as
+// two enums, and then pass them as template args to this template class. Your
+// state machine should then subclass this template class. It then does the work
+// of casting and converting back and forth from your enums to
+// StateMachineBase's numeric State and Event definitions.
+//
+// All the methods in this class, protected and public, match the description
+// and behavioral contracts of the equivalently named method in
+// StateMachineBase.
+template <typename StateEnum, typename EventEnum>
+class StateMachine {
+ public:
+ // --- Nested Types and Constants ---
+
+ explicit StateMachine(const std::string& name) : machine_(this, name) {}
+ virtual ~StateMachine() {}
+
+ void Initialize() { machine_.Initialize(); }
+
+ const char* name() const { return machine_.name(); }
+
+ uint64_t version() const { return machine_.version(); }
+
+ optional<StateEnum> state() const {
+ optional<BaseState> wrappedState = machine_.state();
+ return (wrappedState ? static_cast<StateEnum>(*wrappedState)
+ : optional<StateEnum>());
+ }
+
+ bool IsIn(StateEnum state) const {
+ return machine_.IsIn(static_cast<BaseState>(state));
+ }
+
+ const char* GetStateString(optional<StateEnum> state) const {
+ return machine_.GetStateString(state ? static_cast<BaseState>(*state)
+ : optional<BaseState>());
+ }
+
+ const char* GetEventString(optional<EventEnum> event) const {
+ return machine_.GetEventString(event ? static_cast<BaseEvent>(*event)
+ : optional<BaseEvent>());
+ }
+
+ void Handle(EventEnum event, void* data = NULL) {
+ machine_.Handle(static_cast<BaseEvent>(event), data);
+ }
+
+ protected:
+ // See the other HandledState in StateMachineBase.
+ enum HandledState {
+ kHandled,
+ kNotHandled,
+ };
+
+ // See the other Result in StateMachineBase.
+ struct Result {
+ Result(HandledState handled) // NOLINT(runtime/explicit)
+ : target(),
+ is_transition(false),
+ is_external(false),
+ is_handled(handled == kHandled) {}
+
+ Result(StateEnum transition_target,
+ bool external = false) // NOLINT(runtime/explicit)
+ : target(transition_target),
+ is_transition(true),
+ is_external(external),
+ is_handled(true) {}
+
+ Result& operator=(HandledState rhs) {
+ target = nullopt;
+ is_transition = false;
+ is_external = false;
+ is_handled = (rhs == kHandled);
+ return *this;
+ }
+
+ Result& operator=(StateEnum transition_target) {
+ target = transition_target;
+ is_transition = true;
+ is_external = false;
+ is_handled = true;
+ return *this;
+ }
+
+ optional<StateEnum> target;
+ bool is_transition;
+ bool is_external;
+ bool is_handled;
+ };
+
+ virtual optional<StateEnum> GetUserParentState(StateEnum state) const = 0;
+ virtual optional<StateEnum> GetUserInitialSubstate(StateEnum state) const = 0;
+ virtual StateEnum GetUserInitialState() const = 0;
+ virtual const char* GetUserStateString(StateEnum state) const { return NULL; }
+ virtual const char* GetUserEventString(EventEnum event) const { return NULL; }
+ virtual Result HandleUserStateEvent(StateEnum state,
+ EventEnum event,
+ void* data) = 0;
+ virtual void HandleUserStateEnter(StateEnum state) = 0;
+ virtual void HandleUserStateExit(StateEnum state) = 0;
+
+ void EnableLogging() { machine_.EnableLoggingPublic(); }
+
+ private:
+ typedef StateMachineBase::State BaseState;
+ typedef StateMachineBase::Event BaseEvent;
+
+ // Private contained subclass that forwards and adapts all virtual methods
+ // into this class's equivalent virtual methods.
+ class WrappedMachine : public StateMachineBase {
+ public:
+ WrappedMachine(StateMachine<StateEnum, EventEnum>* wrapper,
+ const std::string& name)
+ : StateMachineBase(name), wrapper_(wrapper) {}
+
+ optional<State> GetUserParentState(State state) const SB_OVERRIDE {
+ optional<StateEnum> result =
+ wrapper_->GetUserParentState(static_cast<StateEnum>(state));
+ return (result ? static_cast<State>(*result) : optional<State>());
+ }
+
+ optional<State> GetUserInitialSubstate(State state) const SB_OVERRIDE {
+ optional<StateEnum> result =
+ wrapper_->GetUserInitialSubstate(static_cast<StateEnum>(state));
+ return (result ? static_cast<State>(*result) : optional<State>());
+ }
+
+ State GetUserInitialState() const SB_OVERRIDE {
+ return static_cast<State>(wrapper_->GetUserInitialState());
+ }
+
+ const char* GetUserStateString(State state) const SB_OVERRIDE {
+ return wrapper_->GetUserStateString(static_cast<StateEnum>(state));
+ }
+
+ const char* GetUserEventString(Event event) const SB_OVERRIDE {
+ return wrapper_->GetUserEventString(static_cast<EventEnum>(event));
+ }
+
+ Result HandleUserStateEvent(State state,
+ Event event,
+ void* data) SB_OVERRIDE {
+ typename StateMachine<StateEnum, EventEnum>::Result result =
+ wrapper_->HandleUserStateEvent(static_cast<StateEnum>(state),
+ static_cast<EventEnum>(event), data);
+ if (result.is_transition) {
+ return Result(static_cast<State>(*result.target), result.is_external);
+ }
+
+ return result.is_handled ? kHandled : kNotHandled;
+ }
+
+ void HandleUserStateEnter(State state) SB_OVERRIDE {
+ wrapper_->HandleUserStateEnter(static_cast<StateEnum>(state));
+ }
+
+ void HandleUserStateExit(State state) SB_OVERRIDE {
+ wrapper_->HandleUserStateExit(static_cast<StateEnum>(state));
+ }
+
+ // A public exposure of EnableLogging so the wrapper can access it. Since
+ // this class is private to the wrapper, it is the only one who can see it.
+ void EnableLoggingPublic() { EnableLogging(); }
+
+ private:
+ StateMachine<StateEnum, EventEnum>* wrapper_;
+ };
+
+ WrappedMachine machine_;
+};
+
+} // namespace starboard
+#endif // __cplusplus
+
+#endif // STARBOARD_COMMON_STATE_MACHINE_H_
diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h
index d6007c9..cb8d84a 100644
--- a/src/starboard/configuration.h
+++ b/src/starboard/configuration.h
@@ -64,6 +64,15 @@
// // exposes functionality for my new feature.
// #define SB_MY_EXPERIMENTAL_FEATURE_VERSION SB_EXPERIMENTAL_API_VERSION
+// SbDecodeTargetInfoPlane's now can specify color plane information.
+// Previously: Planes of type kSbDecodeTargetFormat2PlaneYUVNV12
+// were assumed to have the luma mapped to the alpha channel (GL_ALPHA)
+// and the chroma mapped to blue and alpha (GL_LUMINANCE_ALPHA). However,
+// some graphics systems require that luma is on GL_RED_EXT and the chroma
+// is on GL_RG_EXT.
+
+#define SB_DECODE_TARGET_PLANE_FORMAT_VERSION SB_EXPERIMENTAL_API_VERSION
+
// --- Release Candidate Feature Defines -------------------------------------
#define SB_POINTER_INPUT_API_VERSION SB_RELEASE_CANDIDATE_API_VERSION
@@ -78,6 +87,9 @@
#define SB_LOW_MEMORY_EVENT_API_VERSION SB_RELEASE_CANDIDATE_API_VERSION
#define SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION \
SB_RELEASE_CANDIDATE_API_VERSION
+#define SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION \
+ SB_RELEASE_CANDIDATE_API_VERSION
+#define SB_STORAGE_NAMES_API_VERSION SB_RELEASE_CANDIDATE_API_VERSION
// --- Common Detected Features ----------------------------------------------
@@ -312,6 +324,32 @@
#endif // SB_NORETURN
#endif // SB_API_VERSION >= 4
+// Specifies the alignment for a class, struct, union, enum, class/struct field,
+// or stack variable.
+#if !defined(SB_ALIGNAS)
+#if SB_IS(COMPILER_GCC)
+#define SB_ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
+#elif SB_IS(COMPILER_MSVC)
+#define SB_ALIGNAS(byte_alignment) __declspec(align(byte_alignment))
+#else
+// Fallback to the C++11 form.
+#define SB_ALIGNAS(byte_alignment) alignas(byte_alignment)
+#endif
+#endif // !defined(SB_ALIGNAS)
+
+// Returns the alignment reqiured for any instance of the type indicated by
+// |type|.
+#if !defined(SB_ALIGNOF)
+#if SB_IS(COMPILER_GCC)
+#define SB_ALIGNOF(type) __alignof__(type)
+#elif SB_IS(COMPILER_MSVC)
+#define SB_ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type))
+#else
+// Fallback to the C++11 form.
+#define SB_ALIGNOF(type) alignof(type)
+#endif
+#endif // !defined(SB_ALIGNOF)
+
// --- Configuration Audits --------------------------------------------------
#if !defined(SB_API_VERSION)
diff --git a/src/starboard/decode_target.h b/src/starboard/decode_target.h
index e109b6a..c437c96 100644
--- a/src/starboard/decode_target.h
+++ b/src/starboard/decode_target.h
@@ -287,6 +287,16 @@
// Typically this would be GL_TEXTURE_2D, but some platforms may require
// that it be set to something else like GL_TEXTURE_EXTERNAL_OES.
uint32_t gl_texture_target;
+
+#if SB_API_VERSION >= SB_DECODE_TARGET_FORMAT_VERSION
+ // For kSbDecodeTargetFormat2PlaneYUVNV12 planes: the format of the
+ // texture. Usually, for the luma plane, this is either GL_ALPHA or
+ // GL_RED_EXT. For the chroma plane, this is usually GL_LUMINANCE_ALPHA
+ // or GL_RG_EXT.
+ // Ignored for other plane types.
+ uint32_t gl_texture_format;
+#endif // SB_API_VERSION >= SB_DECODE_TARGET_NV12_R_RG_API_VERSION
+
#endif // SB_HAS(BLITTER)
// The width of the texture/surface for this particular plane.
diff --git a/src/starboard/drm.h b/src/starboard/drm.h
index dad7d24..cae076d 100644
--- a/src/starboard/drm.h
+++ b/src/starboard/drm.h
@@ -52,6 +52,15 @@
int32_t encrypted_byte_count;
} SbDrmSubSampleMapping;
+#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION
+typedef struct SbDrmKeyId {
+ // The ID of the license (or key) required to decrypt this sample. For
+ // PlayReady, this is the license GUID in packed little-endian binary form.
+ uint8_t identifier[16];
+ int identifier_size;
+} SbDrmKeyId;
+#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION
+
// All the optional information needed per sample for encrypted samples.
typedef struct SbDrmSampleInfo {
// The Initialization Vector needed to decrypt this sample.
@@ -113,6 +122,20 @@
int session_id_size,
bool succeeded);
+// A callback for notifications that the status of one or more keys in a session
+// has been changed. All keys of the session and their new status will be
+// passed along. Any keys not in the list is considered as deleted.
+#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION
+typedef void (*SbDrmSessionKeyStatusesChangedFunc)(
+ SbDrmSystem drm_system,
+ void* context,
+ const void* session_id,
+ int session_id_size,
+ int number_of_keys,
+ const SbDrmKeyId* key_ids,
+ const SbDrmKeyStatus* key_statuses);
+#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION
+
// --- Constants -------------------------------------------------------------
// An invalid SbDrmSystem.
@@ -156,12 +179,25 @@
// SbDrmGenerateSessionUpdateRequest() is called.
// |session_updated_callback|: A function that is called every time after
// SbDrmUpdateSession() is called.
+#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION
+
+SB_EXPORT SbDrmSystem SbDrmCreateSystem(
+ const char* key_system,
+ void* context,
+ SbDrmSessionUpdateRequestFunc update_request_callback,
+ SbDrmSessionUpdatedFunc session_updated_callback,
+ SbDrmSessionKeyStatusesChangedFunc key_statuses_changed_callback);
+
+#else // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION
+
SB_EXPORT SbDrmSystem
SbDrmCreateSystem(const char* key_system,
void* context,
SbDrmSessionUpdateRequestFunc update_request_callback,
SbDrmSessionUpdatedFunc session_updated_callback);
+#endif // SB_API_VERSION >= SB_DRM_KEY_STATUS_UPDATE_SUPPORT_API_VERSION
+
// Asynchronously generates a session update request payload for
// |initialization_data|, of |initialization_data_size|, in case sensitive
// |type|, extracted from the media stream, in |drm_system|'s key system.
diff --git a/src/starboard/egl_and_gles/egl_and_gles_angle.gyp b/src/starboard/egl_and_gles/egl_and_gles_angle.gyp
index 8812c25..52a9d96 100644
--- a/src/starboard/egl_and_gles/egl_and_gles_angle.gyp
+++ b/src/starboard/egl_and_gles/egl_and_gles_angle.gyp
@@ -13,6 +13,9 @@
# limitations under the License.
{
+ 'variables': {
+ 'enable_d3d11_feature_level_11%': 0,
+ },
'targets': [
{
'target_name': 'egl_and_gles_implementation',
@@ -27,6 +30,18 @@
'<(DEPTH)/third_party/angle/include',
],
},
+ 'conditions': [
+ # ANGLE supports GLES3 on Windows only if DirectX11 feauture level 11 is
+ # supported.
+ ['target_os=="win" and enable_d3d11_feature_level_11==1', {
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'GLES3_SUPPORTED',
+ 'GL_GLEXT_PROTOTYPES',
+ ],
+ },
+ }]
+ ]
},
],
}
diff --git a/src/starboard/examples/BUILD.gn b/src/starboard/examples/BUILD.gn
new file mode 100644
index 0000000..0012617
--- /dev/null
+++ b/src/starboard/examples/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//starboard/build/config/base.gni")
+
+group("examples") {
+ deps = [
+ "//starboard/examples/blitter",
+ "//starboard/examples/window",
+ ]
+
+ if (gl_type != "none") {
+ deps += [
+ "//starboard/examples/glclear",
+ ]
+ }
+}
diff --git a/src/starboard/examples/blitter/BUILD.gn b/src/starboard/examples/blitter/BUILD.gn
new file mode 100644
index 0000000..403815f
--- /dev/null
+++ b/src/starboard/examples/blitter/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+final_executable("blitter") {
+ output_name = "starboard_blitter_example"
+
+ sources = [
+ "main.cc",
+ ]
+
+ deps = [
+ "//starboard",
+ ]
+}
+
+# TODO: add the deploy target if it's desirable
diff --git a/src/starboard/examples/glclear/BUILD.gn b/src/starboard/examples/glclear/BUILD.gn
new file mode 100644
index 0000000..d90f020
--- /dev/null
+++ b/src/starboard/examples/glclear/BUILD.gn
@@ -0,0 +1,29 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+final_executable("glclear") {
+ output_name = "starboard_glclear_example"
+
+ sources = [
+ "main.cc",
+ ]
+
+ deps = [
+ "//starboard",
+ # TODO: convert this target over
+ # "//starboard/egl_and_gles",
+ ]
+}
+
+# TODO: add the deploy target if it's desirable
diff --git a/src/starboard/examples/window/BUILD.gn b/src/starboard/examples/window/BUILD.gn
new file mode 100644
index 0000000..b8a295a
--- /dev/null
+++ b/src/starboard/examples/window/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+final_executable("window") {
+ output_name = "starboard_window_example"
+
+ sources = [
+ "main.cc",
+ ]
+
+ deps = [
+ "//starboard",
+ ]
+}
+
+# TODO: add the deploy target if it's desirable
diff --git a/src/starboard/input.h b/src/starboard/input.h
index 0959a00..9c1e2cc 100644
--- a/src/starboard/input.h
+++ b/src/starboard/input.h
@@ -173,7 +173,10 @@
unsigned int key_modifiers;
// The (x, y) coordinates of the persistent cursor controlled by this device.
- // The value is |0| if this data is not applicable.
+ // The value is |0| if this data is not applicable. For events with type
+ // kSbInputEventTypeMove and device_type kSbInputDeviceTypeGamepad, this field
+ // is interpreted as a stick position with the range [-1, 1], with positive
+ // values for the up and left direction.
SbInputVector position;
// The relative motion vector of this input. The value is |0| if this data is
diff --git a/src/starboard/linux/shared/BUILD.gn b/src/starboard/linux/shared/BUILD.gn
new file mode 100644
index 0000000..66579d8
--- /dev/null
+++ b/src/starboard/linux/shared/BUILD.gn
@@ -0,0 +1,608 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//starboard/build/config/base.gni")
+import("//starboard/build/config/fastbuild.gni")
+import("//starboard/build/config/sanitizers.gni")
+import("//starboard/build/toolchain/asan_symbolizer_path.gni")
+import("//starboard/build/delegated_config.gni")
+import("//starboard/linux/shared/clang.gni")
+import("//starboard/linux/shared/dlmalloc.gni")
+
+# =============================================================================
+# DEFAULT COMPILER CONFIGS
+# =============================================================================
+
+config("compiler_defaults") {
+ cflags = [
+ # We'll pretend not to be Linux, but Starboard instead.
+ "-U__linux__",
+ ]
+
+ cflags_c = [
+ # Limit to C99. This allows Linux to be a canary build for any
+ # C11 features that are not supported on some platforms' compilers.
+ "-std=c99",
+ ]
+
+ cflags_cc = [
+ "-std=gnu++11",
+ ]
+
+ libs = [
+ "asound",
+ "avcodec",
+ "avformat",
+ "avresample",
+ "avutil",
+ "pthread",
+ "rt",
+ ]
+
+ ldflags = []
+
+ if (use_dlmalloc_allocator && !use_asan) {
+ ldflags += [
+ "-Wl,--wrap=malloc",
+ "-Wl,--wrap=calloc",
+ "-Wl,--wrap=realloc",
+ "-Wl,--wrap=memalign",
+ "-Wl,--wrap=reallocalign",
+ "-Wl,--wrap=free",
+ "-Wl,--wrap=strdup",
+ "-Wl,--wrap=malloc_usable_size",
+ "-Wl,--wrap=malloc_stats_fast",
+ "-Wl,--wrap=__cxa_demangle",
+ ]
+ }
+
+ defines = [
+ # Cobalt on Linux flag
+ "COBALT_LINUX",
+ "__STDC_FORMAT_MACROS", # so that we get PRI*
+ # Enable GNU extensions to get prototypes like ffsl.
+ "_GNU_SOURCE=1",
+
+ # By default, <EGL/eglplatform.h> pulls in some X11 headers that have some
+ # nasty macros (|Status|, for example) that conflict with Chromium base.
+ "MESA_EGL_NO_X11_HEADERS",
+ ]
+
+ if (use_clang) {
+ cflags += [
+ "-Werror",
+ "-fcolor-diagnostics",
+ # Default visibility to hidden, to enable dead stripping.
+ "-fvisibility=hidden",
+ # Warn for implicit type conversions that may change a value.
+ "-Wconversion",
+ "-Wno-c++11-compat",
+ # This complains about "override", which we use heavily.
+ "-Wno-c++11-extensions",
+ # Warns on switches on enums that cover all enum values but
+ # also contain a default: branch. Chrome is full of that.
+ "-Wno-covered-switch-default",
+ # protobuf uses hash_map.
+ "-Wno-deprecated",
+ "-fno-exceptions",
+ # Don't warn about the "struct foo f = {0};" initialization pattern.
+ "-Wno-missing-field-initializers",
+ # Do not warn for implicit sign conversions.
+ "-Wno-sign-conversion",
+ "-fno-strict-aliasing", # See http://crbug.com/32204
+ "-Wno-unnamed-type-template-args",
+ # Triggered by the COMPILE_ASSERT macro.
+ "-Wno-unused-local-typedef",
+ # Do not warn if a function or variable cannot be implicitly
+ # instantiated.
+ "-Wno-undefined-var-template",
+ # Do not warn about an implicit exception spec mismatch.
+ "-Wno-implicit-exception-spec-mismatch",
+ ]
+
+ ldflags += [ "-fuse-ld=lld" ]
+
+ if (use_asan) {
+ cflags += [
+ "-fsanitize=address",
+ "-fno-omit-frame-pointer",
+ ]
+
+ ldflags += [
+ "-fsanitize=address",
+ # Force linking of the helpers in sanitizer_options.cc
+ "-Wl,-u_sanitizer_options_link_helper",
+ ]
+
+ defines += [
+ "ADDRESS_SANITIZER",
+ ]
+
+ if (asan_symbolizer_path != "") {
+ defines += [
+ "ASAN_SYMBOLIZER_PATH=\"$asan_symbolizer_path\"",
+ ]
+ }
+ }
+
+ if (use_tsan) {
+ cflags += [
+ "-fsanitize=thread",
+ "-fno-omit-frame-pointer",
+ ]
+
+ ldflags += [
+ "-fsanitize-thread",
+ ]
+
+ defines += [
+ "THREAD_SANITIZER",
+ ]
+ }
+ }
+}
+
+config("compiler_defaults_debug") {
+ cflags = []
+ if (!cobalt_use_fastbuild) {
+ cflags += [ "-g" ]
+ }
+}
+
+config("compiler_defaults_devel") {
+ cflags = []
+ if (!cobalt_use_fastbuild) {
+ cflags += [ "-g" ]
+ }
+}
+
+config("compiler_defaults_qa") {
+ cflags = [
+ "-gline-tables-only",
+ ]
+}
+
+config("compiler_defaults_gold") {
+ cflags = [
+ "-gline-tables-only",
+ ]
+}
+
+config("compiler_defaults_host") {
+ cflags = [
+ "-O2",
+ ]
+}
+
+# ==============================================================================
+# DELEGATED CONFIGS
+# ==============================================================================
+
+config("pedantic_warnings") {
+ cflags = [
+ "-Wall",
+ "-Wextra",
+ "-Wunreachable-code",
+ ]
+}
+
+config("no_pedantic_warnings") {
+ cflags = [
+ # "this" pointer cannot be NULL...pointer may be assumed
+ # to always convert to true.
+ "-Wno-undefined-bool-conversion",
+ # Skia doesn't use overrides.
+ "-Wno-inconsistent-missing-override",
+ # Do not warn about unused function params.
+ "-Wno-unused-parameter",
+ # Do not warn for implicit type conversions that may change a value.
+ "-Wno-conversion",
+ # shifting a negative signed value is undefined
+ "-Wno-shift-negative-value",
+ # Width of bit-field exceeds width of its type- value will be truncated
+ "-Wno-bitfield-width",
+ "-Wno-undefined-var-template",
+ ]
+}
+
+
+delegated_config("optimizations") {
+ path = "//starboard/build/toolchain/linux/config"
+ prefixes = [ "no", "debuggable", "full" ]
+ generate_default = false
+}
+
+config("default_optimizations") {
+ if (cobalt_config == "debug") {
+ configs = [ ":no_optimizations" ]
+ } else {
+ configs = [ ":debuggable_optimizations" ]
+ }
+}
+
+
+delegated_config("rtti") {
+ path = "//starboard/build/toolchain/linux/config"
+ generate_default = false
+}
+
+config("default_rtti") {
+ if (cobalt_config == "debug" || cobalt_config == "devel") {
+ configs = [ ":rtti" ]
+ } else {
+ configs = [ ":no_rtti" ]
+ }
+}
+
+
+config("wexit_time_destructors") {
+ if (use_clang) {
+ configs =
+ [ "//starboard/build/toolchain/linux/config:wexit_time_destructors" ]
+ }
+}
+
+# =============================================================================
+# starboard_platform TARGET
+# =============================================================================
+
+source_set("starboard_platform") {
+ visibility = [ "//starboard/linux/*" ]
+
+ sources = [
+ "//starboard/linux/shared/atomic_public.h",
+ "//starboard/linux/shared/configuration_public.h",
+ "//starboard/linux/shared/decode_target_get_info.cc",
+ "//starboard/linux/shared/decode_target_internal.cc",
+ "//starboard/linux/shared/decode_target_internal.h",
+ "//starboard/linux/shared/decode_target_release.cc",
+ "//starboard/linux/shared/media_is_video_supported.cc",
+ "//starboard/linux/shared/player_components_impl.cc",
+ "//starboard/linux/shared/system_get_connection_type.cc",
+ "//starboard/linux/shared/system_get_device_type.cc",
+ "//starboard/linux/shared/system_get_path.cc",
+ "//starboard/linux/shared/system_has_capability.cc",
+ "//starboard/shared/alsa/alsa_audio_sink_type.cc",
+ "//starboard/shared/alsa/alsa_audio_sink_type.h",
+ "//starboard/shared/alsa/alsa_util.cc",
+ "//starboard/shared/alsa/alsa_util.h",
+ "//starboard/shared/alsa/audio_sink_get_max_channels.cc",
+ "//starboard/shared/alsa/audio_sink_get_nearest_supported_sample_frequency.cc",
+ "//starboard/shared/alsa/audio_sink_is_audio_frame_storage_type_supported.cc",
+ "//starboard/shared/alsa/audio_sink_is_audio_sample_type_supported.cc",
+ "//starboard/shared/dlmalloc/memory_map.cc",
+ "//starboard/shared/dlmalloc/memory_unmap.cc",
+ "//starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc",
+ "//starboard/shared/ffmpeg/ffmpeg_audio_decoder.h",
+ "//starboard/shared/ffmpeg/ffmpeg_audio_resampler.cc",
+ "//starboard/shared/ffmpeg/ffmpeg_audio_resampler.h",
+ "//starboard/shared/ffmpeg/ffmpeg_common.cc",
+ "//starboard/shared/ffmpeg/ffmpeg_common.h",
+ "//starboard/shared/ffmpeg/ffmpeg_video_decoder.cc",
+ "//starboard/shared/ffmpeg/ffmpeg_video_decoder.h",
+ "//starboard/shared/gcc/atomic_gcc_public.h",
+ "//starboard/shared/iso/character_is_alphanumeric.cc",
+ "//starboard/shared/iso/character_is_digit.cc",
+ "//starboard/shared/iso/character_is_hex_digit.cc",
+ "//starboard/shared/iso/character_is_space.cc",
+ "//starboard/shared/iso/character_is_upper.cc",
+ "//starboard/shared/iso/character_to_lower.cc",
+ "//starboard/shared/iso/character_to_upper.cc",
+ "//starboard/shared/iso/directory_close.cc",
+ "//starboard/shared/iso/directory_get_next.cc",
+ "//starboard/shared/iso/directory_open.cc",
+ "//starboard/shared/iso/double_absolute.cc",
+ "//starboard/shared/iso/double_exponent.cc",
+ "//starboard/shared/iso/double_floor.cc",
+ "//starboard/shared/iso/double_is_finite.cc",
+ "//starboard/shared/iso/double_is_nan.cc",
+ "//starboard/shared/iso/memory_compare.cc",
+ "//starboard/shared/iso/memory_copy.cc",
+ "//starboard/shared/iso/memory_find_byte.cc",
+ "//starboard/shared/iso/memory_move.cc",
+ "//starboard/shared/iso/memory_set.cc",
+ "//starboard/shared/iso/string_compare.cc",
+ "//starboard/shared/iso/string_compare_all.cc",
+ "//starboard/shared/iso/string_find_character.cc",
+ "//starboard/shared/iso/string_find_last_character.cc",
+ "//starboard/shared/iso/string_find_string.cc",
+ "//starboard/shared/iso/string_get_length.cc",
+ "//starboard/shared/iso/string_get_length_wide.cc",
+ "//starboard/shared/iso/string_parse_double.cc",
+ "//starboard/shared/iso/string_parse_signed_integer.cc",
+ "//starboard/shared/iso/string_parse_uint64.cc",
+ "//starboard/shared/iso/string_parse_unsigned_integer.cc",
+ "//starboard/shared/iso/string_scan.cc",
+ "//starboard/shared/iso/system_binary_search.cc",
+ "//starboard/shared/iso/system_sort.cc",
+ "//starboard/shared/libevent/socket_waiter_add.cc",
+ "//starboard/shared/libevent/socket_waiter_create.cc",
+ "//starboard/shared/libevent/socket_waiter_destroy.cc",
+ "//starboard/shared/libevent/socket_waiter_internal.cc",
+ "//starboard/shared/libevent/socket_waiter_remove.cc",
+ "//starboard/shared/libevent/socket_waiter_wait.cc",
+ "//starboard/shared/libevent/socket_waiter_wait_timed.cc",
+ "//starboard/shared/libevent/socket_waiter_wake_up.cc",
+ "//starboard/shared/libvpx/vpx_video_decoder.cc",
+ "//starboard/shared/libvpx/vpx_video_decoder.h",
+ "//starboard/shared/linux/byte_swap.cc",
+ "//starboard/shared/linux/get_home_directory.cc",
+ "//starboard/shared/linux/memory_get_stack_bounds.cc",
+ "//starboard/shared/linux/page_internal.cc",
+ "//starboard/shared/linux/socket_get_interface_address.cc",
+ "//starboard/shared/linux/socket_get_local_interface_address.cc",
+ "//starboard/shared/linux/system_get_random_data.cc",
+ "//starboard/shared/linux/system_get_stack.cc",
+ "//starboard/shared/linux/system_get_total_cpu_memory.cc",
+ "//starboard/shared/linux/system_is_debugger_attached.cc",
+ "//starboard/shared/linux/system_symbolize.cc",
+ "//starboard/shared/linux/thread_get_id.cc",
+ "//starboard/shared/linux/thread_get_name.cc",
+ "//starboard/shared/linux/thread_set_name.cc",
+ "//starboard/shared/nouser/user_get_current.cc",
+ "//starboard/shared/nouser/user_get_property.cc",
+ "//starboard/shared/nouser/user_get_signed_in.cc",
+ "//starboard/shared/nouser/user_internal.cc",
+ "//starboard/shared/posix/directory_create.cc",
+ "//starboard/shared/posix/file_can_open.cc",
+ "//starboard/shared/posix/file_close.cc",
+ "//starboard/shared/posix/file_delete.cc",
+ "//starboard/shared/posix/file_exists.cc",
+ "//starboard/shared/posix/file_flush.cc",
+ "//starboard/shared/posix/file_get_info.cc",
+ "//starboard/shared/posix/file_get_path_info.cc",
+ "//starboard/shared/posix/file_open.cc",
+ "//starboard/shared/posix/file_read.cc",
+ "//starboard/shared/posix/file_seek.cc",
+ "//starboard/shared/posix/file_truncate.cc",
+ "//starboard/shared/posix/file_write.cc",
+ "//starboard/shared/posix/log.cc",
+ "//starboard/shared/posix/log_flush.cc",
+ "//starboard/shared/posix/log_format.cc",
+ "//starboard/shared/posix/log_is_tty.cc",
+ "//starboard/shared/posix/log_raw.cc",
+ "//starboard/shared/posix/memory_flush.cc",
+ "//starboard/shared/posix/set_non_blocking_internal.cc",
+ "//starboard/shared/posix/socket_accept.cc",
+ "//starboard/shared/posix/socket_bind.cc",
+ "//starboard/shared/posix/socket_clear_last_error.cc",
+ "//starboard/shared/posix/socket_connect.cc",
+ "//starboard/shared/posix/socket_create.cc",
+ "//starboard/shared/posix/socket_destroy.cc",
+ "//starboard/shared/posix/socket_free_resolution.cc",
+ "//starboard/shared/posix/socket_get_last_error.cc",
+ "//starboard/shared/posix/socket_get_local_address.cc",
+ "//starboard/shared/posix/socket_internal.cc",
+ "//starboard/shared/posix/socket_is_connected.cc",
+ "//starboard/shared/posix/socket_is_connected_and_idle.cc",
+ "//starboard/shared/posix/socket_join_multicast_group.cc",
+ "//starboard/shared/posix/socket_listen.cc",
+ "//starboard/shared/posix/socket_receive_from.cc",
+ "//starboard/shared/posix/socket_resolve.cc",
+ "//starboard/shared/posix/socket_send_to.cc",
+ "//starboard/shared/posix/socket_set_broadcast.cc",
+ "//starboard/shared/posix/socket_set_receive_buffer_size.cc",
+ "//starboard/shared/posix/socket_set_reuse_address.cc",
+ "//starboard/shared/posix/socket_set_send_buffer_size.cc",
+ "//starboard/shared/posix/socket_set_tcp_keep_alive.cc",
+ "//starboard/shared/posix/socket_set_tcp_no_delay.cc",
+ "//starboard/shared/posix/socket_set_tcp_window_scaling.cc",
+ "//starboard/shared/posix/string_compare_no_case.cc",
+ "//starboard/shared/posix/string_compare_no_case_n.cc",
+ "//starboard/shared/posix/string_compare_wide.cc",
+ "//starboard/shared/posix/string_format.cc",
+ "//starboard/shared/posix/string_format_wide.cc",
+ "//starboard/shared/posix/system_break_into_debugger.cc",
+ "//starboard/shared/posix/system_clear_last_error.cc",
+ "//starboard/shared/posix/system_get_error_string.cc",
+ "//starboard/shared/posix/system_get_last_error.cc",
+ "//starboard/shared/posix/system_get_locale_id.cc",
+ "//starboard/shared/posix/system_get_number_of_processors.cc",
+ "//starboard/shared/posix/thread_sleep.cc",
+ "//starboard/shared/posix/time_get_monotonic_now.cc",
+ "//starboard/shared/posix/time_get_monotonic_thread_now.cc",
+ "//starboard/shared/posix/time_get_now.cc",
+ "//starboard/shared/posix/time_zone_get_current.cc",
+ "//starboard/shared/posix/time_zone_get_dst_name.cc",
+ "//starboard/shared/posix/time_zone_get_name.cc",
+ "//starboard/shared/pthread/condition_variable_broadcast.cc",
+ "//starboard/shared/pthread/condition_variable_create.cc",
+ "//starboard/shared/pthread/condition_variable_destroy.cc",
+ "//starboard/shared/pthread/condition_variable_signal.cc",
+ "//starboard/shared/pthread/condition_variable_wait.cc",
+ "//starboard/shared/pthread/condition_variable_wait_timed.cc",
+ "//starboard/shared/pthread/mutex_acquire.cc",
+ "//starboard/shared/pthread/mutex_acquire_try.cc",
+ "//starboard/shared/pthread/mutex_create.cc",
+ "//starboard/shared/pthread/mutex_destroy.cc",
+ "//starboard/shared/pthread/mutex_release.cc",
+ "//starboard/shared/pthread/once.cc",
+ "//starboard/shared/pthread/thread_create.cc",
+ "//starboard/shared/pthread/thread_create_local_key.cc",
+ "//starboard/shared/pthread/thread_create_priority.h",
+ "//starboard/shared/pthread/thread_destroy_local_key.cc",
+ "//starboard/shared/pthread/thread_detach.cc",
+ "//starboard/shared/pthread/thread_get_current.cc",
+ "//starboard/shared/pthread/thread_get_local_value.cc",
+ "//starboard/shared/pthread/thread_is_equal.cc",
+ "//starboard/shared/pthread/thread_join.cc",
+ "//starboard/shared/pthread/thread_set_local_value.cc",
+ "//starboard/shared/pthread/thread_yield.cc",
+ "//starboard/shared/signal/crash_signals.h",
+ "//starboard/shared/signal/crash_signals_sigaction.cc",
+ "//starboard/shared/signal/suspend_signals.cc",
+ "//starboard/shared/signal/suspend_signals.h",
+ "//starboard/shared/starboard/application.cc",
+ "//starboard/shared/starboard/audio_sink/audio_sink_create.cc",
+ "//starboard/shared/starboard/audio_sink/audio_sink_destroy.cc",
+ "//starboard/shared/starboard/audio_sink/audio_sink_internal.cc",
+ "//starboard/shared/starboard/audio_sink/audio_sink_internal.h",
+ "//starboard/shared/starboard/audio_sink/audio_sink_is_valid.cc",
+ "//starboard/shared/starboard/audio_sink/stub_audio_sink_type.cc",
+ "//starboard/shared/starboard/audio_sink/stub_audio_sink_type.h",
+ "//starboard/shared/starboard/command_line.cc",
+ "//starboard/shared/starboard/command_line.h",
+ "//starboard/shared/starboard/directory_can_open.cc",
+ "//starboard/shared/starboard/event_cancel.cc",
+ "//starboard/shared/starboard/event_schedule.cc",
+ "//starboard/shared/starboard/file_mode_string_to_flags.cc",
+ "//starboard/shared/starboard/file_storage/storage_close_record.cc",
+ "//starboard/shared/starboard/file_storage/storage_delete_record.cc",
+ "//starboard/shared/starboard/file_storage/storage_get_record_size.cc",
+ "//starboard/shared/starboard/file_storage/storage_open_record.cc",
+ "//starboard/shared/starboard/file_storage/storage_read_record.cc",
+ "//starboard/shared/starboard/file_storage/storage_write_record.cc",
+ "//starboard/shared/starboard/log_message.cc",
+ "//starboard/shared/starboard/log_raw_dump_stack.cc",
+ "//starboard/shared/starboard/log_raw_format.cc",
+ "//starboard/shared/starboard/media/codec_util.cc",
+ "//starboard/shared/starboard/media/codec_util.h",
+ "//starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc",
+ "//starboard/shared/starboard/media/media_get_audio_configuration_stereo_only.cc",
+ "//starboard/shared/starboard/media/media_get_audio_output_count_stereo_only.cc",
+ "//starboard/shared/starboard/media/media_is_audio_supported_aac_and_opus.cc",
+ "//starboard/shared/starboard/media/media_is_output_protected.cc",
+ "//starboard/shared/starboard/media/media_set_output_protection.cc",
+ "//starboard/shared/starboard/media/media_util.cc",
+ "//starboard/shared/starboard/media/media_util.h",
+ "//starboard/shared/starboard/media/mime_type.cc",
+ "//starboard/shared/starboard/media/mime_type.h",
+ "//starboard/shared/starboard/new.cc",
+ "//starboard/shared/starboard/player/decoded_audio_internal.cc",
+ "//starboard/shared/starboard/player/decoded_audio_internal.h",
+ "//starboard/shared/starboard/player/filter/audio_decoder_internal.h",
+ "//starboard/shared/starboard/player/filter/audio_frame_tracker.h",
+ "//starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc",
+ "//starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h",
+ "//starboard/shared/starboard/player/filter/audio_renderer_internal.h",
+ "//starboard/shared/starboard/player/filter/audio_time_stretcher.cc",
+ "//starboard/shared/starboard/player/filter/audio_time_stretcher.h",
+ "//starboard/shared/starboard/player/filter/decoded_audio_queue.cc",
+ "//starboard/shared/starboard/player/filter/decoded_audio_queue.h",
+ "//starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc",
+ "//starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h",
+ "//starboard/shared/starboard/player/filter/player_components.h",
+ "//starboard/shared/starboard/player/filter/video_decoder_internal.h",
+ "//starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc",
+ "//starboard/shared/starboard/player/filter/video_renderer_impl_internal.h",
+ "//starboard/shared/starboard/player/filter/video_renderer_internal.h",
+ "//starboard/shared/starboard/player/filter/wsola_internal.cc",
+ "//starboard/shared/starboard/player/filter/wsola_internal.h",
+ "//starboard/shared/starboard/player/input_buffer_internal.cc",
+ "//starboard/shared/starboard/player/input_buffer_internal.h",
+ "//starboard/shared/starboard/player/job_queue.cc",
+ "//starboard/shared/starboard/player/job_queue.h",
+ "//starboard/shared/starboard/player/player_create.cc",
+ "//starboard/shared/starboard/player/player_destroy.cc",
+ "//starboard/shared/starboard/player/player_get_current_frame.cc",
+ "//starboard/shared/starboard/player/player_get_info.cc",
+ "//starboard/shared/starboard/player/player_internal.cc",
+ "//starboard/shared/starboard/player/player_internal.h",
+ "//starboard/shared/starboard/player/player_output_mode_supported.cc",
+ "//starboard/shared/starboard/player/player_seek.cc",
+ "//starboard/shared/starboard/player/player_set_bounds.cc",
+ "//starboard/shared/starboard/player/player_set_pause.cc",
+ "//starboard/shared/starboard/player/player_set_playback_rate.cc",
+ "//starboard/shared/starboard/player/player_set_volume.cc",
+ "//starboard/shared/starboard/player/player_worker.cc",
+ "//starboard/shared/starboard/player/player_worker.h",
+ "//starboard/shared/starboard/player/player_write_end_of_stream.cc",
+ "//starboard/shared/starboard/player/player_write_sample.cc",
+ "//starboard/shared/starboard/player/video_frame_internal.cc",
+ "//starboard/shared/starboard/player/video_frame_internal.h",
+ "//starboard/shared/starboard/queue_application.cc",
+ "//starboard/shared/starboard/string_concat.cc",
+ "//starboard/shared/starboard/string_concat_wide.cc",
+ "//starboard/shared/starboard/string_copy.cc",
+ "//starboard/shared/starboard/string_copy_wide.cc",
+ "//starboard/shared/starboard/string_duplicate.cc",
+ "//starboard/shared/starboard/system_get_random_uint64.cc",
+ "//starboard/shared/starboard/system_request_pause.cc",
+ "//starboard/shared/starboard/system_request_stop.cc",
+ "//starboard/shared/starboard/system_request_suspend.cc",
+ "//starboard/shared/starboard/system_request_unpause.cc",
+ "//starboard/shared/starboard/window_set_default_options.cc",
+ "//starboard/shared/stub/accessibility_get_display_settings.cc",
+ "//starboard/shared/stub/accessibility_get_text_to_speech_settings.cc",
+ "//starboard/shared/stub/cryptography_create_transformer.cc",
+ "//starboard/shared/stub/cryptography_destroy_transformer.cc",
+ "//starboard/shared/stub/cryptography_get_tag.cc",
+ "//starboard/shared/stub/cryptography_set_authenticated_data.cc",
+ "//starboard/shared/stub/cryptography_set_initialization_vector.cc",
+ "//starboard/shared/stub/cryptography_transform.cc",
+ "//starboard/shared/stub/drm_close_session.cc",
+ "//starboard/shared/stub/drm_create_system.cc",
+ "//starboard/shared/stub/drm_destroy_system.cc",
+ "//starboard/shared/stub/drm_generate_session_update_request.cc",
+ "//starboard/shared/stub/drm_system_internal.h",
+ "//starboard/shared/stub/drm_update_session.cc",
+ "//starboard/shared/stub/image_decode.cc",
+ "//starboard/shared/stub/image_is_decode_supported.cc",
+ "//starboard/shared/stub/media_is_supported.cc",
+ "//starboard/shared/stub/media_is_transfer_characteristics_supported.cc",
+ "//starboard/shared/stub/microphone_close.cc",
+ "//starboard/shared/stub/microphone_create.cc",
+ "//starboard/shared/stub/microphone_destroy.cc",
+ "//starboard/shared/stub/microphone_get_available.cc",
+ "//starboard/shared/stub/microphone_is_sample_rate_supported.cc",
+ "//starboard/shared/stub/microphone_open.cc",
+ "//starboard/shared/stub/microphone_read.cc",
+ "//starboard/shared/stub/system_clear_platform_error.cc",
+ "//starboard/shared/stub/system_get_total_gpu_memory.cc",
+ "//starboard/shared/stub/system_get_used_gpu_memory.cc",
+ "//starboard/shared/stub/system_hide_splash_screen.cc",
+ "//starboard/shared/stub/system_raise_platform_error.cc",
+ ]
+
+ if (use_dlmalloc_allocator) {
+ sources += [
+ "//starboard/shared/dlmalloc/memory_allocate_aligned_unchecked.cc",
+ "//starboard/shared/dlmalloc/memory_allocate_unchecked.cc",
+ "//starboard/shared/dlmalloc/memory_free.cc",
+ "//starboard/shared/dlmalloc/memory_free_aligned.cc",
+ "//starboard/shared/dlmalloc/memory_reallocate_unchecked.cc",
+ "//starboard/shared/dlmalloc/system_get_used_cpu_memory.cc",
+ ]
+ } else {
+ sources += [
+ "//starboard/shared/iso/memory_allocate_unchecked.cc",
+ "//starboard/shared/iso/memory_free.cc",
+ "//starboard/shared/iso/memory_reallocate_unchecked.cc",
+ "//starboard/shared/linux/system_get_used_cpu_memory.cc",
+ "//starboard/shared/posix/memory_allocate_aligned_unchecked.cc",
+ "//starboard/shared/posix/memory_free_aligned.cc",
+ ]
+ }
+
+ defines = [
+ # This must be defined when building Starboard, and must not when
+ # building Starboard client code.
+ "STARBOARD_IMPLEMENTATION",
+ ]
+
+ deps = [
+ "//starboard/common",
+ ":starboard_base_symbolize",
+ "//third_party/dlmalloc",
+ "//third_party/libevent",
+ "//third_party/libvpx",
+ ]
+}
+
+source_set("starboard_base_symbolize") {
+ sources = [
+ "//base/third_party/symbolize/demangle.cc",
+ "//base/third_party/symbolize/symbolize.cc",
+ ]
+}
diff --git a/src/starboard/linux/shared/buildconfig.gni b/src/starboard/linux/shared/buildconfig.gni
new file mode 100644
index 0000000..9cbc874
--- /dev/null
+++ b/src/starboard/linux/shared/buildconfig.gni
@@ -0,0 +1,43 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//starboard/linux/shared/clang.gni")
+
+###############################################################################
+# This file is imported into BUILDCONFIG.gn. As a side effect, any variable
+# defined here becomes a global variable in all GN files.
+#
+# Adding new variables to this file could result in variable name conflicts, so
+# keep the number of variables in this file to a minimum!
+#
+# If you need to define a temporary variable, prefix it with an underscore like
+# _this. Prefixing a variable with an underscore makes it a private variable
+# that won't bleed into other files.
+###############################################################################
+
+# Target OS and CPU.
+# BUILDCONFIG.gn sets target_os and target_cpu to the values of these two
+# variables below. Unfortunately, due to GN's restrictions on how variables can
+# be changed, we can't directly set target_os and target_cpu here.
+target_os_ = "linux"
+target_cpu_ = "x64"
+
+# The target and host toolchain
+if (use_clang) {
+ target_toolchain = "//starboard/build/toolchain/linux:clang_x64"
+ host_toolchain = "//starboard/build/toolchain/linux:clang_$host_cpu"
+} else {
+ target_toolchain = "//starboard/build/toolchain/linux:x64"
+ host_toolchain = "//starboard/build/toolchain/linux:$host_cpu"
+}
diff --git a/src/starboard/linux/shared/clang.gni b/src/starboard/linux/shared/clang.gni
new file mode 100644
index 0000000..a9aa3f4
--- /dev/null
+++ b/src/starboard/linux/shared/clang.gni
@@ -0,0 +1,18 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+declare_args() {
+ # Whether to use Clang.
+ use_clang = true
+}
diff --git a/src/starboard/linux/shared/configuration.gni b/src/starboard/linux/shared/configuration.gni
new file mode 100644
index 0000000..99cb78e
--- /dev/null
+++ b/src/starboard/linux/shared/configuration.gni
@@ -0,0 +1,46 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Set to true to build with DIAL support.
+enable_in_app_dial = true
+
+# The source of EGL and GLES headers and libraries.
+# Valid values (case and everything sensitive!):
+# "none" - No EGL + GLES implementation is available on this platform.
+# "system_gles3" - Use the system implementation of EGL + GLES3. The
+# headers and libraries must be on the system include and
+# link paths.
+# "system_gles2" - Use the system implementation of EGL + GLES2. The
+# headers and libraries must be on the system include and
+# link paths.
+# "glimp" - Cobalt's own EGL + GLES2 implementation. This requires a
+# valid Glimp implementation for the platform.
+# "angle" - A DirectX-to-OpenGL adaptation layer. This requires a valid
+# ANGLE implementation for the platform.
+# Choosing an unsupported value will result in a GYP error:
+# "cobalt/renderer/egl_and_gles/egl_and_gles_<gl_type>.gyp not found"
+gl_type = "system_gles3"
+
+# Use media source extension implementation that is conformed to the
+# Candidate Recommandation of July 5th 2016.
+cobalt_use_media_source_2016 = true
+
+# Use ASAN by default when building with Clang.
+use_asan_by_default = true
+
+declare_args() {
+ # Set to true to enable distributed compilation using Goma. By default we
+ # use Goma for stub and linux.
+ use_goma = true
+}
diff --git a/src/starboard/linux/shared/dlmalloc.gni b/src/starboard/linux/shared/dlmalloc.gni
new file mode 100644
index 0000000..73c1137
--- /dev/null
+++ b/src/starboard/linux/shared/dlmalloc.gni
@@ -0,0 +1,19 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+declare_args() {
+ # Whether to use the dlmalloc allocator instead of the system allocator
+ use_dlmalloc_allocator = false
+}
+
diff --git a/src/starboard/linux/shared/launcher.py b/src/starboard/linux/shared/launcher.py
index 73e708a..3b476d1 100644
--- a/src/starboard/linux/shared/launcher.py
+++ b/src/starboard/linux/shared/launcher.py
@@ -1,4 +1,3 @@
-#!/usr/bin/python
#
# Copyright 2017 Google Inc. All Rights Reserved.
#
@@ -15,17 +14,25 @@
# limitations under the License.
"""Linux implementation of Starboard launcher abstraction."""
-import imp
+import importlib
import os
+import sys
+
+if "environment" in sys.modules:
+ environment = sys.modules["environment"]
+else:
+ env_path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir,
+ os.pardir, "tools"))
+ if env_path not in sys.path:
+ sys.path.append(env_path)
+ environment = importlib.import_module("environment")
+
+
import signal
import socket
import subprocess
-module_path = os.path.abspath(
- os.path.join(os.path.dirname(__file__),
- os.pardir, os.pardir, "tools", "abstract_launcher.py"))
-
-abstract_launcher = imp.load_source("abstract_launcher", module_path)
+import starboard.tools.abstract_launcher as abstract_launcher
class Launcher(abstract_launcher.AbstractLauncher):
@@ -57,6 +64,7 @@
proc = subprocess.Popen([self.executable] + self.target_command_line_params)
self.pid = proc.pid
proc.wait()
+ return proc.returncode
def Kill(self):
print "\n***Killing Launcher***\n"
diff --git a/src/starboard/linux/shared/starboard_platform.gypi b/src/starboard/linux/shared/starboard_platform.gypi
index f896d17..311618c 100644
--- a/src/starboard/linux/shared/starboard_platform.gypi
+++ b/src/starboard/linux/shared/starboard_platform.gypi
@@ -90,6 +90,8 @@
'<(DEPTH)/starboard/shared/libvpx/vpx_video_decoder.cc',
'<(DEPTH)/starboard/shared/libvpx/vpx_video_decoder.h',
'<(DEPTH)/starboard/shared/linux/byte_swap.cc',
+ '<(DEPTH)/starboard/shared/linux/dev_input/dev_input.cc',
+ '<(DEPTH)/starboard/shared/linux/dev_input/dev_input.h',
'<(DEPTH)/starboard/shared/linux/get_home_directory.cc',
'<(DEPTH)/starboard/shared/linux/memory_get_stack_bounds.cc',
'<(DEPTH)/starboard/shared/linux/page_internal.cc',
@@ -98,7 +100,6 @@
'<(DEPTH)/starboard/shared/linux/system_get_random_data.cc',
'<(DEPTH)/starboard/shared/linux/system_get_stack.cc',
'<(DEPTH)/starboard/shared/linux/system_get_total_cpu_memory.cc',
- '<(DEPTH)/starboard/shared/linux/system_get_used_cpu_memory.cc',
'<(DEPTH)/starboard/shared/linux/system_is_debugger_attached.cc',
'<(DEPTH)/starboard/shared/linux/system_symbolize.cc',
'<(DEPTH)/starboard/shared/linux/thread_get_id.cc',
@@ -326,12 +327,14 @@
'<(DEPTH)/starboard/shared/dlmalloc/memory_free.cc',
'<(DEPTH)/starboard/shared/dlmalloc/memory_free_aligned.cc',
'<(DEPTH)/starboard/shared/dlmalloc/memory_reallocate_unchecked.cc',
+ '<(DEPTH)/starboard/shared/dlmalloc/system_get_used_cpu_memory.cc',
],
}, {
'starboard_platform_sources': [
'<(DEPTH)/starboard/shared/iso/memory_allocate_unchecked.cc',
'<(DEPTH)/starboard/shared/iso/memory_free.cc',
'<(DEPTH)/starboard/shared/iso/memory_reallocate_unchecked.cc',
+ '<(DEPTH)/starboard/shared/linux/system_get_used_cpu_memory.cc',
'<(DEPTH)/starboard/shared/posix/memory_allocate_aligned_unchecked.cc',
'<(DEPTH)/starboard/shared/posix/memory_free_aligned.cc',
],
diff --git a/src/starboard/linux/shared/system_get_path.cc b/src/starboard/linux/shared/system_get_path.cc
index 4ae443b..315903be 100644
--- a/src/starboard/linux/shared/system_get_path.cc
+++ b/src/starboard/linux/shared/system_get_path.cc
@@ -36,14 +36,12 @@
home_path, kMaxPathSize)) {
return false;
}
- int result =
- SbStringFormatF(out_path, path_size, "%s/.cache/cobalt", home_path);
+ int result = SbStringFormatF(out_path, path_size, "%s/.cache", home_path);
if (result < 0 || result >= path_size) {
out_path[0] = '\0';
return false;
}
-
- return true;
+ return SbDirectoryCreate(out_path);
}
// Places up to |path_size| - 1 characters of the path to the current
@@ -144,7 +142,12 @@
if (!GetCacheDirectory(path, kPathSize)) {
return false;
}
- SbDirectoryCreate(path);
+ if (SbStringConcat(path, "/cobalt", kPathSize) >= kPathSize) {
+ return false;
+ }
+ if (!SbDirectoryCreate(path)) {
+ return false;
+ }
break;
case kSbSystemPathDebugOutputDirectory:
if (!SbSystemGetPath(kSbSystemPathTempDirectory, path, kPathSize)) {
diff --git a/src/starboard/linux/x64directfb/future/gyp_configuration.py b/src/starboard/linux/x64directfb/future/gyp_configuration.py
index b31713a..1074bc3 100644
--- a/src/starboard/linux/x64directfb/future/gyp_configuration.py
+++ b/src/starboard/linux/x64directfb/future/gyp_configuration.py
@@ -14,15 +14,9 @@
"""Starboard Linux X64 DirectFB future platform configuration for gyp_cobalt."""
import logging
-import os
-import sys
# Import the shared Linux platform configuration.
-sys.path.append(
- os.path.realpath(
- os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir, 'shared')))
-import gyp_configuration
+from starboard.linux.shared import gyp_configuration
def CreatePlatformConfig():
diff --git a/src/starboard/linux/x64directfb/gyp_configuration.py b/src/starboard/linux/x64directfb/gyp_configuration.py
index 9933052..7e60294 100644
--- a/src/starboard/linux/x64directfb/gyp_configuration.py
+++ b/src/starboard/linux/x64directfb/gyp_configuration.py
@@ -14,13 +14,9 @@
"""Starboard Linux X64 DirectFB platform configuration for gyp_cobalt."""
import logging
-import os
-import sys
# Import the shared Linux platform configuration.
-sys.path.append(os.path.realpath(os.path.join(
- os.path.dirname(__file__), os.pardir, 'shared')))
-import gyp_configuration
+from starboard.linux.shared import gyp_configuration
def CreatePlatformConfig():
diff --git a/src/starboard/linux/x64x11/BUILD.gn b/src/starboard/linux/x64x11/BUILD.gn
new file mode 100644
index 0000000..259502b
--- /dev/null
+++ b/src/starboard/linux/x64x11/BUILD.gn
@@ -0,0 +1,98 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//starboard/build/delegated_config.gni")
+
+# =============================================================================
+# DEFAULT COMPILER CONFIGS
+# =============================================================================
+
+config("compiler_defaults") {
+ libs = [
+ "EGL",
+ "GLESv2",
+ "X11",
+ "Xcomposite",
+ "Xrender",
+ ]
+
+ configs = [ "//starboard/linux/shared:compiler_defaults" ]
+}
+
+config("compiler_defaults_debug") {
+ configs = [ "//starboard/linux/shared:compiler_defaults_debug" ]
+}
+
+config("compiler_defaults_devel") {
+ configs = [ "//starboard/linux/shared:compiler_defaults_devel" ]
+}
+
+config("compiler_defaults_qa") {
+ configs = [ "//starboard/linux/shared:compiler_defaults_qa" ]
+}
+
+config("compiler_defaults_gold") {
+ configs = [ "//starboard/linux/shared:compiler_defaults_gold" ]
+}
+
+# =============================================================================
+# DELEGATED CONFIGS
+# =============================================================================
+
+delegated_config("pedantic_warnings") {
+ path = "//starboard/linux/shared"
+ generate_default = false
+}
+
+delegated_config("optimizations") {
+ path = "//starboard/linux/shared"
+ prefixes = [ "no", "debuggable", "full" ]
+}
+
+delegated_config("rtti") {
+ path = "//starboard/linux/shared"
+}
+
+config("wexit_time_destructors") {
+ configs = [ "//starboard/linux/shared:wexit_time_destructors" ]
+}
+
+# =============================================================================
+# starboard_platform TARGET
+# =============================================================================
+
+static_library("starboard_platform") {
+ sources = [
+ "//starboard/linux/x64x11/main.cc",
+ "//starboard/linux/x64x11/sanitizer_options.cc",
+ "//starboard/linux/x64x11/system_get_property.cc",
+ "//starboard/shared/starboard/link_receiver.cc",
+ "//starboard/shared/x11/application_x11.cc",
+ "//starboard/shared/x11/window_create.cc",
+ "//starboard/shared/x11/window_destroy.cc",
+ "//starboard/shared/x11/window_get_platform_handle.cc",
+ "//starboard/shared/x11/window_get_size.cc",
+ "//starboard/shared/x11/window_internal.cc",
+ ]
+
+ defines = [
+ # This must be defined when building Starboard, and must not when
+ # building Starboard client code.
+ "STARBOARD_IMPLEMENTATION",
+ ]
+
+ deps = [
+ "//starboard/linux/shared:starboard_platform",
+ ]
+}
diff --git a/src/starboard/linux/x64x11/buildconfig.gni b/src/starboard/linux/x64x11/buildconfig.gni
new file mode 100644
index 0000000..4335652
--- /dev/null
+++ b/src/starboard/linux/x64x11/buildconfig.gni
@@ -0,0 +1,15 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//starboard/linux/shared/buildconfig.gni")
diff --git a/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.py b/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.py
index 67a704c..58d9f75 100644
--- a/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.py
+++ b/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.py
@@ -14,20 +14,12 @@
"""Starboard Linux X64 X11 Clang 3.6 platform configuration for gyp_cobalt."""
import logging
-import os
-import sys
# Import the shared Linux platform configuration.
-sys.path.append(
- os.path.realpath(
- os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
- 'shared')))
-# pylint: disable=import-self,g-import-not-at-top
-import gyp_configuration as shared_configuration
+from starboard.linux.shared import gyp_configuration
-class PlatformConfig(shared_configuration.PlatformConfig):
+class PlatformConfig(gyp_configuration.PlatformConfig):
"""Starboard Linux platform configuration."""
def __init__(self, platform, asan_enabled_by_default=True):
diff --git a/src/starboard/linux/x64x11/configuration.gni b/src/starboard/linux/x64x11/configuration.gni
new file mode 100644
index 0000000..bb3a238
--- /dev/null
+++ b/src/starboard/linux/x64x11/configuration.gni
@@ -0,0 +1,19 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//starboard/linux/shared/configuration.gni")
+
+# Enable support for the map to mesh filter, which is primarily used to
+# implement spherical video playback.
+enable_map_to_mesh = true
diff --git a/src/starboard/linux/x64x11/directgles/gyp_configuration.py b/src/starboard/linux/x64x11/directgles/gyp_configuration.py
index 4fc899f..ca2ca64 100644
--- a/src/starboard/linux/x64x11/directgles/gyp_configuration.py
+++ b/src/starboard/linux/x64x11/directgles/gyp_configuration.py
@@ -14,16 +14,9 @@
"""Starboard Linux X64 X11 future platform configuration for gyp_cobalt."""
import logging
-import os
-import sys
# Import the shared Linux platform configuration.
-sys.path.append(
- os.path.realpath(
- os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir, 'shared')))
-# pylint: disable=import-self,g-import-not-at-top
-import gyp_configuration
+from starboard.linux.shared import gyp_configuration
def CreatePlatformConfig():
diff --git a/src/starboard/linux/x64x11/future/gyp_configuration.py b/src/starboard/linux/x64x11/future/gyp_configuration.py
index 5f82ad7..3a3e34f 100644
--- a/src/starboard/linux/x64x11/future/gyp_configuration.py
+++ b/src/starboard/linux/x64x11/future/gyp_configuration.py
@@ -14,15 +14,9 @@
"""Starboard Linux X64 X11 future platform configuration for gyp_cobalt."""
import logging
-import os
-import sys
# Import the shared Linux platform configuration.
-sys.path.append(
- os.path.realpath(
- os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir, 'shared')))
-import gyp_configuration
+from starboard.linux.shared import gyp_configuration
def CreatePlatformConfig():
diff --git a/src/starboard/linux/x64x11/gcc/6.3/gyp_configuration.py b/src/starboard/linux/x64x11/gcc/6.3/gyp_configuration.py
index bac3a98..3c1702d 100644
--- a/src/starboard/linux/x64x11/gcc/6.3/gyp_configuration.py
+++ b/src/starboard/linux/x64x11/gcc/6.3/gyp_configuration.py
@@ -16,20 +16,15 @@
import logging
import os
import subprocess
-import sys
-# Import the shared Linux platform configuration.
-sys.path.append(
- os.path.realpath(
- os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
- 'shared')))
+
# pylint: disable=import-self,g-import-not-at-top
-import gyp_configuration as shared_configuration
import gyp_utils
+# Import the shared Linux platform configuration.
+from starboard.linux.shared import gyp_configuration
-class PlatformConfig(shared_configuration.PlatformConfig):
+class PlatformConfig(gyp_configuration.PlatformConfig):
"""Starboard Linux platform configuration."""
def __init__(self, platform, asan_enabled_by_default=False):
diff --git a/src/starboard/linux/x64x11/mock/gyp_configuration.gypi b/src/starboard/linux/x64x11/mock/gyp_configuration.gypi
index 659c47d..f76e9ea 100644
--- a/src/starboard/linux/x64x11/mock/gyp_configuration.gypi
+++ b/src/starboard/linux/x64x11/mock/gyp_configuration.gypi
@@ -29,6 +29,7 @@
'cobalt_enable_jit': 0,
'cobalt_media_source_2016': 1,
+ 'cobalt_encrypted_media_extension_enable_key_statuses_update': 0,
'platform_libraries': [
'-lpthread',
diff --git a/src/starboard/log.h b/src/starboard/log.h
index 596bc88..bd0edef 100644
--- a/src/starboard/log.h
+++ b/src/starboard/log.h
@@ -145,7 +145,7 @@
}
#if defined(__cplusplus_winrt)
-inline std::ostream& operator<<(std::ostream& out, ::Platform::String ^ str) {
+inline std::ostream& operator<<(std::ostream& out, ::Platform::String^ str) {
return out << std::wstring(str->Begin(), str->End());
}
#endif
@@ -156,7 +156,10 @@
const SbLogPriority SB_LOG_FATAL = kSbLogPriorityFatal;
const SbLogPriority SB_LOG_0 = SB_LOG_ERROR;
-class SB_EXPORT LogMessage {
+// TODO: Export this, e.g. by wrapping in straight-C functions which can then be
+// SB_EXPORT'd. Using SB_EXPORT here directly causes issues on Windows because
+// it uses std classes which also need to be exported.
+class LogMessage {
public:
LogMessage(const char* file, int line, SbLogPriority priority);
~LogMessage();
diff --git a/src/starboard/nplb/BUILD.gn b/src/starboard/nplb/BUILD.gn
new file mode 100644
index 0000000..29d0b35
--- /dev/null
+++ b/src/starboard/nplb/BUILD.gn
@@ -0,0 +1,297 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//starboard/build/deploy.gni")
+
+group("all") {
+ testonly = true
+ deps = [
+ ":nplb",
+ ":deploy",
+ ]
+}
+
+test("nplb") {
+ testonly = true
+ sources = [
+ "//starboard/common/test_main.cc",
+ "accessibility_get_setting_test.cc",
+ "align_test.cc",
+ "atomic_test.cc",
+ "audio_sink_create_test.cc",
+ "audio_sink_destroy_test.cc",
+ "audio_sink_get_max_channels_test.cc",
+ "audio_sink_get_nearest_supported_sample_frequency_test.cc",
+ "audio_sink_helpers.cc",
+ "audio_sink_helpers.h",
+ "audio_sink_is_audio_frame_storage_type_supported_test.cc",
+ "audio_sink_is_audio_sample_type_supported_test.cc",
+ "audio_sink_test.cc",
+ "blitter_blit_rect_to_rect_test.cc",
+ "blitter_blit_rect_to_rect_tiled_test.cc",
+ "blitter_blit_rects_to_rects_test.cc",
+ "blitter_create_context_test.cc",
+ "blitter_create_default_device_test.cc",
+ "blitter_create_pixel_data_test.cc",
+ "blitter_create_render_target_surface_test.cc",
+ "blitter_create_surface_from_pixel_data_test.cc",
+ "blitter_create_swap_chain_from_window_test.cc",
+ "blitter_destroy_context_test.cc",
+ "blitter_destroy_device_test.cc",
+ "blitter_destroy_pixel_data_test.cc",
+ "blitter_destroy_surface_test.cc",
+ "blitter_destroy_swap_chain_test.cc",
+ "blitter_download_surface_pixels_test.cc",
+ "blitter_fill_rect_test.cc",
+ "blitter_flip_swap_chain_test.cc",
+ "blitter_flush_context_test.cc",
+ "blitter_get_max_contexts_test.cc",
+ "blitter_get_pixel_data_pitch_in_bytes_test.cc",
+ "blitter_get_pixel_data_pointer_test.cc",
+ "blitter_get_render_target_from_surface_test.cc",
+ "blitter_get_render_target_from_swap_chain_test.cc",
+ "blitter_get_surface_info_test.cc",
+ "blitter_helpers.cc",
+ "blitter_is_pixel_format_supported_by_download_surface_pixels_test.cc",
+ "blitter_is_pixel_format_supported_by_pixel_data_test.cc",
+ "blitter_is_pixel_format_supported_by_render_target_surface_test.cc",
+ "blitter_set_blending_test.cc",
+ "blitter_set_modulate_blits_with_color_test.cc",
+ "blitter_set_render_target_test.cc",
+ "blitter_set_scissor_test.cc",
+ "byte_swap_test.cc",
+ "char_is_signed_test.cc",
+ "character_is_alphanumeric_test.cc",
+ "character_is_digit_test.cc",
+ "character_is_hex_digit_test.cc",
+ "character_is_space_test.cc",
+ "character_is_upper_test.cc",
+ "character_to_lower_test.cc",
+ "character_to_upper_test.cc",
+ "condition_variable_broadcast_test.cc",
+ "condition_variable_create_test.cc",
+ "condition_variable_destroy_test.cc",
+ "condition_variable_signal_test.cc",
+ "condition_variable_wait_test.cc",
+ "condition_variable_wait_timed_test.cc",
+ "configuration_test.cc",
+ "cryptography_create_transformer_test.cc",
+ "cryptography_helpers.cc",
+ "cryptography_helpers.h",
+ "cryptography_transform_gcm_test.cc",
+ "cryptography_transform_test.cc",
+ "decode_target_create_test.cc",
+ "decode_target_provider_test.cc",
+ "directory_can_open_test.cc",
+ "directory_close_test.cc",
+ "directory_create_test.cc",
+ "directory_get_next_test.cc",
+ "directory_open_test.cc",
+ "double_absolute_test.cc",
+ "double_exponent_test.cc",
+ "double_floor_test.cc",
+ "double_is_finite_test.cc",
+ "double_is_nan_test.cc",
+ "file_can_open_test.cc",
+ "file_close_test.cc",
+ "file_get_info_test.cc",
+ "file_get_path_info_test.cc",
+ "file_helpers.cc",
+ "file_mode_string_to_flags_test.cc",
+ "file_open_test.cc",
+ "file_read_test.cc",
+ "file_seek_test.cc",
+ "file_truncate_test.cc",
+ "file_write_test.cc",
+ "flat_map_test.cc",
+ "include_all.c",
+ "include_all_too.c",
+ "log_flush_test.cc",
+ "log_format_test.cc",
+ "log_is_tty_test.cc",
+ "log_raw_dump_stack_test.cc",
+ "log_raw_test.cc",
+ "log_test.cc",
+ "memory_align_to_page_size_test.cc",
+ "memory_allocate_aligned_test.cc",
+ "memory_allocate_test.cc",
+ "memory_compare_test.cc",
+ "memory_copy_test.cc",
+ "memory_deallocate_aligned_test.cc",
+ "memory_deallocate_test.cc",
+ "memory_find_byte_test.cc",
+ "memory_get_stack_bounds_test.cc",
+ "memory_is_zero_test.cc",
+ "memory_map_test.cc",
+ "memory_move_test.cc",
+ "memory_reallocate_test.cc",
+ "memory_reporter_test.cc",
+ "memory_set_test.cc",
+ "microphone_close_test.cc",
+ "microphone_create_test.cc",
+ "microphone_destroy_test.cc",
+ "microphone_get_available_test.cc",
+ "microphone_is_sample_rate_supported_test.cc",
+ "microphone_open_test.cc",
+ "microphone_read_test.cc",
+ "mutex_acquire_test.cc",
+ "mutex_acquire_try_test.cc",
+ "mutex_create_test.cc",
+ "mutex_destroy_test.cc",
+ "once_test.cc",
+ "optional_test.cc",
+ "player_create_test.cc",
+ "random_helpers.cc",
+ "rwlock_test.cc",
+ "semaphore_test.cc",
+ "socket_accept_test.cc",
+ "socket_bind_test.cc",
+ "socket_clear_last_error_test.cc",
+ "socket_connect_test.cc",
+ "socket_create_test.cc",
+ "socket_destroy_test.cc",
+ "socket_get_interface_address_test.cc",
+ "socket_get_last_error_test.cc",
+ "socket_get_local_address_test.cc",
+ "socket_get_local_interface_address_test.cc",
+ "socket_helpers.cc",
+ "socket_is_connected_and_idle_test.cc",
+ "socket_is_connected_test.cc",
+ "socket_join_multicast_group_test.cc",
+ "socket_listen_test.cc",
+ "socket_receive_from_test.cc",
+ "socket_resolve_test.cc",
+ "socket_send_to_test.cc",
+ "socket_set_options_test.cc",
+ "socket_waiter_add_test.cc",
+ "socket_waiter_create_test.cc",
+ "socket_waiter_destroy_test.cc",
+ "socket_waiter_remove_test.cc",
+ "socket_waiter_wait_test.cc",
+ "socket_waiter_wait_timed_test.cc",
+ "socket_waiter_wake_up_test.cc",
+ "socket_wrapper_test.cc",
+ "speech_recognizer_cancel_test.cc",
+ "speech_recognizer_create_test.cc",
+ "speech_recognizer_destroy_test.cc",
+ "speech_recognizer_helper.h",
+ "speech_recognizer_start_test.cc",
+ "speech_recognizer_stop_test.cc",
+ "speech_synthesis_basic_test.cc",
+ "storage_close_record_test.cc",
+ "storage_delete_record_test.cc",
+ "storage_get_record_size_test.cc",
+ "storage_open_record_test.cc",
+ "storage_read_record_test.cc",
+ "storage_write_record_test.cc",
+ "state_machine_test.cc",
+ "string_compare_all_test.cc",
+ "string_compare_no_case_n_test.cc",
+ "string_compare_no_case_test.cc",
+ "string_compare_test.cc",
+ "string_compare_wide_test.cc",
+ "string_concat_test.cc",
+ "string_concat_wide_test.cc",
+ "string_copy_test.cc",
+ "string_copy_wide_test.cc",
+ "string_duplicate_test.cc",
+ "string_find_character_test.cc",
+ "string_find_last_character_test.cc",
+ "string_find_string_test.cc",
+ "string_format_test.cc",
+ "string_format_wide_test.cc",
+ "string_parse_double_test.cc",
+ "string_parse_signed_integer_test.cc",
+ "string_parse_uint64_test.cc",
+ "string_parse_unsigned_integer_test.cc",
+ "string_scan_test.cc",
+ "system_binary_search_test.cc",
+ "system_clear_last_error_test.cc",
+ "system_get_error_string_test.cc",
+ "system_get_last_error_test.cc",
+ "system_get_locale_id_test.cc",
+ "system_get_number_of_processors_test.cc",
+ "system_get_path_test.cc",
+ "system_get_property_test.cc",
+ "system_get_random_data_test.cc",
+ "system_get_random_uint64_test.cc",
+ "system_get_stack_test.cc",
+ "system_get_total_cpu_memory_test.cc",
+ "system_get_total_gpu_memory_test.cc",
+ "system_get_used_cpu_memory_test.cc",
+ "system_get_used_gpu_memory_test.cc",
+ "system_has_capability_test.cc",
+ "system_hide_splash_screen_test.cc",
+ "system_is_debugger_attached_test.cc",
+ "system_sort_test.cc",
+ "system_symbolize_test.cc",
+ "thread_create_test.cc",
+ "thread_detach_test.cc",
+ "thread_get_current_test.cc",
+ "thread_get_id_test.cc",
+ "thread_get_name_test.cc",
+ "thread_helpers.cc",
+ "thread_is_equal_test.cc",
+ "thread_join_test.cc",
+ "thread_local_value_test.cc",
+ "thread_set_name_test.cc",
+ "thread_sleep_test.cc",
+ "thread_yield_test.cc",
+ "time_get_monotonic_now_test.cc",
+ "time_get_now_test.cc",
+ "time_narrow_test.cc",
+ "time_zone_get_current_test.cc",
+ "time_zone_get_dst_name_test.cc",
+ "time_zone_get_name_test.cc",
+ "user_get_current_test.cc",
+ "user_get_property_test.cc",
+ "user_get_signed_in_test.cc",
+ "window_create_test.cc",
+ "window_destroy_test.cc",
+ "window_get_platform_handle_test.cc",
+ "window_get_size_test.cc",
+ ]
+ # Include private C headers, if present.
+ private_sources = exec_script("//starboard/tools/find_private_files.py",
+ [
+ rebase_path("//", root_build_dir),
+ "nplb/include_all_private.c",
+ ],
+ "list lines",
+ [ "." ])
+ # Include private tests, if present.
+ private_sources += exec_script("//starboard/tools/find_private_files.py",
+ [
+ rebase_path("//", root_build_dir),
+ "nplb/*_test.cc",
+ ],
+ "list lines",
+ [ "." ])
+ sources += rebase_path(private_sources, ".", root_build_dir)
+
+ deps = [
+ "//starboard",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
+
+deploy("deploy") {
+ testonly = true
+ executable_name = "nplb"
+
+ deps = [
+ ":nplb",
+ ]
+}
diff --git a/src/starboard/nplb/align_test.cc b/src/starboard/nplb/align_test.cc
new file mode 100644
index 0000000..ce53310
--- /dev/null
+++ b/src/starboard/nplb/align_test.cc
@@ -0,0 +1,157 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/common/scoped_ptr.h"
+#include "starboard/configuration.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+bool IsAligned(void *pointer, size_t alignment) {
+ return (reinterpret_cast<uintptr_t>(pointer) % alignment) == 0;
+}
+
+size_t GetAlignment(void *pointer) {
+ for (size_t alignment = static_cast<size_t>(1) << ((sizeof(size_t) * 8) - 1);
+ alignment != 0; alignment /= 2) {
+ if (IsAligned(pointer, alignment)) {
+ return alignment;
+ }
+ }
+
+ return 1;
+}
+
+struct AlignedFields {
+ char unaligned1;
+ SB_ALIGNAS(2) char by_2;
+ char unaligned2;
+ SB_ALIGNAS(4) char by_4;
+ char unaligned3;
+ SB_ALIGNAS(8) char by_8;
+ char unaligned4;
+ SB_ALIGNAS(16) char by_16;
+ char unaligned5;
+ SB_ALIGNAS(32) char by_32;
+ char unaligned6;
+ SB_ALIGNAS(64) char by_64;
+ char unaligned7;
+ SB_ALIGNAS(128) char by_128;
+ char unaligned8;
+ SB_ALIGNAS(256) char by_256;
+ char unaligned9;
+};
+
+struct AlignedFieldsOf {
+ char unaligned1;
+ SB_ALIGNAS(SB_ALIGNOF(void*)) char by_void_star;
+ char unaligned2;
+ SB_ALIGNAS(SB_ALIGNOF(int)) char by_int;
+ char unaligned3;
+ SB_ALIGNAS(SB_ALIGNOF(uint64_t)) char by_uint64_t;
+ char unaligned4;
+};
+
+TEST(SbAlignTest, AlignAsStructFieldOnStack) {
+ char unaligned = 0;
+ EXPECT_NE(1, unaligned);
+ AlignedFields aligned;
+ EXPECT_LE(2, GetAlignment(&(aligned.by_2)));
+ EXPECT_LE(4, GetAlignment(&(aligned.by_4)));
+ EXPECT_LE(8, GetAlignment(&(aligned.by_8)));
+ EXPECT_LE(16, GetAlignment(&(aligned.by_16)));
+ EXPECT_LE(32, GetAlignment(&(aligned.by_32)));
+ EXPECT_LE(64, GetAlignment(&(aligned.by_64)));
+ EXPECT_LE(128, GetAlignment(&(aligned.by_128)));
+ EXPECT_LE(256, GetAlignment(&(aligned.by_256)));
+}
+
+TEST(SbAlignTest, AlignAsStackVariable) {
+ char unaligned1 = 1;
+ SB_ALIGNAS(2) char by_2;
+ char unaligned2 = 2;
+ EXPECT_NE(unaligned2, unaligned1); // These are to try to keep the stack
+ // variables around.
+ SB_ALIGNAS(4) char by_4;
+ char unaligned3 = 3;
+ EXPECT_NE(unaligned3, unaligned1);
+ SB_ALIGNAS(8) char by_8;
+ char unaligned4 = 4;
+ EXPECT_NE(unaligned4, unaligned1);
+ SB_ALIGNAS(16) char by_16;
+ char unaligned5 = 5;
+ EXPECT_NE(unaligned5, unaligned1);
+
+ EXPECT_LE(2, GetAlignment(&by_2));
+ EXPECT_LE(4, GetAlignment(&by_4));
+ EXPECT_LE(8, GetAlignment(&by_8));
+ EXPECT_LE(16, GetAlignment(&by_16));
+
+#if !SB_HAS_QUIRK(DOES_NOT_STACK_ALIGN_OVER_16_BYTES)
+ SB_ALIGNAS(32) char by_32;
+ char unaligned6 = 6;
+ EXPECT_NE(unaligned6, unaligned1);
+ SB_ALIGNAS(64) char by_64;
+ char unaligned7 = 7;
+ EXPECT_NE(unaligned7, unaligned1);
+ SB_ALIGNAS(128) char by_128;
+ char unaligned8 = 8;
+ EXPECT_NE(unaligned8, unaligned1);
+ SB_ALIGNAS(256) char by_256;
+ char unaligned9 = 9;
+ EXPECT_NE(unaligned9, unaligned1);
+
+ EXPECT_LE(32, GetAlignment(&by_32));
+ EXPECT_LE(64, GetAlignment(&by_64));
+ EXPECT_LE(128, GetAlignment(&by_128));
+ EXPECT_LE(256, GetAlignment(&by_256));
+#endif // !SB_HAS_QUIRK(DOES_NOT_STACK_ALIGN_OVER_16_BYTES)
+}
+
+TEST(SbAlignTest, AlignOf) {
+ EXPECT_LE(sizeof(uint8_t), SB_ALIGNOF(uint8_t));
+ EXPECT_LE(sizeof(uint16_t), SB_ALIGNOF(uint16_t));
+ EXPECT_LE(sizeof(uint32_t), SB_ALIGNOF(uint32_t));
+ EXPECT_LE(sizeof(uint64_t), SB_ALIGNOF(uint64_t));
+ EXPECT_LE(sizeof(uintptr_t), SB_ALIGNOF(uintptr_t));
+ EXPECT_LE(sizeof(void*), SB_ALIGNOF(void*));
+}
+
+TEST(SbAlignTest, AlignAsAlignOfStructFieldOnStack) {
+ char unaligned = 0;
+ EXPECT_NE(1, unaligned);
+
+ AlignedFieldsOf aligned;
+ EXPECT_LE(SB_ALIGNOF(void*), GetAlignment(&(aligned.by_void_star)));
+ EXPECT_LE(SB_ALIGNOF(int), GetAlignment(&(aligned.by_int)));
+ EXPECT_LE(SB_ALIGNOF(uint64_t), GetAlignment(&(aligned.by_uint64_t)));
+}
+
+TEST(SbAlignTest, AlignAsAlignOfStackVariable) {
+ char unaligned = 0;
+ EXPECT_NE(1, unaligned);
+ SB_ALIGNAS(SB_ALIGNOF(void*)) char by_void_star;
+ SB_ALIGNAS(SB_ALIGNOF(int)) char by_int;
+ SB_ALIGNAS(SB_ALIGNOF(uint64_t)) char by_uint64_t;
+
+ EXPECT_LE(SB_ALIGNOF(void*), GetAlignment(&by_void_star));
+ EXPECT_LE(SB_ALIGNOF(int), GetAlignment(&by_int));
+ EXPECT_LE(SB_ALIGNOF(uint64_t), GetAlignment(&by_uint64_t));
+}
+
+} // namespace
+} // namespace nplb
+} // namespace starboard
diff --git a/src/starboard/nplb/file_helpers.cc b/src/starboard/nplb/file_helpers.cc
index f6a9f43..07421a9 100644
--- a/src/starboard/nplb/file_helpers.cc
+++ b/src/starboard/nplb/file_helpers.cc
@@ -41,6 +41,13 @@
}
// static
+std::string ScopedRandomFile::MakeRandomFilename() {
+ std::ostringstream filename_stream;
+ filename_stream << "ScopedRandomFile.File_" << SbSystemGetRandomUInt64();
+ return filename_stream.str();
+}
+
+// static
void ScopedRandomFile::ExpectPattern(int pattern_offset,
void* buffer,
int size,
@@ -53,22 +60,19 @@
}
// static
-std::string ScopedRandomFile::MakeRandomFilename() {
- char path[kPathSize] = {0};
- bool result = SbSystemGetPath(kSbSystemPathTempDirectory, path, kPathSize);
- EXPECT_TRUE(result);
- if (!result) {
+std::string ScopedRandomFile::MakeRandomFilePath() {
+ std::ostringstream filename_stream;
+ filename_stream << GetTempDir();
+ if (!filename_stream.tellp()) {
return "";
}
- std::ostringstream filename_stream;
- filename_stream << path << SB_FILE_SEP_CHAR << "ScopedRandomFile.File_"
- << SbSystemGetRandomUInt64();
+ filename_stream << SB_FILE_SEP_CHAR << MakeRandomFilename();
return filename_stream.str();
}
std::string ScopedRandomFile::MakeRandomFile(int length) {
- std::string filename = MakeRandomFilename();
+ std::string filename = MakeRandomFilePath();
if (filename.empty()) {
return filename;
}
diff --git a/src/starboard/nplb/file_helpers.h b/src/starboard/nplb/file_helpers.h
index ad0c946..0a8ba5b 100644
--- a/src/starboard/nplb/file_helpers.h
+++ b/src/starboard/nplb/file_helpers.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef STARBOARD_NBLP_FILE_HELPERS_H_
-#define STARBOARD_NBLP_FILE_HELPERS_H_
+#ifndef STARBOARD_NPLB_FILE_HELPERS_H_
+#define STARBOARD_NPLB_FILE_HELPERS_H_
#include <string>
@@ -44,7 +44,7 @@
}
// Will create a file |length| bytes long.
- ScopedRandomFile(int length) : size_(length) {
+ explicit ScopedRandomFile(int length) : size_(length) {
filename_ = MakeRandomFile(size_);
}
@@ -52,18 +52,22 @@
// filename. |create| is whether to create the file or not.
ScopedRandomFile(int length, Create create) : size_(length) {
filename_ =
- (create == kCreate ? MakeRandomFile(size_) : MakeRandomFilename());
+ (create == kCreate ? MakeRandomFile(size_) : MakeRandomFilePath());
}
// Will either create a file of |kDefaultLength| bytes long, or will just
// generate a filename. |create| is whether to create the file or not.
- ScopedRandomFile(Create create) : size_(kDefaultLength) {
+ explicit ScopedRandomFile(Create create) : size_(kDefaultLength) {
filename_ =
- (create == kCreate ? MakeRandomFile(size_) : MakeRandomFilename());
+ (create == kCreate ? MakeRandomFile(size_) : MakeRandomFilePath());
}
~ScopedRandomFile() { SbFileDelete(filename_.c_str()); }
+ // Creates and returns a random filename (no path), but does not create the
+ // file.
+ static std::string MakeRandomFilename();
+
// Returns the filename generated for this file.
const std::string& filename() const { return filename_; }
@@ -83,8 +87,8 @@
// the new file.
static std::string MakeRandomFile(int length);
- // Creates and returns a random filename, but does not create the file.
- static std::string MakeRandomFilename();
+ // Creates and returns a path to a random file, but does not create the file.
+ static std::string MakeRandomFilePath();
std::string filename_;
int size_;
@@ -93,4 +97,4 @@
} // namespace nplb
} // namespace starboard
-#endif
+#endif // STARBOARD_NPLB_FILE_HELPERS_H_
diff --git a/src/starboard/nplb/nplb.gyp b/src/starboard/nplb/nplb.gyp
index 6c0c76f..274a67f 100644
--- a/src/starboard/nplb/nplb.gyp
+++ b/src/starboard/nplb/nplb.gyp
@@ -24,6 +24,7 @@
'sources': [
'<(DEPTH)/starboard/common/test_main.cc',
'accessibility_get_setting_test.cc',
+ 'align_test.cc',
'atomic_test.cc',
'audio_sink_create_test.cc',
'audio_sink_destroy_test.cc',
@@ -146,6 +147,7 @@
'mutex_create_test.cc',
'mutex_destroy_test.cc',
'once_test.cc',
+ 'optional_test.cc',
'player_create_test.cc',
'random_helpers.cc',
'rwlock_test.cc',
@@ -184,6 +186,7 @@
'speech_recognizer_start_test.cc',
'speech_recognizer_stop_test.cc',
'speech_synthesis_basic_test.cc',
+ 'state_machine_test.cc',
'storage_close_record_test.cc',
'storage_delete_record_test.cc',
'storage_get_record_size_test.cc',
diff --git a/src/starboard/nplb/optional_test.cc b/src/starboard/nplb/optional_test.cc
new file mode 100644
index 0000000..c467d2a
--- /dev/null
+++ b/src/starboard/nplb/optional_test.cc
@@ -0,0 +1,830 @@
+/*
+ * Copyright 2014 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <set>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include "starboard/common/optional.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::InSequence;
+
+namespace starboard {
+namespace {
+
+TEST(OptionalTest, EnsureDefaultConstructorGivesDisengagedOptional) {
+ optional<int> test;
+ EXPECT_TRUE(!test);
+}
+
+TEST(OptionalTest, EnsureNullOptConstructorGivesDisengagedOptional) {
+ optional<int> test(nullopt);
+ EXPECT_TRUE(!test);
+}
+
+TEST(OptionalTest, InitializeConstructor) {
+ optional<int> test(2);
+ EXPECT_FALSE(!test);
+ EXPECT_EQ(2, test.value());
+}
+
+TEST(OptionalTest, BoolCastOperator) {
+ optional<int> test;
+ EXPECT_FALSE(static_cast<bool>(test));
+
+ test = 5;
+ EXPECT_TRUE(static_cast<bool>(test));
+}
+
+TEST(OptionalTest, InitializeAssign) {
+ optional<int> test = 2;
+ EXPECT_FALSE(!test);
+ EXPECT_EQ(2, test.value());
+}
+
+TEST(OptionalTest, ReassignValue) {
+ optional<int> test(2);
+ test = 5;
+ EXPECT_FALSE(!test);
+ EXPECT_EQ(5, test.value());
+}
+
+TEST(OptionalTest, CopyAssignment) {
+ optional<int> a;
+ optional<int> b = 2;
+ optional<int> c = 3;
+ a = b;
+ EXPECT_FALSE(!a);
+ EXPECT_EQ(2, a.value());
+
+ a = c;
+ EXPECT_FALSE(!a);
+ EXPECT_EQ(3, a.value());
+}
+
+TEST(OptionalTest, ClearAssignment) {
+ optional<int> test(2);
+ test = optional<int>();
+ EXPECT_FALSE(test);
+}
+
+TEST(OptionalTest, EnsureAssignmentOfNullOptResultsInDisengagement) {
+ optional<int> test(2);
+ test = nullopt;
+ EXPECT_FALSE(test);
+}
+
+TEST(OptionalTest, EnsureAssignmentOfDefaultOptionalResultsInDisengagement) {
+ optional<int> test(2);
+ test = optional<int>();
+ EXPECT_FALSE(test);
+}
+
+TEST(OptionalTest, CopyConstruction) {
+ optional<int> test1(2);
+ optional<int> test2(test1);
+
+ EXPECT_FALSE(!test2);
+ EXPECT_EQ(2, test2.value());
+}
+
+TEST(OptionalTest, Swap) {
+ optional<int> test1(1);
+ optional<int> test2(2);
+
+ // Swap two engaged optionals.
+ test1.swap(test2);
+ EXPECT_FALSE(!test1);
+ EXPECT_EQ(2, test1.value());
+ EXPECT_EQ(1, test2.value());
+
+ // Swap two optionals where only one is engaged.
+ test1 = nullopt;
+ test1.swap(test2);
+ EXPECT_FALSE(test2);
+ EXPECT_FALSE(!test1);
+ EXPECT_EQ(1, test1.value());
+
+ // Swap two optionals where only one is engaged, except the other way around.
+ test1.swap(test2);
+ EXPECT_FALSE(test1);
+ EXPECT_FALSE(!test2);
+ EXPECT_EQ(1, test2.value());
+
+ // Swap two disengaged optionals.
+ test2 = nullopt;
+ test1.swap(test2);
+ EXPECT_FALSE(test1);
+ EXPECT_FALSE(test2);
+}
+
+TEST(OptionalTest, StdSwap) {
+ optional<int> test1(1);
+ optional<int> test2(2);
+
+ // Swap two engaged optionals.
+ std::swap(test1, test2);
+ EXPECT_FALSE(!test1);
+ EXPECT_EQ(2, test1.value());
+ EXPECT_EQ(1, test2.value());
+
+ // Swap two optionals where only one is engaged.
+ test1 = nullopt;
+ std::swap(test1, test2);
+ EXPECT_FALSE(test2);
+ EXPECT_FALSE(!test1);
+ EXPECT_EQ(1, test1.value());
+
+ // Swap two optionals where only one is engaged, except the other way around.
+ std::swap(test1, test2);
+ EXPECT_FALSE(test1);
+ EXPECT_FALSE(!test2);
+ EXPECT_EQ(1, test2.value());
+
+ // Swap two disengaged optionals.
+ test2 = nullopt;
+ std::swap(test1, test2);
+ EXPECT_FALSE(test1);
+ EXPECT_FALSE(test2);
+}
+
+TEST(OptionalTest, SwapWithSelf) {
+ optional<int> test(1);
+
+ test.swap(test);
+ EXPECT_EQ(1, test.value());
+
+ std::swap(test, test);
+ EXPECT_EQ(1, test.value());
+}
+
+TEST(OptionalTest, AsteriskDereference) {
+ optional<int> test(2);
+ EXPECT_EQ(2, *test);
+
+ *test = 5;
+ EXPECT_EQ(5, test.value());
+}
+
+struct TestStruct {
+ int foobar;
+};
+
+TEST(OptionalTest, ArrowDereference) {
+ TestStruct a;
+ a.foobar = 2;
+
+ optional<TestStruct> test(a);
+ EXPECT_EQ(2, test->foobar);
+
+ test->foobar = 5;
+ EXPECT_EQ(5, test.value().foobar);
+
+ // Test const arrow dereference.
+ const optional<TestStruct> test_const(a);
+ EXPECT_EQ(2, test_const->foobar);
+}
+
+class NoDefaultTest {
+ public:
+ explicit NoDefaultTest(int i) { foobar_ = i; }
+ int foobar() const { return foobar_; }
+
+ private:
+ NoDefaultTest();
+
+ int foobar_;
+};
+
+TEST(OptionalTest, NoDefaultConstructorIsSupported) {
+ // First test with an object passed in upon construction
+ optional<NoDefaultTest> test1(NoDefaultTest(2));
+ EXPECT_EQ(2, test1.value().foobar());
+
+ // Now test with an object assignment after construction
+ optional<NoDefaultTest> test2;
+ test2 = NoDefaultTest(5);
+ EXPECT_EQ(5, test2.value().foobar());
+}
+
+TEST(OptionalTest, TestEquivalenceComparisons) {
+ optional<int> test1 = 1;
+ optional<int> test2 = 2;
+ optional<int> test3;
+ optional<int> test4 = 2;
+
+ EXPECT_FALSE(test1 == test2); // NOLINT(readability/check)
+ EXPECT_FALSE(test2 == test1); // NOLINT(readability/check)
+ EXPECT_FALSE(test1 == test3); // NOLINT(readability/check)
+ EXPECT_FALSE(test3 == test1); // NOLINT(readability/check)
+ EXPECT_FALSE(2 == test1); // NOLINT(readability/check)
+ EXPECT_FALSE(test1 == 2); // NOLINT(readability/check)
+ EXPECT_EQ(1, test1);
+ EXPECT_EQ(test1, 1);
+ EXPECT_EQ(test4, test2);
+ EXPECT_EQ(test2, test4);
+
+ // Test nullopt comparisons
+ EXPECT_TRUE(test3 == nullopt);
+ EXPECT_TRUE(nullopt == test3);
+ EXPECT_FALSE(test1 == nullopt);
+ EXPECT_FALSE(nullopt == test1);
+}
+
+TEST(OptionalTest, TestLessThanComparisons) {
+ optional<int> test1 = 1;
+ optional<int> test2 = 2;
+ optional<int> test3;
+ optional<int> test4 = 2;
+
+ EXPECT_TRUE(test1 < test2);
+ EXPECT_FALSE(test2 < test1);
+ EXPECT_FALSE(test1 < test1);
+ EXPECT_TRUE(test3 < test1);
+ EXPECT_FALSE(test1 < test3);
+ EXPECT_FALSE(test3 < test3);
+
+ EXPECT_TRUE(nullopt < test1);
+ EXPECT_FALSE(test1 < nullopt);
+
+ EXPECT_TRUE(test1 < 2); // NOLINT(readability/check)
+ EXPECT_FALSE(2 < test1); // NOLINT(readability/check)
+}
+
+TEST(OptionalTest, EnsureOptionalWorksWithFunnyAlignments) {
+ struct {
+ char c;
+ optional<uint64_t> number;
+ } foo;
+
+ EXPECT_FALSE(!!foo.number);
+ foo.number = 1;
+ EXPECT_TRUE(!!foo.number);
+ EXPECT_EQ(1, foo.number.value());
+}
+
+class DestructorCallTester {
+ public:
+ DestructorCallTester() {}
+ DestructorCallTester(const DestructorCallTester&) {}
+ ~DestructorCallTester() { Die(); }
+ MOCK_METHOD0(Die, void());
+};
+
+TEST(OptionalTest, EnsureDestructorIsCalled) {
+ {
+ // Ensure destructor is called upon optional destruction
+ optional<DestructorCallTester> test(in_place);
+ EXPECT_CALL(test.value(), Die());
+ }
+
+ {
+ // Ensure destructor is called upon assignment to null
+ optional<DestructorCallTester> test1(in_place);
+ optional<DestructorCallTester> test2(in_place);
+ {
+ InSequence s;
+ EXPECT_CALL(test1.value(), Die());
+ EXPECT_CALL(test2.value(), Die());
+ }
+ test1 = nullopt;
+ }
+}
+
+// This class counts all calls to the set of methods declared in the class.
+// It can be used to verify that certain methods are indeed called.
+class MethodCallCounter {
+ public:
+ MethodCallCounter() {
+ ResetCounts();
+ ++default_constructor_calls_;
+ }
+
+ MethodCallCounter(const MethodCallCounter& other) {
+ // A very non-standard copy constructor, since this is a test object
+ // intended to count method calls on this object and only this object.
+ ResetCounts();
+ ++copy_constructor_calls_;
+ }
+
+ MethodCallCounter(MethodCallCounter&& other) { // NOLINT(build/c++11)
+ // A very non-standard move constructor, since this is a test object
+ // intended to count method calls on this object and only this object.
+ ResetCounts();
+ ++move_constructor_calls_;
+ }
+
+ MethodCallCounter& operator=(const MethodCallCounter& other) {
+ ++assignment_calls_;
+ return *this;
+ }
+
+ // NOLINTNEXTLINE(build/c++11)
+ MethodCallCounter& operator=(MethodCallCounter&& other) {
+ ++move_assignment_calls_;
+ return *this;
+ }
+
+ int assignment_calls() const { return assignment_calls_; }
+ int copy_constructor_calls() const { return copy_constructor_calls_; }
+ int default_constructor_calls() const { return default_constructor_calls_; }
+ int move_assignment_calls() const { return move_assignment_calls_; }
+ int move_constructor_calls() const { return move_constructor_calls_; }
+
+ private:
+ void ResetCounts() {
+ assignment_calls_ = 0;
+ copy_constructor_calls_ = 0;
+ default_constructor_calls_ = 0;
+ move_assignment_calls_ = 0;
+ move_constructor_calls_ = 0;
+ }
+
+ int assignment_calls_;
+ int copy_constructor_calls_;
+ int default_constructor_calls_;
+ int move_assignment_calls_;
+ int move_constructor_calls_;
+};
+
+TEST(OptionalTest, CopyConstructorIsCalledByValueCopyConstructor) {
+ MethodCallCounter original_counter;
+ optional<MethodCallCounter> test(original_counter);
+ EXPECT_EQ(0, test->assignment_calls());
+ EXPECT_EQ(1, test->copy_constructor_calls());
+ EXPECT_EQ(0, test->default_constructor_calls());
+ EXPECT_EQ(0, test->move_assignment_calls());
+ EXPECT_EQ(0, test->move_constructor_calls());
+}
+
+TEST(OptionalTest, CopyConstructorIsCalledByOptionalCopyConstructor) {
+ optional<MethodCallCounter> test1(in_place);
+ optional<MethodCallCounter> test2(test1);
+
+ EXPECT_EQ(0, test2->assignment_calls());
+ EXPECT_EQ(1, test2->copy_constructor_calls());
+ EXPECT_EQ(0, test2->default_constructor_calls());
+ EXPECT_EQ(0, test2->move_assignment_calls());
+ EXPECT_EQ(0, test2->move_constructor_calls());
+}
+
+TEST(OptionalTest, CopyConstructorIsCalledByOptionalAssignment) {
+ optional<MethodCallCounter> test1(in_place);
+ optional<MethodCallCounter> test2;
+ test2 = test1;
+
+ EXPECT_EQ(0, test2->assignment_calls());
+ EXPECT_EQ(1, test2->copy_constructor_calls());
+ EXPECT_EQ(0, test2->default_constructor_calls());
+ EXPECT_EQ(0, test2->move_assignment_calls());
+ EXPECT_EQ(0, test2->move_constructor_calls());
+}
+
+TEST(OptionalTest, AssignmentIsCalledByValueAssignment) {
+ MethodCallCounter original_counter;
+ optional<MethodCallCounter> test(in_place);
+ test = original_counter;
+
+ EXPECT_EQ(1, test->assignment_calls());
+ EXPECT_EQ(0, test->copy_constructor_calls());
+ EXPECT_EQ(1, test->default_constructor_calls());
+ EXPECT_EQ(0, test->move_assignment_calls());
+ EXPECT_EQ(0, test->move_constructor_calls());
+}
+
+TEST(OptionalTest, AssignmentIsCalledByOptionalAssignment) {
+ optional<MethodCallCounter> test1(in_place);
+ optional<MethodCallCounter> test2(in_place);
+ test2 = test1;
+
+ EXPECT_EQ(1, test2->assignment_calls());
+ EXPECT_EQ(0, test2->copy_constructor_calls());
+ EXPECT_EQ(1, test2->default_constructor_calls());
+ EXPECT_EQ(0, test2->move_assignment_calls());
+ EXPECT_EQ(0, test2->move_constructor_calls());
+}
+
+TEST(OptionalTest, MoveConstructorIsCalledOnOptionalMoveConstructor) {
+ optional<MethodCallCounter> test(
+ std::move(optional<MethodCallCounter>(in_place)));
+
+ EXPECT_EQ(0, test->assignment_calls());
+ EXPECT_EQ(0, test->copy_constructor_calls());
+ EXPECT_EQ(0, test->default_constructor_calls());
+ EXPECT_EQ(0, test->move_assignment_calls());
+ EXPECT_EQ(1, test->move_constructor_calls());
+}
+
+TEST(OptionalTest, MoveConstructorIsCalledOnUnengagedOptionalMoveAssignment) {
+ optional<MethodCallCounter> test;
+ test = std::move(optional<MethodCallCounter>(in_place));
+
+ EXPECT_EQ(0, test->assignment_calls());
+ EXPECT_EQ(0, test->copy_constructor_calls());
+ EXPECT_EQ(0, test->default_constructor_calls());
+ EXPECT_EQ(0, test->move_assignment_calls());
+ EXPECT_EQ(1, test->move_constructor_calls());
+}
+
+TEST(OptionalTest, MoveAssignmentIsCalledOnEngagedMoveOptionalAssignment) {
+ optional<MethodCallCounter> test(in_place);
+ test = std::move(optional<MethodCallCounter>(in_place));
+
+ EXPECT_EQ(0, test->assignment_calls());
+ EXPECT_EQ(0, test->copy_constructor_calls());
+ EXPECT_EQ(1, test->default_constructor_calls());
+ EXPECT_EQ(1, test->move_assignment_calls());
+ EXPECT_EQ(0, test->move_constructor_calls());
+}
+
+TEST(OptionalTest, MoveConstructorIsCalledOnUnengagedMoveValueConstructor) {
+ MethodCallCounter original_counter;
+ optional<MethodCallCounter> test(std::move(original_counter));
+
+ EXPECT_EQ(0, test->assignment_calls());
+ EXPECT_EQ(0, test->copy_constructor_calls());
+ EXPECT_EQ(0, test->default_constructor_calls());
+ EXPECT_EQ(0, test->move_assignment_calls());
+ EXPECT_EQ(1, test->move_constructor_calls());
+}
+
+TEST(OptionalTest, MoveConstructorIsCalledOnUnengagedMoveValueAssignment) {
+ MethodCallCounter original_counter;
+ optional<MethodCallCounter> test;
+ test = std::move(original_counter);
+
+ EXPECT_EQ(0, test->assignment_calls());
+ EXPECT_EQ(0, test->copy_constructor_calls());
+ EXPECT_EQ(0, test->default_constructor_calls());
+ EXPECT_EQ(0, test->move_assignment_calls());
+ EXPECT_EQ(1, test->move_constructor_calls());
+}
+
+TEST(OptionalTest, MoveAssignmentIsCalledOnEngagedMoveValueAssignment) {
+ MethodCallCounter original_counter;
+ optional<MethodCallCounter> test(in_place);
+ test = std::move(original_counter);
+
+ EXPECT_EQ(0, test->assignment_calls());
+ EXPECT_EQ(0, test->copy_constructor_calls());
+ EXPECT_EQ(1, test->default_constructor_calls());
+ EXPECT_EQ(1, test->move_assignment_calls());
+ EXPECT_EQ(0, test->move_constructor_calls());
+}
+
+TEST(OptionalTest, EnsureSelfAssignmentIsOkay) {
+ // Ensure that values are as we expect them to be.
+ optional<int> test1(5);
+
+ test1 = test1;
+
+ EXPECT_FALSE(!test1);
+ EXPECT_EQ(5, test1.value());
+
+ // Ensure that the methods we expect to be called are actually called.
+ optional<MethodCallCounter> test2(in_place);
+
+ test2 = test2;
+
+ EXPECT_EQ(1, test2->assignment_calls());
+ EXPECT_EQ(0, test2->copy_constructor_calls());
+ EXPECT_EQ(1, test2->default_constructor_calls());
+ EXPECT_EQ(0, test2->move_assignment_calls());
+ EXPECT_EQ(0, test2->move_constructor_calls());
+}
+
+// Helper classes to ensure that we can assign different values to optionals
+// so long as the wrapped value can be assigned and constructed from the other.
+struct XType {
+ explicit XType(int number) { number_ = number; }
+
+ int number_;
+};
+
+struct YType {
+ explicit YType(int number) { number_ = number; }
+
+ explicit YType(const XType& x_type) { number_ = x_type.number_; }
+
+ YType& operator=(const XType& x_type) {
+ number_ = x_type.number_;
+ return *this;
+ }
+
+ int number_;
+};
+
+TEST(OptionalTest, CopyConstructorIsCalledByValueAssignmentFromOtherType) {
+ XType x_type(1);
+ optional<YType> test;
+ test = x_type;
+ EXPECT_FALSE(!test);
+ EXPECT_EQ(1, test->number_);
+}
+
+TEST(OptionalTest, AssignmentIsCalledByValueAssignmentFromOtherType) {
+ XType x_type(1);
+ optional<YType> test(in_place, 2);
+ test = x_type;
+ EXPECT_FALSE(!test);
+ EXPECT_EQ(1, test->number_);
+}
+
+TEST(OptionalTest, TestMakeOptional) {
+ optional<int> test = make_optional(5);
+
+ EXPECT_FALSE(!test);
+ EXPECT_EQ(5, test.value());
+}
+
+TEST(OptionalTest, ValueOrTest) {
+ optional<int> test;
+
+ EXPECT_EQ(4, test.value_or(4));
+
+ test = 2;
+
+ EXPECT_EQ(2, test.value_or(4));
+}
+
+TEST(OptionalTest, ConstOptionalsTest) {
+ const optional<int> test1(5);
+
+ EXPECT_FALSE(!test1);
+ EXPECT_EQ(5, test1.value());
+ EXPECT_EQ(5, *test1);
+
+ const optional<int> test2(test1);
+
+ EXPECT_FALSE(!test2);
+ EXPECT_EQ(5, test2.value());
+ EXPECT_EQ(5, *test2);
+
+ optional<int> test3;
+ test3 = test2;
+
+ EXPECT_FALSE(!test3);
+ EXPECT_EQ(5, test3.value());
+ EXPECT_EQ(5, *test3);
+}
+
+TEST(OptionalTest, EmplaceInt) {
+ optional<int> test;
+
+ test.emplace(5);
+ EXPECT_FALSE(!test);
+ EXPECT_EQ(5, test.value());
+}
+
+TEST(OptionalTest, EmplaceWithDefaultConstructor) {
+ optional<MethodCallCounter> test;
+ test.emplace();
+
+ EXPECT_FALSE(!test);
+ EXPECT_EQ(0, test->assignment_calls());
+ EXPECT_EQ(0, test->copy_constructor_calls());
+ EXPECT_EQ(1, test->default_constructor_calls());
+ EXPECT_EQ(0, test->move_assignment_calls());
+ EXPECT_EQ(0, test->move_constructor_calls());
+}
+
+class NoDefaultOrCopyConstructor {
+ public:
+ NoDefaultOrCopyConstructor(int x, int y) {
+ x_ = x;
+ y_ = y;
+ }
+
+ int x() const { return x_; }
+ int y() const { return y_; }
+
+ private:
+ NoDefaultOrCopyConstructor();
+ NoDefaultOrCopyConstructor(const NoDefaultOrCopyConstructor&);
+
+ int x_;
+ int y_;
+};
+
+TEST(OptionalTest, EmplaceObjectWithNoDefaultOrCopyConstructor) {
+ optional<NoDefaultOrCopyConstructor> test;
+ test.emplace(1, 2);
+ EXPECT_FALSE(!test);
+ EXPECT_EQ(1, test->x());
+ EXPECT_EQ(2, test->y());
+}
+
+class NonConstPointerInConstructor {
+ public:
+ explicit NonConstPointerInConstructor(int* param) { param_ = param; }
+
+ void SetParam(int value) { *param_ = value; }
+
+ private:
+ int* param_;
+};
+
+TEST(OptionalTest, EmplaceObjectWithNonConstPointer) {
+ int value = 0;
+ optional<NonConstPointerInConstructor> test;
+ test.emplace(&value);
+ test->SetParam(5);
+ EXPECT_EQ(5, value);
+}
+
+TEST(OptionalTest, ForwardingConstructorInt) {
+ optional<int> test(in_place, 5);
+ EXPECT_FALSE(!test);
+ EXPECT_EQ(5, test.value());
+}
+
+TEST(OptionalTest, ForwardingConstructorWithDefaultConstructor) {
+ optional<MethodCallCounter> test(in_place);
+ EXPECT_FALSE(!test);
+ EXPECT_EQ(1, test->default_constructor_calls());
+ EXPECT_EQ(0, test->copy_constructor_calls());
+ EXPECT_EQ(0, test->assignment_calls());
+}
+
+TEST(OptionalTest, ForwardingConstructorObjectWithNoDefaultOrCopyConstructor) {
+ optional<NoDefaultOrCopyConstructor> test(in_place, 1, 2);
+ EXPECT_FALSE(!test);
+ EXPECT_EQ(1, test->x());
+ EXPECT_EQ(2, test->y());
+}
+
+TEST(OptionalTest, ForwardingConstructorObjectWithNonConstPointer) {
+ int value = 0;
+ optional<NonConstPointerInConstructor> test(in_place, &value);
+ test->SetParam(5);
+ EXPECT_EQ(5, value);
+}
+
+TEST(OptionalTest, OptionalStringTest) {
+ {
+ optional<std::string> test;
+ EXPECT_TRUE(!test);
+
+ test = std::string("foo");
+ EXPECT_STREQ("foo", test->c_str());
+ }
+
+ {
+ optional<std::string> test(std::string("foo"));
+ EXPECT_FALSE(!test);
+
+ EXPECT_STREQ("foo", test->c_str());
+ optional<std::string> test2(test);
+ EXPECT_STREQ("foo", test2->c_str());
+ }
+}
+
+TEST(OptionalTest, OptionalStringInSetTest) {
+ // Optional strings in map test
+ std::set<optional<std::string>> optional_string_set;
+
+ optional_string_set.insert(std::string("foo"));
+ optional_string_set.insert(std::string("bar"));
+
+ EXPECT_TRUE(optional_string_set.find(std::string("foo")) !=
+ optional_string_set.end());
+ EXPECT_TRUE(optional_string_set.find(std::string("bar")) !=
+ optional_string_set.end());
+ EXPECT_FALSE(optional_string_set.find(optional<std::string>()) !=
+ optional_string_set.end());
+
+ optional_string_set.insert(optional<std::string>());
+
+ EXPECT_TRUE(optional_string_set.find(std::string("foo")) !=
+ optional_string_set.end());
+ EXPECT_TRUE(optional_string_set.find(std::string("bar")) !=
+ optional_string_set.end());
+ EXPECT_TRUE(optional_string_set.find(optional<std::string>()) !=
+ optional_string_set.end());
+}
+
+TEST(OptionalTest, StdVectorOfOptionalsWorksFine) {
+ std::vector<optional<int>> test_vector;
+
+ test_vector.reserve(test_vector.capacity() + 1);
+ test_vector.resize(test_vector.capacity());
+
+ // Make sure all current optionals are disengaged.
+ for (std::vector<optional<int>>::const_iterator iter = test_vector.begin();
+ iter != test_vector.end(); ++iter) {
+ EXPECT_TRUE(!*iter);
+ }
+ EXPECT_TRUE(!test_vector[0]);
+
+ test_vector.clear();
+ test_vector.resize(test_vector.capacity() + 1, 5);
+ for (std::vector<optional<int>>::const_iterator iter = test_vector.begin();
+ iter != test_vector.end(); ++iter) {
+ ASSERT_FALSE(!*iter);
+ EXPECT_EQ(5, **iter);
+ }
+ ASSERT_FALSE(!test_vector[0]);
+ EXPECT_EQ(5, *test_vector[0]);
+
+ test_vector.push_back(8);
+ ASSERT_FALSE(!test_vector.back());
+ EXPECT_EQ(8, *test_vector.back());
+}
+
+TEST(OptionalTest, OptionalStringInUnorderedSet) {
+ std::unordered_set<optional<std::string>> optional_string_set;
+
+ optional_string_set.insert(std::string());
+ optional_string_set.insert(std::string("7"));
+ optional_string_set.insert(std::string("123456"));
+
+ EXPECT_TRUE(optional_string_set.find(std::string("7")) !=
+ optional_string_set.end());
+ EXPECT_TRUE(optional_string_set.find(std::string("123456")) !=
+ optional_string_set.end());
+ EXPECT_TRUE(optional_string_set.find(std::string()) !=
+ optional_string_set.end());
+ EXPECT_FALSE(optional_string_set.find(optional<std::string>()) !=
+ optional_string_set.end());
+
+ optional_string_set.insert(optional<std::string>());
+
+ EXPECT_TRUE(optional_string_set.find(std::string("7")) !=
+ optional_string_set.end());
+ EXPECT_TRUE(optional_string_set.find(std::string("123456")) !=
+ optional_string_set.end());
+ EXPECT_TRUE(optional_string_set.find(std::string()) !=
+ optional_string_set.end());
+ EXPECT_TRUE(optional_string_set.find(optional<std::string>()) !=
+ optional_string_set.end());
+
+ optional_string_set.erase(std::string());
+
+ EXPECT_FALSE(optional_string_set.find(std::string()) !=
+ optional_string_set.end());
+ EXPECT_TRUE(optional_string_set.find(optional<std::string>()) !=
+ optional_string_set.end());
+}
+
+TEST(OptionalTest, OptionalIntInUnorderedSet) {
+ std::unordered_set<optional<int>> optional_int_set;
+
+ optional_int_set.insert(0);
+ optional_int_set.insert(7);
+ optional_int_set.insert(123456);
+
+ EXPECT_TRUE(optional_int_set.find(7) != optional_int_set.end());
+ EXPECT_TRUE(optional_int_set.find(123456) != optional_int_set.end());
+ EXPECT_TRUE(optional_int_set.find(0) != optional_int_set.end());
+ EXPECT_FALSE(optional_int_set.find(optional<int>()) !=
+ optional_int_set.end());
+
+ optional_int_set.insert(optional<int>());
+
+ EXPECT_TRUE(optional_int_set.find(7) != optional_int_set.end());
+ EXPECT_TRUE(optional_int_set.find(123456) != optional_int_set.end());
+ EXPECT_TRUE(optional_int_set.find(0) != optional_int_set.end());
+ EXPECT_TRUE(optional_int_set.find(optional<int>()) != optional_int_set.end());
+
+ optional_int_set.erase(0);
+
+ EXPECT_FALSE(optional_int_set.find(0) != optional_int_set.end());
+ EXPECT_TRUE(optional_int_set.find(optional<int>()) != optional_int_set.end());
+}
+
+optional<int> ConditionallyMakeOptional(bool should_make, int value) {
+ if (should_make) {
+ return optional<int>(value);
+ } else {
+ return nullopt;
+ }
+}
+
+TEST(OptionalTest, OptionalCanBeReturnedFromFunction) {
+ optional<int> test1 = ConditionallyMakeOptional(true, 5);
+ ASSERT_FALSE(!test1);
+ EXPECT_EQ(5, test1.value());
+
+ optional<int> test2 = ConditionallyMakeOptional(false, 5);
+ EXPECT_TRUE(!test2);
+}
+
+} // namespace
+} // namespace starboard
diff --git a/src/starboard/nplb/state_machine_test.cc b/src/starboard/nplb/state_machine_test.cc
new file mode 100644
index 0000000..86888c0
--- /dev/null
+++ b/src/starboard/nplb/state_machine_test.cc
@@ -0,0 +1,740 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "starboard/common/state_machine.h"
+
+#include <iostream>
+#include <list>
+
+#include "starboard/log.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Enables some verbose logging for debugging the state machine test and
+// implementation.
+#define STATE_MACHINE_TEST_DEBUG 0
+
+namespace starboard {
+namespace {
+namespace hsm {
+
+// Constant to represent no version for TestHsm::Expect.
+static const uint64_t kNoVersion = static_cast<uint64_t>(-1);
+
+// States for the test HSM
+enum TestState {
+ kStateS0,
+ kStateS1,
+ kStateS11,
+ kStateS2,
+ kStateS21,
+ kStateS211,
+ kStateT0,
+};
+
+// Events for the test HSM
+enum TestEvent {
+ kEventA,
+ kEventB,
+ kEventC,
+ kEventD,
+ kEventE,
+ kEventF,
+ kEventG,
+ kEventH,
+ kEventI,
+ kEventJ,
+};
+
+// An enumeration of things that the HSM does that we can sense and then
+// assert about.
+enum HsmEvent { kHsmEnter, kHsmExit, kHsmHandled };
+
+} // namespace hsm
+
+// --- Test Subclass ---
+
+// StateMachine is an abstract class, so we must subclass it to test it.
+// This class uses the sample test state machine specified by Miro Samek in his
+// Practical Statecharts book. It covers the interesting transitions and
+// topologies, so if it's fully exercised, it should represent a
+// close-to-canonical test of the state machine's facilities.
+//
+// The diagram of this statechart is reproduced here:
+// http://www.state-machine.com/resources/Heinzmann04.pdf
+//
+// This version has:
+// - A new event, I, in state S11, to test reentrant event handling.
+// - A new event, J, and new state T0, to test the no top state case.
+class TestHsm : public StateMachine<hsm::TestState, hsm::TestEvent> {
+ public:
+ // --- Some types to aid sensing ---
+
+ struct ResultEvent {
+ // The state the HSM was in when it handled the event.
+ const optional<hsm::TestState> state;
+
+ // The data passed into the event, if any.
+ const void* data;
+
+ // The state that actually handled the event (could be an ancestor of the
+ // current state.
+ const optional<hsm::TestState> event_state;
+
+ // The event that was handled.
+ const optional<hsm::TestEvent> event;
+
+ // The "HSM Event" that occurred causing this to be recorded.
+ const hsm::HsmEvent hsm_event;
+
+ // The state version at the time the HsmEvent occured.
+ const uint64_t version;
+ };
+
+ // --- Extra state to aid sensing ---
+
+ // Foo is used as extended state and in guard conditions in the test HSM (see
+ // link above).
+ bool foo_;
+
+ // A counter for how many times the S11 I handler is invoked.
+ int event_i_count_;
+
+ // A collection of interesting things that has happened to this state
+ // machine. Used to validate that the HSM behaved as expected.
+ std::list<ResultEvent> results;
+
+ TestHsm()
+ : StateMachine<hsm::TestState, hsm::TestEvent>("TestHsm"),
+ foo_(true),
+ event_i_count_(0) {
+#if STATE_MACHINE_TEST_DEBUG
+ EnableLogging();
+#endif
+ }
+ virtual ~TestHsm() {}
+
+ // Clears the results list, so nothing bleeds between test cases.
+ void ClearResults() { results.clear(); }
+
+ // Consumes and validates a ResultEvent from the results list.
+ void Expect(hsm::HsmEvent hsm_event,
+ optional<hsm::TestState> event_state = nullopt,
+ optional<hsm::TestEvent> event = nullopt,
+ optional<hsm::TestState> current_state = nullopt,
+ void* data = NULL,
+ uint64_t version = hsm::kNoVersion) {
+#if STATE_MACHINE_TEST_DEBUG
+ SB_DLOG(INFO) << __FUNCTION__ << ": hsm_event=" << hsm_event
+ << ", event_state=" << GetStateString(event_state)
+ << ", event=" << GetEventString(event)
+ << ", current_state=" << GetStateString(current_state)
+ << ", data=0x" << std::hex << data << ", version=" << version;
+#endif // STATE_MACHINE_TEST_DEBUG
+
+ EXPECT_FALSE(results.empty());
+ TestHsm::ResultEvent result = results.front();
+ results.pop_front();
+ EXPECT_EQ(hsm_event, result.hsm_event);
+ if (event_state) {
+ EXPECT_EQ(event_state, result.event_state);
+ if (!current_state) {
+ EXPECT_EQ(event_state, result.state);
+ }
+ }
+
+ if (current_state) {
+ EXPECT_EQ(current_state, result.state);
+ }
+
+ if (event) {
+ EXPECT_EQ(event, result.event);
+ }
+ EXPECT_EQ(data, result.data);
+
+ if (version != hsm::kNoVersion) {
+ EXPECT_EQ(version, result.version);
+ }
+ }
+
+ // --- StateMachine Implementation ---
+ protected:
+ virtual optional<hsm::TestState> GetUserParentState(
+ hsm::TestState state) const SB_OVERRIDE {
+ switch (state) {
+ case hsm::kStateS1:
+ case hsm::kStateS2:
+ return hsm::kStateS0;
+ case hsm::kStateS11:
+ return hsm::kStateS1;
+ case hsm::kStateS21:
+ return hsm::kStateS2;
+ case hsm::kStateS211:
+ return hsm::kStateS21;
+ default:
+ return nullopt;
+ }
+ }
+
+ virtual optional<hsm::TestState> GetUserInitialSubstate(
+ hsm::TestState state) const SB_OVERRIDE {
+ switch (state) {
+ case hsm::kStateS0:
+ return hsm::kStateS1;
+ case hsm::kStateS1:
+ return hsm::kStateS11;
+ case hsm::kStateS2:
+ return hsm::kStateS21;
+ case hsm::kStateS21:
+ return hsm::kStateS211;
+ default:
+ return nullopt;
+ }
+ }
+
+ virtual hsm::TestState GetUserInitialState() const SB_OVERRIDE {
+ return hsm::kStateS0;
+ }
+
+ virtual const char* GetUserStateString(hsm::TestState state) const
+ SB_OVERRIDE {
+ switch (state) {
+ case hsm::kStateS0:
+ return "S0";
+ case hsm::kStateS1:
+ return "S1";
+ case hsm::kStateS11:
+ return "S11";
+ case hsm::kStateS2:
+ return "S2";
+ case hsm::kStateS21:
+ return "S21";
+ case hsm::kStateS211:
+ return "S211";
+ case hsm::kStateT0:
+ return "T0";
+ default:
+ return NULL;
+ }
+ }
+
+ virtual const char* GetUserEventString(hsm::TestEvent event) const
+ SB_OVERRIDE {
+ switch (event) {
+ case hsm::kEventA:
+ return "A";
+ case hsm::kEventB:
+ return "B";
+ case hsm::kEventC:
+ return "C";
+ case hsm::kEventD:
+ return "D";
+ case hsm::kEventE:
+ return "E";
+ case hsm::kEventF:
+ return "F";
+ case hsm::kEventG:
+ return "G";
+ case hsm::kEventH:
+ return "H";
+ case hsm::kEventI:
+ return "I";
+ case hsm::kEventJ:
+ return "J";
+ default:
+ return NULL;
+ }
+ }
+
+ virtual Result HandleUserStateEvent(hsm::TestState state,
+ hsm::TestEvent event,
+ void* data) SB_OVERRIDE {
+#if STATE_MACHINE_TEST_DEBUG
+ SB_DLOG(INFO) << __FUNCTION__ << "(" << GetStateString(state) << ", "
+ << GetEventString(event) << ", 0x" << std::hex << data
+ << ");";
+#endif // STATE_MACHINE_TEST_DEBUG
+
+ Result result(kNotHandled);
+ switch (state) {
+ case hsm::kStateS0:
+ switch (event) {
+ case hsm::kEventE:
+ result = hsm::kStateS211;
+ break;
+ case hsm::kEventJ:
+ result = hsm::kStateT0;
+ break;
+ default:
+ // Not Handled
+ break;
+ }
+ break;
+
+ case hsm::kStateS1:
+ switch (event) {
+ case hsm::kEventA:
+ result = Result(hsm::kStateS1, true);
+ break;
+ case hsm::kEventB:
+ result = hsm::kStateS11;
+ break;
+ case hsm::kEventC:
+ result = hsm::kStateS2;
+ break;
+ case hsm::kEventD:
+ result = hsm::kStateS0;
+ break;
+ case hsm::kEventF:
+ result = hsm::kStateS211;
+ break;
+ default:
+ // Not Handled
+ break;
+ }
+ break;
+
+ case hsm::kStateS11:
+ switch (event) {
+ case hsm::kEventG:
+ result = hsm::kStateS211;
+ break;
+ case hsm::kEventH:
+ if (foo_) {
+ foo_ = false;
+ result = kHandled;
+ break;
+ }
+ break;
+ case hsm::kEventI:
+ // Inject another I every other time I is handled so every I should
+ // ultimately increase event_i_count_ by 2.
+ ++event_i_count_;
+ if (event_i_count_ % 2 == 1) {
+ // This should queue and be run before Handle() returns.
+ Handle(hsm::kEventI);
+ result = hsm::kStateS1;
+ break;
+ } else {
+ result = kHandled;
+ break;
+ }
+ break;
+ default:
+ // Not Handled
+ break;
+ }
+ break;
+
+ case hsm::kStateS2:
+ switch (event) {
+ case hsm::kEventC:
+ result = hsm::kStateS1;
+ break;
+ case hsm::kEventF:
+ result = hsm::kStateS11;
+ break;
+ default:
+ // Not Handled
+ break;
+ }
+ break;
+
+ case hsm::kStateS21:
+ switch (event) {
+ case hsm::kEventB:
+ result = hsm::kStateS211;
+ break;
+ case hsm::kEventH:
+ if (!foo_) {
+ foo_ = true;
+ result = Result(hsm::kStateS21, true);
+ break;
+ }
+ break;
+ default:
+ // Not Handled
+ break;
+ }
+ break;
+
+ case hsm::kStateS211:
+ switch (event) {
+ case hsm::kEventD:
+ result = hsm::kStateS21;
+ break;
+ case hsm::kEventG:
+ result = hsm::kStateS0;
+ break;
+ default:
+ // Not Handled
+ break;
+ }
+ break;
+
+ case hsm::kStateT0:
+ switch (event) {
+ case hsm::kEventJ:
+ result = hsm::kStateS0;
+ break;
+ default:
+ // Not Handled
+ break;
+ }
+ break;
+
+ default:
+ // Not Handled
+ break;
+ }
+
+ if (result.is_handled) {
+ AddEvent(state, event, data, hsm::kHsmHandled);
+ }
+
+ return result;
+ }
+
+ virtual void HandleUserStateEnter(hsm::TestState state) SB_OVERRIDE {
+#if STATE_MACHINE_TEST_DEBUG
+ SB_DLOG(INFO) << __FUNCTION__ << "(" << GetStateString(state)
+ << ", ENTER);";
+#endif // STATE_MACHINE_TEST_DEBUG
+
+ AddEvent(state, nullopt, NULL, hsm::kHsmEnter);
+ }
+
+ virtual void HandleUserStateExit(hsm::TestState state) SB_OVERRIDE {
+#if STATE_MACHINE_TEST_DEBUG
+ SB_DLOG(INFO) << __FUNCTION__ << "(" << GetStateString(state) << ", EXIT);";
+#endif // STATE_MACHINE_TEST_DEBUG
+
+ AddEvent(state, nullopt, NULL, hsm::kHsmExit);
+ }
+
+ private:
+ // Adds a new record to the result list.
+ void AddEvent(hsm::TestState state,
+ optional<hsm::TestEvent> event,
+ void* data,
+ hsm::HsmEvent hsm_event) {
+ ResultEvent result_event = {this->state(), data, state,
+ event, hsm_event, this->version()};
+ results.push_back(result_event);
+ }
+};
+
+// --- Test Definitions ---
+
+// This test validates that a state machine will initialize itself when it
+// handles its first event, even if the user has not explicitly called
+// initialize.
+TEST(StateMachineTest, AutoInit) {
+ TestHsm hsm;
+
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventA);
+
+ // The HSM should Auto-Initialize
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS0);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS11);
+
+ // Then it should handle the event
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS1, hsm::kEventA, hsm::kStateS11, 0);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS11);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(1, hsm.version());
+ EXPECT_EQ(hsm::kStateS11, hsm.state());
+}
+
+// This test validates that if Handle() is called from within an event handler,
+// it queues the event rather than trying to Handle the next event
+// reentrantly. This behavior, or something like it, is required to make the
+// state machine truly run-to-completion.
+TEST(StateMachineTest, ReentrantHandle) {
+ TestHsm hsm;
+ hsm.Initialize();
+ EXPECT_EQ(0, hsm.version());
+ hsm.ClearResults();
+
+ // Test a Handle() inside Handle()
+ EXPECT_EQ(0, hsm.event_i_count_);
+ hsm.Handle(hsm::kEventI);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS11, hsm::kEventI, hsm::kStateS11,
+ NULL, 0);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS11, hsm::kEventI, hsm::kStateS11,
+ NULL, 1);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(1, hsm.version());
+ EXPECT_EQ(2, hsm.event_i_count_);
+}
+
+// This test validates that every meaningful event in every state in the test
+// state machine behaves as expected. This should cover all normal operation of
+// the state machine framework, except what is extracted into their own test
+// cases above.
+TEST(StateMachineTest, KitNKaboodle) {
+ TestHsm hsm;
+
+ // Test the initial state
+ EXPECT_EQ(0, hsm.version());
+ hsm.Initialize();
+ EXPECT_EQ(0, hsm.version());
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS0);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS11);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS11, hsm.state());
+
+ // Test IsIn
+ EXPECT_TRUE(hsm.IsIn(hsm::kStateS11));
+ EXPECT_TRUE(hsm.IsIn(hsm::kStateS1));
+ EXPECT_TRUE(hsm.IsIn(hsm::kStateS0));
+ EXPECT_FALSE(hsm.IsIn(hsm::kStateS2));
+ EXPECT_FALSE(hsm.IsIn(hsm::kStateS21));
+ EXPECT_FALSE(hsm.IsIn(hsm::kStateS211));
+
+ // State: S11, Event: A
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventA);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS1, hsm::kEventA, hsm::kStateS11, 0);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS11);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(1, hsm.version());
+ EXPECT_EQ(hsm::kStateS11, hsm.state());
+
+ // State: S11, Event: B
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventB);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS1, hsm::kEventB, hsm::kStateS11,
+ NULL, 1);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS11);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(2, hsm.version());
+ EXPECT_EQ(hsm::kStateS11, hsm.state());
+
+ // State: S11, Event: D
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventD);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS1, hsm::kEventD, hsm::kStateS11,
+ NULL, 2);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS11);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(3, hsm.version());
+ EXPECT_EQ(hsm::kStateS11, hsm.state());
+
+ // State: S11, Event: H (foo == true)
+ hsm.ClearResults();
+ EXPECT_TRUE(hsm.foo_);
+ hsm.Handle(hsm::kEventH);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS11, hsm::kEventH, hsm::kStateS11,
+ NULL, 3);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(3, hsm.version());
+ EXPECT_EQ(hsm::kStateS11, hsm.state());
+ EXPECT_FALSE(hsm.foo_);
+
+ // State: S11, Event: H (foo == false)
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventH);
+ EXPECT_FALSE(hsm.foo_);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(3, hsm.version());
+ EXPECT_EQ(hsm::kStateS11, hsm.state());
+
+ // State: S11, Event: C
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventC);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS1, hsm::kEventC, hsm::kStateS11,
+ NULL, 3);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS2);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS211);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(4, hsm.version());
+ EXPECT_EQ(hsm::kStateS211, hsm.state());
+
+ // State: S211, Event: A
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventA);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS211, hsm.state());
+
+ // State: S211, Event: B
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventB);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS21, hsm::kEventB, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS211);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS211, hsm.state());
+
+ // State: S211, Event: D
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventD);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS211, hsm::kEventD, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS211);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS211, hsm.state());
+
+ // State: S211, Event: E
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventE);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS0, hsm::kEventE, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS2);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS2);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS211);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS211, hsm.state());
+
+ // State: S211, Event: F
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventF);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS2, hsm::kEventF, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS2);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS11);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS11, hsm.state());
+
+ // State: S11, Event: E
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventE);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS0, hsm::kEventE, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS2);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS211);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS211, hsm.state());
+
+ // State: S211, Event: G
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventG);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS211, hsm::kEventG, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS2);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS11);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS11, hsm.state());
+
+ // State: S11, Event: F
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventF);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS1, hsm::kEventF, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS2);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS211);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS211, hsm.state());
+
+ // State: S211, Event: H (foo == false)
+ EXPECT_FALSE(hsm.foo_);
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventH);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS21, hsm::kEventH, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS211);
+ EXPECT_TRUE(hsm.foo_);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS211, hsm.state());
+
+ // State: S211, Event: H (foo == true)
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventH);
+ EXPECT_TRUE(hsm.foo_);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS211, hsm.state());
+
+ // State: S211, Event: C
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventC);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS2, hsm::kEventC, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS2);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS11);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS11, hsm.state());
+
+ // State: S11, Event: G
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventG);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS11, hsm::kEventG, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS2);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS211);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS211, hsm.state());
+
+ // State: S211, Event: J
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventJ);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS0, hsm::kEventJ, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS211);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS2);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS0);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateT0);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateT0, hsm.state());
+
+ // State: T0, Event: J
+ hsm.ClearResults();
+ hsm.Handle(hsm::kEventJ);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateT0, hsm::kEventJ);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateT0);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS0);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS11);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS11, hsm.state());
+
+ // Test that event data gets passed through to the handler
+ hsm.ClearResults();
+ void* data = reinterpret_cast<void*>(7);
+ hsm.Handle(hsm::kEventC, data);
+ hsm.Expect(hsm::kHsmHandled, hsm::kStateS1, hsm::kEventC, hsm::kStateS11,
+ data);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS11);
+ hsm.Expect(hsm::kHsmExit, hsm::kStateS1);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS2);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS21);
+ hsm.Expect(hsm::kHsmEnter, hsm::kStateS211);
+ EXPECT_EQ(0, hsm.results.size());
+ EXPECT_EQ(hsm::kStateS211, hsm.state());
+}
+
+} // namespace
+} // namespace starboard
diff --git a/src/starboard/nplb/storage_delete_record_test.cc b/src/starboard/nplb/storage_delete_record_test.cc
index 16ade12..ef0fc73 100644
--- a/src/starboard/nplb/storage_delete_record_test.cc
+++ b/src/starboard/nplb/storage_delete_record_test.cc
@@ -14,6 +14,7 @@
// Sunny Day cases tested in the read/write tests.
+#include "starboard/nplb/file_helpers.h"
#include "starboard/storage.h"
#include "starboard/user.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,10 +23,25 @@
namespace nplb {
namespace {
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+
+TEST(SbStorageDeleteRecordTest, RainyDayInvalidUserValidName) {
+ EXPECT_FALSE(SbStorageDeleteRecord(
+ kSbUserInvalid, ScopedRandomFile::MakeRandomFilename().c_str()));
+}
+
+TEST(SbStorageDeleteRecordTest, RainyDayInvalidUserNullName) {
+ EXPECT_FALSE(SbStorageDeleteRecord(kSbUserInvalid, NULL));
+}
+
+#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+
TEST(SbStorageDeleteRecordTest, RainyDayInvalidUser) {
EXPECT_FALSE(SbStorageDeleteRecord(kSbUserInvalid));
}
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+
} // namespace
} // namespace nplb
} // namespace starboard
diff --git a/src/starboard/nplb/storage_helpers.h b/src/starboard/nplb/storage_helpers.h
index efc422e..c587203 100644
--- a/src/starboard/nplb/storage_helpers.h
+++ b/src/starboard/nplb/storage_helpers.h
@@ -28,23 +28,49 @@
// Deletes the storage for the current user.
static SB_C_INLINE void ClearStorageRecord() {
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ SbStorageDeleteRecord(SbUserGetCurrent(), NULL);
+#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
SbStorageDeleteRecord(SbUserGetCurrent());
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
}
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+// Deletes the named storage record for the current user.
+static SB_C_INLINE void ClearStorageRecord(const char* name) {
+ SbStorageDeleteRecord(SbUserGetCurrent(), name);
+}
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+
// Opens the storage record for the current user, validating that it is valid.
static SB_C_INLINE SbStorageRecord OpenStorageRecord() {
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ SbStorageRecord record = SbStorageOpenRecord(SbUserGetCurrent(), NULL);
+#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
SbStorageRecord record = SbStorageOpenRecord(SbUserGetCurrent());
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
EXPECT_TRUE(SbStorageIsValidRecord(record));
return record;
}
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+// Opens the named storage record for the current user, validating that it is
+// valid.
+static SB_C_INLINE SbStorageRecord OpenStorageRecord(const char* name) {
+ SbStorageRecord record = SbStorageOpenRecord(SbUserGetCurrent(), name);
+ EXPECT_TRUE(SbStorageIsValidRecord(record));
+ return record;
+}
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+
// Writes a standard pattern of |size| bytes into the given open storage
// |record|.
static SB_C_INLINE void WriteStorageRecord(SbStorageRecord record,
- int64_t size) {
+ int64_t size,
+ int64_t pattern_offset = 0) {
char* data = new char[size];
for (int64_t i = 0; i < size; ++i) {
- data[i] = static_cast<char>(i + 2 % 0xFF);
+ data[i] = static_cast<char>((i + pattern_offset + 2) % 0xFF);
}
EXPECT_TRUE(SbStorageWriteRecord(record, data, size));
EXPECT_EQ(size, SbStorageGetRecordSize(record));
@@ -65,15 +91,18 @@
// WriteStorageRecord) to start at |offset| and continue for |length|, and the
// rest of the buffer, before and after, should be set to 0.
static SB_C_INLINE void CheckStorageBuffer(char* data,
- int64_t offset,
- int64_t length,
- int64_t total) {
+ int64_t offset,
+ int64_t length,
+ int64_t total,
+ int64_t pattern_offset = 0) {
for (int64_t i = 0; i < offset; ++i) {
EXPECT_EQ(0, data[i]) << "i = " << i;
}
for (int64_t i = 0; i < length; ++i) {
- EXPECT_EQ(static_cast<char>(i + 2 % 0xFF), data[i + offset]) << "i=" << i;
+ EXPECT_EQ(static_cast<char>((i + pattern_offset + 2) % 0xFF),
+ data[i + offset])
+ << "i=" << i;
}
for (int64_t i = length + offset; i < total; ++i) {
@@ -86,15 +115,16 @@
// read bytes is |expected_length| and then checks the buffer for the expected
// pattern written in WriteStorageRecord over the expected range of the buffer.
static SB_C_INLINE void ReadAndCheckStorage(SbStorageRecord record,
- int64_t offset,
- int64_t expected_length,
- int64_t length,
- int64_t total) {
+ int64_t offset,
+ int64_t expected_length,
+ int64_t length,
+ int64_t total,
+ int64_t pattern_offset = 0) {
char* data = new char[total];
SbMemorySet(data, 0, total);
EXPECT_EQ(expected_length,
SbStorageReadRecord(record, data + offset, length));
- CheckStorageBuffer(data, offset, expected_length, total);
+ CheckStorageBuffer(data, offset, expected_length, total, pattern_offset);
delete[] data;
}
diff --git a/src/starboard/nplb/storage_open_record_test.cc b/src/starboard/nplb/storage_open_record_test.cc
index ec1e588..c935e4a 100644
--- a/src/starboard/nplb/storage_open_record_test.cc
+++ b/src/starboard/nplb/storage_open_record_test.cc
@@ -14,6 +14,7 @@
// Sunny Day cases tested in the read/write tests.
+#include "starboard/nplb/file_helpers.h"
#include "starboard/storage.h"
#include "starboard/user.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,10 +23,26 @@
namespace nplb {
namespace {
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+
+TEST(SbStorageOpenRecordTest, RainyDayInvalidUserValidName) {
+ EXPECT_FALSE(SbStorageIsValidRecord(SbStorageOpenRecord(
+ kSbUserInvalid, ScopedRandomFile::MakeRandomFilename().c_str())));
+}
+
+TEST(SbStorageOpenRecordTest, RainyDayInvalidUserNullName) {
+ EXPECT_FALSE(
+ SbStorageIsValidRecord(SbStorageOpenRecord(kSbUserInvalid, NULL)));
+}
+
+#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+
TEST(SbStorageOpenRecordTest, RainyDayInvalidUser) {
EXPECT_FALSE(SbStorageIsValidRecord(SbStorageOpenRecord(kSbUserInvalid)));
}
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+
} // namespace
} // namespace nplb
} // namespace starboard
diff --git a/src/starboard/nplb/storage_read_record_test.cc b/src/starboard/nplb/storage_read_record_test.cc
index 4f11a0d..336e716 100644
--- a/src/starboard/nplb/storage_read_record_test.cc
+++ b/src/starboard/nplb/storage_read_record_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "starboard/nplb/file_helpers.h"
#include "starboard/nplb/storage_helpers.h"
#include "starboard/storage.h"
#include "starboard/user.h"
@@ -22,19 +23,26 @@
namespace {
TEST(SbStorageReadRecordTest, SunnyDay) {
+ int64_t pattern = 0;
ClearStorageRecord();
SbStorageRecord record = OpenStorageRecord();
- WriteStorageRecord(record, kStorageSize);
+ WriteStorageRecord(record, kStorageSize, pattern);
ReadAndCheckStorage(record, kStorageOffset, kStorageSize, kStorageSize2,
- kStorageSize2);
+ kStorageSize2, pattern);
+ pattern = 6;
+ // Write different data and check again.
+ WriteStorageRecord(record, kStorageSize, pattern);
+ ReadAndCheckStorage(record, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern);
EXPECT_TRUE(SbStorageCloseRecord(record));
// Now we'll open again and make sure it is the same.
record = OpenStorageRecord();
ReadAndCheckStorage(record, kStorageOffset, kStorageSize, kStorageSize2,
- kStorageSize2);
+ kStorageSize2, pattern);
EXPECT_TRUE(SbStorageCloseRecord(record));
+ ClearStorageRecord();
}
TEST(SbStorageReadRecordTest, SunnyDaySmallBuffer) {
@@ -46,12 +54,118 @@
EXPECT_TRUE(SbStorageCloseRecord(record));
}
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+TEST(SbStorageReadRecordTest, SunnyDayNamed) {
+ int64_t pattern = 0;
+ std::string name = ScopedRandomFile::MakeRandomFilename();
+ ClearStorageRecord(name.c_str());
+
+ SbStorageRecord record = OpenStorageRecord(name.c_str());
+ WriteStorageRecord(record, kStorageSize, pattern);
+ ReadAndCheckStorage(record, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern);
+ // Write different data and check again.
+ pattern = 6;
+ WriteStorageRecord(record, kStorageSize, pattern);
+ ReadAndCheckStorage(record, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern);
+ EXPECT_TRUE(SbStorageCloseRecord(record));
+
+ // Now we'll open again and make sure it is the same.
+ record = OpenStorageRecord(name.c_str());
+ ReadAndCheckStorage(record, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern);
+ EXPECT_TRUE(SbStorageCloseRecord(record));
+
+ ClearStorageRecord(name.c_str());
+}
+
+TEST(SbStorageReadRecordTest, SunnyDayNamed2) {
+ int64_t pattern1 = 2;
+ int64_t pattern2 = 8;
+ std::string name1 = ScopedRandomFile::MakeRandomFilename();
+ std::string name2 = ScopedRandomFile::MakeRandomFilename();
+ ClearStorageRecord(name1.c_str());
+ ClearStorageRecord(name2.c_str());
+
+ SbStorageRecord record1 = OpenStorageRecord(name1.c_str());
+ SbStorageRecord record2 = OpenStorageRecord(name2.c_str());
+ WriteStorageRecord(record1, kStorageSize, pattern1);
+ WriteStorageRecord(record2, kStorageSize, pattern2);
+ ReadAndCheckStorage(record1, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern1);
+ ReadAndCheckStorage(record2, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern2);
+ EXPECT_TRUE(SbStorageCloseRecord(record1));
+ EXPECT_TRUE(SbStorageCloseRecord(record2));
+
+ // Now we'll open again and make sure they are the same.
+ record1 = OpenStorageRecord(name1.c_str());
+ record2 = OpenStorageRecord(name2.c_str());
+ ReadAndCheckStorage(record1, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern1);
+ ReadAndCheckStorage(record2, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern2);
+ EXPECT_TRUE(SbStorageCloseRecord(record1));
+ EXPECT_TRUE(SbStorageCloseRecord(record2));
+
+ ClearStorageRecord(name1.c_str());
+ ClearStorageRecord(name2.c_str());
+}
+
+TEST(SbStorageReadRecordTest, SunnyDayNamed3) {
+ int64_t pattern1 = 3;
+ int64_t pattern2 = 5;
+ int64_t pattern3 = 7;
+ std::string name1 = ScopedRandomFile::MakeRandomFilename();
+ std::string name2 = ScopedRandomFile::MakeRandomFilename();
+ ClearStorageRecord(name1.c_str());
+ ClearStorageRecord(name2.c_str());
+ ClearStorageRecord();
+
+ SbStorageRecord record1 = OpenStorageRecord(name1.c_str());
+ SbStorageRecord record2 = OpenStorageRecord(name2.c_str());
+ SbStorageRecord record3 = OpenStorageRecord();
+ WriteStorageRecord(record1, kStorageSize, pattern1);
+ WriteStorageRecord(record2, kStorageSize, pattern2);
+ WriteStorageRecord(record3, kStorageSize, pattern3);
+ ReadAndCheckStorage(record1, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern1);
+ ReadAndCheckStorage(record2, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern2);
+ ReadAndCheckStorage(record3, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern3);
+ EXPECT_TRUE(SbStorageCloseRecord(record1));
+ EXPECT_TRUE(SbStorageCloseRecord(record2));
+ EXPECT_TRUE(SbStorageCloseRecord(record3));
+
+ // Now we'll open again and make sure they are the same.
+ record1 = OpenStorageRecord(name1.c_str());
+ record2 = OpenStorageRecord(name2.c_str());
+ record3 = OpenStorageRecord();
+ ReadAndCheckStorage(record1, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern1);
+ ReadAndCheckStorage(record2, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern2);
+ ReadAndCheckStorage(record3, kStorageOffset, kStorageSize, kStorageSize2,
+ kStorageSize2, pattern3);
+ EXPECT_TRUE(SbStorageCloseRecord(record1));
+ EXPECT_TRUE(SbStorageCloseRecord(record2));
+ EXPECT_TRUE(SbStorageCloseRecord(record3));
+
+ ClearStorageRecord(name1.c_str());
+ ClearStorageRecord(name2.c_str());
+ ClearStorageRecord();
+}
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+
TEST(SbStorageReadRecordTest, SunnyDayNonexistant) {
ClearStorageRecord();
SbStorageRecord record = OpenStorageRecord();
ReadAndCheckStorage(record, kStorageOffset, 0, 0, kStorageSize);
EXPECT_TRUE(SbStorageCloseRecord(record));
+ ClearStorageRecord();
}
TEST(SbStorageReadRecordTest, RainyDayInvalidRecord) {
diff --git a/src/starboard/nplb/system_get_path_test.cc b/src/starboard/nplb/system_get_path_test.cc
index ea36035..9d2bb59 100644
--- a/src/starboard/nplb/system_get_path_test.cc
+++ b/src/starboard/nplb/system_get_path_test.cc
@@ -14,6 +14,9 @@
#include <string.h>
+#include "starboard/memory.h"
+#include "starboard/nplb/file_helpers.h"
+#include "starboard/string.h"
#include "starboard/system.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -29,15 +32,15 @@
bool expected_result,
int line) {
#define LOCAL_CONTEXT "Context : id=" << id << ", line=" << line;
- char path[kPathSize] = {0};
- memset(path, 0xCD, kPathSize);
+ char path[kPathSize];
+ SbMemorySet(path, 0xCD, kPathSize);
bool result = SbSystemGetPath(id, path, kPathSize);
if (expect_result) {
EXPECT_EQ(expected_result, result) << LOCAL_CONTEXT;
}
if (result) {
EXPECT_NE('\xCD', path[0]) << LOCAL_CONTEXT;
- int len = static_cast<int>(strlen(path));
+ int len = static_cast<int>(SbStringGetLength(path));
EXPECT_GT(len, 0) << LOCAL_CONTEXT;
} else {
EXPECT_EQ('\xCD', path[0]) << LOCAL_CONTEXT;
@@ -47,6 +50,7 @@
TEST(SbSystemGetPathTest, ReturnsRequiredPaths) {
BasicTest(kSbSystemPathContentDirectory, true, true, __LINE__);
+ BasicTest(kSbSystemPathCacheDirectory, true, true, __LINE__);
}
TEST(SbSystemGetPathTest, FailsGracefullyZeroBufferLength) {
@@ -75,12 +79,86 @@
BasicTest(kSbSystemPathSourceDirectory, false, false, __LINE__);
BasicTest(kSbSystemPathTempDirectory, false, false, __LINE__);
BasicTest(kSbSystemPathTestOutputDirectory, false, false, __LINE__);
+ BasicTest(kSbSystemPathCacheDirectory, false, false, __LINE__);
#if SB_API_VERSION >= 4
BasicTest(kSbSystemPathFontDirectory, false, false, __LINE__);
BasicTest(kSbSystemPathFontConfigurationDirectory, false, false, __LINE__);
#endif // SB_API_VERSION >= 4
}
+TEST(SbSystemGetPathTest, CanCreateAndRemoveDirectoryInCache) {
+ char path[kPathSize];
+ SbMemorySet(path, 0xCD, kPathSize);
+ bool result = SbSystemGetPath(kSbSystemPathCacheDirectory, path, kPathSize);
+ EXPECT_TRUE(result);
+ if (result) {
+ EXPECT_NE('\xCD', path[0]);
+ // Delete a directory and confirm that it does not exist.
+ std::string sub_path =
+ SB_FILE_SEP_STRING + ScopedRandomFile::MakeRandomFilename();
+ EXPECT_GT(SbStringConcat(path, sub_path.c_str(), kPathSize), 0);
+ EXPECT_TRUE(SbFileDelete(path));
+ EXPECT_FALSE(SbFileExists(path));
+
+ // Create the directory and confirm it exists and can be opened.
+ EXPECT_TRUE(SbDirectoryCreate(path));
+ EXPECT_TRUE(SbFileExists(path));
+ EXPECT_TRUE(SbDirectoryCanOpen(path));
+ SbDirectory directory = SbDirectoryOpen(path, NULL);
+ EXPECT_TRUE(SbDirectoryIsValid(directory));
+
+ // Lastly, close and delete the directory.
+ EXPECT_TRUE(SbDirectoryClose(directory));
+ EXPECT_TRUE(SbFileDelete(path));
+ EXPECT_FALSE(SbFileExists(path));
+ }
+}
+TEST(SbSystemGetPathTest, CanWriteAndReadCache) {
+ char path[kPathSize];
+ SbMemorySet(path, 0xCD, kPathSize);
+ bool result = SbSystemGetPath(kSbSystemPathCacheDirectory, path, kPathSize);
+ EXPECT_TRUE(result);
+ if (result) {
+ EXPECT_NE('\xCD', path[0]);
+ int len = static_cast<int>(SbStringGetLength(path));
+ EXPECT_GT(len, 0);
+ // Delete a file and confirm that it does not exist.
+ std::string sub_path =
+ SB_FILE_SEP_STRING + ScopedRandomFile::MakeRandomFilename();
+ EXPECT_GT(SbStringConcat(path, sub_path.c_str(), kPathSize), 0);
+ EXPECT_TRUE(SbFileDelete(path));
+ EXPECT_FALSE(SbFileExists(path));
+
+ // Write to the file and check that we can read from it.
+ std::string content_to_write = "test content";
+ {
+ starboard::ScopedFile test_file_writer(
+ path, kSbFileCreateAlways | kSbFileWrite, NULL, NULL);
+ EXPECT_GT(
+ test_file_writer.WriteAll(content_to_write.c_str(),
+ static_cast<int>(content_to_write.size())),
+ 0);
+ }
+ EXPECT_TRUE(SbFileExists(path));
+ SbFileInfo info;
+ EXPECT_TRUE(SbFileGetPathInfo(path, &info));
+ const int kFileSize = static_cast<int>(info.size);
+ EXPECT_GT(kFileSize, 0);
+ const int kBufferLength = 16 * 1024;
+ char content_read[kBufferLength] = {0};
+ {
+ starboard::ScopedFile test_file_reader(
+ path, kSbFileOpenOnly | kSbFileRead, NULL, NULL);
+ EXPECT_GT(test_file_reader.ReadAll(content_read, kFileSize), 0);
+ }
+ EXPECT_EQ(content_read, content_to_write);
+
+ // Lastly, delete the file.
+ EXPECT_TRUE(SbFileDelete(path));
+ EXPECT_FALSE(SbFileExists(path));
+ }
+}
+
} // namespace
} // namespace nplb
} // namespace starboard
diff --git a/src/starboard/raspi/shared/configuration_public.h b/src/starboard/raspi/shared/configuration_public.h
index dc0b878..76ea308 100644
--- a/src/starboard/raspi/shared/configuration_public.h
+++ b/src/starboard/raspi/shared/configuration_public.h
@@ -396,6 +396,13 @@
// The maximum number of users that can be signed in at the same time.
#define SB_USER_MAX_SIGNED_IN 1
+// The Raspberry Pi does not apparently align fields in a heap-allocated struct
+// by over 16 bytes.
+#define SB_HAS_QUIRK_DOES_NOT_ALIGN_FIELDS_IN_HEAP_OVER_16_BYTES 1
+
+// The Raspberry Pi does not apparently align stack variables by over 16 bytes.
+#define SB_HAS_QUIRK_DOES_NOT_STACK_ALIGN_OVER_16_BYTES 1
+
// --- Timing API ------------------------------------------------------------
// Whether this platform has an API to retrieve how long the current thread
diff --git a/src/starboard/raspi/shared/starboard_platform.gypi b/src/starboard/raspi/shared/starboard_platform.gypi
index 1170664..030fec1 100644
--- a/src/starboard/raspi/shared/starboard_platform.gypi
+++ b/src/starboard/raspi/shared/starboard_platform.gypi
@@ -79,6 +79,7 @@
'<(DEPTH)/starboard/shared/dlmalloc/memory_map.cc',
'<(DEPTH)/starboard/shared/dlmalloc/memory_reallocate_unchecked.cc',
'<(DEPTH)/starboard/shared/dlmalloc/memory_unmap.cc',
+ '<(DEPTH)/starboard/shared/dlmalloc/system_get_used_cpu_memory.cc',
'<(DEPTH)/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc',
'<(DEPTH)/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h',
'<(DEPTH)/starboard/shared/ffmpeg/ffmpeg_audio_resampler.cc',
@@ -138,7 +139,6 @@
'<(DEPTH)/starboard/shared/linux/system_get_random_data.cc',
'<(DEPTH)/starboard/shared/linux/system_get_stack.cc',
'<(DEPTH)/starboard/shared/linux/system_get_total_cpu_memory.cc',
- '<(DEPTH)/starboard/shared/linux/system_get_used_cpu_memory.cc',
'<(DEPTH)/starboard/shared/linux/system_is_debugger_attached.cc',
'<(DEPTH)/starboard/shared/linux/system_symbolize.cc',
'<(DEPTH)/starboard/shared/linux/thread_get_id.cc',
diff --git a/src/starboard/shared/alsa/alsa_audio_sink_type.cc b/src/starboard/shared/alsa/alsa_audio_sink_type.cc
index 25688a5..e0cbd79 100644
--- a/src/starboard/shared/alsa/alsa_audio_sink_type.cc
+++ b/src/starboard/shared/alsa/alsa_audio_sink_type.cc
@@ -99,6 +99,11 @@
}
#endif // SB_API_VERSION >= 4
+ void SetVolume(double volume) SB_OVERRIDE {
+ ScopedLock lock(mutex_);
+ volume_ = volume;
+ }
+
bool is_valid() { return playback_handle_ != NULL; }
private:
@@ -124,6 +129,7 @@
void* context_;
double playback_rate_;
+ double volume_;
std::vector<uint8_t> resample_buffer_;
int channels_;
@@ -157,6 +163,7 @@
void* context)
: type_(type),
playback_rate_(1.0),
+ volume_(1.0),
resample_buffer_(channels * kFramesPerRequest *
GetSampleSize(sample_type)),
channels_(channels),
@@ -272,6 +279,7 @@
bool AlsaAudioSink::PlaybackLoop() {
SB_DLOG(INFO) << "alsa::AlsaAudioSink enters playback loop";
+ // TODO: Also handle |volume_| here.
double playback_rate = 1.0;
for (;;) {
int delayed_frame = AlsaGetBufferedFrames(playback_handle_);
diff --git a/src/starboard/shared/dlmalloc/system_get_used_cpu_memory.cc b/src/starboard/shared/dlmalloc/system_get_used_cpu_memory.cc
new file mode 100644
index 0000000..0fe2662
--- /dev/null
+++ b/src/starboard/shared/dlmalloc/system_get_used_cpu_memory.cc
@@ -0,0 +1,39 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/memory.h"
+
+#include "starboard/shared/dlmalloc/page_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Returns the number of bytes obtained from the system. The total
+// number of bytes allocated by malloc, realloc etc., is less than this
+// value. Unlike mallinfo, this function returns only a precomputed
+// result, so can be called frequently to monitor memory consumption.
+// Even if locks are otherwise defined, this function does not use them,
+// so results might not be up to date.
+//
+// See http://gee.cs.oswego.edu/pub/misc/malloc.h for more details.
+size_t SB_ALLOCATOR(malloc_footprint)();
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+int64_t SbSystemGetUsedCPUMemory() {
+ return static_cast<int64_t>(SB_ALLOCATOR(malloc_footprint)());
+}
diff --git a/src/starboard/shared/linux/dev_input/dev_input.cc b/src/starboard/shared/linux/dev_input/dev_input.cc
index bc3202e..d0bd7fe 100644
--- a/src/starboard/shared/linux/dev_input/dev_input.cc
+++ b/src/starboard/shared/linux/dev_input/dev_input.cc
@@ -24,6 +24,8 @@
#include <vector>
#include <algorithm>
+#include <cmath>
+#include <map>
#include <string>
#include "starboard/configuration.h"
@@ -44,15 +46,44 @@
using ::starboard::shared::starboard::Application;
typedef int FileDescriptor;
-const FileDescriptor kInvalidFd = -1;
-const int kKeyboardDeviceId = 1;
+const FileDescriptor kInvalidFd = -ENODEV;
+
+enum InputDeviceIds {
+ kKeyboardDeviceId = 1,
+ kGamepadDeviceId,
+};
+
+enum TouchPadPositionState {
+ kTouchPadPositionNone = 0,
+ kTouchPadPositionX = 1,
+ kTouchPadPositionY = 2,
+ kTouchPadPositionAll = kTouchPadPositionX | kTouchPadPositionY
+};
+
+struct InputDeviceInfo {
+ InputDeviceInfo() : fd(-1), touchpad_position_state(kTouchPadPositionNone) {}
+
+ // File descriptor open for the device
+ FileDescriptor fd;
+ // Absolute Axis info.
+ std::map<int, struct input_absinfo> axis_info;
+ std::map<int, float> axis_value;
+ int touchpad_position_state;
+};
+
+bool IsTouchpadPositionKnown(InputDeviceInfo* device_info) {
+ return device_info->touchpad_position_state == kTouchPadPositionAll;
+}
// Private implementation of DevInput.
class DevInputImpl : public DevInput {
public:
explicit DevInputImpl(SbWindow window);
+ DevInputImpl(SbWindow window, FileDescriptor wake_up_fd);
~DevInputImpl() SB_OVERRIDE;
+ void InitDevInputImpl(SbWindow window);
+
Event* PollNextSystemEvent() SB_OVERRIDE;
Event* WaitForSystemEventWithTimeout(SbTime time) SB_OVERRIDE;
void WakeSystemEventWait() SB_OVERRIDE;
@@ -61,13 +92,27 @@
// Converts an input_event into a kSbEventInput Application::Event. The caller
// is responsible for deleting the returned event.
Event* InputToApplicationEvent(const struct input_event& event,
+ InputDeviceInfo* device_info,
int modifiers);
+ // Converts an input_event containing a key input into a kSbEventInput
+ // Application::Event. The caller is responsible for deleting the returned
+ // event.
+ Event* KeyInputToApplicationEvent(const struct input_event& event,
+ int modifiers);
+
+ // Converts an input_event containing an axis event into a kSbEventInput
+ // Application::Event. The caller is responsible for deleting the returned
+ // event.
+ Event* AxisInputToApplicationEvent(const struct input_event& event,
+ InputDeviceInfo* device_info,
+ int modifiers);
+
// The window to attribute /dev/input events to.
SbWindow window_;
// A set of read-only file descriptor of keyboard input devices.
- std::vector<FileDescriptor> keyboard_fds_;
+ std::vector<InputDeviceInfo> input_devices_;
// A file descriptor of the write end of a pipe that can be written to from
// any thread to wake up this waiter in a thread-safe manner.
@@ -76,6 +121,8 @@
// A file descriptor of the read end of a pipe that this waiter will wait on
// to allow it to be signalled safely from other threads.
FileDescriptor wakeup_read_fd_;
+
+ FileDescriptor wake_up_fd_;
};
// Helper class to manage a file descriptor set.
@@ -126,16 +173,12 @@
case KEY_PAGEDOWN:
return kSbKeyNext;
case KEY_LEFT:
- case BTN_DPAD_LEFT:
return kSbKeyLeft;
case KEY_RIGHT:
- case BTN_DPAD_RIGHT:
return kSbKeyRight;
case KEY_DOWN:
- case BTN_DPAD_DOWN:
return kSbKeyDown;
case KEY_UP:
- case BTN_DPAD_UP:
return kSbKeyUp;
case KEY_ESC:
return kSbKeyEscape;
@@ -374,6 +417,49 @@
return kSbKeyBrightnessDown;
case KEY_BRIGHTNESSUP:
return kSbKeyBrightnessUp;
+
+ // Gamepad buttons.
+ // https://www.kernel.org/doc/Documentation/input/gamepad.txt
+ case BTN_TL:
+ return kSbKeyGamepadLeftTrigger;
+ case BTN_TR:
+ return kSbKeyGamepadRightTrigger;
+ case BTN_DPAD_DOWN:
+ return kSbKeyGamepadDPadDown;
+ case BTN_DPAD_UP:
+ return kSbKeyGamepadDPadUp;
+ case BTN_DPAD_LEFT:
+ return kSbKeyGamepadDPadLeft;
+ case BTN_DPAD_RIGHT:
+ return kSbKeyGamepadDPadRight;
+ // The mapping for the buttons below can vary from controller to controller.
+ // TODO: Include button mapping for controllers with different layout.
+ case BTN_B:
+ return kSbKeyGamepad1;
+ case BTN_C:
+ return kSbKeyGamepad2;
+ case BTN_A:
+ return kSbKeyGamepad3;
+ case BTN_X:
+ return kSbKeyGamepad4;
+ case BTN_Y:
+ return kSbKeyGamepadLeftBumper;
+ case BTN_Z:
+ return kSbKeyGamepadRightBumper;
+ case BTN_TL2:
+ return kSbKeyGamepad5;
+ case BTN_TR2:
+ return kSbKeyGamepad6;
+ case BTN_SELECT:
+ return kSbKeyGamepadLeftStick;
+ case BTN_START:
+ return kSbKeyGamepadRightStick;
+ case BTN_MODE:
+ return kSbKeyGamepadSystem;
+ case BTN_THUMBL:
+ return kSbKeyGamepad1;
+ case BTN_THUMBR:
+ return kSbKeyGamepad1;
}
SB_DLOG(WARNING) << "Unknown code: 0x" << std::hex << code;
return kSbKeyUnknown;
@@ -408,21 +494,129 @@
return !!(bitset.at(bit / 8) & (1 << (bit % 8)));
}
-// Searches for the keyboard /dev/input devices, opens them and returns the file
-// descriptors that report keyboard events.
-std::vector<FileDescriptor> GetKeyboardFds() {
- const char kDevicePath[] = "/dev/input";
- SbDirectory directory = SbDirectoryOpen(kDevicePath, NULL);
- std::vector<FileDescriptor> fds;
- if (!SbDirectoryIsValid(directory)) {
- SB_DLOG(ERROR) << __FUNCTION__ << ": No /dev/input support, "
- << "unable to open: " << kDevicePath;
- return fds;
+bool IsAxisFlat(float median, const struct input_absinfo& axis_info) {
+ SB_DCHECK((axis_info.flat * 2) <= (axis_info.maximum - axis_info.minimum));
+ return (axis_info.flat != 0) && (axis_info.value > median - axis_info.flat) &&
+ (axis_info.value < median + axis_info.flat);
+}
+
+float GetAxisValue(const struct input_absinfo& axis_info) {
+ float median =
+ static_cast<float>(axis_info.maximum + axis_info.minimum) / 2.0f;
+ if (IsAxisFlat(median, axis_info))
+ return 0;
+ float range = static_cast<float>(axis_info.maximum - axis_info.minimum);
+ float radius = range / 2.0f;
+ // Scale the axis value to [-1, 1].
+ float axis_value = (static_cast<float>(axis_info.value) - median) / radius;
+
+ if (axis_info.flat != 0) {
+ // Calculate the flat value scaled to [0, 1].
+ float flat = static_cast<float>(axis_info.flat) / range;
+
+ int sign = axis_value < 0.0f ? -1 : 1;
+ // Rescale the range:
+ // [-1.0f, -flat] to [-1.0f, 0.0f] and [flat, 1.0f] to [0.0f, 1.0f].
+ axis_value = (axis_value - sign * flat) / (1 - flat);
+ }
+ return axis_value;
+}
+
+void GetInputDeviceAbsoluteAxisInfo(int axis,
+ const std::vector<uint8_t>& bits,
+ InputDeviceInfo* info) {
+ if (IsBitSet(bits, axis)) {
+ struct input_absinfo axis_info;
+ int result = ioctl(info->fd, EVIOCGABS(axis), &axis_info);
+ if (result < 0) {
+ return;
+ }
+ info->axis_info.insert(std::make_pair(axis, axis_info));
+ info->axis_value.insert(std::make_pair(axis, GetAxisValue(axis_info)));
+ }
+}
+
+void GetInputDeviceInfo(InputDeviceInfo* info) {
+ std::vector<uint8_t> axis_bits(BytesNeededForBitSet(KEY_MAX));
+ int result =
+ ioctl(info->fd, EVIOCGBIT(EV_ABS, axis_bits.size()), axis_bits.data());
+ if (result < 0) {
+ return;
+ }
+
+ GetInputDeviceAbsoluteAxisInfo(ABS_X, axis_bits, info);
+ GetInputDeviceAbsoluteAxisInfo(ABS_Y, axis_bits, info);
+ GetInputDeviceAbsoluteAxisInfo(ABS_Z, axis_bits, info);
+ GetInputDeviceAbsoluteAxisInfo(ABS_RZ, axis_bits, info);
+ GetInputDeviceAbsoluteAxisInfo(ABS_RX, axis_bits, info);
+ GetInputDeviceAbsoluteAxisInfo(ABS_RY, axis_bits, info);
+ GetInputDeviceAbsoluteAxisInfo(ABS_HAT0X, axis_bits, info);
+ GetInputDeviceAbsoluteAxisInfo(ABS_HAT0Y, axis_bits, info);
+ GetInputDeviceAbsoluteAxisInfo(ABS_MT_POSITION_X, axis_bits, info);
+ GetInputDeviceAbsoluteAxisInfo(ABS_MT_POSITION_Y, axis_bits, info);
+ GetInputDeviceAbsoluteAxisInfo(ABS_MT_TRACKING_ID, axis_bits, info);
+ // TODO: Handle multi-touch using ABS_MT_SLOT.
+}
+
+FileDescriptor OpenDeviceIfKeyboardOrGamepad(const char* path) {
+ FileDescriptor fd = open(path, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ // Open can fail if the application doesn't have permission to access
+ // the input device directly.
+ return kInvalidFd;
}
std::vector<uint8_t> ev_bits(BytesNeededForBitSet(EV_CNT));
std::vector<uint8_t> key_bits(BytesNeededForBitSet(KEY_MAX));
+ int result = ioctl(fd, EVIOCGBIT(0, ev_bits.size()), ev_bits.data());
+ if (result < 0) {
+ close(fd);
+ return kInvalidFd;
+ }
+
+ bool has_ev_key = IsBitSet(ev_bits, EV_KEY);
+ if (!has_ev_key) {
+ close(fd);
+ return kInvalidFd;
+ }
+
+ result = ioctl(fd, EVIOCGBIT(EV_KEY, key_bits.size()), key_bits.data());
+ if (result < 0) {
+ close(fd);
+ return kInvalidFd;
+ }
+
+ bool has_key_space = IsBitSet(key_bits, KEY_SPACE);
+ bool has_gamepad_button = IsBitSet(key_bits, BTN_GAMEPAD);
+ if (!has_key_space && !has_gamepad_button) {
+ // If it doesn't have a space key or gamepad button, it may be a mouse.
+ close(fd);
+ return kInvalidFd;
+ }
+
+ result = ioctl(fd, EVIOCGRAB, 1);
+ if (result != 0) {
+ SB_DLOG(ERROR) << __FUNCTION__ << ": "
+ << "Unable to get exclusive access to \"" << path << "\".";
+ close(fd);
+ return kInvalidFd;
+ }
+ return fd;
+}
+
+// Searches for the keyboard and game controller /dev/input devices, opens them
+// and returns the device info with a file descriptor and absolute axis details.
+std::vector<InputDeviceInfo> GetInputDevices() {
+ const char kDevicePath[] = "/dev/input";
+ SbDirectory directory = SbDirectoryOpen(kDevicePath, NULL);
+ std::vector<InputDeviceInfo> input_devices;
+ if (!SbDirectoryIsValid(directory)) {
+ SB_DLOG(ERROR) << __FUNCTION__ << ": No /dev/input support, "
+ << "unable to open: " << kDevicePath;
+ return input_devices;
+ }
+
while (true) {
SbDirectoryEntry entry;
if (!SbDirectoryGetNext(directory, &entry)) {
@@ -438,60 +632,25 @@
continue;
}
- FileDescriptor fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
- if (fd < 0) {
- SB_DLOG(ERROR) << __FUNCTION__ << ": Unable to open \"" << path << "\".";
+ FileDescriptor fd = OpenDeviceIfKeyboardOrGamepad(path.c_str());
+ if (fd == kInvalidFd) {
continue;
}
+ InputDeviceInfo info;
+ info.fd = fd;
+ GetInputDeviceInfo(&info);
- int result = ioctl(fd, EVIOCGBIT(0, ev_bits.size()), ev_bits.data());
-
- if (result < 0) {
- close(fd);
- continue;
- }
-
- bool has_ev_key = IsBitSet(ev_bits, EV_KEY);
-
- if (!has_ev_key) {
- close(fd);
- continue;
- }
-
- result = ioctl(fd, EVIOCGBIT(EV_KEY, key_bits.size()), key_bits.data());
-
- if (result < 0) {
- close(fd);
- continue;
- }
-
- bool has_key_space = IsBitSet(key_bits, KEY_SPACE);
-
- if (!has_key_space) {
- // If it doesn't have a space key, it may be a mouse
- close(fd);
- continue;
- }
-
- result = ioctl(fd, EVIOCGRAB, 1);
- if (result != 0) {
- SB_DLOG(ERROR) << __FUNCTION__ << ": "
- << "Unable to get exclusive access to \"" << path << "\".";
- close(fd);
- continue;
- }
-
- SB_DCHECK(fd != kInvalidFd);
- fds.push_back(fd);
+ SB_DCHECK(info.fd != kInvalidFd);
+ input_devices.push_back(info);
}
- if (fds.empty()) {
+ if (input_devices.empty()) {
SB_DLOG(ERROR) << __FUNCTION__ << ": No /dev/input support. "
- << "No keyboards available.";
+ << "No keyboards or game controllers available.";
}
SbDirectoryClose(directory);
- return fds;
+ return input_devices;
}
// Returns whether |key_code|'s bit is set in the bitmap |map|, assuming
@@ -513,14 +672,14 @@
return 0;
}
-// Polls the given keyboard file descriptor for an input_event. If there are no
+// Polls the given input file descriptor for an input_event. If there are no
// bytes available, assumes that there is no input event to read. If it gets a
// partial event, it will assume that it will be completed, and spins until it
// receives an entire event.
-bool PollKeyboardEvent(FileDescriptor fd,
- struct input_event* out_event,
- int* out_modifiers) {
- if (fd == kInvalidFd) {
+bool PollInputEvent(InputDeviceInfo* device_info,
+ struct input_event* out_event,
+ int* out_modifiers) {
+ if (device_info->fd == kInvalidFd) {
return false;
}
@@ -531,7 +690,7 @@
size_t remaining = kEventSize;
char* buffer = reinterpret_cast<char*>(out_event);
while (remaining > 0) {
- int bytes_read = read(fd, buffer, remaining);
+ int bytes_read = read(device_info->fd, buffer, remaining);
if (bytes_read <= 0) {
if (errno == EAGAIN || bytes_read == 0) {
if (remaining == kEventSize) {
@@ -544,18 +703,18 @@
}
// Some unexpected type of read error occured.
- SB_DLOG(ERROR) << __FUNCTION__ << ": Error reading keyboard: " << errno
+ SB_DLOG(ERROR) << __FUNCTION__ << ": Error reading input: " << errno
<< " - " << strerror(errno);
return false;
}
- SB_DCHECK(bytes_read <= remaining) << "bytes_read=" << bytes_read
- << ", remaining=" << remaining;
+ SB_DCHECK(bytes_read <= remaining)
+ << "bytes_read=" << bytes_read << ", remaining=" << remaining;
remaining -= bytes_read;
buffer += bytes_read;
}
- if (out_event->type != EV_KEY) {
+ if ((out_event->type != EV_KEY) && (out_event->type != EV_ABS)) {
return false;
}
@@ -563,7 +722,7 @@
int modifiers = 0;
char map[(KEY_MAX / 8) + 1] = {0};
errno = 0;
- int result = ioctl(fd, EVIOCGKEY(sizeof(map)), map);
+ int result = ioctl(device_info->fd, EVIOCGKEY(sizeof(map)), map);
if (result != -1) {
modifiers |=
GetModifier(KEY_LEFTSHIFT, KEY_RIGHTSHIFT, kSbKeyModifiersShift, map);
@@ -593,20 +752,35 @@
// Also in starboard/shared/libevent/socket_waiter_internal.cc
// TODO: Consider consolidating.
-int SetNonBlocking(int fd) {
+int SetNonBlocking(FileDescriptor fd) {
int flags = fcntl(fd, F_GETFL, 0);
- if (flags == -1)
+ if (flags == -1) {
flags = 0;
+ }
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
DevInputImpl::DevInputImpl(SbWindow window)
: window_(window),
- keyboard_fds_(GetKeyboardFds()),
+ input_devices_(GetInputDevices()),
wakeup_write_fd_(kInvalidFd),
- wakeup_read_fd_(kInvalidFd) {
+ wakeup_read_fd_(kInvalidFd),
+ wake_up_fd_(kInvalidFd) {
+ InitDevInputImpl(window);
+}
+
+DevInputImpl::DevInputImpl(SbWindow window, FileDescriptor wake_up_fd)
+ : window_(window),
+ input_devices_(GetInputDevices()),
+ wakeup_write_fd_(kInvalidFd),
+ wakeup_read_fd_(kInvalidFd),
+ wake_up_fd_(wake_up_fd) {
+ InitDevInputImpl(window);
+}
+
+void DevInputImpl::InitDevInputImpl(SbWindow window) {
// Initialize wakeup pipe.
- int fds[2] = {kInvalidFd, kInvalidFd};
+ FileDescriptor fds[2] = {kInvalidFd, kInvalidFd};
int result = pipe(fds);
SB_DCHECK(result == 0) << "result=" << result;
@@ -622,9 +796,8 @@
}
DevInputImpl::~DevInputImpl() {
- for (std::vector<FileDescriptor>::const_iterator it = keyboard_fds_.begin();
- it != keyboard_fds_.end(); ++it) {
- close(*it);
+ for (const auto& device : input_devices_) {
+ close(device.fd);
}
CloseFdSafely(&wakeup_write_fd_);
CloseFdSafely(&wakeup_read_fd_);
@@ -633,13 +806,12 @@
DevInput::Event* DevInputImpl::PollNextSystemEvent() {
struct input_event event;
int modifiers = 0;
- for (std::vector<FileDescriptor>::const_iterator it = keyboard_fds_.begin();
- it != keyboard_fds_.end(); ++it) {
- if (!PollKeyboardEvent(*it, &event, &modifiers)) {
+ for (auto& device : input_devices_) {
+ if (!PollInputEvent(&device, &event, &modifiers)) {
continue;
}
- return InputToApplicationEvent(event, modifiers);
+ return InputToApplicationEvent(event, &device, modifiers);
}
return NULL;
}
@@ -651,9 +823,13 @@
}
FdSet read_set;
- for (std::vector<FileDescriptor>::const_iterator it = keyboard_fds_.begin();
- it != keyboard_fds_.end(); ++it) {
- read_set.Set(*it);
+ if (wake_up_fd_ != kInvalidFd) {
+ read_set.Set(wake_up_fd_);
+ }
+
+ for (std::vector<InputDeviceInfo>::const_iterator it = input_devices_.begin();
+ it != input_devices_.end(); ++it) {
+ read_set.Set(it->fd);
}
read_set.Set(wakeup_read_fd_);
@@ -693,13 +869,256 @@
}
}
-DevInput::Event* DevInputImpl::InputToApplicationEvent(
- const struct input_event& event,
- int modifiers) {
- if (event.type != EV_KEY) {
+namespace {
+
+// Creates a key event for an analog button input.
+DevInput::Event* CreateAnalogButtonKeyEvent(SbWindow window,
+ float axis_value,
+ float previous_axis_value,
+ SbKey key,
+ SbKeyLocation location,
+ int modifiers,
+ const struct input_event& event) {
+ SbInputEventType previous_type =
+ (std::abs(previous_axis_value) > 0.5 ? kSbInputEventTypePress
+ : kSbInputEventTypeUnpress);
+ SbInputEventType type =
+ (std::abs(axis_value) > 0.5 ? kSbInputEventTypePress
+ : kSbInputEventTypeUnpress);
+ if (previous_type == type) {
+ // Key press/unpress state did not change.
return NULL;
}
+ SbInputData* data = new SbInputData();
+ SbMemorySet(data, 0, sizeof(*data));
+ data->window = window;
+ data->type = type;
+ data->device_type = kSbInputDeviceTypeGamepad;
+ data->device_id = kGamepadDeviceId;
+ data->key = key;
+ data->key_location = location;
+ data->key_modifiers = modifiers;
+ return new DevInput::Event(kSbEventTypeInput, data,
+ &Application::DeleteDestructor<SbInputData>);
+}
+
+// Creates a move event with key for a stick input.
+DevInput::Event* CreateMoveEventWithKey(SbWindow window,
+ SbKey key,
+ SbKeyLocation location,
+ int modifiers,
+ const SbInputVector& input_vector) {
+ SbInputData* data = new SbInputData();
+ SbMemorySet(data, 0, sizeof(*data));
+
+ data->window = window;
+ data->type = kSbInputEventTypeMove;
+ data->device_type = kSbInputDeviceTypeGamepad;
+ data->device_id = kGamepadDeviceId;
+
+ data->key = key;
+ data->key_location = location;
+ data->key_modifiers = modifiers;
+ data->position = input_vector;
+#if SB_API_VERSION >= SB_POINTER_INPUT_API_VERSION
+ data->pressure = NAN;
+ data->size = {NAN, NAN};
+ data->tilt = {NAN, NAN};
+#endif
+
+ return new DevInput::Event(kSbEventTypeInput, data,
+ &Application::DeleteDestructor<SbInputData>);
+}
+
+DevInput::Event* CreateTouchPadEvent(SbWindow window,
+ SbInputEventType type,
+ SbKey key,
+ SbKeyLocation location,
+ int modifiers,
+ const SbInputVector& input_vector) {
+ SbInputData* data = new SbInputData();
+ SbMemorySet(data, 0, sizeof(*data));
+
+ data->window = window;
+ data->type = type;
+ data->device_type = kSbInputDeviceTypeTouchPad;
+ data->device_id = kGamepadDeviceId;
+
+ data->key = key;
+ data->key_location = location;
+ data->key_modifiers = modifiers;
+ data->position = input_vector;
+#if SB_API_VERSION >= SB_POINTER_INPUT_API_VERSION
+ data->pressure = NAN;
+ data->size = {NAN, NAN};
+ data->tilt = {NAN, NAN};
+#endif
+
+ return new DevInput::Event(kSbEventTypeInput, data,
+ &Application::DeleteDestructor<SbInputData>);
+}
+
+} // namespace
+
+DevInput::Event* DevInputImpl::AxisInputToApplicationEvent(
+ const struct input_event& event,
+ InputDeviceInfo* device_info,
+ int modifiers) {
+ SB_DCHECK(event.type == EV_ABS);
+ SbKey key = kSbKeyUnknown;
+ float axis_value = 0;
+ float previous_axis_value = 0;
+ auto axis_info_it = device_info->axis_info.find(event.code);
+ if (axis_info_it != device_info->axis_info.end()) {
+ struct input_absinfo& axis_info = axis_info_it->second;
+ axis_info.value = event.value;
+ axis_value = GetAxisValue(axis_info);
+ float& stored_axis_value = device_info->axis_value[event.code];
+ previous_axis_value = stored_axis_value;
+ if (previous_axis_value == axis_value) {
+ // If the value is unchanged, don't do anything.
+ return NULL;
+ }
+ stored_axis_value = axis_value;
+ }
+
+ SbKeyLocation location = kSbKeyLocationUnspecified;
+ SbInputVector input_vector;
+ // The mapping for the axis codes can vary from controller to controller.
+ // TODO: Include axis mapping for controllers with different layout.
+ switch (event.code) {
+ case ABS_X:
+ // Report up and left as positive values.
+ input_vector.x = -axis_value;
+ input_vector.y = -device_info->axis_value[ABS_Y];
+ key = kSbKeyGamepadLeftStickLeft;
+ location = kSbKeyLocationLeft;
+ return CreateMoveEventWithKey(window_, key, location, modifiers,
+ input_vector);
+ case ABS_Y: {
+ // Report up and left as positive values.
+ input_vector.x = -device_info->axis_value[ABS_X];
+ input_vector.y = -axis_value;
+ key = kSbKeyGamepadLeftStickUp;
+ location = kSbKeyLocationLeft;
+ return CreateMoveEventWithKey(window_, key, location, modifiers,
+ input_vector);
+ }
+ case ABS_Z:
+ // Report up and left as positive values.
+ input_vector.x = -axis_value;
+ input_vector.y = -device_info->axis_value[ABS_RZ];
+ key = kSbKeyGamepadRightStickLeft;
+ location = kSbKeyLocationRight;
+ return CreateMoveEventWithKey(window_, key, location, modifiers,
+ input_vector);
+ case ABS_RZ:
+ // Report up and left as positive values.
+ input_vector.x = -device_info->axis_value[ABS_Z];
+ input_vector.y = -axis_value;
+ key = kSbKeyGamepadRightStickUp;
+ location = kSbKeyLocationRight;
+ return CreateMoveEventWithKey(window_, key, location, modifiers,
+ input_vector);
+ case ABS_RX: {
+ key = kSbKeyGamepadLeftTrigger;
+ location = kSbKeyLocationLeft;
+ // For trigger buttons, the range is [0..1].
+ float trigger_value = (axis_value + 1) / 2;
+ float previous_trigger_value = (previous_axis_value + 1) / 2;
+ return CreateAnalogButtonKeyEvent(window_, trigger_value,
+ previous_trigger_value, key, location,
+ modifiers, event);
+ }
+ case ABS_RY: {
+ key = kSbKeyGamepadRightTrigger;
+ location = kSbKeyLocationRight;
+ // For trigger buttons, the range is [0..1].
+ float trigger_value = (axis_value + 1) / 2;
+ float previous_trigger_value = (previous_axis_value + 1) / 2;
+ return CreateAnalogButtonKeyEvent(window_, trigger_value,
+ previous_trigger_value, key, location,
+ modifiers, event);
+ }
+ case ABS_HAT0X: {
+ float axis_value_for_key =
+ std::abs(axis_value) > 0.5f ? axis_value : previous_axis_value;
+ key = (axis_value_for_key < 0) ? kSbKeyGamepadDPadLeft
+ : kSbKeyGamepadDPadRight;
+ return CreateAnalogButtonKeyEvent(window_, axis_value,
+ previous_axis_value, key, location,
+ modifiers, event);
+ }
+ case ABS_HAT0Y: {
+ float axis_value_for_key =
+ std::abs(axis_value) > 0.5f ? axis_value : previous_axis_value;
+ key = (axis_value_for_key < 0) ? kSbKeyGamepadDPadUp
+ : kSbKeyGamepadDPadDown;
+ return CreateAnalogButtonKeyEvent(window_, axis_value,
+ previous_axis_value, key, location,
+ modifiers, event);
+ }
+ case ABS_MT_TRACKING_ID:
+ if (event.value == -1) {
+ bool touchpad_position_is_known = IsTouchpadPositionKnown(device_info);
+ device_info->touchpad_position_state = kTouchPadPositionNone;
+ if (touchpad_position_is_known) {
+ // Touch point is released, report last known position as unpress.
+ input_vector.x = (device_info->axis_value[ABS_MT_POSITION_X] + 1 / 2);
+ input_vector.y = (device_info->axis_value[ABS_MT_POSITION_Y] + 1 / 2);
+ return CreateTouchPadEvent(window_, kSbInputEventTypeUnpress, key,
+ location, modifiers, input_vector);
+ }
+ }
+ return NULL;
+ case ABS_MT_POSITION_X: {
+ // If all positions were known before this event, then this event is a
+ // move.
+ SbInputEventType type = IsTouchpadPositionKnown(device_info)
+ ? kSbInputEventTypeMove
+ : kSbInputEventTypePress;
+ device_info->touchpad_position_state |= kTouchPadPositionX;
+ if (IsTouchpadPositionKnown(device_info)) {
+ // For touchpads, the range is [0..1].
+ input_vector.x = (axis_value + 1) / 2;
+ input_vector.y = (device_info->axis_value[ABS_MT_POSITION_Y] + 1) / 2;
+ return CreateTouchPadEvent(window_, type, key, location, modifiers,
+ input_vector);
+ }
+ // Not all axis positions are known yet.
+ return NULL;
+ }
+ case ABS_MT_POSITION_Y: {
+ // If all positions were known before this event, then this event is a
+ // move.
+ SbInputEventType type = IsTouchpadPositionKnown(device_info)
+ ? kSbInputEventTypeMove
+ : kSbInputEventTypePress;
+ device_info->touchpad_position_state |= kTouchPadPositionY;
+ if (IsTouchpadPositionKnown(device_info)) {
+ // For touchpads, the range is [0..1].
+ input_vector.x = (device_info->axis_value[ABS_MT_POSITION_X] + 1) / 2;
+ input_vector.y = (axis_value + 1) / 2;
+ return CreateTouchPadEvent(window_, type, key, location, modifiers,
+ input_vector);
+ }
+ // Not all axis positions are known yet.
+ return NULL;
+ }
+ default:
+ // Ignored event codes.
+ return NULL;
+ }
+
+ SB_NOTREACHED();
+ return NULL;
+}
+
+DevInput::Event* DevInputImpl::KeyInputToApplicationEvent(
+ const struct input_event& event,
+ int modifiers) {
+ SB_DCHECK(event.type == EV_KEY);
SB_DCHECK(event.value <= 2);
SbInputData* data = new SbInputData();
SbMemorySet(data, 0, sizeof(*data));
@@ -715,6 +1134,21 @@
&Application::DeleteDestructor<SbInputData>);
}
+DevInput::Event* DevInputImpl::InputToApplicationEvent(
+ const struct input_event& event,
+ InputDeviceInfo* device_info,
+ int modifiers) {
+ // EV_ABS events are axis values: Sticks, dpad, and touchpad.
+ // https://www.kernel.org/doc/Documentation/input/event-codes.txt
+ switch (event.type) {
+ case EV_ABS:
+ return AxisInputToApplicationEvent(event, device_info, modifiers);
+ case EV_KEY:
+ return KeyInputToApplicationEvent(event, modifiers);
+ }
+ return NULL;
+}
+
} // namespace
// static
@@ -722,6 +1156,11 @@
return new DevInputImpl(window);
}
+// static
+DevInput* DevInput::Create(SbWindow window, int wake_up_fd) {
+ return new DevInputImpl(window, wake_up_fd);
+}
+
} // namespace dev_input
} // namespace shared
} // namespace starboard
diff --git a/src/starboard/shared/linux/dev_input/dev_input.h b/src/starboard/shared/linux/dev_input/dev_input.h
index aa8577a..11b94c4 100644
--- a/src/starboard/shared/linux/dev_input/dev_input.h
+++ b/src/starboard/shared/linux/dev_input/dev_input.h
@@ -48,6 +48,11 @@
// Creates an instance of DevInput for the given window.
static DevInput* Create(SbWindow window);
+ // Creates an instance of DevInput for the given window.
+ // The wake_up_fd will be used in WaitForSystemEventWithTimeout() to return
+ // early when input is available on it.
+ static DevInput* Create(SbWindow window, int wake_up_fd);
+
protected:
DevInput() {}
};
diff --git a/src/starboard/shared/msvc/uwp/toolchain.py b/src/starboard/shared/msvc/uwp/msvc_toolchain.py
similarity index 100%
rename from src/starboard/shared/msvc/uwp/toolchain.py
rename to src/starboard/shared/msvc/uwp/msvc_toolchain.py
diff --git a/src/starboard/shared/starboard/audio_sink/audio_sink_internal.h b/src/starboard/shared/starboard/audio_sink/audio_sink_internal.h
index cf40ad5..4aaeef1 100644
--- a/src/starboard/shared/starboard/audio_sink/audio_sink_internal.h
+++ b/src/starboard/shared/starboard/audio_sink/audio_sink_internal.h
@@ -42,6 +42,9 @@
#if SB_API_VERSION >= 4
virtual void SetPlaybackRate(double playback_rate) = 0;
#endif // SB_API_VERSION >= 4
+
+ virtual void SetVolume(double volume) = 0;
+
virtual bool IsType(Type* type) = 0;
// The following two functions will be called during application startup and
diff --git a/src/starboard/shared/starboard/audio_sink/stub_audio_sink_type.cc b/src/starboard/shared/starboard/audio_sink/stub_audio_sink_type.cc
index 597820a..f6ccd09 100644
--- a/src/starboard/shared/starboard/audio_sink/stub_audio_sink_type.cc
+++ b/src/starboard/shared/starboard/audio_sink/stub_audio_sink_type.cc
@@ -44,6 +44,10 @@
}
#endif // SB_API_VERSION >= 4
+ void SetVolume(double volume) SB_OVERRIDE {
+ SB_UNREFERENCED_PARAMETER(volume);
+ }
+
private:
static void* ThreadEntryPoint(void* context);
void AudioThreadFunc();
diff --git a/src/starboard/shared/starboard/file_storage/storage_delete_record.cc b/src/starboard/shared/starboard/file_storage/storage_delete_record.cc
index 891fbbb..c5c7fe3 100644
--- a/src/starboard/shared/starboard/file_storage/storage_delete_record.cc
+++ b/src/starboard/shared/starboard/file_storage/storage_delete_record.cc
@@ -18,14 +18,23 @@
#include "starboard/shared/starboard/file_storage/storage_internal.h"
#include "starboard/user.h"
-bool SbStorageDeleteRecord(SbUser user) {
+bool SbStorageDeleteRecord(SbUser user
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ ,
+ const char* name
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ ) {
if (!SbUserIsValid(user)) {
return false;
}
+#if SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION
+ const char* name = NULL;
+#endif // SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION
+
char path[SB_FILE_MAX_PATH];
bool success = starboard::shared::starboard::GetUserStorageFilePath(
- user, path, SB_ARRAY_SIZE_INT(path));
+ user, name, path, SB_ARRAY_SIZE_INT(path));
if (!success) {
return false;
}
diff --git a/src/starboard/shared/starboard/file_storage/storage_internal.h b/src/starboard/shared/starboard/file_storage/storage_internal.h
index 6bb3362..a56cd34 100644
--- a/src/starboard/shared/starboard/file_storage/storage_internal.h
+++ b/src/starboard/shared/starboard/file_storage/storage_internal.h
@@ -18,6 +18,8 @@
#ifndef STARBOARD_SHARED_STARBOARD_FILE_STORAGE_STORAGE_INTERNAL_H_
#define STARBOARD_SHARED_STARBOARD_FILE_STORAGE_STORAGE_INTERNAL_H_
+#include <string>
+
#include "starboard/file.h"
#include "starboard/shared/internal_only.h"
#include "starboard/storage.h"
@@ -27,6 +29,9 @@
struct SbStorageRecordPrivate {
SbUser user;
SbFile file;
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ std::string name;
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
};
namespace starboard {
@@ -34,6 +39,7 @@
namespace starboard {
// Gets the path to the storage file for the given user.
static SB_C_INLINE bool GetUserStorageFilePath(SbUser user,
+ const char* name,
char* out_path,
int path_size) {
bool success = SbUserGetProperty(user, kSbUserPropertyHomeDirectory, out_path,
@@ -42,7 +48,12 @@
return false;
}
- SbStringConcat(out_path, "/.starboard.storage", path_size);
+ SbStringConcat(out_path, "/.starboard", path_size);
+ if (name && SbStringGetLength(name) > 0) {
+ SbStringConcat(out_path, ".", path_size);
+ SbStringConcat(out_path, name, path_size);
+ }
+ SbStringConcat(out_path, ".storage", path_size);
return true;
}
} // namespace starboard
diff --git a/src/starboard/shared/starboard/file_storage/storage_open_record.cc b/src/starboard/shared/starboard/file_storage/storage_open_record.cc
index 5be40f4..aaea393 100644
--- a/src/starboard/shared/starboard/file_storage/storage_open_record.cc
+++ b/src/starboard/shared/starboard/file_storage/storage_open_record.cc
@@ -19,14 +19,23 @@
#include "starboard/shared/starboard/file_storage/storage_internal.h"
#include "starboard/user.h"
-SbStorageRecord SbStorageOpenRecord(SbUser user) {
+SbStorageRecord SbStorageOpenRecord(SbUser user
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ ,
+ const char* name
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ ) {
if (!SbUserIsValid(user)) {
return kSbStorageInvalidRecord;
}
+#if SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION
+ const char* name = NULL;
+#endif // SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION
+
char path[SB_FILE_MAX_PATH];
bool success = starboard::shared::starboard::GetUserStorageFilePath(
- user, path, SB_ARRAY_SIZE_INT(path));
+ user, name, path, SB_ARRAY_SIZE_INT(path));
if (!success) {
return kSbStorageInvalidRecord;
}
@@ -43,5 +52,10 @@
SB_DCHECK(SbStorageIsValidRecord(result));
result->user = user;
result->file = file;
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ if (name) {
+ result->name = name;
+ }
+#endif
return result;
}
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
index dbaa49e..9e63967 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
@@ -71,6 +71,7 @@
sink_sample_type_(GetSinkAudioSampleType()),
bytes_per_frame_(media::GetBytesPerSample(sink_sample_type_) * channels_),
playback_rate_(1.0),
+ volume_(1.0),
paused_(true),
seeking_(false),
seeking_to_pts_(0),
@@ -178,6 +179,14 @@
}
#endif // SB_API_VERSION >= 4
+void AudioRendererImpl::SetVolume(double volume) {
+ SB_DCHECK(BelongsToCurrentThread());
+ volume_ = volume;
+ if (audio_sink_) {
+ audio_sink_->SetVolume(volume_);
+ }
+}
+
void AudioRendererImpl::Seek(SbMediaTime seek_to_pts) {
SB_DCHECK(BelongsToCurrentThread());
SB_DCHECK(seek_to_pts >= 0);
@@ -287,6 +296,7 @@
// support play/pause.
audio_sink_->SetPlaybackRate(playback_rate_ > 0.0 ? 1.0 : 0.0);
#endif // SB_API_VERSION >= 4
+ audio_sink_->SetVolume(volume_);
}
void AudioRendererImpl::UpdateSourceStatus(int* frames_in_buffer,
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
index d9278da..a469037 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
@@ -60,6 +60,7 @@
#if SB_API_VERSION >= 4
void SetPlaybackRate(double playback_rate) SB_OVERRIDE;
#endif // SB_API_VERSION >= 4
+ void SetVolume(double volume) SB_OVERRIDE;
void Seek(SbMediaTime seek_to_pts) SB_OVERRIDE;
bool IsEndOfStreamWritten() const SB_OVERRIDE {
@@ -117,6 +118,7 @@
scoped_ptr<AudioResampler> resampler_;
AudioTimeStretcher time_stretcher_;
double playback_rate_;
+ double volume_;
atomic_bool paused_;
atomic_bool seeking_;
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h b/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h
index 1c192c1..a6ca64b 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h
@@ -38,6 +38,7 @@
#if SB_API_VERSION >= 4
virtual void SetPlaybackRate(double playback_rate) = 0;
#endif // SB_API_VERSION >= 4
+ virtual void SetVolume(double volume) = 0;
virtual void Seek(SbMediaTime seek_to_pts) = 0;
virtual bool IsEndOfStreamWritten() const = 0;
virtual bool IsEndOfStreamPlayed() const = 0;
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
index 76b6e53..c373d90 100644
--- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
+++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
@@ -62,7 +62,11 @@
audio_codec_(audio_codec),
drm_system_(drm_system),
audio_header_(audio_header),
- paused_(false)
+ paused_(false),
+#if SB_API_VERSION >= 4
+ playback_rate_(1.0),
+#endif // SB_API_VERSION >= 4
+ volume_(1.0)
#if SB_API_VERSION >= 4
,
output_mode_(output_mode),
@@ -87,12 +91,12 @@
bounds_ = PlayerWorker::Bounds();
}
-bool FilterBasedPlayerWorkerHandler::IsPunchoutMode() const {
-#if SB_API_VERSION >= 4
- return (output_mode_ == kSbPlayerOutputModePunchOut);
-#else
- return true;
-#endif // SB_API_VERSION >= 4
+bool FilterBasedPlayerWorkerHandler::IsPunchoutMode() const {
+#if SB_API_VERSION >= 4
+ return (output_mode_ == kSbPlayerOutputModePunchOut);
+#else
+ return true;
+#endif // SB_API_VERSION >= 4
}
bool FilterBasedPlayerWorkerHandler::Init(
@@ -144,6 +148,11 @@
::starboard::ScopedLock lock(video_renderer_existence_mutex_);
media_components->GetRenderers(&audio_renderer_, &video_renderer_);
+#if SB_API_VERSION >= 4
+ audio_renderer_->SetPlaybackRate(playback_rate_);
+#endif // SB_API_VERSION >= 4
+ audio_renderer_->SetVolume(volume_);
+
job_queue_->Schedule(update_closure_, kUpdateInterval);
return true;
@@ -276,15 +285,26 @@
bool FilterBasedPlayerWorkerHandler::SetPlaybackRate(double playback_rate) {
SB_DCHECK(job_queue_->BelongsToCurrentThread());
+ playback_rate_ = playback_rate;
+
if (!audio_renderer_) {
return false;
}
- audio_renderer_->SetPlaybackRate(playback_rate);
+ audio_renderer_->SetPlaybackRate(playback_rate_);
return true;
}
#endif // SB_API_VERSION >= 4
+void FilterBasedPlayerWorkerHandler::SetVolume(double volume) {
+ SB_DCHECK(job_queue_->BelongsToCurrentThread());
+
+ volume_ = volume;
+ if (audio_renderer_) {
+ audio_renderer_->SetVolume(volume_);
+ }
+}
+
bool FilterBasedPlayerWorkerHandler::SetBounds(
const PlayerWorker::Bounds& bounds) {
SB_DCHECK(job_queue_->BelongsToCurrentThread());
@@ -328,9 +348,9 @@
player_worker_->UpdateDroppedVideoFrames(
video_renderer_->GetDroppedFrames());
- if (IsPunchoutMode()) {
- shared::starboard::Application::Get()->HandleFrame(
- player_, frame, bounds_.x, bounds_.y, bounds_.width, bounds_.height);
+ if (IsPunchoutMode()) {
+ shared::starboard::Application::Get()->HandleFrame(
+ player_, frame, bounds_.x, bounds_.y, bounds_.width, bounds_.height);
}
(*player_worker_.*update_media_time_cb_)(audio_renderer_->GetCurrentTime());
@@ -355,10 +375,10 @@
}
video_renderer.reset();
- if (IsPunchoutMode()) {
- // Clear the video frame as we terminate.
- shared::starboard::Application::Get()->HandleFrame(
- player_, VideoFrame::CreateEOSFrame(), 0, 0, 0, 0);
+ if (IsPunchoutMode()) {
+ // Clear the video frame as we terminate.
+ shared::starboard::Application::Get()->HandleFrame(
+ player_, VideoFrame::CreateEOSFrame(), 0, 0, 0, 0);
}
}
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
index 8715ab9..20655ca 100644
--- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
+++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
@@ -68,6 +68,7 @@
#if SB_API_VERSION >= 4
bool SetPlaybackRate(double playback_rate) SB_OVERRIDE;
#endif // SB_API_VERSION >= 4
+ void SetVolume(double volume) SB_OVERRIDE;
bool SetBounds(const PlayerWorker::Bounds& bounds) SB_OVERRIDE;
void Stop() SB_OVERRIDE;
@@ -98,6 +99,10 @@
scoped_ptr<VideoRenderer> video_renderer_;
bool paused_;
+#if SB_API_VERSION >= 4
+ double playback_rate_;
+#endif // SB_API_VERSION >= 4
+ double volume_;
PlayerWorker::Bounds bounds_;
Closure update_closure_;
diff --git a/src/starboard/shared/starboard/player/player_internal.cc b/src/starboard/shared/starboard/player/player_internal.cc
index 20268ea..3b46a5d 100644
--- a/src/starboard/shared/starboard/player/player_internal.cc
+++ b/src/starboard/shared/starboard/player/player_internal.cc
@@ -133,8 +133,8 @@
#endif // SB_API_VERSION >= 4
void SbPlayerPrivate::SetVolume(double volume) {
- SB_UNREFERENCED_PARAMETER(volume);
- SB_NOTIMPLEMENTED();
+ volume_ = volume;
+ worker_->SetVolume(volume_);
}
void SbPlayerPrivate::UpdateMediaTime(SbMediaTime media_time, int ticket) {
diff --git a/src/starboard/shared/starboard/player/player_worker.cc b/src/starboard/shared/starboard/player/player_worker.cc
index 38a0a25..24e834c 100644
--- a/src/starboard/shared/starboard/player/player_worker.cc
+++ b/src/starboard/shared/starboard/player/player_worker.cc
@@ -270,6 +270,11 @@
}
#endif // SB_API_VERSION >= 4
+void PlayerWorker::DoSetVolume(double volume) {
+ SB_DCHECK(job_queue_->BelongsToCurrentThread());
+ handler_->SetVolume(volume);
+}
+
void PlayerWorker::DoStop() {
SB_DCHECK(job_queue_->BelongsToCurrentThread());
diff --git a/src/starboard/shared/starboard/player/player_worker.h b/src/starboard/shared/starboard/player/player_worker.h
index a1d9333..84be839 100644
--- a/src/starboard/shared/starboard/player/player_worker.h
+++ b/src/starboard/shared/starboard/player/player_worker.h
@@ -83,6 +83,8 @@
#if SB_API_VERSION >= 4
virtual bool SetPlaybackRate(double playback_rate) = 0;
#endif // SB_API_VERSION >= 4
+ virtual void SetVolume(double volume) = 0;
+
virtual bool SetBounds(const Bounds& bounds) = 0;
// Once this function returns, all processing on the Handler and related
@@ -147,6 +149,10 @@
}
#endif // SB_API_VERSION >= 4
+ void SetVolume(double volume) {
+ job_queue_->Schedule(Bind(&PlayerWorker::DoSetVolume, this, volume));
+ }
+
void UpdateDroppedVideoFrames(int dropped_video_frames) {
host_->UpdateDroppedVideoFrames(dropped_video_frames);
}
@@ -177,6 +183,7 @@
#if SB_API_VERSION >= 4
void DoSetPlaybackRate(double rate);
#endif // SB_API_VERSION >= 4
+ void DoSetVolume(double volume);
void DoStop();
void UpdateDecoderState(SbMediaType type, SbPlayerDecoderState state);
diff --git a/src/starboard/shared/stub/drm_create_system.cc b/src/starboard/shared/stub/drm_create_system.cc
index a9a1c84..64139a9 100644
--- a/src/starboard/shared/stub/drm_create_system.cc
+++ b/src/starboard/shared/stub/drm_create_system.cc
@@ -14,6 +14,24 @@
#include "starboard/drm.h"
+#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION
+
+SbDrmSystem SbDrmCreateSystem(
+ const char* key_system,
+ void* context,
+ SbDrmSessionUpdateRequestFunc update_request_callback,
+ SbDrmSessionUpdatedFunc session_updated_callback,
+ SbDrmSessionKeyStatusesChangedFunc key_statuses_changed_callback) {
+ SB_UNREFERENCED_PARAMETER(context);
+ SB_UNREFERENCED_PARAMETER(key_system);
+ SB_UNREFERENCED_PARAMETER(update_request_callback);
+ SB_UNREFERENCED_PARAMETER(session_updated_callback);
+ SB_UNREFERENCED_PARAMETER(key_statuses_changed_callback);
+ return kSbDrmSystemInvalid;
+}
+
+#else // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION
+
SbDrmSystem SbDrmCreateSystem(
const char* key_system,
void* context,
@@ -25,3 +43,5 @@
SB_UNREFERENCED_PARAMETER(session_updated_callback);
return kSbDrmSystemInvalid;
}
+
+#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION
diff --git a/src/starboard/shared/stub/storage_delete_record.cc b/src/starboard/shared/stub/storage_delete_record.cc
index ba13cd1..a669054 100644
--- a/src/starboard/shared/stub/storage_delete_record.cc
+++ b/src/starboard/shared/stub/storage_delete_record.cc
@@ -14,6 +14,11 @@
#include "starboard/storage.h"
-bool SbStorageDeleteRecord(SbUser /*user*/) {
+bool SbStorageDeleteRecord(SbUser /*user*/
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ ,
+ const char* /*name*/
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ ) {
return false;
}
diff --git a/src/starboard/shared/stub/storage_open_record.cc b/src/starboard/shared/stub/storage_open_record.cc
index bcd5f3d..b0f503e 100644
--- a/src/starboard/shared/stub/storage_open_record.cc
+++ b/src/starboard/shared/stub/storage_open_record.cc
@@ -14,6 +14,11 @@
#include "starboard/storage.h"
-SbStorageRecord SbStorageOpenRecord(SbUser /*user*/) {
+SbStorageRecord SbStorageOpenRecord(SbUser /*user*/
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ ,
+ const char* /*name*/
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ ) {
return kSbStorageInvalidRecord;
}
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/shared/test_webapi_extension/my_new_enum.idl
similarity index 76%
copy from src/starboard/win/lib/atomic_public.h
copy to src/starboard/shared/test_webapi_extension/my_new_enum.idl
index be4e805..1a6f73c 100644
--- a/src/starboard/win/lib/atomic_public.h
+++ b/src/starboard/shared/test_webapi_extension/my_new_enum.idl
@@ -12,9 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
-#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
-
-#include "starboard/shared/win32/atomic_public.h"
-
-#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
+enum MyNewEnum {
+ "apples",
+ "oranges",
+ "peaches"
+};
diff --git a/src/starboard/shared/test_webapi_extension/my_new_interface.cc b/src/starboard/shared/test_webapi_extension/my_new_interface.cc
new file mode 100644
index 0000000..18af5b4
--- /dev/null
+++ b/src/starboard/shared/test_webapi_extension/my_new_interface.cc
@@ -0,0 +1,29 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/test_webapi_extension/my_new_interface.h"
+
+namespace cobalt {
+namespace webapi_extension {
+
+MyNewInterface::MyNewInterface(const scoped_refptr<dom::Window>& window) {
+ UNREFERENCED_PARAMETER(window);
+ // Provide an initial value for the enum.
+ enum_value_ = kMyNewEnumApples;
+}
+
+MyNewInterface::~MyNewInterface() OVERRIDE {}
+
+} // namespace webapi_extension
+} // namespace cobalt
diff --git a/src/starboard/shared/test_webapi_extension/my_new_interface.h b/src/starboard/shared/test_webapi_extension/my_new_interface.h
new file mode 100644
index 0000000..eb30d4e
--- /dev/null
+++ b/src/starboard/shared/test_webapi_extension/my_new_interface.h
@@ -0,0 +1,55 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_TEST_WEBAPI_EXTENSION_MY_NEW_INTERFACE_H_
+#define STARBOARD_SHARED_TEST_WEBAPI_EXTENSION_MY_NEW_INTERFACE_H_
+
+#include <string>
+
+#include "cobalt/dom/window.h"
+#include "cobalt/script/wrappable.h"
+#include "starboard/shared/test_webapi_extension/my_new_enum.h"
+
+namespace cobalt {
+namespace webapi_extension {
+
+class MyNewInterface : public script::Wrappable {
+ public:
+ explicit MyNewInterface(const scoped_refptr<dom::Window>& window);
+
+ const std::string& foo() const { return foo_; }
+ void set_foo(const std::string& value) { foo_ = value; }
+
+ void SetMyNewEnum(MyNewEnum value) { enum_value_ = value; }
+ MyNewEnum GetMyNewEnum() const { return enum_value_; }
+
+ // All types derived from script::Wrappable must have this annotation.
+ DEFINE_WRAPPABLE_TYPE(MyNewInterface);
+
+ private:
+ // Since script::Wrappable inherits from base::RefCounted<>, we make the
+ // destructor private.
+ ~MyNewInterface() OVERRIDE;
+
+ std::string foo_;
+
+ MyNewEnum enum_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(MyNewInterface);
+};
+
+} // namespace webapi_extension
+} // namespace cobalt
+
+#endif // STARBOARD_SHARED_TEST_WEBAPI_EXTENSION_MY_NEW_INTERFACE_H_
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/shared/test_webapi_extension/my_new_interface.idl
similarity index 76%
copy from src/starboard/win/lib/atomic_public.h
copy to src/starboard/shared/test_webapi_extension/my_new_interface.idl
index be4e805..3e64764 100644
--- a/src/starboard/win/lib/atomic_public.h
+++ b/src/starboard/shared/test_webapi_extension/my_new_interface.idl
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
-#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
+interface MyNewInterface {
+ attribute DOMString foo;
-#include "starboard/shared/win32/atomic_public.h"
-
-#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
+ void SetMyNewEnum(MyNewEnum value);
+ MyNewEnum GetMyNewEnum();
+};
diff --git a/src/starboard/shared/test_webapi_extension/test_webapi_extension.gypi b/src/starboard/shared/test_webapi_extension/test_webapi_extension.gypi
new file mode 100644
index 0000000..74de31a
--- /dev/null
+++ b/src/starboard/shared/test_webapi_extension/test_webapi_extension.gypi
@@ -0,0 +1,29 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This file can be included from a platform's gyp_configuration.gypi file to
+# setup the test custom webapi_extension defined in this directory to be
+# injected into that platform.
+{
+ 'variables': {
+ 'cobalt_webapi_extension_source_idl_files': [
+ 'my_new_interface.idl'
+ ],
+ 'cobalt_webapi_extension_generated_header_idl_files': [
+ 'my_new_enum.idl'
+ ],
+ 'cobalt_webapi_extension_gyp_target':
+ '<(DEPTH)/starboard/shared/test_webapi_extension/webapi_extension.gyp:cobalt_test_webapi_extension',
+ },
+}
\ No newline at end of file
diff --git a/src/starboard/shared/test_webapi_extension/webapi_extension.cc b/src/starboard/shared/test_webapi_extension/webapi_extension.cc
new file mode 100644
index 0000000..06bb89c
--- /dev/null
+++ b/src/starboard/shared/test_webapi_extension/webapi_extension.cc
@@ -0,0 +1,38 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/browser/webapi_extension.h"
+
+#include "base/compiler_specific.h"
+#include "cobalt/script/global_environment.h"
+#include "starboard/shared/test_webapi_extension/my_new_interface.h"
+
+namespace cobalt {
+namespace browser {
+
+base::optional<std::string> GetWebAPIExtensionObjectPropertyName() {
+ return std::string("myInterface");
+}
+
+scoped_refptr<script::Wrappable> CreateWebAPIExtensionObject(
+ const scoped_refptr<dom::Window>& window,
+ script::GlobalEnvironment* global_environment) {
+ UNREFERENCED_PARAMETER(global_environment);
+
+ return scoped_refptr<script::Wrappable>(
+ new webapi_extension::MyNewInterface(window));
+}
+
+} // namespace browser
+} // namespace cobalt
diff --git a/src/starboard/shared/test_webapi_extension/webapi_extension.gyp b/src/starboard/shared/test_webapi_extension/webapi_extension.gyp
new file mode 100644
index 0000000..5c238e0
--- /dev/null
+++ b/src/starboard/shared/test_webapi_extension/webapi_extension.gyp
@@ -0,0 +1,35 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+{
+ 'targets': [
+ {
+ 'target_name': 'cobalt_test_webapi_extension',
+ 'type': 'static_library',
+
+ # List of all source files and header files needed to support the IDL
+ # definitions.
+ 'sources': [
+ 'my_new_interface.h',
+ 'my_new_interface.cc',
+ 'webapi_extension.cc',
+ ],
+
+ 'dependencies': [
+ '<(DEPTH)/cobalt/dom/dom.gyp:dom',
+ '<(DEPTH)/cobalt/script/script.gyp:script',
+ '<(DEPTH)/base/base.gyp:base',
+ ],
+ },
+ ],
+}
diff --git a/src/starboard/shared/uwp/cobalt/xhr_modify_headers.cc b/src/starboard/shared/uwp/cobalt/xhr_modify_headers.cc
index eaf8bd3..6f71b80 100644
--- a/src/starboard/shared/uwp/cobalt/xhr_modify_headers.cc
+++ b/src/starboard/shared/uwp/cobalt/xhr_modify_headers.cc
@@ -98,7 +98,7 @@
WebTokenRequestResult^ RequestToken(WebTokenRequest^ request) {
using starboard::shared::uwp::WaitForResult;
- IAsyncOperation<WebTokenRequestResult ^> ^ request_operation = nullptr;
+ IAsyncOperation<WebTokenRequestResult^>^ request_operation = nullptr;
base::WaitableEvent request_operation_set(false, false);
// Ensure WebAuthenticationCoreManager::RequestTokenAsync is called on the
// UI thread, since documentation states that "This method cannot be called
diff --git a/src/starboard/shared/uwp/starboard_platform.gypi b/src/starboard/shared/uwp/starboard_platform.gypi
index ee1b5bd..85f0f72 100644
--- a/src/starboard/shared/uwp/starboard_platform.gypi
+++ b/src/starboard/shared/uwp/starboard_platform.gypi
@@ -22,6 +22,8 @@
'system_clear_platform_error.cc',
'system_get_device_type.cc',
'system_get_property.cc',
+ 'system_get_total_cpu_memory.cc',
+ 'system_get_used_cpu_memory.cc',
'system_raise_platform_error.cc',
'window_create.cc',
'window_destroy.cc',
diff --git a/src/starboard/shared/uwp/system_get_device_type.cc b/src/starboard/shared/uwp/system_get_device_type.cc
index 81179ca..33ce323 100644
--- a/src/starboard/shared/uwp/system_get_device_type.cc
+++ b/src/starboard/shared/uwp/system_get_device_type.cc
@@ -23,7 +23,7 @@
using Windows::System::Profile::AnalyticsVersionInfo;
SbSystemDeviceType SbSystemGetDeviceType() {
- AnalyticsVersionInfo ^ version_info = AnalyticsInfo::VersionInfo;
+ AnalyticsVersionInfo^ version_info = AnalyticsInfo::VersionInfo;
std::string family = starboard::shared::win32::platformStringToString(
version_info->DeviceFamily);
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/shared/uwp/system_get_total_cpu_memory.cc
similarity index 76%
copy from src/starboard/win/lib/atomic_public.h
copy to src/starboard/shared/uwp/system_get_total_cpu_memory.cc
index be4e805..293fd7d 100644
--- a/src/starboard/win/lib/atomic_public.h
+++ b/src/starboard/shared/uwp/system_get_total_cpu_memory.cc
@@ -12,9 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
-#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
+#include "starboard/system.h"
-#include "starboard/shared/win32/atomic_public.h"
+using Windows::System::MemoryManager;
-#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
+int64_t SbSystemGetTotalCPUMemory() {
+ return static_cast<int64_t>(MemoryManager::AppMemoryUsageLimit);
+}
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/shared/uwp/system_get_used_cpu_memory.cc
similarity index 76%
copy from src/starboard/win/lib/atomic_public.h
copy to src/starboard/shared/uwp/system_get_used_cpu_memory.cc
index be4e805..adc9c0d 100644
--- a/src/starboard/win/lib/atomic_public.h
+++ b/src/starboard/shared/uwp/system_get_used_cpu_memory.cc
@@ -12,9 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
-#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
+#include "starboard/system.h"
-#include "starboard/shared/win32/atomic_public.h"
+using Windows::System::MemoryManager;
-#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
+int64_t SbSystemGetUsedCPUMemory() {
+ return static_cast<int64_t>(MemoryManager::AppMemoryUsage);
+}
diff --git a/src/starboard/shared/win32/audio_decoder.cc b/src/starboard/shared/win32/audio_decoder.cc
index d6749f2..879202c 100644
--- a/src/starboard/shared/win32/audio_decoder.cc
+++ b/src/starboard/shared/win32/audio_decoder.cc
@@ -56,19 +56,24 @@
};
AudioDecoder::AudioDecoder(SbMediaAudioCodec audio_codec,
- const SbMediaAudioHeader& audio_header)
- : sample_type_(kSbMediaAudioSampleTypeFloat32),
- stream_ended_(false),
- audio_codec_(audio_codec),
- audio_header_(audio_header) {
+ const SbMediaAudioHeader& audio_header,
+ SbDrmSystem drm_system)
+ : audio_codec_(audio_codec),
+ audio_header_(audio_header),
+ drm_system_(drm_system),
+ sample_type_(kSbMediaAudioSampleTypeFloat32),
+ stream_ended_(false) {
SB_DCHECK(audio_codec == kSbMediaAudioCodecAac);
decoder_impl_ = AbstractWin32AudioDecoder::Create(
- audio_codec_, GetStorageType(), GetSampleType(), audio_header_);
+ audio_codec_, GetStorageType(), GetSampleType(), audio_header_,
+ drm_system_);
decoder_thread_.reset(new AudioDecoderThread(decoder_impl_.get(), this));
callback_scheduler_.reset(new CallbackScheduler());
}
AudioDecoder::~AudioDecoder() {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+
decoder_thread_.reset(nullptr);
decoder_impl_.reset(nullptr);
callback_scheduler_.reset(nullptr);
@@ -76,7 +81,9 @@
void AudioDecoder::Decode(const scoped_refptr<InputBuffer>& input_buffer,
const Closure& consumed_cb) {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
SB_DCHECK(input_buffer);
+
callback_scheduler_->SetCallbackOnce(consumed_cb);
callback_scheduler_->OnCallbackSignaled();
const bool can_take_more_data = decoder_thread_->QueueInput(input_buffer);
@@ -91,22 +98,29 @@
}
void AudioDecoder::WriteEndOfStream() {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+
::starboard::ScopedLock lock(mutex_);
stream_ended_ = true;
decoder_thread_->QueueEndOfStream();
}
scoped_refptr<AudioDecoder::DecodedAudio> AudioDecoder::Read() {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+
DecodedAudioPtr data = decoded_data_.PopFront();
SB_DCHECK(data);
return data;
}
void AudioDecoder::Reset() {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+
decoder_thread_.reset(nullptr);
decoder_impl_.reset(nullptr);
decoder_impl_ = AbstractWin32AudioDecoder::Create(
- audio_codec_, GetStorageType(), GetSampleType(), audio_header_);
+ audio_codec_, GetStorageType(), GetSampleType(), audio_header_,
+ drm_system_);
decoder_thread_.reset(new AudioDecoderThread(decoder_impl_.get(), this));
decoded_data_.Clear();
stream_ended_ = false;
@@ -114,14 +128,20 @@
}
SbMediaAudioSampleType AudioDecoder::GetSampleType() const {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+
return sample_type_;
}
int AudioDecoder::GetSamplesPerSecond() const {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+
return audio_header_.samples_per_second;
}
void AudioDecoder::Initialize(const Closure& output_cb) {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+
SB_DCHECK(output_cb.is_valid());
SB_DCHECK(!output_cb_.is_valid());
output_cb_ = output_cb;
diff --git a/src/starboard/shared/win32/audio_decoder.h b/src/starboard/shared/win32/audio_decoder.h
index f036287..5bd335c 100644
--- a/src/starboard/shared/win32/audio_decoder.h
+++ b/src/starboard/shared/win32/audio_decoder.h
@@ -18,11 +18,13 @@
#include "starboard/common/ref_counted.h"
#include "starboard/common/scoped_ptr.h"
#include "starboard/configuration.h"
+#include "starboard/drm.h"
#include "starboard/media.h"
#include "starboard/shared/internal_only.h"
#include "starboard/shared/starboard/player/decoded_audio_internal.h"
#include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
#include "starboard/shared/starboard/player/job_queue.h"
+#include "starboard/shared/starboard/thread_checker.h"
#include "starboard/shared/win32/atomic_queue.h"
#include "starboard/shared/win32/audio_decoder_thread.h"
#include "starboard/shared/win32/media_common.h"
@@ -32,16 +34,14 @@
namespace shared {
namespace win32 {
-using JobQueue = ::starboard::shared::starboard::player::JobQueue;
-using JobOwner = JobQueue::JobOwner;
-
class AudioDecoder
: public ::starboard::shared::starboard::player::filter::AudioDecoder,
- private JobOwner,
+ private ::starboard::shared::starboard::player::JobQueue::JobOwner,
private AudioDecodedCallback {
public:
AudioDecoder(SbMediaAudioCodec audio_codec,
- const SbMediaAudioHeader& audio_header);
+ const SbMediaAudioHeader& audio_header,
+ SbDrmSystem drm_system);
~AudioDecoder() SB_OVERRIDE;
void Decode(const scoped_refptr<InputBuffer>& input_buffer,
@@ -60,9 +60,13 @@
private:
class CallbackScheduler;
- SbMediaAudioHeader audio_header_;
- SbMediaAudioSampleType sample_type_;
+
+ ::starboard::shared::starboard::ThreadChecker thread_checker_;
+
SbMediaAudioCodec audio_codec_;
+ SbMediaAudioHeader audio_header_;
+ SbDrmSystem drm_system_;
+ SbMediaAudioSampleType sample_type_;
bool stream_ended_;
AtomicQueue<DecodedAudioPtr> decoded_data_;
@@ -71,7 +75,7 @@
scoped_ptr<AudioDecoderThread> decoder_thread_;
Closure output_cb_;
- ::starboard::Mutex mutex_;
+ Mutex mutex_;
};
} // namespace win32
diff --git a/src/starboard/shared/win32/audio_sink.cc b/src/starboard/shared/win32/audio_sink.cc
index c5d8de2..5967211 100644
--- a/src/starboard/shared/win32/audio_sink.cc
+++ b/src/starboard/shared/win32/audio_sink.cc
@@ -72,6 +72,10 @@
ScopedLock lock(mutex_);
playback_rate_ = playback_rate;
}
+ void SetVolume(double volume) SB_OVERRIDE {
+ ScopedLock lock(mutex_);
+ volume_ = volume;
+ }
private:
static void* ThreadEntryPoint(void* context);
@@ -99,6 +103,7 @@
::starboard::Mutex mutex_;
bool destroying_;
double playback_rate_;
+ double volume_;
};
XAudioAudioSink::XAudioAudioSink(
@@ -118,7 +123,8 @@
frame_buffers_size_in_frames_(frame_buffers_size_in_frames),
wfx_(wfx),
destroying_(false),
- playback_rate_(1.0) {
+ playback_rate_(1.0),
+ volume_(1.0) {
// TODO: Check MaxFrequencyRatio
CHECK_HRESULT_OK(
type_->x_audio2_->CreateSourceVoice(&source_voice_, &wfx, 0,
@@ -187,6 +193,7 @@
int frames_in_buffer, offset_in_frames;
bool is_playing, is_eos_reached;
bool is_playback_rate_zero;
+ // TODO: Support |volume_| here as well...
{
ScopedLock lock(mutex_);
is_playback_rate_zero = playback_rate_ == 0.0;
diff --git a/src/starboard/shared/win32/decode_target_internal.cc b/src/starboard/shared/win32/decode_target_internal.cc
index 70b8e32..8188621 100644
--- a/src/starboard/shared/win32/decode_target_internal.cc
+++ b/src/starboard/shared/win32/decode_target_internal.cc
@@ -26,6 +26,7 @@
#include "third_party/angle/include/EGL/egl.h"
#include "third_party/angle/include/EGL/eglext.h"
#include "third_party/angle/include/GLES2/gl2.h"
+#include "third_party/angle/include/GLES2/gl2ext.h"
using Microsoft::WRL::ComPtr;
using starboard::shared::win32::VideoFramePtr;
@@ -73,24 +74,24 @@
SbDecodeTargetInfoPlane* planeY = &(info.planes[kSbDecodeTargetPlaneY]);
SbDecodeTargetInfoPlane* planeUV = &(info.planes[kSbDecodeTargetPlaneUV]);
- planeY->width = texture_desc.Width;
- planeY->height = texture_desc.Height;
+ planeY->width = info.width;
+ planeY->height = info.height;
planeY->content_region.left = 0;
- planeY->content_region.top = 0;
- planeY->content_region.right = texture_desc.Width;
- planeY->content_region.bottom = texture_desc.Height;
+ planeY->content_region.top = info.height;
+ planeY->content_region.right = frame->width();
+ planeY->content_region.bottom = info.height - frame->height();
- planeUV->width = texture_desc.Width / 2;
- planeUV->height = texture_desc.Height / 2;
- planeUV->content_region.left = 0;
- planeUV->content_region.top = 0;
- planeUV->content_region.right = texture_desc.Width / 2;
- planeUV->content_region.bottom = texture_desc.Height / 2;
+ planeUV->width = info.width / 2;
+ planeUV->height = info.height / 2;
+ planeUV->content_region.left = planeY->content_region.left / 2;
+ planeUV->content_region.top = planeY->content_region.top / 2;
+ planeUV->content_region.right = planeY->content_region.right / 2;
+ planeUV->content_region.bottom = planeY->content_region.bottom / 2;
EGLint luma_texture_attributes[] = {EGL_WIDTH,
- static_cast<EGLint>(texture_desc.Width),
+ static_cast<EGLint>(info.width),
EGL_HEIGHT,
- static_cast<EGLint>(texture_desc.Height),
+ static_cast<EGLint>(info.height),
EGL_TEXTURE_TARGET,
EGL_TEXTURE_2D,
EGL_TEXTURE_FORMAT,
@@ -119,16 +120,16 @@
dxgi_buffer.GetAddressOf());
SB_DCHECK(SUCCEEDED(hr));
- EGLSurface surface = eglCreatePbufferFromClientBuffer(
- display, EGL_D3D_TEXTURE_ANGLE, d3texture.Get(), config,
- luma_texture_attributes);
+ surface[0] = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE,
+ d3texture.Get(), config,
+ luma_texture_attributes);
- SB_DCHECK(surface != EGL_NO_SURFACE);
+ SB_DCHECK(surface[0] != EGL_NO_SURFACE);
glBindTexture(GL_TEXTURE_2D, gl_textures[0]);
SB_DCHECK(glGetError() == GL_NO_ERROR);
- ok = eglBindTexImage(display, surface, EGL_BACK_BUFFER);
+ ok = eglBindTexImage(display, surface[0], EGL_BACK_BUFFER);
SB_DCHECK(ok);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -136,6 +137,7 @@
planeY->texture = gl_textures[0];
planeY->gl_texture_target = GL_TEXTURE_2D;
+ planeY->gl_texture_format = GL_RED_EXT;
// This tells ANGLE that the texture it creates should draw
// the chroma channel on R8G8.
@@ -145,24 +147,24 @@
EGLint chroma_texture_attributes[] = {
EGL_WIDTH,
- static_cast<EGLint>(texture_desc.Width) / 2,
+ static_cast<EGLint>(info.width) / 2,
EGL_HEIGHT,
- static_cast<EGLint>(texture_desc.Height) / 2,
+ static_cast<EGLint>(info.height) / 2,
EGL_TEXTURE_TARGET,
EGL_TEXTURE_2D,
EGL_TEXTURE_FORMAT,
EGL_TEXTURE_RGBA,
EGL_NONE};
- surface = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE,
- d3texture.Get(), config,
- chroma_texture_attributes);
+ surface[1] = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE,
+ d3texture.Get(), config,
+ chroma_texture_attributes);
- SB_DCHECK(surface != EGL_NO_SURFACE);
+ SB_DCHECK(surface[1] != EGL_NO_SURFACE);
glBindTexture(GL_TEXTURE_2D, gl_textures[1]);
SB_DCHECK(glGetError() == GL_NO_ERROR);
- ok = eglBindTexImage(display, surface, EGL_BACK_BUFFER);
+ ok = eglBindTexImage(display, surface[1], EGL_BACK_BUFFER);
SB_DCHECK(ok);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -170,6 +172,7 @@
planeUV->texture = gl_textures[1];
planeUV->gl_texture_target = GL_TEXTURE_2D;
+ planeUV->gl_texture_format = GL_RG_EXT;
hr = d3texture->SetPrivateData(kCobaltDxgiBuffer, 0, nullptr);
SB_DCHECK(SUCCEEDED(hr));
@@ -178,6 +181,14 @@
SbDecodeTargetPrivate::~SbDecodeTargetPrivate() {
glDeleteTextures(1, &(info.planes[kSbDecodeTargetPlaneY].texture));
glDeleteTextures(1, &(info.planes[kSbDecodeTargetPlaneUV].texture));
+
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ eglReleaseTexImage(display, surface[0], EGL_BACK_BUFFER);
+ eglDestroySurface(display, surface[0]);
+
+ eglReleaseTexImage(display, surface[1], EGL_BACK_BUFFER);
+ eglDestroySurface(display, surface[1]);
}
void SbDecodeTargetRelease(SbDecodeTarget decode_target) {
diff --git a/src/starboard/shared/win32/decode_target_internal.h b/src/starboard/shared/win32/decode_target_internal.h
index 6204200..81aa66e 100644
--- a/src/starboard/shared/win32/decode_target_internal.h
+++ b/src/starboard/shared/win32/decode_target_internal.h
@@ -23,6 +23,9 @@
// Publicly accessible information about the decode target.
SbDecodeTargetInfo info;
::starboard::shared::win32::VideoFramePtr frame;
+ // EGLSurface is defined as void* in "third_party/angle/include/EGL/egl.h".
+ // Use void* directly here to avoid `egl.h` being included broadly.
+ void* surface[2];
explicit SbDecodeTargetPrivate(starboard::shared::win32::VideoFramePtr frame);
~SbDecodeTargetPrivate();
};
diff --git a/src/starboard/shared/win32/gyp_configuration.py b/src/starboard/shared/win32/gyp_configuration.py
index 0bf0e26..93f92f1 100644
--- a/src/starboard/shared/win32/gyp_configuration.py
+++ b/src/starboard/shared/win32/gyp_configuration.py
@@ -85,5 +85,5 @@
def GetToolchain(self):
sys.path.append(
os.path.join(STARBOARD_ROOT, 'shared', 'msvc', 'uwp'))
- from toolchain import MSVCUWPToolchain # pylint: disable=g-import-not-at-top,g-bad-import-order
+ from msvc_toolchain import MSVCUWPToolchain # pylint: disable=g-import-not-at-top,g-bad-import-order
return MSVCUWPToolchain()
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/shared/win32/media_is_output_protected.cc
similarity index 76%
copy from src/starboard/win/lib/atomic_public.h
copy to src/starboard/shared/win32/media_is_output_protected.cc
index be4e805..73d2f07 100644
--- a/src/starboard/win/lib/atomic_public.h
+++ b/src/starboard/shared/win32/media_is_output_protected.cc
@@ -1,20 +1,21 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
-#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
-
-#include "starboard/shared/win32/atomic_public.h"
-
-#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/media.h"
+
+bool SbMediaIsOutputProtected() {
+ // Pretend that HDCP is always on.
+ // TODO: Fix this with proper HDCP query.
+ return true;
+}
diff --git a/src/starboard/shared/win32/player_components_impl.cc b/src/starboard/shared/win32/player_components_impl.cc
index cc86d10..fa2c4af 100644
--- a/src/starboard/shared/win32/player_components_impl.cc
+++ b/src/starboard/shared/win32/player_components_impl.cc
@@ -35,9 +35,13 @@
using VideoRendererImpl = ::starboard::shared::win32::VideoRendererImpl;
AudioDecoderImpl* audio_decoder = new AudioDecoderImpl(
- audio_parameters.audio_codec, audio_parameters.audio_header);
+ audio_parameters.audio_codec, audio_parameters.audio_header,
+ audio_parameters.drm_system);
- VideoDecoderImpl* video_decoder = new VideoDecoderImpl(video_parameters);
+ VideoDecoderImpl* video_decoder = new VideoDecoderImpl(
+ video_parameters.video_codec, video_parameters.output_mode,
+ video_parameters.decode_target_graphics_context_provider,
+ video_parameters.drm_system);
AudioRendererImpl* audio_renderer =
new AudioRendererImpl(scoped_ptr<AudioDecoder>(audio_decoder).Pass(),
diff --git a/src/starboard/shared/win32/video_decoder.cc b/src/starboard/shared/win32/video_decoder.cc
index 40fd85d..0a08c9a 100644
--- a/src/starboard/shared/win32/video_decoder.cc
+++ b/src/starboard/shared/win32/video_decoder.cc
@@ -24,17 +24,24 @@
namespace shared {
namespace win32 {
-VideoDecoder::VideoDecoder(const VideoParameters& params)
- : video_codec_(params.video_codec),
+VideoDecoder::VideoDecoder(SbMediaVideoCodec video_codec,
+ SbPlayerOutputMode output_mode,
+ SbDecodeTargetGraphicsContextProvider*
+ decode_target_graphics_context_provider,
+ SbDrmSystem drm_system)
+ : video_codec_(video_codec),
+ drm_system_(drm_system),
host_(NULL),
- output_mode_(params.output_mode),
+ output_mode_(output_mode),
decode_target_graphics_context_provider_(
- params.decode_target_graphics_context_provider) {
- impl_ = AbstractWin32VideoDecoder::Create(video_codec_);
+ decode_target_graphics_context_provider) {
+ impl_ = AbstractWin32VideoDecoder::Create(video_codec_, drm_system_);
video_decoder_thread_.reset(new VideoDecoderThread(impl_.get(), this));
}
VideoDecoder::~VideoDecoder() {
+ SB_DCHECK(thread_checker_.CalledOnValidThread());
+
video_decoder_thread_.reset(nullptr);
impl_.reset(nullptr);
}
@@ -71,7 +78,7 @@
SB_DCHECK(host_);
video_decoder_thread_.reset(nullptr);
impl_.reset(nullptr);
- impl_ = AbstractWin32VideoDecoder::Create(video_codec_);
+ impl_ = AbstractWin32VideoDecoder::Create(video_codec_, drm_system_);
video_decoder_thread_.reset(new VideoDecoderThread(impl_.get(), this));
}
@@ -83,7 +90,7 @@
}
void VideoDecoder::OnVideoDecoded(VideoFramePtr data) {
- Status sts = data->IsEndOfStream() ? kBufferFull : kNeedMoreInput;
+ Status sts = (data && data->IsEndOfStream()) ? kBufferFull : kNeedMoreInput;
host_->OnDecoderStatusUpdate(sts, data);
}
diff --git a/src/starboard/shared/win32/video_decoder.h b/src/starboard/shared/win32/video_decoder.h
index 1fd2bfa..5d3734b 100644
--- a/src/starboard/shared/win32/video_decoder.h
+++ b/src/starboard/shared/win32/video_decoder.h
@@ -18,6 +18,7 @@
#include "starboard/common/ref_counted.h"
#include "starboard/common/scoped_ptr.h"
#include "starboard/configuration.h"
+#include "starboard/drm.h"
#include "starboard/shared/starboard/player/filter/player_components.h"
#include "starboard/shared/starboard/player/filter/video_decoder_internal.h"
#include "starboard/shared/starboard/player/input_buffer_internal.h"
@@ -38,7 +39,11 @@
private ::starboard::shared::starboard::player::JobQueue::JobOwner,
private VideoDecodedCallback {
public:
- explicit VideoDecoder(const VideoParameters& params);
+ VideoDecoder(SbMediaVideoCodec video_codec,
+ SbPlayerOutputMode output_mode,
+ SbDecodeTargetGraphicsContextProvider*
+ decode_target_graphics_context_provider,
+ SbDrmSystem drm_system);
~VideoDecoder() SB_OVERRIDE;
void SetHost(Host* host) SB_OVERRIDE;
@@ -53,22 +58,23 @@
void OnVideoDecoded(VideoFramePtr data) SB_OVERRIDE;
private:
+ ::starboard::shared::starboard::ThreadChecker thread_checker_;
+
// These variables will be initialized inside ctor or SetHost() and will not
// be changed during the life time of this class.
const SbMediaVideoCodec video_codec_;
+ SbDrmSystem drm_system_;
Host* host_;
// Decode-to-texture related state.
- SbPlayerOutputMode output_mode_;
-
- SbDecodeTargetGraphicsContextProvider*
+ const SbPlayerOutputMode output_mode_;
+ SbDecodeTargetGraphicsContextProvider* const
decode_target_graphics_context_provider_;
scoped_ptr<AbstractWin32VideoDecoder> impl_;
AtomicQueue<VideoFramePtr> decoded_data_;
- ::starboard::Mutex mutex_;
+ Mutex mutex_;
scoped_ptr<VideoDecoderThread> video_decoder_thread_;
- ::starboard::shared::starboard::ThreadChecker thread_checker_;
};
} // namespace win32
diff --git a/src/starboard/shared/win32/video_decoder_thread.cc b/src/starboard/shared/win32/video_decoder_thread.cc
index 64a7b2e..d2f8ba2 100644
--- a/src/starboard/shared/win32/video_decoder_thread.cc
+++ b/src/starboard/shared/win32/video_decoder_thread.cc
@@ -102,6 +102,7 @@
if (number_written > 0) {
processing_elements_.fetch_sub(static_cast<int32_t>(number_written));
work_done = true;
+ callback_->OnVideoDecoded(NULL);
}
while (VideoFramePtr decoded_datum =
diff --git a/src/starboard/shared/win32/win32_audio_decoder.cc b/src/starboard/shared/win32/win32_audio_decoder.cc
index 0b85f30..4142764 100644
--- a/src/starboard/shared/win32/win32_audio_decoder.cc
+++ b/src/starboard/shared/win32/win32_audio_decoder.cc
@@ -103,18 +103,19 @@
};
class AbstractWin32AudioDecoderImpl : public AbstractWin32AudioDecoder,
- public MediaBufferConsumerInterface {
+ public MediaBufferConsumerInterface {
public:
AbstractWin32AudioDecoderImpl(SbMediaAudioCodec codec,
- SbMediaAudioFrameStorageType audio_frame_fmt,
- SbMediaAudioSampleType sample_type,
- const SbMediaAudioHeader& audio_header)
+ SbMediaAudioFrameStorageType audio_frame_fmt,
+ SbMediaAudioSampleType sample_type,
+ const SbMediaAudioHeader& audio_header,
+ SbDrmSystem drm_system)
: codec_(codec),
audio_frame_fmt_(audio_frame_fmt),
sample_type_(sample_type),
audio_header_(audio_header) {
MediaBufferConsumerInterface* media_cb = this;
- impl_.reset(new DecoderImpl("audio", media_cb));
+ impl_.reset(new DecoderImpl("audio", media_cb, drm_system));
EnsureAudioDecoderCreated();
}
@@ -151,6 +152,8 @@
media_buffer->Unlock();
}
+ void OnNewOutputType(const ComPtr<IMFMediaType>& /*type*/) override {}
+
ComPtr<IMFMediaType> Configure(IMFTransform* decoder) {
ComPtr<IMFMediaType> input_type;
HRESULT hr = MFCreateMediaType(&input_type);
@@ -209,7 +212,6 @@
SB_DCHECK(decoder);
impl_->set_decoder(decoder);
- impl_->ActivateDecryptor(media_type);
// TODO: MFWinAudioFormat_PCM?
ComPtr<IMFMediaType> output_type =
@@ -234,17 +236,40 @@
const int size = buff.size();
const int64_t media_timestamp = buff.pts();
- // These parameters are used for decryption. But these are not used right
- // now and so remain empty.
std::vector<uint8_t> key_id;
std::vector<uint8_t> iv;
std::vector<Subsample> subsamples;
+ const SbDrmSampleInfo* drm_info = buff.drm_info();
+
+ if (drm_info != NULL && drm_info->initialization_vector_size != 0) {
+ key_id.assign(drm_info->identifier,
+ drm_info->identifier + drm_info->identifier_size);
+ iv.assign(drm_info->initialization_vector,
+ drm_info->initialization_vector +
+ drm_info->initialization_vector_size);
+ subsamples.reserve(drm_info->subsample_count);
+ for (int32_t i = 0; i < drm_info->subsample_count; ++i) {
+ Subsample subsample = {
+ static_cast<uint32_t>(
+ drm_info->subsample_mapping[i].clear_byte_count),
+ static_cast<uint32_t>(
+ drm_info->subsample_mapping[i].encrypted_byte_count)};
+ subsamples.push_back(subsample);
+ }
+ }
+
const std::int64_t win32_time_stamp = ConvertToWin32Time(media_timestamp);
// Adjust the offset for 7 bytes to remove the ADTS header.
- const uint8_t* audio_start = static_cast<const uint8_t*>(data) + 7;
- const int audio_size = size - 7;
+ const int kADTSHeaderSize = 7;
+ const uint8_t* audio_start =
+ static_cast<const uint8_t*>(data) + kADTSHeaderSize;
+ const int audio_size = size - kADTSHeaderSize;
+ if (!subsamples.empty()) {
+ SB_DCHECK(subsamples[0].clear_bytes == kADTSHeaderSize);
+ subsamples[0].clear_bytes = 0;
+ }
const bool write_ok = impl_->TryWriteInputBuffer(
audio_start, audio_size, win32_time_stamp, key_id, iv, subsamples);
@@ -282,10 +307,11 @@
SbMediaAudioCodec code,
SbMediaAudioFrameStorageType audio_frame_fmt,
SbMediaAudioSampleType sample_type,
- const SbMediaAudioHeader& audio_header) {
- return scoped_ptr<AbstractWin32AudioDecoder>(new
- AbstractWin32AudioDecoderImpl(code, audio_frame_fmt, sample_type,
- audio_header));
+ const SbMediaAudioHeader& audio_header,
+ SbDrmSystem drm_system) {
+ return scoped_ptr<AbstractWin32AudioDecoder>(
+ new AbstractWin32AudioDecoderImpl(code, audio_frame_fmt, sample_type,
+ audio_header, drm_system));
}
} // namespace win32
diff --git a/src/starboard/shared/win32/win32_audio_decoder.h b/src/starboard/shared/win32/win32_audio_decoder.h
index 4cc5f27..3bfe78c 100644
--- a/src/starboard/shared/win32/win32_audio_decoder.h
+++ b/src/starboard/shared/win32/win32_audio_decoder.h
@@ -18,6 +18,7 @@
#include <vector>
#include "starboard/common/scoped_ptr.h"
+#include "starboard/drm.h"
#include "starboard/media.h"
#include "starboard/shared/starboard/player/decoded_audio_internal.h"
#include "starboard/shared/starboard/player/video_frame_internal.h"
@@ -35,7 +36,8 @@
SbMediaAudioCodec codec,
SbMediaAudioFrameStorageType audio_frame_fmt,
SbMediaAudioSampleType sample_type,
- const SbMediaAudioHeader& audio_header);
+ const SbMediaAudioHeader& audio_header,
+ SbDrmSystem drm_system);
virtual ~AbstractWin32AudioDecoder() {}
// INPUT:
diff --git a/src/starboard/shared/win32/win32_decoder_impl.cc b/src/starboard/shared/win32/win32_decoder_impl.cc
index b06fcdc..b41b418 100644
--- a/src/starboard/shared/win32/win32_decoder_impl.cc
+++ b/src/starboard/shared/win32/win32_decoder_impl.cc
@@ -117,11 +117,15 @@
} // namespace
DecoderImpl::DecoderImpl(const std::string& type,
- MediaBufferConsumerInterface* media_buffer_consumer)
+ MediaBufferConsumerInterface* media_buffer_consumer,
+ SbDrmSystem drm_system)
: type_(type),
media_buffer_consumer_(media_buffer_consumer),
discontinuity_(false) {
SB_DCHECK(media_buffer_consumer_);
+ drm_system_ =
+ static_cast<::starboard::xb1::shared::playready::SbDrmSystemPlayready*>(
+ drm_system);
}
DecoderImpl::~DecoderImpl() {
@@ -137,13 +141,29 @@
return decoder;
}
-void DecoderImpl::ActivateDecryptor(ComPtr<IMFMediaType> input_type) {
+void DecoderImpl::ActivateDecryptor() {
+ SB_DCHECK(decoder_);
+
if (!decryptor_) {
return;
}
- HRESULT hr = decryptor_->SetInputType(kStreamId, input_type.Get(),
- 0); // MFT_SET_TYPE_TEST_FLAGS.
+ ComPtr<IMFMediaType> decryptor_input_type;
+
+ HRESULT hr = decoder_->GetInputCurrentType(
+ kStreamId, decryptor_input_type.GetAddressOf());
+ CheckResult(hr);
+
+ GUID original_sub_type;
+ {
+ ComPtr<IMFMediaType> output_type;
+ hr = decoder_->GetOutputCurrentType(kStreamId, output_type.GetAddressOf());
+ CheckResult(hr);
+ output_type->GetGUID(MF_MT_SUBTYPE, &original_sub_type);
+ }
+
+ const DWORD kFlags = 0;
+ hr = decryptor_->SetInputType(kStreamId, decryptor_input_type.Get(), kFlags);
CheckResult(hr);
// Ensure that the decryptor and the decoder agrees on the protection of
@@ -158,7 +178,6 @@
BYTE* crypt_seed = NULL;
DWORD crypt_seed_size = 0;
ComPtr<IMFMediaType> decoder_input_type;
- ComPtr<IMFMediaType> decoder_output_type;
hr = decryptor_.As(&decryption_sample_protection);
CheckResult(hr);
@@ -211,6 +230,21 @@
// Start the decryptor, note that this should be better abstracted.
SendMFTMessage(decryptor_.Get(), MFT_MESSAGE_NOTIFY_BEGIN_STREAMING);
SendMFTMessage(decryptor_.Get(), MFT_MESSAGE_NOTIFY_START_OF_STREAM);
+
+ for (int index = 0;; ++index) {
+ ComPtr<IMFMediaType> output_type;
+ hr = decoder_->GetOutputAvailableType(0, index, &output_type);
+ if (SUCCEEDED(hr)) {
+ GUID sub_type;
+ output_type->GetGUID(MF_MT_SUBTYPE, &sub_type);
+ if (IsEqualGUID(sub_type, original_sub_type)) {
+ hr = decoder_->SetOutputType(0, output_type.Get(), 0);
+ CheckResult(hr);
+ break;
+ }
+ }
+ output_type.Reset();
+ }
}
bool DecoderImpl::TryWriteInputBuffer(
@@ -236,6 +270,19 @@
// Better check the key id size is 16 and iv size is 8 or 16.
bool encrypted = !key_id.empty() && !iv.empty();
if (encrypted) {
+ if (!decryptor_) {
+ scoped_refptr<::starboard::xb1::shared::playready::PlayreadyLicense>
+ license = drm_system_->GetLicense(key_id.data(),
+ static_cast<int>(key_id.size()));
+ if (license && license->usable()) {
+ decryptor_ = license->decryptor();
+ ActivateDecryptor();
+ }
+ }
+ if (!decryptor_) {
+ SB_NOTREACHED();
+ return false;
+ }
size_t iv_size = iv.size();
const char kEightZeros[8] = {0};
if (iv_size == 16 && SbMemoryCompare(iv.data() + 8, kEightZeros, 8) == 0) {
@@ -315,27 +362,33 @@
bool DecoderImpl::DeliverOneOutputOnAllTransforms() {
SB_DCHECK(decoder_);
- bool delivered = false;
if (decryptor_) {
- if (ComPtr<IMFSample> sample = DeliverOutputOnTransform(decryptor_)) {
- HRESULT hr = decoder_->ProcessInput(kStreamId, sample.Get(), 0);
+ if (!cached_decryptor_output_) {
+ cached_decryptor_output_ = DeliverOutputOnTransform(decryptor_);
+ }
+ while (cached_decryptor_output_) {
+ HRESULT hr =
+ decoder_->ProcessInput(kStreamId, cached_decryptor_output_.Get(), 0);
if (hr == MF_E_NOTACCEPTING) {
- // The protocol says that when ProcessInput() returns MF_E_NOTACCEPTING,
- // there must be some output available. Retrieve the output and the next
- // ProcessInput() should succeed.
- ComPtr<IMFSample> sample_inner = DeliverOutputOnTransform(decoder_);
- if (sample_inner) {
- DeliverDecodedSample(sample_inner);
- delivered = true;
- }
- hr = decoder_->ProcessInput(kStreamId, sample.Get(), 0);
+ break;
+ } else {
CheckResult(hr);
- return delivered;
+ cached_decryptor_output_ = DeliverOutputOnTransform(decryptor_);
}
- CheckResult(hr);
- delivered = true;
+ }
+ if (cached_decryptor_output_) {
+ // The protocol says that when ProcessInput() returns MF_E_NOTACCEPTING,
+ // there must be some output available. Retrieve the output and the next
+ // ProcessInput() should succeed.
+ ComPtr<IMFSample> decoder_output = DeliverOutputOnTransform(decoder_);
+ if (decoder_output) {
+ DeliverDecodedSample(decoder_output);
+ }
+ return decoder_output != NULL;
}
}
+
+ bool delivered = false;
if (ComPtr<IMFSample> sample = DeliverOutputOnTransform(decoder_)) {
DeliverDecodedSample(sample);
delivered = true;
@@ -371,18 +424,6 @@
HRESULT hr = transform->GetOutputStreamInfo(kStreamId, &output_stream_info);
CheckResult(hr);
- // Each media sample (IMFSample interface) of output data from the MFT
- // contains complete, unbroken units of data. The definition of a unit
- // of data depends on the media type: For uncompressed video, a video
- // frame; for compressed data, a compressed packet; for uncompressed audio,
- // a single audio frame.
- //
- // For uncompressed audio formats, this flag is always implied. (It is valid
- // to set the flag, but not required.) An uncompressed audio frame should
- // never span more than one media sample.
- SB_DCHECK((output_stream_info.dwFlags & MFT_OUTPUT_STREAM_WHOLE_SAMPLES) !=
- 0);
-
if (StreamAllocatesMemory(output_stream_info.dwFlags)) {
// Try to let the IMFTransform allocate the memory if possible.
return;
@@ -431,9 +472,21 @@
hr = transform->SetOutputType(kStreamId, media_type.Get(), 0);
CheckResult(hr);
- return NULL;
- } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT ||
- output_data_buffer.dwStatus == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE) {
+
+ media_buffer_consumer_->OnNewOutputType(media_type);
+
+ hr = transform->ProcessOutput(kFlags, kNumberOfBuffers, &output_data_buffer,
+ &status);
+
+ SB_DCHECK(!output_data_buffer.pEvents);
+
+ output = output_data_buffer.pSample;
+ ReleaseIfNotNull(&output_data_buffer.pEvents);
+ ReleaseIfNotNull(&output_data_buffer.pSample);
+ }
+
+ if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT ||
+ output_data_buffer.dwStatus == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE) {
return NULL;
}
diff --git a/src/starboard/shared/win32/win32_decoder_impl.h b/src/starboard/shared/win32/win32_decoder_impl.h
index 38374ff..cef0d5d 100644
--- a/src/starboard/shared/win32/win32_decoder_impl.h
+++ b/src/starboard/shared/win32/win32_decoder_impl.h
@@ -25,10 +25,14 @@
#include <vector>
#include "starboard/common/scoped_ptr.h"
+#include "starboard/drm.h"
#include "starboard/media.h"
#include "starboard/shared/win32/media_common.h"
#include "starboard/types.h"
+// TODO: Win32 code shouldn't depend on Xb1 code. Refactor this.
+#include "starboard/xb1/shared/playready/drm_system_playready.h"
+
namespace starboard {
namespace shared {
namespace win32 {
@@ -38,6 +42,8 @@
virtual void Consume(Microsoft::WRL::ComPtr<IMFMediaBuffer> media_buffer,
int64_t win32_timestamp) = 0;
+ virtual void OnNewOutputType(const ComPtr<IMFMediaType>& type) = 0;
+
protected:
~MediaBufferConsumerInterface() {}
};
@@ -50,12 +56,13 @@
class DecoderImpl {
public:
DecoderImpl(const std::string& type,
- MediaBufferConsumerInterface* media_buffer_consumer);
+ MediaBufferConsumerInterface* media_buffer_consumer,
+ SbDrmSystem drm_system);
~DecoderImpl();
static Microsoft::WRL::ComPtr<IMFTransform> CreateDecoder(CLSID clsid);
- void ActivateDecryptor(Microsoft::WRL::ComPtr<IMFMediaType> input_type);
+ void ActivateDecryptor();
bool TryWriteInputBuffer(const void* data,
int size,
std::int64_t win32_timestamp,
@@ -84,9 +91,11 @@
const std::string type_; // For debugging purpose.
// This is the target for the all completed media buffers.
MediaBufferConsumerInterface* media_buffer_consumer_;
+ ::starboard::xb1::shared::playready::SbDrmSystemPlayready* drm_system_;
bool discontinuity_;
Microsoft::WRL::ComPtr<IMFTransform> decryptor_;
+ Microsoft::WRL::ComPtr<IMFSample> cached_decryptor_output_;
Microsoft::WRL::ComPtr<IMFTransform> decoder_;
};
diff --git a/src/starboard/shared/win32/win32_video_decoder.cc b/src/starboard/shared/win32/win32_video_decoder.cc
index 93bc487..667b2e5 100644
--- a/src/starboard/shared/win32/win32_video_decoder.cc
+++ b/src/starboard/shared/win32/win32_video_decoder.cc
@@ -36,31 +36,22 @@
// This magic number is taken directly from sample from MS. Can be further
// tuned in case if there is playback issues.
const int kSampleAllocatorFramesMax = 5;
+// This is the minimum allocated frames in the output ring buffer. Can be
+// further tuned to save memory. Note that use a value that is too small leads
+// to hang when calling ProcessOutput().
+const int kMinimumOutputSampleCount = 10;
// CLSID_CMSVideoDecoderMFT {62CE7E72-4C71-4D20-B15D-452831A87D9D}
const GUID CLSID_VideoDecoder = {0x62CE7E72, 0x4C71, 0x4d20, 0xB1, 0x5D, 0x45,
0x28, 0x31, 0xA8, 0x7D, 0x9D};
-ComPtr<ID3D11Texture2D> GetTexture2D(ComPtr<IMFMediaBuffer> media_buffer) {
- ComPtr<IMFDXGIBuffer> dxgi_buffer;
- HRESULT hr = media_buffer.As(&dxgi_buffer);
- CheckResult(hr);
- SB_DCHECK(dxgi_buffer.Get());
-
- ComPtr<ID3D11Texture2D> dx_texture;
- hr = dxgi_buffer->GetResource(IID_PPV_ARGS(&dx_texture));
- CheckResult(hr);
- return dx_texture;
-}
-
class VideoFrameFactory {
public:
static VideoFramePtr Construct(SbMediaTime timestamp,
- ComPtr<IMFMediaBuffer> media_buffer) {
- ComPtr<ID3D11Texture2D> texture = GetTexture2D(media_buffer);
- D3D11_TEXTURE2D_DESC tex_desc;
- texture->GetDesc(&tex_desc);
- VideoFramePtr out(new VideoFrame(tex_desc.Width, tex_desc.Height,
+ ComPtr<IMFMediaBuffer> media_buffer,
+ uint32_t width,
+ uint32_t height) {
+ VideoFramePtr out(new VideoFrame(width, height,
timestamp, media_buffer.Detach(),
nullptr, DeleteTextureFn));
frames_in_flight_.increment();
@@ -84,10 +75,10 @@
class AbstractWin32VideoDecoderImpl : public AbstractWin32VideoDecoder,
public MediaBufferConsumerInterface {
public:
- explicit AbstractWin32VideoDecoderImpl(SbMediaVideoCodec codec)
+ AbstractWin32VideoDecoderImpl(SbMediaVideoCodec codec, SbDrmSystem drm_system)
: codec_(codec), surface_width_(0), surface_height_(0) {
MediaBufferConsumerInterface* media_cb = this;
- impl_.reset(new DecoderImpl("video", media_cb));
+ impl_.reset(new DecoderImpl("video", media_cb, drm_system));
EnsureVideoDecoderCreated();
}
@@ -95,10 +86,32 @@
int64_t win32_timestamp) {
const SbMediaTime media_timestamp = ConvertToMediaTime(win32_timestamp);
VideoFramePtr frame_output =
- VideoFrameFactory::Construct(media_timestamp, media_buffer);
+ VideoFrameFactory::Construct(media_timestamp, media_buffer,
+ surface_width_, surface_height_);
output_queue_.PushBack(frame_output);
}
+ void OnNewOutputType(const ComPtr<IMFMediaType>& type) override {
+ MFVideoArea aperture;
+ HRESULT hr = type->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE,
+ reinterpret_cast<UINT8*>(&aperture), sizeof(MFVideoArea), nullptr);
+ if (SUCCEEDED(hr)) {
+ // TODO: consider offset as well
+ surface_width_ = aperture.Area.cx;
+ surface_height_ = aperture.Area.cy;
+ return;
+ }
+
+ uint32_t width;
+ uint32_t height;
+ hr = MFGetAttributeSize(type.Get(), MF_MT_FRAME_SIZE,
+ &width, &height);
+ if (SUCCEEDED(hr)) {
+ surface_width_ = width;
+ surface_height_ = height;
+ }
+ }
+
ComPtr<IMFMediaType> Configure(IMFTransform* decoder) {
ComPtr<IMFMediaType> input_type;
HRESULT hr = MFCreateMediaType(&input_type);
@@ -160,8 +173,6 @@
SB_DCHECK(1 == input_stream_count);
SB_DCHECK(1 == output_stream_count);
- impl_->ActivateDecryptor(media_type);
-
ComPtr<IMFMediaType> output_type =
FindMediaType(MFVideoFormat_YV12, decoder.Get());
@@ -174,6 +185,10 @@
hr = decoder->GetAttributes(attributes.GetAddressOf());
CheckResult(hr);
+ hr = attributes->SetUINT32(MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT,
+ kMinimumOutputSampleCount);
+ CheckResult(hr);
+
UINT32 value = 0;
hr = attributes->GetUINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, &value);
SB_DCHECK(hr == S_OK || hr == MF_E_ATTRIBUTENOTFOUND);
@@ -225,19 +240,35 @@
return false; // Wait for more data.
}
- // This would be used for decrypting content.
- // For now this is empty.
std::vector<uint8_t> key_id;
std::vector<uint8_t> iv;
+ std::vector<Subsample> subsamples;
- std::vector<Subsample> empty_subsample;
+ // TODO: Merge this with similar code in the audio decoder.
+ const SbDrmSampleInfo* drm_info = buff->drm_info();
+
+ if (drm_info != NULL && drm_info->initialization_vector_size != 0) {
+ key_id.assign(drm_info->identifier,
+ drm_info->identifier + drm_info->identifier_size);
+ iv.assign(drm_info->initialization_vector,
+ drm_info->initialization_vector +
+ drm_info->initialization_vector_size);
+ subsamples.reserve(drm_info->subsample_count);
+ for (int32_t i = 0; i < drm_info->subsample_count; ++i) {
+ Subsample subsample = {
+ static_cast<uint32_t>(
+ drm_info->subsample_mapping[i].clear_byte_count),
+ static_cast<uint32_t>(
+ drm_info->subsample_mapping[i].encrypted_byte_count)};
+ subsamples.push_back(subsample);
+ }
+ }
const SbMediaTime media_timestamp = buff->pts();
const int64_t win32_timestamp = ConvertToWin32Time(media_timestamp);
const bool write_ok = impl_->TryWriteInputBuffer(
- buff->data(), buff->size(), win32_timestamp,
- key_id, iv, empty_subsample);
+ buff->data(), buff->size(), win32_timestamp, key_id, iv, subsamples);
return write_ok;
}
@@ -271,12 +302,14 @@
uint32_t surface_height_;
HardwareDecoderContext dx_decoder_ctx_;
};
+
} // anonymous namespace.
scoped_ptr<AbstractWin32VideoDecoder> AbstractWin32VideoDecoder::Create(
- SbMediaVideoCodec codec) {
+ SbMediaVideoCodec codec,
+ SbDrmSystem drm_system) {
return scoped_ptr<AbstractWin32VideoDecoder>(
- new AbstractWin32VideoDecoderImpl(codec));
+ new AbstractWin32VideoDecoderImpl(codec, drm_system));
}
} // namespace win32
diff --git a/src/starboard/shared/win32/win32_video_decoder.h b/src/starboard/shared/win32/win32_video_decoder.h
index 84ff7b7..a32158b 100644
--- a/src/starboard/shared/win32/win32_video_decoder.h
+++ b/src/starboard/shared/win32/win32_video_decoder.h
@@ -20,6 +20,7 @@
#include "starboard/common/ref_counted.h"
#include "starboard/common/scoped_ptr.h"
+#include "starboard/drm.h"
#include "starboard/media.h"
#include "starboard/shared/starboard/player/decoded_audio_internal.h"
#include "starboard/shared/starboard/player/video_frame_internal.h"
@@ -33,7 +34,8 @@
// VideoDecoder for Win32.
class AbstractWin32VideoDecoder {
public:
- static scoped_ptr<AbstractWin32VideoDecoder> Create(SbMediaVideoCodec codec);
+ static scoped_ptr<AbstractWin32VideoDecoder> Create(SbMediaVideoCodec codec,
+ SbDrmSystem drm_system);
virtual ~AbstractWin32VideoDecoder() {}
virtual bool TryWrite(const scoped_refptr<InputBuffer>& buff) = 0;
diff --git a/src/starboard/shared/x11/application_x11.cc b/src/starboard/shared/x11/application_x11.cc
index 19fb1f2..c4a5cb6 100644
--- a/src/starboard/shared/x11/application_x11.cc
+++ b/src/starboard/shared/x11/application_x11.cc
@@ -43,6 +43,9 @@
namespace starboard {
namespace shared {
namespace x11 {
+
+using ::starboard::shared::dev_input::DevInput;
+
namespace {
enum {
@@ -647,28 +650,6 @@
}
#endif
-bool XNextEventTimed(Display* display, XEvent* out_event, SbTime duration) {
- if (XPending(display) == 0) {
- if (duration <= SbTime()) {
- return false;
- }
-
- int fd = ConnectionNumber(display);
- fd_set read_set;
- FD_ZERO(&read_set);
- FD_SET(fd, &read_set);
- struct timeval tv;
- SbTime clamped_duration = std::max(duration, SbTime());
- ToTimevalDuration(clamped_duration, &tv);
- if (select(fd + 1, &read_set, NULL, NULL, &tv) == 0) {
- return false;
- }
- }
-
- XNextEvent(display, out_event);
- return true;
-}
-
void XSendAtom(Window window, Atom atom) {
// XLib is not thread-safe. Since we may be coming from another thread, we
// have to open another connection to the display to inject the wake-up event.
@@ -732,6 +713,10 @@
SbWindow window = new SbWindowPrivate(display_, options);
windows_.push_back(window);
+ if (!dev_input_) {
+ // evdev input will be sent to the first created window only.
+ dev_input_.reset(DevInput::Create(window, ConnectionNumber(display_)));
+ }
return window;
}
@@ -745,6 +730,12 @@
std::find(windows_.begin(), windows_.end(), window);
SB_DCHECK(iterator != windows_.end());
windows_.erase(iterator);
+
+ if (windows_.empty()) {
+ SB_DCHECK(dev_input_);
+ dev_input_.reset();
+ }
+
delete window;
if (windows_.empty()) {
StopX();
@@ -849,23 +840,29 @@
ApplicationX11::WaitForSystemEventWithTimeout(SbTime time) {
SB_DCHECK(display_);
- XEvent x_event;
-
shared::starboard::Application::Event* pending_event = GetPendingEvent();
if (pending_event) {
return pending_event;
}
- if (XNextEventTimed(display_, &x_event, time)) {
+ SB_DCHECK(dev_input_);
+ shared::starboard::Application::Event* evdev_event =
+ dev_input_->WaitForSystemEventWithTimeout(time);
+
+ if (!evdev_event && XPending(display_) != 0) {
+ XEvent x_event;
+ XNextEvent(display_, &x_event);
return XEventToEvent(&x_event);
- } else {
- return NULL;
}
+
+ return evdev_event;
}
void ApplicationX11::WakeSystemEventWait() {
SB_DCHECK(!windows_.empty());
XSendAtom((*windows_.begin())->window, wake_up_atom_);
+ SB_DCHECK(dev_input_);
+ dev_input_->WakeSystemEventWait();
}
bool ApplicationX11::EnsureX() {
@@ -879,7 +876,7 @@
XSetErrorHandler(ErrorHandler);
display_ = XOpenDisplay(NULL);
if (!display_) {
- const char *display_environment = getenv("DISPLAY");
+ const char* display_environment = getenv("DISPLAY");
if (display_environment == NULL) {
SB_LOG(ERROR) << "Unable to open display, DISPLAY not set.";
} else {
diff --git a/src/starboard/shared/x11/application_x11.h b/src/starboard/shared/x11/application_x11.h
index a0235b1..cadfc90 100644
--- a/src/starboard/shared/x11/application_x11.h
+++ b/src/starboard/shared/x11/application_x11.h
@@ -20,9 +20,11 @@
#include <queue>
#include <vector>
+#include "base/memory/scoped_ptr.h"
#include "starboard/configuration.h"
#include "starboard/player.h"
#include "starboard/shared/internal_only.h"
+#include "starboard/shared/linux/dev_input/dev_input.h"
#include "starboard/shared/starboard/application.h"
#include "starboard/shared/starboard/queue_application.h"
#include "starboard/types.h"
@@ -117,6 +119,9 @@
// Indicates whether a key press event that requires a matching release has
// been dispatched.
bool paste_buffer_key_release_pending_;
+
+ // The /dev/input input handler. Only set when there is an open window.
+ scoped_ptr<::starboard::shared::dev_input::DevInput> dev_input_;
};
} // namespace x11
diff --git a/src/starboard/storage.h b/src/starboard/storage.h
index 37ccc10..33ba547 100644
--- a/src/starboard/storage.h
+++ b/src/starboard/storage.h
@@ -51,13 +51,34 @@
return record != kSbStorageInvalidRecord;
}
-// Opens and returns a SbStorageRecord for |user|, blocking I/O on the calling
-// thread until it returns. If |user| is not a valid |SbUser|, the function
-// returns |kSbStorageInvalidRecord|.
+#if SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION
+
+// Opens and returns the default SbStorageRecord for |user|, blocking I/O on the
+// calling thread until the open is completed. If |user| is not a valid
+// |SbUser|, the function returns |kSbStorageInvalidRecord|. Will return an
+// |SbStorageRecord| of size zero if the record does not yet exist. Opening an
+// already-open |SbStorageRecord| has undefined behavior.
//
-// |user|: The user for which the storage record is opened.
+// |user|: The user for which the storage record will be opened.
SB_EXPORT SbStorageRecord SbStorageOpenRecord(SbUser user);
+#else // SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION
+
+// Opens and returns the SbStorageRecord for |user| named |name|, blocking I/O
+// on the calling thread until the open is completed. If |user| is not a valid
+// |SbUser|, the function returns |kSbStorageInvalidRecord|. Will return an
+// |SbStorageRecord| of size zero if the record does not yet exist. Opening an
+// already-open |SbStorageRecord| has undefined behavior.
+//
+// If |name| is NULL, opens the default storage record for the user, like what
+// would have been saved with the previous version of SbStorageOpenRecord.
+//
+// |user|: The user for which the storage record will be opened.
+// |name|: The filesystem-safe name of the record to open.
+SB_EXPORT SbStorageRecord SbStorageOpenRecord(SbUser user, const char* name);
+
+#endif // SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION
+
// Closes |record|, synchronously ensuring that all written data is flushed.
// This function performs blocking I/O on the calling thread.
//
@@ -91,9 +112,15 @@
// Replaces the data in |record| with |data_size| bytes from |data|. This
// function always deletes any previous data in that record. The return value
-// indicates whether the write succeeded. This function makes a best-effort
-// to read the entire record, and it performs performs blocking I/O on the
-// calling thread until the entire record is read or an error is encountered.
+// indicates whether the write succeeded. This function makes a best-effort to
+// write the entire record, and it may perform blocking I/O on the calling
+// thread until the entire record is written or an error is encountered.
+//
+// While |SbStorageWriteRecord()| may defer the persistence,
+// |SbStorageReadRecord()| is expected to work as expected immediately
+// afterwards, even without a call to |SbStorageCloseRecord()|. The data should
+// be persisted after a short time, even if there is an unexpected process
+// termination before |SbStorageCloseRecord()| is called.
//
// |record|: The record to be written to.
// |data|: The data to write to the record.
@@ -104,21 +131,43 @@
const char* data,
int64_t data_size);
-// Deletes the |SbStorageRecord| for the specified user. The return value
+#if SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION
+
+// Deletes the default |SbStorageRecord| for the |user|. The return value
// indicates whether the record existed and was successfully deleted. If the
// record did not exist or could not be deleted, the function returns |false|.
//
// This function must not be called while the user's storage record is open.
// This function performs blocking I/O on the calling thread.
//
-// |user|: The user for whom the record is deleted.
+// |user|: The user for whom the record will be deleted.
SB_EXPORT bool SbStorageDeleteRecord(SbUser user);
+#else // SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION
+
+// Deletes the |SbStorageRecord| for |user| named |name|. The return value
+// indicates whether the record existed and was successfully deleted. If the
+// record did not exist or could not be deleted, the function returns |false|.
+//
+// If |name| is NULL, deletes the default storage record for the user, like what
+// would have been deleted with the previous version of SbStorageDeleteRecord.
+//
+// This function must not be called while the user's storage record is open.
+// This function performs blocking I/O on the calling thread.
+//
+// |user|: The user for whom the record will be deleted.
+// |name|: The filesystem-safe name of the record to open.
+SB_EXPORT bool SbStorageDeleteRecord(SbUser user, const char* name);
+
+#endif // SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION
+
#ifdef __cplusplus
} // extern "C"
#endif
#ifdef __cplusplus
+#include <string>
+
namespace starboard {
// Inline scoped wrapper for SbStorageRecord.
@@ -126,18 +175,28 @@
public:
StorageRecord()
: user_(SbUserGetCurrent()), record_(kSbStorageInvalidRecord) {
- if (SbUserIsValid(user_)) {
- record_ = SbStorageOpenRecord(user_);
- }
+ Initialize();
}
explicit StorageRecord(SbUser user)
: user_(user), record_(kSbStorageInvalidRecord) {
- if (SbUserIsValid(user_)) {
- record_ = SbStorageOpenRecord(user_);
- }
+ Initialize();
}
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ explicit StorageRecord(const char* name)
+ : user_(SbUserGetCurrent()),
+ name_(name),
+ record_(kSbStorageInvalidRecord) {
+ Initialize();
+ }
+
+ StorageRecord(SbUser user, const char* name)
+ : user_(user), name_(name), record_(kSbStorageInvalidRecord) {
+ Initialize();
+ }
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+
~StorageRecord() { Close(); }
bool IsValid() { return SbStorageIsValidRecord(record_); }
int64_t GetSize() { return SbStorageGetRecordSize(record_); }
@@ -160,11 +219,36 @@
bool Delete() {
Close();
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ if (!name_.empty()) {
+ return SbStorageDeleteRecord(user_, name_.c_str());
+ } else {
+ return SbStorageDeleteRecord(user_, NULL);
+ }
+#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
return SbStorageDeleteRecord(user_);
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
}
private:
+ void Initialize() {
+ if (SbUserIsValid(user_)) {
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ if (!name_.empty()) {
+ record_ = SbStorageOpenRecord(user_, name_.c_str());
+ } else {
+ record_ = SbStorageOpenRecord(user_, NULL);
+ }
+#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ record_ = SbStorageOpenRecord(user_);
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ }
+ }
+
SbUser user_;
+#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
+ std::string name_;
+#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION
SbStorageRecord record_;
};
diff --git a/src/starboard/stub/BUILD.gn b/src/starboard/stub/BUILD.gn
new file mode 100644
index 0000000..18ad876
--- /dev/null
+++ b/src/starboard/stub/BUILD.gn
@@ -0,0 +1,428 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//starboard/build/config/fastbuild.gni")
+import("//starboard/build/delegated_config.gni")
+
+# =============================================================================
+# DEFAULT COMPILER CONFIGS
+# =============================================================================
+
+config("compiler_defaults") {
+ cflags = [
+ # We'll pretend not to be Linux, but Starboard instead.
+ "-U__linux__",
+ "-Werror",
+ "-fcolor-diagnostics",
+ # Default visibility to hidden, to enable dead stripping.
+ "-fvisibility=hidden",
+ # Warn for implicit type conversions that may change a value.
+ "-Wconversion",
+ "-Wno-c++11-compat",
+ # This (rightfully) complains about "override", which we use heavily.
+ "-Wno-c++11-extensions",
+ # Warns on switches on enums that cover all enum values but also contain a
+ # default: branch. Chrome is full of that.
+ "-Wno-covered-switch-default",
+ # protobuf uses hash_map.
+ "-Wno-deprecated",
+ "-fno-exceptions",
+ # Don't warn about the "struct foo f = {0};" initialization pattern.
+ "-Wno-missing-field-initializers",
+ # Do not warn for implicit sign conversions.
+ "-Wno-sign-conversion",
+ "-fno-strict-aliasing", # See http://crbug.com/32204
+ # TODO(pkasting): In C++11 this is legal, so this should be removed when we
+ # change to that. (This is also why we don't bother fixing all these cases
+ # today.)
+ "-Wno-unnamed-type-template-args",
+ # Triggered by the COMPILE_ASSERT macro.
+ "-Wno-unused-local-typedef",
+ # Do not warn if a function or variable cannot be implicitly
+ # instantiated.
+ "-Wno-undefined-var-template",
+ ]
+
+ defines = [
+ "__STDC_FORMAT_MACROS",
+ ]
+
+ cflags_cc = [
+ "-std=gnu++11",
+ ]
+}
+
+config("compiler_defaults_debug") {
+ cflags = []
+ if (!cobalt_use_fastbuild) {
+ cflags += [ "-g" ]
+ }
+}
+
+config("compiler_defaults_devel") {
+ cflags = []
+ if (!cobalt_use_fastbuild) {
+ cflags += [ "-g" ]
+ }
+}
+
+config("compiler_defaults_qa") {
+ cflags = [
+ "-gline-tables-only",
+ ]
+}
+
+config("compiler_defaults_gold") {
+ cflags = [
+ "-gline-tables-only",
+ ]
+}
+
+# =============================================================================
+# DELEGATED CONFIGS
+# =============================================================================
+
+config("pedantic_warnings") {
+ cflags = [
+ "-Wall",
+ "-Wextra",
+ "-Wunreachable-code",
+ ]
+}
+
+config("no_pedantic_warnings") {
+ cflags = [
+ # "this" pointer cannot be NULL...pointer may be assumed
+ # to always convert to true.
+ "-Wno-undefined-bool-conversion",
+ # Skia doesn't use overrides.
+ "-Wno-inconsistent-missing-override",
+ # Do not warn about unused function params.
+ "-Wno-unused-parameter",
+ # Do not warn for implicit type conversions that may change a value.
+ "-Wno-conversion",
+ # shifting a negative signed value is undefined
+ "-Wno-shift-negative-value",
+ # Width of bit-field exceeds width of its type- value will be truncated
+ "-Wno-bitfield-width",
+ ]
+}
+
+
+delegated_config("optimizations") {
+ path = "//starboard/build/toolchain/linux/config"
+ prefixes = [ "no", "debuggable", "full" ]
+ generate_default = false
+}
+
+config("default_optimizations") {
+ if (cobalt_config == "debug") {
+ configs = [ ":no_optimizations" ]
+ } else {
+ configs = [ ":debuggable_optimizations" ]
+ }
+}
+
+
+delegated_config("rtti") {
+ path = "//starboard/build/toolchain/linux/config"
+ generate_default = false
+}
+
+config("default_rtti") {
+ if (cobalt_config == "debug" || cobalt_config == "devel") {
+ configs = [ ":rtti" ]
+ } else {
+ configs = [ ":no_rtti" ]
+ }
+}
+
+
+config("wexit_time_destructors") {
+ configs = [ "//starboard/build/toolchain/linux/config:wexit_time_destructors" ]
+}
+
+# =============================================================================
+# starboard_platform TARGET
+# =============================================================================
+
+static_library("starboard_platform") {
+ sources = [
+ "//starboard/shared/starboard/application.cc",
+ "//starboard/shared/starboard/command_line.cc",
+ "//starboard/shared/starboard/command_line.h",
+ "//starboard/shared/starboard/event_cancel.cc",
+ "//starboard/shared/starboard/event_schedule.cc",
+ "//starboard/shared/starboard/file_mode_string_to_flags.cc",
+ "//starboard/shared/starboard/log_message.cc",
+ "//starboard/shared/starboard/player/filter/stub_player_components_impl.cc",
+ "//starboard/shared/starboard/queue_application.cc",
+ "//starboard/shared/stub/accessibility_get_display_settings.cc",
+ "//starboard/shared/stub/accessibility_get_text_to_speech_settings.cc",
+ "//starboard/shared/stub/atomic_public.h",
+ "//starboard/shared/stub/audio_sink_create.cc",
+ "//starboard/shared/stub/audio_sink_destroy.cc",
+ "//starboard/shared/stub/audio_sink_get_max_channels.cc",
+ "//starboard/shared/stub/audio_sink_get_nearest_supported_sample_frequency.cc",
+ "//starboard/shared/stub/audio_sink_is_audio_frame_storage_type_supported.cc",
+ "//starboard/shared/stub/audio_sink_is_audio_sample_type_supported.cc",
+ "//starboard/shared/stub/audio_sink_is_valid.cc",
+ "//starboard/shared/stub/byte_swap.cc",
+ "//starboard/shared/stub/character_is_alphanumeric.cc",
+ "//starboard/shared/stub/character_is_digit.cc",
+ "//starboard/shared/stub/character_is_hex_digit.cc",
+ "//starboard/shared/stub/character_is_space.cc",
+ "//starboard/shared/stub/character_is_upper.cc",
+ "//starboard/shared/stub/character_to_lower.cc",
+ "//starboard/shared/stub/character_to_upper.cc",
+ "//starboard/shared/stub/condition_variable_broadcast.cc",
+ "//starboard/shared/stub/condition_variable_create.cc",
+ "//starboard/shared/stub/condition_variable_destroy.cc",
+ "//starboard/shared/stub/condition_variable_signal.cc",
+ "//starboard/shared/stub/condition_variable_wait.cc",
+ "//starboard/shared/stub/condition_variable_wait_timed.cc",
+ "//starboard/shared/stub/cryptography_create_transformer.cc",
+ "//starboard/shared/stub/cryptography_destroy_transformer.cc",
+ "//starboard/shared/stub/cryptography_get_tag.cc",
+ "//starboard/shared/stub/cryptography_set_authenticated_data.cc",
+ "//starboard/shared/stub/cryptography_set_initialization_vector.cc",
+ "//starboard/shared/stub/cryptography_transform.cc",
+ "//starboard/shared/stub/directory_can_open.cc",
+ "//starboard/shared/stub/directory_close.cc",
+ "//starboard/shared/stub/directory_create.cc",
+ "//starboard/shared/stub/directory_get_next.cc",
+ "//starboard/shared/stub/directory_open.cc",
+ "//starboard/shared/stub/double_absolute.cc",
+ "//starboard/shared/stub/double_exponent.cc",
+ "//starboard/shared/stub/double_floor.cc",
+ "//starboard/shared/stub/double_is_finite.cc",
+ "//starboard/shared/stub/double_is_nan.cc",
+ "//starboard/shared/stub/drm_close_session.cc",
+ "//starboard/shared/stub/drm_create_system.cc",
+ "//starboard/shared/stub/drm_destroy_system.cc",
+ "//starboard/shared/stub/drm_generate_session_update_request.cc",
+ "//starboard/shared/stub/drm_system_internal.h",
+ "//starboard/shared/stub/drm_update_session.cc",
+ "//starboard/shared/stub/file_can_open.cc",
+ "//starboard/shared/stub/file_close.cc",
+ "//starboard/shared/stub/file_delete.cc",
+ "//starboard/shared/stub/file_exists.cc",
+ "//starboard/shared/stub/file_flush.cc",
+ "//starboard/shared/stub/file_get_info.cc",
+ "//starboard/shared/stub/file_get_path_info.cc",
+ "//starboard/shared/stub/file_open.cc",
+ "//starboard/shared/stub/file_read.cc",
+ "//starboard/shared/stub/file_seek.cc",
+ "//starboard/shared/stub/file_truncate.cc",
+ "//starboard/shared/stub/file_write.cc",
+ "//starboard/shared/stub/log.cc",
+ "//starboard/shared/stub/log_flush.cc",
+ "//starboard/shared/stub/log_format.cc",
+ "//starboard/shared/stub/log_is_tty.cc",
+ "//starboard/shared/stub/log_raw.cc",
+ "//starboard/shared/stub/log_raw_dump_stack.cc",
+ "//starboard/shared/stub/log_raw_format.cc",
+ "//starboard/shared/stub/media_can_play_mime_and_key_system.cc",
+ "//starboard/shared/stub/media_get_audio_configuration.cc",
+ "//starboard/shared/stub/media_get_audio_output_count.cc",
+ "//starboard/shared/stub/media_is_audio_supported.cc",
+ "//starboard/shared/stub/media_is_output_protected.cc",
+ "//starboard/shared/stub/media_is_supported.cc",
+ "//starboard/shared/stub/media_is_transfer_characteristics_supported.cc",
+ "//starboard/shared/stub/media_is_video_supported.cc",
+ "//starboard/shared/stub/media_set_output_protection.cc",
+ "//starboard/shared/stub/memory_allocate_aligned_unchecked.cc",
+ "//starboard/shared/stub/memory_allocate_unchecked.cc",
+ "//starboard/shared/stub/memory_compare.cc",
+ "//starboard/shared/stub/memory_copy.cc",
+ "//starboard/shared/stub/memory_find_byte.cc",
+ "//starboard/shared/stub/memory_flush.cc",
+ "//starboard/shared/stub/memory_free.cc",
+ "//starboard/shared/stub/memory_free_aligned.cc",
+ "//starboard/shared/stub/memory_get_stack_bounds.cc",
+ "//starboard/shared/stub/memory_map.cc",
+ "//starboard/shared/stub/memory_move.cc",
+ "//starboard/shared/stub/memory_reallocate_unchecked.cc",
+ "//starboard/shared/stub/memory_set.cc",
+ "//starboard/shared/stub/memory_unmap.cc",
+ "//starboard/shared/stub/microphone_close.cc",
+ "//starboard/shared/stub/microphone_create.cc",
+ "//starboard/shared/stub/microphone_destroy.cc",
+ "//starboard/shared/stub/microphone_get_available.cc",
+ "//starboard/shared/stub/microphone_is_sample_rate_supported.cc",
+ "//starboard/shared/stub/microphone_open.cc",
+ "//starboard/shared/stub/microphone_read.cc",
+ "//starboard/shared/stub/mutex_acquire.cc",
+ "//starboard/shared/stub/mutex_acquire_try.cc",
+ "//starboard/shared/stub/mutex_create.cc",
+ "//starboard/shared/stub/mutex_destroy.cc",
+ "//starboard/shared/stub/mutex_release.cc",
+ "//starboard/shared/stub/once.cc",
+ "//starboard/shared/stub/player_create.cc",
+ "//starboard/shared/stub/player_destroy.cc",
+ "//starboard/shared/stub/player_get_current_frame.cc",
+ "//starboard/shared/stub/player_get_info.cc",
+ "//starboard/shared/stub/player_output_mode_supported.cc",
+ "//starboard/shared/stub/player_seek.cc",
+ "//starboard/shared/stub/player_set_bounds.cc",
+ "//starboard/shared/stub/player_set_pause.cc",
+ "//starboard/shared/stub/player_set_playback_rate.cc",
+ "//starboard/shared/stub/player_set_volume.cc",
+ "//starboard/shared/stub/player_write_end_of_stream.cc",
+ "//starboard/shared/stub/player_write_sample.cc",
+ "//starboard/shared/stub/socket_accept.cc",
+ "//starboard/shared/stub/socket_bind.cc",
+ "//starboard/shared/stub/socket_clear_last_error.cc",
+ "//starboard/shared/stub/socket_connect.cc",
+ "//starboard/shared/stub/socket_create.cc",
+ "//starboard/shared/stub/socket_destroy.cc",
+ "//starboard/shared/stub/socket_free_resolution.cc",
+ "//starboard/shared/stub/socket_get_interface_address.cc",
+ "//starboard/shared/stub/socket_get_last_error.cc",
+ "//starboard/shared/stub/socket_get_local_address.cc",
+ "//starboard/shared/stub/socket_get_local_interface_address.cc",
+ "//starboard/shared/stub/socket_is_connected.cc",
+ "//starboard/shared/stub/socket_is_connected_and_idle.cc",
+ "//starboard/shared/stub/socket_join_multicast_group.cc",
+ "//starboard/shared/stub/socket_listen.cc",
+ "//starboard/shared/stub/socket_receive_from.cc",
+ "//starboard/shared/stub/socket_resolve.cc",
+ "//starboard/shared/stub/socket_send_to.cc",
+ "//starboard/shared/stub/socket_set_broadcast.cc",
+ "//starboard/shared/stub/socket_set_receive_buffer_size.cc",
+ "//starboard/shared/stub/socket_set_reuse_address.cc",
+ "//starboard/shared/stub/socket_set_send_buffer_size.cc",
+ "//starboard/shared/stub/socket_set_tcp_keep_alive.cc",
+ "//starboard/shared/stub/socket_set_tcp_no_delay.cc",
+ "//starboard/shared/stub/socket_set_tcp_window_scaling.cc",
+ "//starboard/shared/stub/socket_waiter_add.cc",
+ "//starboard/shared/stub/socket_waiter_create.cc",
+ "//starboard/shared/stub/socket_waiter_destroy.cc",
+ "//starboard/shared/stub/socket_waiter_remove.cc",
+ "//starboard/shared/stub/socket_waiter_wait.cc",
+ "//starboard/shared/stub/socket_waiter_wait_timed.cc",
+ "//starboard/shared/stub/socket_waiter_wake_up.cc",
+ "//starboard/shared/stub/speech_recognizer_cancel.cc",
+ "//starboard/shared/stub/speech_recognizer_create.cc",
+ "//starboard/shared/stub/speech_recognizer_destroy.cc",
+ "//starboard/shared/stub/speech_recognizer_start.cc",
+ "//starboard/shared/stub/speech_recognizer_stop.cc",
+ "//starboard/shared/stub/speech_synthesis_cancel.cc",
+ "//starboard/shared/stub/speech_synthesis_set_language.cc",
+ "//starboard/shared/stub/speech_synthesis_speak.cc",
+ "//starboard/shared/stub/storage_close_record.cc",
+ "//starboard/shared/stub/storage_delete_record.cc",
+ "//starboard/shared/stub/storage_get_record_size.cc",
+ "//starboard/shared/stub/storage_open_record.cc",
+ "//starboard/shared/stub/storage_read_record.cc",
+ "//starboard/shared/stub/storage_write_record.cc",
+ "//starboard/shared/stub/string_compare.cc",
+ "//starboard/shared/stub/string_compare_all.cc",
+ "//starboard/shared/stub/string_compare_no_case.cc",
+ "//starboard/shared/stub/string_compare_no_case_n.cc",
+ "//starboard/shared/stub/string_compare_wide.cc",
+ "//starboard/shared/stub/string_concat.cc",
+ "//starboard/shared/stub/string_concat_wide.cc",
+ "//starboard/shared/stub/string_copy.cc",
+ "//starboard/shared/stub/string_copy_wide.cc",
+ "//starboard/shared/stub/string_duplicate.cc",
+ "//starboard/shared/stub/string_find_character.cc",
+ "//starboard/shared/stub/string_find_last_character.cc",
+ "//starboard/shared/stub/string_find_string.cc",
+ "//starboard/shared/stub/string_format.cc",
+ "//starboard/shared/stub/string_format_wide.cc",
+ "//starboard/shared/stub/string_get_length.cc",
+ "//starboard/shared/stub/string_get_length_wide.cc",
+ "//starboard/shared/stub/string_parse_double.cc",
+ "//starboard/shared/stub/string_parse_signed_integer.cc",
+ "//starboard/shared/stub/string_parse_uint64.cc",
+ "//starboard/shared/stub/string_parse_unsigned_integer.cc",
+ "//starboard/shared/stub/string_scan.cc",
+ "//starboard/shared/stub/system_binary_search.cc",
+ "//starboard/shared/stub/system_break_into_debugger.cc",
+ "//starboard/shared/stub/system_clear_last_error.cc",
+ "//starboard/shared/stub/system_clear_platform_error.cc",
+ "//starboard/shared/stub/system_get_connection_type.cc",
+ "//starboard/shared/stub/system_get_device_type.cc",
+ "//starboard/shared/stub/system_get_error_string.cc",
+ "//starboard/shared/stub/system_get_last_error.cc",
+ "//starboard/shared/stub/system_get_locale_id.cc",
+ "//starboard/shared/stub/system_get_number_of_processors.cc",
+ "//starboard/shared/stub/system_get_path.cc",
+ "//starboard/shared/stub/system_get_property.cc",
+ "//starboard/shared/stub/system_get_random_data.cc",
+ "//starboard/shared/stub/system_get_random_uint64.cc",
+ "//starboard/shared/stub/system_get_stack.cc",
+ "//starboard/shared/stub/system_get_total_cpu_memory.cc",
+ "//starboard/shared/stub/system_get_total_gpu_memory.cc",
+ "//starboard/shared/stub/system_get_used_cpu_memory.cc",
+ "//starboard/shared/stub/system_get_used_gpu_memory.cc",
+ "//starboard/shared/stub/system_has_capability.cc",
+ "//starboard/shared/stub/system_hide_splash_screen.cc",
+ "//starboard/shared/stub/system_is_debugger_attached.cc",
+ "//starboard/shared/stub/system_raise_platform_error.cc",
+ "//starboard/shared/stub/system_request_pause.cc",
+ "//starboard/shared/stub/system_request_stop.cc",
+ "//starboard/shared/stub/system_request_suspend.cc",
+ "//starboard/shared/stub/system_request_unpause.cc",
+ "//starboard/shared/stub/system_sort.cc",
+ "//starboard/shared/stub/system_symbolize.cc",
+ "//starboard/shared/stub/thread_create.cc",
+ "//starboard/shared/stub/thread_create_local_key.cc",
+ "//starboard/shared/stub/thread_destroy_local_key.cc",
+ "//starboard/shared/stub/thread_detach.cc",
+ "//starboard/shared/stub/thread_get_current.cc",
+ "//starboard/shared/stub/thread_get_id.cc",
+ "//starboard/shared/stub/thread_get_local_value.cc",
+ "//starboard/shared/stub/thread_get_name.cc",
+ "//starboard/shared/stub/thread_is_equal.cc",
+ "//starboard/shared/stub/thread_join.cc",
+ "//starboard/shared/stub/thread_set_local_value.cc",
+ "//starboard/shared/stub/thread_set_name.cc",
+ "//starboard/shared/stub/thread_sleep.cc",
+ "//starboard/shared/stub/thread_types_public.h",
+ "//starboard/shared/stub/thread_yield.cc",
+ "//starboard/shared/stub/time_get_monotonic_now.cc",
+ "//starboard/shared/stub/time_get_monotonic_thread_now.cc",
+ "//starboard/shared/stub/time_get_now.cc",
+ "//starboard/shared/stub/time_zone_get_current.cc",
+ "//starboard/shared/stub/time_zone_get_dst_name.cc",
+ "//starboard/shared/stub/time_zone_get_name.cc",
+ "//starboard/shared/stub/user_get_current.cc",
+ "//starboard/shared/stub/user_get_property.cc",
+ "//starboard/shared/stub/user_get_signed_in.cc",
+ "//starboard/shared/stub/window_create.cc",
+ "//starboard/shared/stub/window_destroy.cc",
+ "//starboard/shared/stub/window_get_platform_handle.cc",
+ "//starboard/shared/stub/window_get_size.cc",
+ "//starboard/shared/stub/window_set_default_options.cc",
+ "application_stub.cc",
+ "application_stub.h",
+ "atomic_public.h",
+ "main.cc",
+ "thread_types_public.h",
+ ]
+
+ # Include private stubs, if present.
+ private_sources = exec_script("//starboard/tools/find_private_files.py",
+ [
+ rebase_path("//", root_build_dir),
+ "shared/stub/*.cc",
+ ],
+ "list lines",
+ [ "//starboard/private/shared/stub" ])
+ sources += rebase_path(private_sources, ".", root_build_dir)
+
+ defines = [ "STARBOARD_IMPLEMENTATION" ]
+}
diff --git a/src/starboard/stub/buildconfig.gni b/src/starboard/stub/buildconfig.gni
new file mode 100644
index 0000000..8e4bdee
--- /dev/null
+++ b/src/starboard/stub/buildconfig.gni
@@ -0,0 +1,36 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+###############################################################################
+# This file is imported into BUILDCONFIG.gn. As a side effect, any variable
+# defined here becomes a global variable in all GN files.
+#
+# Adding new variables to this file could result in variable name conflicts, so
+# keep the number of variables in this file to a minimum!
+#
+# If you need to define a temporary variable, prefix it with an underscore like
+# _this. Prefixing a variable with an underscore makes it a private variable
+# that won't bleed into other files.
+###############################################################################
+
+# Target OS and CPU.
+# BUILDCONFIG.gn sets target_os and target_cpu to the values of these two
+# variables below. Unfortunately, due to GN's restrictions on how variables can
+# be changed, we can't directly set target_os and target_cpu here.
+target_os_ = "linux"
+target_cpu_ = "x64"
+
+# The target and host toolchain
+target_toolchain = "//starboard/build/toolchain/linux:clang_x64"
+host_toolchain = "//starboard/build/toolchain/linux:clang_$host_cpu"
diff --git a/src/starboard/stub/configuration.gni b/src/starboard/stub/configuration.gni
new file mode 100644
index 0000000..55a886e
--- /dev/null
+++ b/src/starboard/stub/configuration.gni
@@ -0,0 +1,29 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Use a stub rasterizer and graphical setup
+rasterizer_type = "stub"
+
+# No GL drivers available
+gl_type = "none"
+
+# Use media source extension implementation that is conformed to the
+# Candidate Recommandation of July 5th 2016.
+cobalt_use_media_source_2016 = true
+
+declare_args() {
+ # Set to true to enable distributed compilation using Goma. By default we
+ # use Goma for stub and linux.
+ use_goma = true
+}
diff --git a/src/starboard/tools/abstract_launcher.py b/src/starboard/tools/abstract_launcher.py
index 65bc1ea..a840cde 100644
--- a/src/starboard/tools/abstract_launcher.py
+++ b/src/starboard/tools/abstract_launcher.py
@@ -1,4 +1,5 @@
-#!/usr/bin/python
+#
+# Copyright 2017 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -10,59 +11,25 @@
# 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."""
+# limitations under the License.
"""Abstraction for running Cobalt development tools."""
-import abc
-import imp
+import importlib
import os
-import re
import sys
-platform_module = imp.load_source(
- "platform", os.path.abspath(
- os.path.join(os.path.dirname(__file__), "platform.py")))
+if "environment" in sys.modules:
+ environment = sys.modules["environment"]
+else:
+ env_path = os.path.abspath(os.path.dirname(__file__))
+ if env_path not in sys.path:
+ sys.path.append(env_path)
+ environment = importlib.import_module("environment")
-def _GetAllPlatforms(path):
- """Retrieves information about all available Cobalt ports.
+import abc
- Args:
- path: Root path that will be crawled to find ports.
-
- Returns:
- Dict mapping available cobalt ports to their respective location in
- the filesystem.
- """
- platform_dict = {}
- for port in platform_module.PlatformInfo.EnumeratePorts(path):
- port_name = re.search(".*starboard-(.*)", port.port_name).group(1)
- platform_dict[port_name] = port.path
- return platform_dict
-
-
-def _GetProjectRoot():
- """Gets the root of this project.
-
- Returns:
- Path to the root of this project
-
- Raises:
- RuntimeError: There is no root.
- """
- current_path = os.path.normpath(os.path.dirname(__file__))
- while not os.access(os.path.join(current_path, ".gclient"), os.R_OK):
- next_path = os.path.dirname(current_path)
- if next_path == current_path:
- current_path = None
- break
- current_path = next_path
- client_root = current_path
-
- if not client_root:
- raise RuntimeError("No project root declared.")
-
- return client_root
+import starboard.tools.platform as platform_module
def _GetLauncherForPlatform(platform_path):
@@ -74,23 +41,9 @@
Returns:
The module containing the platform's launcher implementation.
"""
-
- # Necessary because gyp_configuration modules use relative imports.
- # "cobalt/build" needs to be in sys.path to keep the imports working
- sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),
- os.pardir, os.pardir,
- "cobalt", "build")))
-
- # Necessary because the gyp_configuration for linux-x64x11 imports
- # directly from "starboard/". All of this import logic will eventually be
- # moved to a configuration system.
- sys.path.append(os.path.abspath(os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir)))
-
- module_path = os.path.abspath(os.path.join(platform_path,
- "gyp_configuration.py"))
-
- gyp_module = imp.load_source("platform_module", module_path)
+ if platform_path not in sys.path:
+ sys.path.append(platform_path)
+ gyp_module = importlib.import_module("gyp_configuration")
return gyp_module.CreatePlatformConfig().GetLauncher()
@@ -112,8 +65,7 @@
"""
# Creates launcher for provided platform if the platform has a valid port
- client_root = _GetProjectRoot()
- platform_dict = _GetAllPlatforms(client_root)
+ platform_dict = platform_module.GetAllPorts()
if platform in platform_dict:
platform_path = platform_dict[platform]
launcher_module = _GetLauncherForPlatform(platform_path)
@@ -140,7 +92,11 @@
@abc.abstractmethod
def Run(self):
- """Runs the launcher's executable. Must be implemented in subclasses."""
+ """Runs the launcher's executable. Must be implemented in subclasses.
+
+ Returns:
+ The return code from the launcher's executable.
+ """
pass
@abc.abstractmethod
diff --git a/src/starboard/tools/environment.py b/src/starboard/tools/environment.py
new file mode 100644
index 0000000..e792803
--- /dev/null
+++ b/src/starboard/tools/environment.py
@@ -0,0 +1,94 @@
+#
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License."""
+"""Sets up a Starboard environment for use by the host application.
+
+Applications that use Starboard should contain a Python file, called
+"starboard_configuration.py", somewhere in the ancestor path of their
+"starboard" directory.
+
+The file should contain a variable, called PORT_ROOTS. Assign to it a
+list of paths to directories in which Starboard ports are located.
+Each path should be represented as a list of directory names whose locations
+are relative to the configuration file. Example:
+
+PORT_ROOTS = [
+ ["some_directory", "starboard"]
+ ["somewhere_else", "starboard"]
+]
+
+IF YOU ARE GOING TO USE STARBOARD FILES OUTSIDE OF STARBOARD, YOU NEED TO IMPORT
+THIS MODULE FIRST. Otherwise, sys.path will not be configured properly, none of
+your code will work, and you'll be sad.
+"""
+
+import importlib
+import os
+import sys
+
+PATHS = [
+ # Necessary because the gyp_configuration for linux-x64x11 imports
+ # directly from "starboard/".
+ os.path.abspath(os.path.join(
+ os.path.dirname(__file__), os.pardir, os.pardir)),
+
+ # Necessary because gyp_configuration modules use relative imports.
+ # "cobalt/build" needs to be in sys.path to keep the imports working
+ os.path.abspath(os.path.join(
+ os.path.dirname(__file__), os.pardir, os.pardir,
+ "cobalt", "build"))
+]
+
+# This module should only add the above paths to sys.path when they are not
+# present in the list already.
+for new_path in PATHS:
+ if new_path not in sys.path:
+ sys.path.append(new_path)
+
+
+def _GetStarboardConfigPath():
+ """Gets the path to the "starboard_configuration.py" file from the host app.
+
+ Returns:
+ Path to the "starboard_configuration.py" file from the host app
+
+ Raises:
+ RuntimeError: There is no configuration file.
+ """
+ current_path = os.path.normpath(os.path.dirname(__file__))
+ while not os.path.exists(os.path.join(current_path,
+ "starboard_configuration.py")):
+ next_path = os.path.dirname(current_path)
+ if next_path == current_path:
+ current_path = None
+ break
+ current_path = next_path
+ config_path = current_path
+
+ if not config_path:
+ raise RuntimeError("No starboard configuration declared.")
+
+ return config_path
+
+
+def GetStarboardPortRoots():
+ """Gets paths to the host app's Starboard port directories."""
+ config_path = _GetStarboardConfigPath()
+ sys.path.append(config_path)
+ config_module = importlib.import_module("starboard_configuration")
+ port_roots = config_module.PORT_ROOTS
+ port_root_paths = [os.path.abspath(os.path.join(
+ config_path, os.sep.join(root))) for root in port_roots]
+ return port_root_paths
+
diff --git a/src/starboard/tools/platform.py b/src/starboard/tools/platform.py
index 7c760f8..76e3438 100644
--- a/src/starboard/tools/platform.py
+++ b/src/starboard/tools/platform.py
@@ -16,8 +16,19 @@
"""Functionality to enumerate and represent starboard ports."""
import importlib
-import logging
import os
+import sys
+
+if "environment" in sys.modules:
+ environment = sys.modules["environment"]
+else:
+ env_path = os.path.abspath(os.path.dirname(__file__))
+ if env_path not in sys.path:
+ sys.path.append(env_path)
+ environment = importlib.import_module("environment")
+
+
+import logging
import re
@@ -61,11 +72,37 @@
return re.sub(r'[^a-zA-Z0-9_]', r'-', directory[start:])
+def _GetAllPlatforms(port_root_paths):
+ """Retrieves information about all available Cobalt ports.
+
+ Args:
+ port_root_paths: List of paths that will be crawled to find ports.
+
+ Returns:
+ Dict mapping each available port to its location in the filesystem.
+ """
+ platform_dict = {}
+ for path in port_root_paths:
+ for port in PlatformInfo.EnumeratePorts(path):
+ platform_dict[port.port_name] = port.path
+ return platform_dict
+
+
+def GetAllPorts():
+ """Gets all available starboard ports from the host app.
+
+ Returns:
+ Dictionary mapping port names to their path in the filesystem.
+ """
+ port_root_paths = environment.GetStarboardPortRoots()
+ return _GetAllPlatforms(port_root_paths)
+
+
class PlatformInfo(object):
"""Information about a specific starboard port."""
@classmethod
- def EnumeratePorts(cls, root_path, exclusion_set = None):
+ def EnumeratePorts(cls, root_path, exclusion_set=None):
"""Generator that iterates over starboard ports found under |path|."""
if not exclusion_set:
exclusion_set = set()
diff --git a/src/starboard/win/lib/gyp_configuration.gypi b/src/starboard/win/lib/gyp_configuration.gypi
index 0dec384..e491c37 100644
--- a/src/starboard/win/lib/gyp_configuration.gypi
+++ b/src/starboard/win/lib/gyp_configuration.gypi
@@ -16,6 +16,16 @@
'variables': {
'javascript_engine': 'mozjs',
'cobalt_enable_jit': 0,
+ # TODO: In theory, there are tools that can combine static libraries into
+ # thick static libraries with all their transitive dependencies. Using
+ # shared_library here can have unexpected consequences. Explore building
+ # this into a thick static library instead.
+ 'final_executable_type': 'shared_library',
+ 'default_renderer_options_dependency': '<(DEPTH)/cobalt/renderer/rasterizer/lib/lib.gyp:external_rasterizer',
+ 'sb_enable_lib': 1,
+ 'angle_build_winrt': 0,
+ 'winrt': 0,
+ 'enable_d3d11_feature_level_11': 1,
},
'includes': [
'../shared/gyp_configuration.gypi',
@@ -23,25 +33,18 @@
'target_defaults': {
'default_configuration': 'win-lib_debug',
'configurations': {
- 'lib_base': {
- 'abstract': 1,
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'SubSystem': '2', # WINDOWS
- }
- }
- },
+
'win-lib_debug': {
- 'inherit_from': ['msvs_debug', 'lib_base'],
+ 'inherit_from': ['win32_base', 'msvs_debug'],
},
'win-lib_devel': {
- 'inherit_from': ['msvs_devel', 'lib_base'],
+ 'inherit_from': ['win32_base', 'msvs_devel'],
},
'win-lib_qa': {
- 'inherit_from': ['msvs_qa', 'lib_base'],
+ 'inherit_from': ['win32_base', 'msvs_qa'],
},
'win-lib_gold': {
- 'inherit_from': ['msvs_gold', 'lib_base'],
+ 'inherit_from': ['win32_base', 'msvs_gold'],
},
}, # end of configurations
},
diff --git a/src/starboard/win/lib/main.cc b/src/starboard/win/lib/main.cc
deleted file mode 100644
index 2ab7084..0000000
--- a/src/starboard/win/lib/main.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <windows.h>
-
-#include <WinSock2.h>
-
-#include <string>
-#include <vector>
-
-#include "starboard/configuration.h"
-#include "starboard/shared/uwp/application_uwp.h"
-#include "starboard/shared/win32/thread_private.h"
-#include "starboard/shared/win32/wchar_utils.h"
-
-using starboard::shared::win32::wchar_tToUTF8;
-
-// TODO: Share more of this logic with xb1 & win-console?
-int main(Platform::Array<Platform::String ^> ^ args) {
- if (!IsDebuggerPresent()) {
- _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
- _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
- _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
- _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
- }
-
- const int kWinSockVersionMajor = 2;
- const int kWinSockVersionMinor = 2;
- WSAData wsaData;
- int init_result = WSAStartup(
- MAKEWORD(kWinSockVersionMajor, kWinSockVersionMajor), &wsaData);
-
- SB_CHECK(init_result == 0);
- // WSAStartup returns the highest version that is supported up to the version
- // we request.
- SB_CHECK(LOBYTE(wsaData.wVersion) == kWinSockVersionMajor &&
- HIBYTE(wsaData.wVersion) == kWinSockVersionMinor);
-
- starboard::shared::win32::RegisterMainThread();
-
- std::vector<std::string> string_args;
- for (auto it = args->begin(); it != args->end(); ++it) {
- Platform::String ^ s = *it;
- string_args.push_back(wchar_tToUTF8(s->Data(), s->Length()));
- }
-
- std::vector<const char*> utf8_args;
- for (auto it = string_args.begin(); it != string_args.end(); ++it) {
- utf8_args.push_back(it->data());
- }
-
- starboard::shared::uwp::ApplicationUwp application;
- int return_value = application.Run(static_cast<int>(utf8_args.size()),
- const_cast<char**>(utf8_args.data()));
-
- WSACleanup();
-
- return return_value;
-}
diff --git a/src/starboard/win/lib/starboard_platform.gyp b/src/starboard/win/lib/starboard_platform.gyp
index d61cc40..04fd716 100644
--- a/src/starboard/win/lib/starboard_platform.gyp
+++ b/src/starboard/win/lib/starboard_platform.gyp
@@ -14,7 +14,6 @@
{
'includes': [
'../shared/starboard_platform.gypi',
- '../../shared/uwp/starboard_platform.gypi'
],
'variables': {
'starboard_platform_dependent_files': [
@@ -22,6 +21,21 @@
'configuration_public.h',
'thread_types_public.h',
'../shared/system_get_path.cc',
+ '<(DEPTH)/starboard/shared/starboard/localized_strings.cc',
+ '<(DEPTH)/starboard/shared/starboard/localized_strings.cc',
+ '<(DEPTH)/starboard/shared/starboard/queue_application.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc',
+ '<(DEPTH)/starboard/shared/stub/decode_target_get_info.cc',
+ '<(DEPTH)/starboard/shared/stub/decode_target_release.cc',
+ '<@(uwp_incompatible_win32)',
+ '<@(stub_media_player)'
],
- }
+ },
}
diff --git a/src/starboard/win/shared/starboard_platform.gypi b/src/starboard/win/shared/starboard_platform.gypi
index 7134bee..43ec50b 100644
--- a/src/starboard/win/shared/starboard_platform.gypi
+++ b/src/starboard/win/shared/starboard_platform.gypi
@@ -17,6 +17,16 @@
'winrt%': 1,
'stub_media_player': [
],
+
+ 'stub_drm_system': [
+ '<(DEPTH)/starboard/shared/stub/drm_close_session.cc',
+ '<(DEPTH)/starboard/shared/stub/drm_create_system.cc',
+ '<(DEPTH)/starboard/shared/stub/drm_destroy_system.cc',
+ '<(DEPTH)/starboard/shared/stub/drm_generate_session_update_request.cc',
+ '<(DEPTH)/starboard/shared/stub/drm_system_internal.h',
+ '<(DEPTH)/starboard/shared/stub/drm_update_session.cc',
+ ],
+
# TODO: Move this and the win32 dependencies below to a shared/win32/starboard_platform.gypi?
'uwp_incompatible_win32': [
'<(DEPTH)/starboard/shared/win32/application_win32_key_event.cc',
@@ -27,6 +37,8 @@
'<(DEPTH)/starboard/shared/win32/system_clear_platform_error.cc',
'<(DEPTH)/starboard/shared/win32/system_get_device_type.cc',
'<(DEPTH)/starboard/shared/win32/system_get_property.cc',
+ '<(DEPTH)/starboard/shared/win32/system_get_total_cpu_memory.cc',
+ '<(DEPTH)/starboard/shared/win32/system_get_used_cpu_memory.cc',
'<(DEPTH)/starboard/shared/win32/system_raise_platform_error.cc',
'<(DEPTH)/starboard/shared/win32/window_create.cc',
'<(DEPTH)/starboard/shared/win32/window_destroy.cc',
@@ -226,12 +238,6 @@
'<(DEPTH)/starboard/shared/stub/cryptography_set_authenticated_data.cc',
'<(DEPTH)/starboard/shared/stub/cryptography_set_initialization_vector.cc',
'<(DEPTH)/starboard/shared/stub/cryptography_transform.cc',
- '<(DEPTH)/starboard/shared/stub/drm_close_session.cc',
- '<(DEPTH)/starboard/shared/stub/drm_create_system.cc',
- '<(DEPTH)/starboard/shared/stub/drm_destroy_system.cc',
- '<(DEPTH)/starboard/shared/stub/drm_generate_session_update_request.cc',
- '<(DEPTH)/starboard/shared/stub/drm_system_internal.h',
- '<(DEPTH)/starboard/shared/stub/drm_update_session.cc',
'<(DEPTH)/starboard/shared/stub/image_decode.cc',
'<(DEPTH)/starboard/shared/stub/image_is_decode_supported.cc',
'<(DEPTH)/starboard/shared/stub/media_set_output_protection.cc',
@@ -334,8 +340,6 @@
'<(DEPTH)/starboard/shared/win32/system_get_connection_type.cc',
'<(DEPTH)/starboard/shared/win32/system_get_error_string.cc',
'<(DEPTH)/starboard/shared/win32/system_get_number_of_processors.cc',
- '<(DEPTH)/starboard/shared/win32/system_get_total_cpu_memory.cc',
- '<(DEPTH)/starboard/shared/win32/system_get_used_cpu_memory.cc',
'<(DEPTH)/starboard/shared/win32/socket_set_broadcast.cc',
'<(DEPTH)/starboard/shared/win32/socket_set_receive_buffer_size.cc',
'<(DEPTH)/starboard/shared/win32/socket_set_reuse_address.cc',
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/win/win32/lib/atomic_public.h
similarity index 81%
rename from src/starboard/win/lib/atomic_public.h
rename to src/starboard/win/win32/lib/atomic_public.h
index be4e805..b85fb12 100644
--- a/src/starboard/win/lib/atomic_public.h
+++ b/src/starboard/win/win32/lib/atomic_public.h
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
-#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
+#ifndef STARBOARD_WIN_WIN32_LIB_ATOMIC_PUBLIC_H_
+#define STARBOARD_WIN_WIN32_LIB_ATOMIC_PUBLIC_H_
#include "starboard/shared/win32/atomic_public.h"
-#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_
+#endif // STARBOARD_WIN_WIN32_LIB_ATOMIC_PUBLIC_H_
diff --git a/src/starboard/win/lib/configuration_public.h b/src/starboard/win/win32/lib/configuration_public.h
similarity index 82%
rename from src/starboard/win/lib/configuration_public.h
rename to src/starboard/win/win32/lib/configuration_public.h
index 800aeb1..8b5f8b1 100644
--- a/src/starboard/win/lib/configuration_public.h
+++ b/src/starboard/win/win32/lib/configuration_public.h
@@ -15,9 +15,9 @@
// Other source files should never include this header directly, but should
// include the generic "starboard/configuration.h" instead.
-#ifndef STARBOARD_WIN_LIB_CONFIGURATION_PUBLIC_H_
-#define STARBOARD_WIN_LIB_CONFIGURATION_PUBLIC_H_
+#ifndef STARBOARD_WIN_WIN32_LIB_CONFIGURATION_PUBLIC_H_
+#define STARBOARD_WIN_WIN32_LIB_CONFIGURATION_PUBLIC_H_
#include "starboard/win/shared/configuration_public.h"
-#endif // STARBOARD_WIN_LIB_CONFIGURATION_PUBLIC_H_
+#endif // STARBOARD_WIN_WIN32_LIB_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/win/win32/lib/gyp_configuration.gypi b/src/starboard/win/win32/lib/gyp_configuration.gypi
new file mode 100644
index 0000000..7d8ddb2
--- /dev/null
+++ b/src/starboard/win/win32/lib/gyp_configuration.gypi
@@ -0,0 +1,51 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+{
+ 'variables': {
+ 'javascript_engine': 'mozjs',
+ 'cobalt_enable_jit': 0,
+ # TODO: In theory, there are tools that can combine static libraries into
+ # thick static libraries with all their transitive dependencies. Using
+ # shared_library here can have unexpected consequences. Explore building
+ # this into a thick static library instead.
+ 'final_executable_type': 'shared_library',
+ 'default_renderer_options_dependency': '<(DEPTH)/cobalt/renderer/rasterizer/lib/lib.gyp:external_rasterizer',
+ 'sb_enable_lib': 1,
+ 'angle_build_winrt': 0,
+ 'winrt': 0,
+ 'enable_d3d11_feature_level_11': 1,
+ },
+ 'includes': [
+ '../../shared/gyp_configuration.gypi',
+ ],
+ 'target_defaults': {
+ 'default_configuration': 'win-win32-lib_debug',
+ 'configurations': {
+
+ 'win-win32-lib_debug': {
+ 'inherit_from': ['win32_base', 'msvs_debug'],
+ },
+ 'win-win32-lib_devel': {
+ 'inherit_from': ['win32_base', 'msvs_devel'],
+ },
+ 'win-win32-lib_qa': {
+ 'inherit_from': ['win32_base', 'msvs_qa'],
+ },
+ 'win-win32-lib_gold': {
+ 'inherit_from': ['win32_base', 'msvs_gold'],
+ },
+ }, # end of configurations
+ },
+}
diff --git a/src/starboard/win/lib/gyp_configuration.py b/src/starboard/win/win32/lib/gyp_configuration.py
similarity index 88%
rename from src/starboard/win/lib/gyp_configuration.py
rename to src/starboard/win/win32/lib/gyp_configuration.py
index e136082..0d1deeb 100644
--- a/src/starboard/win/lib/gyp_configuration.py
+++ b/src/starboard/win/win32/lib/gyp_configuration.py
@@ -21,13 +21,13 @@
os.path.realpath(
os.path.join(
os.path.dirname(__file__), os.pardir,
- os.pardir, 'shared', 'win32')))
+ os.pardir, os.pardir, 'shared', 'win32')))
import gyp_configuration
def CreatePlatformConfig():
try:
- return gyp_configuration.PlatformConfig('win-lib')
+ return gyp_configuration.PlatformConfig('win-win32-lib')
except RuntimeError as e:
logging.critical(e)
return None
diff --git a/src/starboard/win/win32/lib/starboard_platform.gyp b/src/starboard/win/win32/lib/starboard_platform.gyp
new file mode 100644
index 0000000..7216017
--- /dev/null
+++ b/src/starboard/win/win32/lib/starboard_platform.gyp
@@ -0,0 +1,23 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+{
+ 'includes': [
+ '../starboard_platform.gypi',
+ ],
+ 'variables': {
+ 'starboard_platform_dependent_files': [
+ '<@(base_win32_starboard_platform_dependent_files)',
+ ]
+ },
+}
diff --git a/src/starboard/win/lib/starboard_platform_tests.gyp b/src/starboard/win/win32/lib/starboard_platform_tests.gyp
similarity index 96%
rename from src/starboard/win/lib/starboard_platform_tests.gyp
rename to src/starboard/win/win32/lib/starboard_platform_tests.gyp
index 1eb83ba..8961deb 100644
--- a/src/starboard/win/lib/starboard_platform_tests.gyp
+++ b/src/starboard/win/win32/lib/starboard_platform_tests.gyp
@@ -38,7 +38,7 @@
'variables': {
'executable_name': 'starboard_platform_tests',
},
- 'includes': [ '../../build/deploy.gypi' ],
+ 'includes': [ '../../../build/deploy.gypi' ],
},
],
}
diff --git a/src/starboard/win/lib/thread_types_public.h b/src/starboard/win/win32/lib/thread_types_public.h
similarity index 81%
rename from src/starboard/win/lib/thread_types_public.h
rename to src/starboard/win/win32/lib/thread_types_public.h
index 0f8f791..adc6221 100644
--- a/src/starboard/win/lib/thread_types_public.h
+++ b/src/starboard/win/win32/lib/thread_types_public.h
@@ -14,9 +14,9 @@
// Includes threading primitive types and initializers.
-#ifndef STARBOARD_WIN_LIB_THREAD_TYPES_PUBLIC_H_
-#define STARBOARD_WIN_LIB_THREAD_TYPES_PUBLIC_H_
+#ifndef STARBOARD_WIN_WIN32_LIB_THREAD_TYPES_PUBLIC_H_
+#define STARBOARD_WIN_WIN32_LIB_THREAD_TYPES_PUBLIC_H_
#include "starboard/shared/win32/thread_types_public.h"
-#endif // STARBOARD_WIN_LIB_THREAD_TYPES_PUBLIC_H_
+#endif // STARBOARD_WIN_WIN32_LIB_THREAD_TYPES_PUBLIC_H_
diff --git a/src/starboard/win/win32/starboard_platform.gyp b/src/starboard/win/win32/starboard_platform.gyp
index 9373b0a..2027d45 100644
--- a/src/starboard/win/win32/starboard_platform.gyp
+++ b/src/starboard/win/win32/starboard_platform.gyp
@@ -1,40 +1,24 @@
-# Copyright 2017 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-{
- 'includes': [
- '../shared/starboard_platform.gypi',
- ],
- 'variables': {
- 'starboard_platform_dependent_files': [
- 'atomic_public.h',
- 'configuration_public.h',
- 'thread_types_public.h',
- '../shared/system_get_path.cc',
- 'main.cc',
- '<(DEPTH)/starboard/shared/starboard/localized_strings.cc',
- '<(DEPTH)/starboard/shared/starboard/localized_strings.cc',
- '<(DEPTH)/starboard/shared/starboard/queue_application.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc',
- '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc',
- '<@(uwp_incompatible_win32)',
- '<@(stub_media_player)'
- ]
- },
- }
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+{
+ 'includes': [
+ 'starboard_platform.gypi',
+ ],
+ 'variables': {
+ 'starboard_platform_dependent_files': [
+ 'main.cc',
+ '<@(base_win32_starboard_platform_dependent_files)',
+ ]
+ },
+}
diff --git a/src/starboard/win/win32/starboard_platform.gypi b/src/starboard/win/win32/starboard_platform.gypi
new file mode 100644
index 0000000..254ae7b
--- /dev/null
+++ b/src/starboard/win/win32/starboard_platform.gypi
@@ -0,0 +1,42 @@
+# Copyright 2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+{
+ 'includes': [
+ '../shared/starboard_platform.gypi',
+ ],
+ 'variables': {
+ 'base_win32_starboard_platform_dependent_files': [
+ 'atomic_public.h',
+ 'configuration_public.h',
+ 'thread_types_public.h',
+ '<(DEPTH)/starboard/shared/starboard/localized_strings.cc',
+ '<(DEPTH)/starboard/shared/starboard/localized_strings.cc',
+ '<(DEPTH)/starboard/shared/starboard/queue_application.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc',
+ '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc',
+ '<(DEPTH)/starboard/shared/stub/decode_target_get_info.cc',
+ '<(DEPTH)/starboard/shared/stub/decode_target_release.cc',
+ '<(DEPTH)/starboard/win/shared/system_get_path.cc',
+ '<@(uwp_incompatible_win32)',
+ '<@(stub_media_player)',
+ '<@(stub_drm_system)' ,
+ ],
+ },
+}