Skip to content

Commit

Permalink
[DNS] Introduce cast_starboard_api.
Browse files Browse the repository at this point in the history
This patch can be cherry-picked to add Cast Starboard API support to
`lts.23.1+`.

The Cast Starboard API is a shared library which contains the portion of
Starboard required to run Cast.

This includes the following changes:
- Add reference implementation, tests, and README.md into
  `starboard/contrib/cast`
- Add `cast` to `//starboard:gn_all`
- Fix a bug in ApplicationX11 which was preventing it from working in
  modular builds, depending on invocation
  • Loading branch information
saqneo committed Oct 2, 2023
1 parent b5b5685 commit 73f6ba5
Show file tree
Hide file tree
Showing 11 changed files with 546 additions and 7 deletions.
8 changes: 8 additions & 0 deletions starboard/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import("//starboard/contrib/cast/cast.gni")

group("gn_all") {
testonly = true

Expand Down Expand Up @@ -42,6 +44,12 @@ group("gn_all") {
deps += [ platform_tests_path ]
}

if (use_contrib_cast) {
deps += [
"//starboard/contrib/cast/cast_starboard_api/samples:cast",
]
}

if (sb_filter_based_player) {
deps += [
"//starboard/shared/starboard/player/filter/testing:player_filter_tests",
Expand Down
18 changes: 13 additions & 5 deletions starboard/build/config/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

import("//build/config/compiler/compiler.gni")
import("//starboard/contrib/cast/cast.gni")

config("base") {
defines = []
Expand Down Expand Up @@ -90,18 +91,21 @@ config("host") {

config("target") {
if (current_toolchain != host_toolchain) {
if (final_executable_type == "shared_library") {
# Rewrite main() functions into StarboardMain. TODO: This is a
# hack, it would be better to be more surgical, here.
defines = [ "main=StarboardMain" ]

if (final_executable_type == "shared_library" || use_contrib_cast) {
# To link into a shared library on Linux and similar platforms,
# the compiler must be told to generate Position Independent Code.
# This appears to cause errors when linking the code statically,
# however.
cflags = [ "-fPIC" ]
}

if (final_executable_type == "shared_library") {
# Rewrite main() functions into StarboardMain. TODO: This is a
# hack, it would be better to be more surgical, here.
defines = [ "main=StarboardMain" ]
}


if (is_starboard) {
configs = [ ":starboard" ]
}
Expand Down Expand Up @@ -139,6 +143,10 @@ config("starboard") {
if (sb_allows_memory_tracking) {
defines += [ "STARBOARD_ALLOWS_MEMORY_TRACKING" ]
}

if (use_contrib_cast) {
defines += [ "SB_IS_CAST_API=1" ]
}

if (sb_enable_lib) {
defines += [ "SB_IS_LIBRARY=1" ]
Expand Down
53 changes: 53 additions & 0 deletions starboard/contrib/cast/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
## Cast Starboard API

The Cast Starboard API is a shared library which contains the portion of
Starboard required to run Cast.

### Customizations

As of Starboard 14, there are public methods required for Cast that are not
already exposed by `libstarboard_platform_group.so`. These methods are declared
in the header `cast_starboard_api.h`, and a sample implementation is provided
in `cast_starboard_api_impl.cc`.

Cast also requires additional behavior be implemented behind the existing
Starboard APIs. Reference the `Cast TV Integration Guide` for details.

### Reference Implementation

The `cast_starboard_api/samples/` directory contains the reference target
`cast_starboard_api` which can be built when `use_contrib_cast=true` is
specified. To generate the target:

```
gn gen out/linux-x64x11_devel --args="target_platform=\"linux-x64x11\" use_contrib_cast=true build_type=\"devel\""
```

To build the target:

```
ninja -C out/linux-x64x11_devel/ cast_starboard_api
```

### Test Suite

Tests for Cast-specific behaviors are not currently included in NPLB or YTS.

A limited test suite, `cast_starboard_api_test`, is provided to ensure the
standalone library can be initialized and a window surface can be created in the
format required by Cast. To build the test suite:

```
ninja -C out/linux-x64x11_devel/ cast_starboard_api_test
```

To run the test suite:

```
./out/linux-x64x11_devel/cast_starboard_api_test
```

### Known Issues

- When `build_type=\"devel\"`, some systems may SB_DCHECK in `NetworkNotifier`.
- On some toolchains, `use_asan=false` may be required to build cleanly.
5 changes: 5 additions & 0 deletions starboard/contrib/cast/cast.gni
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare_args() {
# Includes `//starboard/contrib/cast/cast_starboard_api/samples:cast` into
# `//starboard:gn_all`.
use_contrib_cast = false
}
41 changes: 41 additions & 0 deletions starboard/contrib/cast/cast_starboard_api/cast_starboard_api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2022 Google LLC. All rights reserved.

#ifndef STARBOARD_CAST_CAST_STARBOARD_API_CAST_STARBOARD_API_H_
#define STARBOARD_CAST_CAST_STARBOARD_API_CAST_STARBOARD_API_H_

#include <starboard/drm.h>
#include <starboard/egl.h>
#include <starboard/event.h>
#include <starboard/gles.h>
#include <starboard/media.h>
#include <starboard/player.h>
#include <starboard/window.h>

#ifdef __cplusplus
extern "C" {
#endif

// Initializes the Starboard thread and event loop. After this function is
// called, the Starboard APIs included above are expected to be available.
//
// Optional command line arguments are passed through |argc| and |argv|.
// The |callback| is analogous to SbEventHandle and must receive SbEvents.
//
// Must be called prior to the other library functions. Not guaranteed to be
// thread-safe; other library functions should not be called until this returns.
SB_EXPORT int CastStarboardApiInitialize(int argc,
char** argv,
void (*callback)(const SbEvent*));

// Finalizes the library in the provided |context|.
//
// Must not be called prior to the other library functions. Not guaranteed to be
// thread-safe; this function should not be called until all other library
// functions have returned.
SB_EXPORT void CastStarboardApiFinalize();

#ifdef __cplusplus
} // extern "C"
#endif

#endif // STARBOARD_CAST_CAST_STARBOARD_API_CAST_STARBOARD_API_H_
79 changes: 79 additions & 0 deletions starboard/contrib/cast/cast_starboard_api/samples/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Copyright 2022 Google LLC. All rights reserved.
import("//starboard/contrib/cast/cast.gni")

assert(use_contrib_cast)

group("cast") {
public_deps = [ ":cast_starboard_api" ]
}

_CAST_STARBOARD_API_SOURCES = [
"../cast_starboard_api.h",
"cast_starboard_api_impl.cc",
]

if (final_executable_type == "shared_library") {
# Sample implementation of cast_starboard_api which utilizes StarboardMain.
# This implementation should work on any platform, but cannot currently be
# used with test because of the way StarboardMain is defined (by redefining
# `main` in the binary)
target(final_executable_type, "cast_starboard_api") {
sources = _CAST_STARBOARD_API_SOURCES
deps = [
"//starboard",
"//$starboard_path:starboard_platform"
]
ldflags = [
# Prevents unresolved symbols
"-Wl,-z,defs",
# This makes Sb*, kSb*, and CastStarboardApi* public, but they could still
# be hidden by other compiler flags.
"-Wl,--version-script=" + rebase_path("./cast_starboard_api.lds",
root_build_dir)
]
}
} else {
# Sample implementation of cast_starboard_api which utilizes a platform-
# specific implementation. It does not require a specific build
# configuration and can be tested with the `cast_starboard_api_test_main`.
shared_library("cast_starboard_api") {
sources = _CAST_STARBOARD_API_SOURCES
defines = [ "CAST_STARBOARD_API_X11"]
deps = [
"//starboard",
]
ldflags = [
# Prevents unresolved symbols
"-Wl,-z,defs",
# This makes Sb*, kSb*, and CastStarboardApi* public, but they could still
# be hidden by other compiler flags.
"-Wl,--version-script=" + rebase_path("./cast_starboard_api.lds",
root_build_dir)
]
}

copy("cast_starboard_api_test_data") {
install_content = true
sources = ["$root_out_dir/libcast_starboard_api.so"]
outputs = [ "$sb_static_contents_output_data_dir/{{source_file_part}}" ]
deps = [
":cast_starboard_api"
]
}

target(gtest_target_type, "cast_starboard_api_test") {
testonly = true
sources = [
"//starboard/common/test_main.cc",
"cast_starboard_api_test.cc",
]
data_deps = [
":cast_starboard_api_test_data",
]
deps = [
"//starboard",
"//testing/gtest",
"//starboard/nplb/testdata/file_tests:nplb_file_tests_data",
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright 2022 Google LLC. All rights reserved.
LIBCAST_STARBOARD_API {
global:
CastStarboardApi*;
kSb*;
Sb*;
local:
*;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright 2022 Google LLC. All rights reserved.

#include "../cast_starboard_api.h"

#include <memory>

#include "starboard/common/condition_variable.h"
#include "starboard/common/log.h"
#include "starboard/common/mutex.h"
#include "starboard/common/thread.h"
#include "starboard/egl.h"
#include "starboard/system.h"

#ifdef CAST_STARBOARD_API_X11
#include <X11/Xlib.h>
#include "starboard/shared/x11/application_x11.h"
#endif // CAST_STARBOARD_API_X11

#ifndef CAST_STARBOARD_API_X11
extern "C" int StarboardMain(int argc, char** argv);
#endif

namespace {
class CastStarboardApiThread : public starboard::Thread {
public:
CastStarboardApiThread() : starboard::Thread("cast_thread") {}

void Run() override {
#ifdef CAST_STARBOARD_API_X11
// In this sample implementation, setting up the application is
// required for some APIs to function correctly. For example,`
// SbWindowCreate will crash without an existing ApplicationX11.
starboard::shared::starboard::CommandLine command_line(0, nullptr);
app = std::make_unique<starboard::shared::x11::ApplicationX11>();

// This never returns until kSbEventTypeStop is sent to the application,
// so it can act as the thread loop.
app->Run(command_line);
#else // CAST_STARBOARD_API_X11
// **NOTE:** Calling StarboardMain(...) here should be enough, without
// needing any other content. Typically StarboardMain is redefined from
// main in builds where `final_executable_type == "shared_library"`.
StarboardMain(0, nullptr);
#endif // CAST_STARBOARD_API_X11
}

private:
#ifdef CAST_STARBOARD_API_X11
std::unique_ptr<starboard::shared::x11::ApplicationX11> app;
#endif // CAST_STARBOARD_API_X11
};

void (*g_callback)(const SbEvent*) = nullptr;
starboard::Mutex g_started_mutex;
std::unique_ptr<starboard::ConditionVariable> g_started_cond;
std::unique_ptr<CastStarboardApiThread> g_thread;
bool g_initialized = false;
} // namespace

int CastStarboardApiInitialize(int argc,
char** argv,
void (*callback)(const SbEvent*)) {
SB_CHECK(!g_thread) << "CastStarboardApiInitialize may only be called once";
SB_CHECK(callback) << "Argument 'callback' must not be NULL";

// Events given to SbEventHandle will be forwarded to |callback|.
g_callback = callback;

// Create event for initialization completion.
g_started_cond =
std::make_unique<starboard::ConditionVariable>(g_started_mutex);

// Create the main Starboard thread.
g_thread = std::make_unique<CastStarboardApiThread>();
g_thread->Start();

// Watch event for initialation completion.
g_started_mutex.Acquire();
g_started_cond->Wait();
g_started_mutex.Release();

return 0;
}

void CastStarboardApiFinalize() {
SB_CHECK(g_thread) << "CastStarboardApiFinalize may only be called after "
"CastStarboardApiInitialize";

// |g_thread| cannot join until its internal event loop stops.
SbSystemRequestStop(0);
g_thread->Join();

// The thread is stopped so it's safe to reset.
g_initialized = false;
g_thread.reset();
g_started_cond.reset();
g_callback = nullptr;
}

void SbEventHandle(const SbEvent* event) {
SB_DCHECK(g_callback);
// Signal that initialization is complete.
if (event->type == kSbEventTypeStart) {
g_started_cond->Signal();
g_initialized = true;
}

if (g_initialized) {
g_callback(event);
}
}
Loading

0 comments on commit 73f6ba5

Please sign in to comment.