Import Cobalt 4.16134
Change-Id: Ibd3aeff170baa0d15baae38e16a1dd59b5387c7a
diff --git a/src/base/atomicops.h b/src/base/atomicops.h
index 230a601..6d04858 100644
--- a/src/base/atomicops.h
+++ b/src/base/atomicops.h
@@ -31,6 +31,10 @@
#include "base/basictypes.h"
#include "build/build_config.h"
+#if defined(OS_STARBOARD)
+#include "starboard/atomic.h"
+#endif // defined(OS_STARBOARD)
+
#if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || defined(__LB_XB360__) || defined(__LB_XB1__)
// windows.h #defines this (only on x64). This causes problems because the
// public API also uses MemoryBarrier at the public name for this fence. So, on
@@ -43,6 +47,12 @@
namespace base {
namespace subtle {
+#if defined(OS_STARBOARD)
+typedef SbAtomic32 Atomic32;
+#if defined(ARCH_CPU_64_BITS)
+typedef SbAtomic64 Atomic64;
+#endif // defined(ARCH_CPU_64_BITS)
+#else
typedef int32 Atomic32;
#ifdef ARCH_CPU_64_BITS
// We need to be able to go between Atomic64 and AtomicWord implicitly. This
@@ -55,6 +65,7 @@
typedef intptr_t Atomic64;
#endif
#endif
+#endif // defined(OS_STARBOARD)
// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or
// Atomic64 routines below, depending on your architecture.
diff --git a/src/base/file_util_unittest.cc b/src/base/file_util_unittest.cc
index 6f4e111..81fdcc7 100644
--- a/src/base/file_util_unittest.cc
+++ b/src/base/file_util_unittest.cc
@@ -211,7 +211,16 @@
// Simple function to dump some text into a new file.
void CreateTextFile(const FilePath& filename,
const std::wstring& contents) {
-#if defined(__LB_PS3__)
+#if defined(OS_STARBOARD)
+ SbFile file =
+ SbFileOpen(filename.value().c_str(), kSbFileCreateAlways | kSbFileWrite,
+ NULL /*out_created*/, NULL /*out_error*/);
+ EXPECT_TRUE(file != kSbFileInvalid);
+ std::string utf8 = WideToUTF8(contents);
+ int bytes_written = SbFileWrite(file, utf8.c_str(), utf8.length());
+ EXPECT_TRUE(bytes_written == utf8.length());
+ SbFileClose(file);
+#elif defined(__LB_PS3__)
FILE *file = fopen(filename.value().c_str(), "w");
ASSERT_TRUE(file != NULL);
fputws(contents.c_str(), file);
@@ -232,18 +241,35 @@
ASSERT_TRUE(file.is_open());
file << contents;
file.close();
-#endif
+#endif // defined(OS_STARBOARD)
}
// Simple function to take out some text from a file.
std::wstring ReadTextFile(const FilePath& filename) {
+#if defined(OS_STARBOARD)
+ SbFile file =
+ SbFileOpen(filename.value().c_str(), kSbFileOpenOnly | kSbFileRead,
+ NULL /*out_created*/, NULL /*out_error*/);
+ EXPECT_TRUE(file != kSbFileInvalid);
+ char utf8_buffer[64] = {0};
+ int bytes_read =
+ SbFileRead(file, utf8_buffer, SB_ARRAY_SIZE_INT(utf8_buffer));
+ EXPECT_TRUE(bytes_read >= 0);
+ SbFileClose(file);
+ std::wstring result;
+ bool did_convert =
+ UTF8ToWide(utf8_buffer, SbStringGetLength(utf8_buffer), &result);
+ EXPECT_TRUE(did_convert);
+ return result;
+#elif defined(__LB_PS3__)
wchar_t contents[64];
-#if defined(__LB_PS3__)
FILE *file = fopen(filename.value().c_str(), "r");
EXPECT_TRUE(file != NULL);
fgetws(contents, arraysize(contents), file);
fclose(file);
+ return std::wstring(contents);
#elif defined(__LB_WIIU__)
+ wchar_t contents[64];
char mb_sequence_buffer[64];
int fd = open(filename.value().c_str(), O_RDONLY);
EXPECT_TRUE(fd >= 0);
@@ -253,14 +279,16 @@
const char * mb_sequence = mb_sequence_buffer;
size_t nbytes = mbsrtowcs(contents, &mb_sequence, sizeof(contents), NULL);
EXPECT_TRUE(mb_sequence == NULL);
+ return std::wstring(contents);
#else
+ wchar_t contents[64];
std::wifstream file;
file.open(filename.value().c_str());
EXPECT_TRUE(file.is_open());
file.getline(contents, arraysize(contents));
file.close();
-#endif
return std::wstring(contents);
+#endif
}
#if defined(OS_WIN)
diff --git a/src/base/i18n/file_util_icu.cc b/src/base/i18n/file_util_icu.cc
index fc07d13..0dd1523 100644
--- a/src/base/i18n/file_util_icu.cc
+++ b/src/base/i18n/file_util_icu.cc
@@ -159,7 +159,7 @@
// Windows uses UTF-16 encoding for filenames.
U16_NEXT(file_name->data(), cursor, static_cast<int>(file_name->length()),
code_point);
-#elif defined(OS_POSIX) || defined(OS_STARBAORD)
+#elif defined(OS_POSIX) || defined(OS_STARBOARD)
// Linux doesn't actually define an encoding. It basically allows anything
// except for a few special ASCII characters.
unsigned char cur_char = static_cast<unsigned char>((*file_name)[cursor++]);
diff --git a/src/base/location.cc b/src/base/location.cc
index b6ded2c..fe8581a 100644
--- a/src/base/location.cc
+++ b/src/base/location.cc
@@ -92,9 +92,11 @@
BASE_EXPORT const void* GetProgramCounter() {
#if defined(COMPILER_MSVC)
return _ReturnAddress();
+#elif defined(COMPILER_SNC)
+ return __builtin_return_address(0);
#elif defined(COMPILER_GCC) && !defined(__LB_PS3__) && !defined(__LB_WIIU__)
return __builtin_extract_return_addr(__builtin_return_address(0));
-#endif // COMPILER_GCC
+#endif // defined(COMPILER_MSVC)
return NULL;
}
diff --git a/src/base/stl_util.h b/src/base/stl_util.h
index c612769..483fd53 100644
--- a/src/base/stl_util.h
+++ b/src/base/stl_util.h
@@ -7,7 +7,7 @@
#include <algorithm>
#include <functional>
-#if defined(__LB_SHELL__) // TODO: Starboard?
+#if defined(__LB_SHELL__) || defined(STARBOARD)
#include <iterator>
#endif
#include <string>
diff --git a/src/base/test/test_file_util_starboard.cc b/src/base/test/test_file_util_starboard.cc
index ef4cdad..f8127c6 100644
--- a/src/base/test/test_file_util_starboard.cc
+++ b/src/base/test/test_file_util_starboard.cc
@@ -36,7 +36,7 @@
// Mostly a verbatim copy of CopyDirectory
bool CopyRecursiveDirNoCache(const FilePath& source_dir,
const FilePath& dest_dir) {
- char top_dir[PATH_MAX];
+ char top_dir[SB_FILE_MAX_PATH];
if (base::strlcpy(top_dir, source_dir.value().c_str(), arraysize(top_dir)) >=
arraysize(top_dir)) {
return false;
diff --git a/src/base/third_party/nspr/prcpucfg_starboard.h b/src/base/third_party/nspr/prcpucfg_starboard.h
index 5bdf40d..3aaa298 100644
--- a/src/base/third_party/nspr/prcpucfg_starboard.h
+++ b/src/base/third_party/nspr/prcpucfg_starboard.h
@@ -55,7 +55,7 @@
# define IS_64
#endif
-#if SB_IS(ARCH_PPC) && SB_IS(32_BIT)
+#if SB_IS(ARCH_PPC)
#define PR_BYTES_PER_BYTE 1
#define PR_BYTES_PER_SHORT 2
#define PR_BYTES_PER_INT 4
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc
index 20bae1a..38699b2 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc
@@ -222,6 +222,15 @@
JSBool set_arbitraryProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<ArbitraryInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
index 67e7e5f..2599232 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
@@ -220,6 +220,15 @@
JSBool set_booleanProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<BooleanTypeTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
index 8ebf68c..fce394f 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
@@ -224,6 +224,15 @@
JSBool set_callbackAttribute(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<CallbackFunctionInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -277,6 +286,15 @@
JSBool set_nullableCallbackAttribute(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<CallbackFunctionInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
index e510b12..468faf3 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
@@ -224,6 +224,15 @@
JSBool set_callbackAttribute(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<CallbackInterfaceInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc
index 12fda2f..2610e00 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc
@@ -223,6 +223,15 @@
JSBool set_enabledAttribute(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<ConditionalInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -278,6 +287,15 @@
JSBool set_disabledAttribute(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<ConditionalInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc
index 4524287..7092da5 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc
@@ -220,6 +220,15 @@
JSBool set_property(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<DOMStringTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -335,6 +344,15 @@
JSBool set_nullIsEmptyProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<DOMStringTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -388,6 +406,15 @@
JSBool set_undefinedIsEmptyProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<DOMStringTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -441,6 +468,15 @@
JSBool set_nullableUndefinedIsEmptyProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<DOMStringTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
index 647ef55..1c88411 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
@@ -436,6 +436,15 @@
JSBool set_propertyOnDerivedClass(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<DerivedGetterSetterInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc
index 5fb88e5..5e3f995 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc
@@ -222,6 +222,15 @@
JSBool set_disabledProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<DisabledInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
index ea07296..38c99f1 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
@@ -231,6 +231,15 @@
JSBool set_enumProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<EnumerationInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc
index b23ae9f..6ab9aab 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc
@@ -222,6 +222,15 @@
JSBool set_attributeThrowsException(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<ExceptionsInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.cc
index df1b224..9ba778e 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.cc
@@ -233,6 +233,15 @@
JSBool set_previous(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<GarbageCollectionTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -286,6 +295,15 @@
JSBool set_next(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<GarbageCollectionTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
index 7f0e6b7..e027bc0 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
@@ -436,6 +436,15 @@
JSBool set_propertyOnBaseClass(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NamedIndexedGetterInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc
index c7945ee..9b732fe 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc
@@ -224,6 +224,15 @@
JSBool set_nestedForwardingAttribute(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NestedPutForwardsInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
index a2d5622..e7533d8 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
@@ -224,6 +224,15 @@
JSBool set_nullableBooleanProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NullableTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -277,6 +286,15 @@
JSBool set_nullableNumericProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NullableTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -330,6 +348,15 @@
JSBool set_nullableStringProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NullableTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -383,6 +410,15 @@
JSBool set_nullableObjectProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NullableTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
index c64b5d9..eb604d8 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
@@ -220,6 +220,15 @@
JSBool set_byteProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NumericTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -273,6 +282,15 @@
JSBool set_octetProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NumericTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -326,6 +344,15 @@
JSBool set_shortProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NumericTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -379,6 +406,15 @@
JSBool set_unsignedShortProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NumericTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -432,6 +468,15 @@
JSBool set_longProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NumericTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -485,6 +530,15 @@
JSBool set_unsignedLongProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NumericTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -538,6 +592,15 @@
JSBool set_longLongProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NumericTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -591,6 +654,15 @@
JSBool set_unsignedLongLongProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NumericTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -644,6 +716,15 @@
JSBool set_doubleProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NumericTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -697,6 +778,15 @@
JSBool set_unrestrictedDoubleProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<NumericTypesTestInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc
index d25a5b1..77631f6 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc
@@ -232,6 +232,15 @@
JSBool set_arbitraryObject(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<ObjectTypeBindingsInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -316,6 +325,15 @@
JSBool set_derivedInterface(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<ObjectTypeBindingsInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -369,6 +387,15 @@
JSBool set_objectProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<ObjectTypeBindingsInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc
index 325c6fd..dfc7ffa 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc
@@ -224,6 +224,15 @@
JSBool set_forwardingAttribute(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<PutForwardsInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
index 30cfd0a..428506c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
@@ -220,6 +220,15 @@
JSBool set_theStringifierAttribute(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<StringifierAttributeInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc
index a81efa7..e6cf73b 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc
@@ -228,6 +228,15 @@
JSBool set_unionProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<UnionTypesInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -281,6 +290,15 @@
JSBool set_unionWithNullableMemberProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<UnionTypesInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -334,6 +352,15 @@
JSBool set_nullableUnionProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<UnionTypesInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
@@ -387,6 +414,15 @@
JSBool set_unionBaseProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<UnionTypesInterface>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
index 673aed8..212ecca 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
@@ -413,6 +413,15 @@
JSBool set_windowProperty(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+ MozjsGlobalEnvironment* global_environment =
+ static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
+ WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
+ if (!wrapper_factory->DoesObjectImplementInterface(
+ object, base::GetTypeId<Window>())) {
+ MozjsExceptionState exception(context);
+ exception.SetSimpleException(script::kDoesNotImplementInterface);
+ return false;
+ }
MozjsExceptionState exception_state(context);
JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/mozjs/templates/interface.cc.template b/src/cobalt/bindings/mozjs/templates/interface.cc.template
index 2dfc9eb..3307b67 100644
--- a/src/cobalt/bindings/mozjs/templates/interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/interface.cc.template
@@ -485,6 +485,7 @@
JSBool set_{{attribute.idl_name}}(
JSContext* context, JS::HandleObject object, JS::HandleId id,
JSBool strict, JS::MutableHandleValue vp) {
+{{ check_if_object_implements_interface() }}
{{ nonstatic_function_prologue(impl_class)}}
{% endif %} {#- attribute.is_static #}
{{ set_attribute_implementation(attribute, impl_class) -}}
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index 72f1dd8..f19023b 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -21,11 +21,13 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/stl_util.h"
#include "base/string_number_conversions.h"
#include "base/string_split.h"
+#include "base/time.h"
#include "cobalt/base/cobalt_paths.h"
#include "cobalt/base/source_location.h"
#include "cobalt/base/tokens.h"
@@ -37,11 +39,70 @@
#include "cobalt/dom/keycode.h"
#include "cobalt/h5vcc/h5vcc.h"
#include "cobalt/input/input_device_manager_fuzzer.h"
+#include "starboard/atomic.h"
+#include "starboard/system.h"
+#include "starboard/time.h"
+
+#if defined(OS_STARBOARD)
+#include "starboard/configuration.h"
+#if SB_HAS(CORE_DUMP_HANDLER_SUPPORT)
+#define HANDLE_CORE_DUMP
+#include "starboard/ps4/core_dump_handler.h"
+#endif // SB_HAS(CORE_DUMP_HANDLER_SUPPORT)
+#endif // OS_STARBOARD
namespace cobalt {
+
+#if defined(COBALT_CHECK_SUBMITDONE_TIMEOUT)
+namespace timestamp {
+// This is a temporary workaround.
+extern SbAtomic64 g_last_submit_done_timestamp;
+} // namespace timestamp
+
+namespace {
+struct NonTrivialGlobalVariables {
+ NonTrivialGlobalVariables();
+
+ SbAtomic64* last_submit_done_timestamp;
+};
+
+NonTrivialGlobalVariables::NonTrivialGlobalVariables() {
+ last_submit_done_timestamp = &cobalt::timestamp::g_last_submit_done_timestamp;
+ SbAtomicNoBarrier_Exchange64(last_submit_done_timestamp,
+ static_cast<SbAtomic64>(SbTimeGetNow()));
+}
+
+base::LazyInstance<NonTrivialGlobalVariables> non_trivial_global_variables =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+#endif
+
namespace browser {
namespace {
+#if defined(COBALT_CHECK_SUBMITDONE_TIMEOUT)
+// Timeout for last submitDone().
+const int kLastSubmitDoneTimeoutSeconds = 15;
+
+// Polling interval for timeout_polling_thread_.
+const int kRenderTimeOutPollingDelaySeconds = 1;
+
+// Minimum number of continuous times the timeout expirations. This is used to
+// prevent unintended behavior in situations such as when returning from
+// suspended state. Note that the timeout response trigger will be delayed
+// after the actual timeout expiration by this value times the polling delay.
+const int kMinimumContinuousRenderTimeoutExpirations = 2;
+
+// Name for timeout_polling_thread_.
+const char* kTimeoutPollingThreadName = "TimeoutPolling";
+
+// This specifies the percentage of calls to OnRenderTimeout() that result in a
+// call to OnError().
+const int kRenderTimeoutErrorPercentage = 99;
+
+#endif
+
// This constant defines the maximum rate at which the layout engine will
// refresh over time. Since there is little benefit in performing a layout
// faster than the display's refresh rate, we set this to 60Hz.
@@ -169,8 +230,25 @@
h5vcc_url_handler_(this, system_window, account_manager)),
web_module_options_(options.web_module_options),
has_resumed_(true, false),
+#if defined(COBALT_CHECK_SUBMITDONE_TIMEOUT)
+ timeout_polling_thread_(kTimeoutPollingThreadName),
+ render_timeout_count_(0),
+#endif
will_quit_(false),
suspended_(false) {
+#if defined(HANDLE_CORE_DUMP)
+ on_error_triggered_count_ = 0;
+ recovery_mechanism_triggered_count_ = 0;
+ submit_done_timeout_count_ = 0;
+ SbCoreDumpRegisterHandler(BrowserModule::CoreDumpHandler, this);
+#endif
+#if defined(COBALT_CHECK_SUBMITDONE_TIMEOUT)
+ timeout_polling_thread_.Start();
+ timeout_polling_thread_.message_loop()->PostDelayedTask(
+ FROM_HERE, base::Bind(&BrowserModule::OnPollForRenderTimeout,
+ base::Unretained(this), url),
+ base::TimeDelta::FromSeconds(kRenderTimeOutPollingDelaySeconds));
+#endif
// Setup our main web module to have the H5VCC API injected into it.
DCHECK(!ContainsKey(web_module_options_.injected_window_attributes, "h5vcc"));
h5vcc::H5vcc::Settings h5vcc_settings;
@@ -216,6 +294,9 @@
BrowserModule::~BrowserModule() {
DCHECK_EQ(MessageLoop::current(), self_message_loop_);
+#if defined(HANDLE_CORE_DUMP)
+ SbCoreDumpUnregisterHandler(BrowserModule::CoreDumpHandler, this);
+#endif
}
void BrowserModule::Navigate(const GURL& url) {
@@ -234,6 +315,20 @@
base::SourceLocation("[object BrowserModule]", 1, 1));
}
+#if defined(HANDLE_CORE_DUMP)
+// static
+void BrowserModule::CoreDumpHandler(void* browser_module_as_void) {
+ BrowserModule* browser_module =
+ static_cast<BrowserModule*>(browser_module_as_void);
+ SbCoreDumpLogInteger("BrowserModule.on_error_triggered_count_",
+ browser_module->on_error_triggered_count_);
+ SbCoreDumpLogInteger("BrowserModule.recovery_mechanism_triggered_count_",
+ browser_module->recovery_mechanism_triggered_count_);
+ SbCoreDumpLogInteger("BrowserModule.submit_done_timeout_count_",
+ browser_module->submit_done_timeout_count_);
+}
+#endif
+
void BrowserModule::NavigateInternal(const GURL& url) {
DCHECK_EQ(MessageLoop::current(), self_message_loop_);
@@ -273,6 +368,13 @@
array_buffer_allocator_.get();
options.dom_settings_options.array_buffer_cache = array_buffer_cache_.get();
#endif // defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
+#if defined(ENABLE_FAKE_MICROPHONE)
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kFakeMicrophone) ||
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kInputFuzzer)) {
+ options.dom_settings_options.enable_fake_microphone = true;
+ }
+#endif // defined(ENABLE_FAKE_MICROPHONE)
+
options.image_cache_capacity_multiplier_when_playing_video =
COBALT_IMAGE_CACHE_CAPACITY_MULTIPLIER_WHEN_PLAYING_VIDEO;
web_module_.reset(new WebModule(
@@ -479,6 +581,9 @@
}
void BrowserModule::OnError(const GURL& url, const std::string& error) {
+#if defined(HANDLE_CORE_DUMP)
+ on_error_triggered_count_++;
+#endif
LOG(ERROR) << error;
std::string url_string = "h5vcc://network-failure";
@@ -706,5 +811,52 @@
}
#endif // OS_STARBOARD
+#if defined(COBALT_CHECK_SUBMITDONE_TIMEOUT)
+void BrowserModule::OnPollForRenderTimeout(const GURL& url) {
+ SbTime last_submitdone_timestamp = static_cast<SbTime>(SbAtomicAcquire_Load64(
+ non_trivial_global_variables.Get().last_submit_done_timestamp));
+ base::Time last_submitdone =
+ base::Time::FromSbTime(last_submitdone_timestamp);
+ bool timeout_expiration =
+ base::Time::Now() -
+ base::TimeDelta::FromSeconds(kLastSubmitDoneTimeoutSeconds) >
+ last_submitdone;
+ bool timeout_response_trigger = false;
+ if (timeout_expiration) {
+ // The timeout only triggers if the timeout expiration has been detected
+ // without interruption at least kMinimumContinuousRenderTimeoutExpirations
+ // times.
+ ++render_timeout_count_;
+ timeout_response_trigger =
+ render_timeout_count_ >= kMinimumContinuousRenderTimeoutExpirations;
+ } else {
+ render_timeout_count_ = 0;
+ }
+
+ if (timeout_response_trigger) {
+#if defined(HANDLE_CORE_DUMP)
+ submit_done_timeout_count_++;
+#endif
+ SbAtomicNoBarrier_Exchange64(
+ non_trivial_global_variables.Get().last_submit_done_timestamp,
+ static_cast<SbAtomic64>(kSbTimeMax));
+ if (SbSystemGetRandomUInt64() <
+ kRenderTimeoutErrorPercentage * (UINT64_MAX / 100)) {
+ OnError(url, std::string("Rendering Timeout"));
+#if defined(HANDLE_CORE_DUMP)
+ recovery_mechanism_triggered_count_++;
+#endif
+ } else {
+ SB_DLOG(INFO) << "Received OnRenderTimeout, ignoring by random chance.";
+ }
+ } else {
+ timeout_polling_thread_.message_loop()->PostDelayedTask(
+ FROM_HERE, base::Bind(&BrowserModule::OnPollForRenderTimeout,
+ base::Unretained(this), url),
+ base::TimeDelta::FromSeconds(kRenderTimeOutPollingDelaySeconds));
+ }
+}
+#endif
+
} // namespace browser
} // namespace cobalt
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index 82322b3..5adc43d 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -23,6 +23,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
#include "cobalt/account/account_manager.h"
#include "cobalt/base/message_queue.h"
#include "cobalt/browser/h5vcc_url_handler.h"
@@ -48,6 +49,10 @@
#include "cobalt/debug/debug_server.h"
#endif // ENABLE_DEBUG_CONSOLE
+#if defined(OS_STARBOARD)
+#include "starboard/configuration.h"
+#endif
+
namespace cobalt {
namespace browser {
@@ -121,6 +126,15 @@
void Resume();
private:
+#if defined(OS_STARBOARD)
+#if SB_HAS(CORE_DUMP_HANDLER_SUPPORT)
+ static void CoreDumpHandler(void* browser_module_as_void);
+ int on_error_triggered_count_;
+ int recovery_mechanism_triggered_count_;
+ int submit_done_timeout_count_;
+#endif
+#endif
+
// Recreates web module with the given URL.
void NavigateInternal(const GURL& url);
@@ -210,6 +224,11 @@
// Process all messages queued into the |render_tree_submission_queue_|.
void ProcessRenderTreeSubmissionQueue();
+#if defined(COBALT_CHECK_SUBMITDONE_TIMEOUT)
+ // Poll for render timeout. Called from timeout_polling_thread_.
+ void OnPollForRenderTimeout(const GURL& url);
+#endif
+
// TODO:
// WeakPtr usage here can be avoided if BrowserModule has a thread to
// own where it can ensure that its tasks are all resolved when it is
@@ -326,6 +345,14 @@
// Reset when the browser is paused, signalled to resume.
base::WaitableEvent has_resumed_;
+#if defined(COBALT_CHECK_SUBMITDONE_TIMEOUT)
+ base::Thread timeout_polling_thread_;
+
+ // Counts the number of continuous render timeout expirations. This value is
+ // updated and used from OnPollForRenderTimeout.
+ int render_timeout_count_;
+#endif
+
// Set when the application is about to quit. May be set from a thread other
// than the one hosting this object, and read from another.
bool will_quit_;
diff --git a/src/cobalt/browser/switches.cc b/src/cobalt/browser/switches.cc
index 73b734a..f0315b7 100644
--- a/src/cobalt/browser/switches.cc
+++ b/src/cobalt/browser/switches.cc
@@ -45,6 +45,10 @@
// Additional base directory for accessing web files via file://.
const char kExtraWebFileDir[] = "web_file_path";
+// If this flag is set, fake microphone will be used to mock the user voice
+// input.
+const char kFakeMicrophone[] = "fake_microphone";
+
// Setting this switch causes all certificate errors to be ignored.
const char kIgnoreCertificateErrors[] = "ignore_certificate_errors";
diff --git a/src/cobalt/browser/switches.h b/src/cobalt/browser/switches.h
index fe02027..70fe5cd 100644
--- a/src/cobalt/browser/switches.h
+++ b/src/cobalt/browser/switches.h
@@ -29,6 +29,7 @@
extern const char kDisableWebmVp9[];
extern const char kEnableWebDriver[];
extern const char kExtraWebFileDir[];
+extern const char kFakeMicrophone[];
extern const char kIgnoreCertificateErrors[];
extern const char kInputFuzzer[];
extern const char kMinLogLevel[];
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index d690671..6f60c5d 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-13403
\ No newline at end of file
+16134
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index 8ba37eb..31b8c5f 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -95,9 +95,11 @@
'lbshell_root%': '<(DEPTH)/lbshell',
# The relative path from src/ to the directory containing the
- # starboard_platform.gyp file, or the empty string if not an autodiscovered
- # platform.
- 'starboard_path%': '',
+ # starboard_platform.gyp file. It is currently set to
+ # 'starboard/<(target_arch)' to make semi-starboard platforms work.
+ # TODO: Set the default value to '' once all semi-starboard platforms are
+ # moved to starboard.
+ 'starboard_path%': 'starboard/<(target_arch)',
# The source of EGL and GLES headers and libraries.
# Valid values (case and everything sensitive!):
@@ -449,6 +451,7 @@
'cobalt_copy_debug_console': 1,
'cobalt_copy_test_data': 1,
'enable_about_scheme': 1,
+ 'enable_fake_microphone': 1,
'enable_file_scheme': 1,
'enable_network_logging': 1,
'enable_remote_debugging%': 1,
@@ -461,6 +464,7 @@
'cobalt_copy_debug_console': 0,
'cobalt_copy_test_data': 0,
'enable_about_scheme': 0,
+ 'enable_fake_microphone': 0,
'enable_file_scheme': 0,
'enable_network_logging': 0,
'enable_remote_debugging%': 0,
diff --git a/src/cobalt/build/gyp_cobalt b/src/cobalt/build/gyp_cobalt
index 0e60bb9..030de0f 100755
--- a/src/cobalt/build/gyp_cobalt
+++ b/src/cobalt/build/gyp_cobalt
@@ -218,6 +218,7 @@
full_starboard_path = platforms[platform]
assert full_starboard_path[:len(source_tree_dir)] == source_tree_dir
starboard_path = full_starboard_path[len(source_tree_dir) + 1:]
+ starboard_path.replace(os.sep, '/')
assert starboard_path[0] not in [ os.sep, os.altsep ]
variables['starboard_path'] = starboard_path
_AppendVariables(variables, self.common_args)
diff --git a/src/cobalt/content/ssl/certs/0a775a30.0 b/src/cobalt/content/ssl/certs/0a775a30.0
new file mode 100644
index 0000000..7d540a4
--- /dev/null
+++ b/src/cobalt/content/ssl/certs/0a775a30.0
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout
+736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A
+DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk
+fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA
+njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd
+-----END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/1001acf7.0 b/src/cobalt/content/ssl/certs/1001acf7.0
new file mode 100644
index 0000000..5496703
--- /dev/null
+++ b/src/cobalt/content/ssl/certs/1001acf7.0
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH
+MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
+QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy
+MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl
+cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM
+f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX
+mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7
+zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P
+fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc
+vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4
+Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp
+zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO
+Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW
+k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+
+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF
+lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW
+Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1
+d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z
+XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR
+gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3
+d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv
+J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg
+DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM
++SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy
+F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9
+SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws
+E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl
+-----END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/626dceaf.0 b/src/cobalt/content/ssl/certs/626dceaf.0
new file mode 100644
index 0000000..984f1d1
--- /dev/null
+++ b/src/cobalt/content/ssl/certs/626dceaf.0
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH
+MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
+QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy
+MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl
+cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv
+CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg
+GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu
+XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd
+re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu
+PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1
+mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K
+8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj
+x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR
+nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0
+kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok
+twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp
+8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT
+vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT
+z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA
+pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb
+pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB
+R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R
+RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk
+0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC
+5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF
+izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn
+yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC
+-----END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/a3418fda.0 b/src/cobalt/content/ssl/certs/a3418fda.0
new file mode 100644
index 0000000..07372d3
--- /dev/null
+++ b/src/cobalt/content/ssl/certs/a3418fda.0
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu
+hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l
+xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0
+CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx
+sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w==
+-----END CERTIFICATE-----
diff --git a/src/cobalt/dom/dom_settings.cc b/src/cobalt/dom/dom_settings.cc
index 1eca2a2..dce0f0b 100644
--- a/src/cobalt/dom/dom_settings.cc
+++ b/src/cobalt/dom/dom_settings.cc
@@ -31,6 +31,7 @@
script::GlobalEnvironment* global_environment,
const Options& options)
: max_dom_element_depth_(max_dom_element_depth),
+ enable_fake_microphone_(options.enable_fake_microphone),
fetcher_factory_(fetcher_factory),
network_module_(network_module),
window_(window),
diff --git a/src/cobalt/dom/dom_settings.h b/src/cobalt/dom/dom_settings.h
index 5bd39e1..0b99ea4 100644
--- a/src/cobalt/dom/dom_settings.h
+++ b/src/cobalt/dom/dom_settings.h
@@ -45,7 +45,10 @@
public:
// Hold optional settings for DOMSettings.
struct Options {
- Options() : array_buffer_allocator(NULL), array_buffer_cache(NULL) {}
+ Options()
+ : array_buffer_allocator(NULL),
+ array_buffer_cache(NULL),
+ enable_fake_microphone(false) {}
// ArrayBuffer allocates its memory on the heap by default and ArrayBuffers
// may occupy a lot of memory. It is possible to provide an allocator via
@@ -56,6 +59,8 @@
// amount of ArrayBuffer inside main memory. So we have provide the
// following cache to manage ArrayBuffer in main memory.
ArrayBuffer::Cache* array_buffer_cache;
+ // Use fake microphone if this flag is set to true.
+ bool enable_fake_microphone;
};
DOMSettings(const int max_dom_element_depth,
@@ -70,6 +75,7 @@
~DOMSettings() OVERRIDE;
int max_dom_element_depth() { return max_dom_element_depth_; }
+ bool enable_fake_microphone() const { return enable_fake_microphone_; }
void set_window(const scoped_refptr<Window>& window) { window_ = window; }
scoped_refptr<Window> window() const { return window_; }
@@ -106,6 +112,7 @@
private:
const int max_dom_element_depth_;
+ const bool enable_fake_microphone_;
loader::FetcherFactory* fetcher_factory_;
network::NetworkModule* network_module_;
scoped_refptr<Window> window_;
diff --git a/src/cobalt/dom_parser/html_decoder_test.cc b/src/cobalt/dom_parser/html_decoder_test.cc
index 92736ea..70019a1 100644
--- a/src/cobalt/dom_parser/html_decoder_test.cc
+++ b/src/cobalt/dom_parser/html_decoder_test.cc
@@ -382,6 +382,34 @@
EXPECT_EQ("💩", text->data());
}
+TEST_F(HTMLDecoderTest, CanParseUTF8SplitInChunks) {
+ const std::string input = "<p>💩</p>";
+
+ for (size_t first_chunk_size = 0; first_chunk_size < input.length();
+ first_chunk_size++) {
+ root_ = new dom::Element(document_, base::Token("element"));
+ html_decoder_.reset(new HTMLDecoder(
+ document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+ base::Closure(), base::Bind(&MockErrorCallback::Run,
+ base::Unretained(&mock_error_callback_)),
+ true));
+
+ // This could cut the input in the middle of a UTF8 character.
+ html_decoder_->DecodeChunk(input.c_str(), first_chunk_size);
+ html_decoder_->DecodeChunk(input.c_str() + first_chunk_size,
+ input.length() - first_chunk_size);
+ html_decoder_->Finish();
+
+ dom::Element* element = root_->first_element_child();
+ ASSERT_TRUE(element);
+ EXPECT_EQ("p", element->tag_name());
+
+ dom::Text* text = element->first_child()->AsText();
+ ASSERT_TRUE(text);
+ EXPECT_EQ("💩", text->data());
+ }
+}
+
// Misnested tags: <b><i></b></i>
// https://www.w3.org/TR/html5/syntax.html#misnested-tags:-b-i-/b-/i
//
diff --git a/src/cobalt/dom_parser/libxml_html_parser_wrapper.cc b/src/cobalt/dom_parser/libxml_html_parser_wrapper.cc
index 968dbe5..7a05cb8 100644
--- a/src/cobalt/dom_parser/libxml_html_parser_wrapper.cc
+++ b/src/cobalt/dom_parser/libxml_html_parser_wrapper.cc
@@ -110,7 +110,10 @@
return;
}
- if (CheckInputAndUpdateSeverity(data, size) == kFatal) {
+ std::string current_chunk;
+ PreprocessChunk(data, size, ¤t_chunk);
+
+ if (max_severity() == kFatal) {
return;
}
@@ -120,9 +123,10 @@
// when used for setting an element's innerHTML.
htmlEmitImpliedRootLevelParagraph(0);
- html_parser_context_ = htmlCreatePushParserCtxt(
- &html_sax_handler, this, data, static_cast<int>(size),
- NULL /*filename*/, XML_CHAR_ENCODING_UTF8);
+ html_parser_context_ =
+ htmlCreatePushParserCtxt(&html_sax_handler, this, current_chunk.c_str(),
+ static_cast<int>(current_chunk.size()),
+ NULL /*filename*/, XML_CHAR_ENCODING_UTF8);
if (!html_parser_context_) {
static const char kErrorUnableCreateParser[] =
@@ -135,7 +139,8 @@
}
} else {
DCHECK(html_parser_context_);
- htmlParseChunk(html_parser_context_, data, static_cast<int>(size),
+ htmlParseChunk(html_parser_context_, current_chunk.c_str(),
+ static_cast<int>(current_chunk.size()),
0 /*do not terminate*/);
}
}
diff --git a/src/cobalt/dom_parser/libxml_parser_wrapper.cc b/src/cobalt/dom_parser/libxml_parser_wrapper.cc
index ef19c762..a86753e 100644
--- a/src/cobalt/dom_parser/libxml_parser_wrapper.cc
+++ b/src/cobalt/dom_parser/libxml_parser_wrapper.cc
@@ -19,6 +19,8 @@
#include "base/logging.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
+#include "base/third_party/icu/icu_utf.h"
+#include "base/utf_string_conversion_utils.h"
#include "cobalt/base/tokens.h"
#include "cobalt/dom/cdata_section.h"
#include "cobalt/dom/comment.h"
@@ -314,34 +316,32 @@
node_stack_.top()->AppendChild(new dom::CDATASection(document_, value));
}
-LibxmlParserWrapper::IssueSeverity
-LibxmlParserWrapper::CheckInputAndUpdateSeverity(const char* data,
- size_t size) {
- if (max_severity_ == kFatal) {
- return max_severity_;
- }
-
+void LibxmlParserWrapper::PreprocessChunk(const char* data, size_t size,
+ std::string* current_chunk) {
+ DCHECK(current_chunk);
// Check the total input size.
total_input_size_ += size;
if (total_input_size_ > kMaxTotalInputSize) {
static const char kMessageInputTooLong[] = "Parser input is too long.";
OnParsingIssue(kFatal, kMessageInputTooLong);
- return max_severity_;
+ return;
}
// Check the encoding of the input.
- if (!IsStringUTF8(std::string(data, size))) {
+ std::string input = next_chunk_start_ + std::string(data, size);
+ TruncateUTF8ToByteSize(input, input.size(), current_chunk);
+ next_chunk_start_ = input.substr(current_chunk->size());
+ if (!IsStringUTF8(*current_chunk)) {
+ current_chunk->clear();
static const char kMessageInputNotUTF8[] =
"Parser input contains non-UTF8 characters.";
OnParsingIssue(kFatal, kMessageInputNotUTF8);
- return max_severity_;
+ return;
}
#if defined(HANDLE_CORE_DUMP)
libxml_parser_wrapper_log.Get().IncrementParsedBytes(static_cast<int>(size));
#endif
-
- return max_severity_;
}
} // namespace dom_parser
diff --git a/src/cobalt/dom_parser/libxml_parser_wrapper.h b/src/cobalt/dom_parser/libxml_parser_wrapper.h
index 98d210e..4c5e233 100644
--- a/src/cobalt/dom_parser/libxml_parser_wrapper.h
+++ b/src/cobalt/dom_parser/libxml_parser_wrapper.h
@@ -121,8 +121,10 @@
// Returns true when the input is a full document, false when it's a fragment.
bool IsFullDocument() { return document_ == parent_node_; }
- // Checks the input, updates and returns the maximum issue severity.
- IssueSeverity CheckInputAndUpdateSeverity(const char* data, size_t size);
+ // Preprocesses the input chunk and updates the max error severity level.
+ // Sets current chunk if successful.
+ void PreprocessChunk(const char* data, size_t size,
+ std::string* current_chunk);
const scoped_refptr<dom::Document>& document() { return document_; }
const base::SourceLocation& first_chunk_location() {
@@ -136,6 +138,8 @@
return node_stack_;
}
+ IssueSeverity max_severity() const { return max_severity_; }
+
private:
// Maximum total input size, as specified in Libxml's value
// XML_MAX_TEXT_LENGTH in parserInternals.h.
@@ -154,6 +158,7 @@
IssueSeverity max_severity_;
size_t total_input_size_;
+ std::string next_chunk_start_;
std::stack<scoped_refptr<dom::Node> > node_stack_;
DISALLOW_COPY_AND_ASSIGN(LibxmlParserWrapper);
diff --git a/src/cobalt/dom_parser/libxml_xml_parser_wrapper.cc b/src/cobalt/dom_parser/libxml_xml_parser_wrapper.cc
index 787970d..dfbb290 100644
--- a/src/cobalt/dom_parser/libxml_xml_parser_wrapper.cc
+++ b/src/cobalt/dom_parser/libxml_xml_parser_wrapper.cc
@@ -79,14 +79,17 @@
return;
}
- if (CheckInputAndUpdateSeverity(data, size) == kFatal) {
+ std::string current_chunk;
+ PreprocessChunk(data, size, ¤t_chunk);
+
+ if (max_severity() == kFatal) {
return;
}
if (!xml_parser_context_) {
- xml_parser_context_ =
- xmlCreatePushParserCtxt(&xml_sax_handler, this, data,
- static_cast<int>(size), NULL /*filename*/);
+ xml_parser_context_ = xmlCreatePushParserCtxt(
+ &xml_sax_handler, this, current_chunk.c_str(),
+ static_cast<int>(current_chunk.size()), NULL /*filename*/);
if (!xml_parser_context_) {
static const char kErrorUnableCreateParser[] =
@@ -94,7 +97,8 @@
OnParsingIssue(kFatal, kErrorUnableCreateParser);
}
} else {
- xmlParseChunk(xml_parser_context_, data, static_cast<int>(size),
+ xmlParseChunk(xml_parser_context_, current_chunk.c_str(),
+ static_cast<int>(current_chunk.size()),
0 /*do not terminate*/);
}
}
diff --git a/src/cobalt/speech/endpointer/endpointer.cc b/src/cobalt/speech/endpointer/endpointer.cc
index b0c09e9..cabad1a 100644
--- a/src/cobalt/speech/endpointer/endpointer.cc
+++ b/src/cobalt/speech/endpointer/endpointer.cc
@@ -9,7 +9,10 @@
using base::Time;
namespace {
-const int kFrameRate = 50; // 1 frame = 20ms of audio.
+// Only send |kFrameSize| of audio data to energy endpointer each time.
+// It should be smaller than the samples of audio bus which is passed in
+// |ProcessAudio|.
+const int kFrameSize = 160;
}
namespace cobalt {
@@ -20,11 +23,9 @@
speech_input_complete_silence_length_us_(-1),
audio_frame_time_us_(0),
sample_rate_(sample_rate),
- frame_size_(0) {
+ frame_rate_(sample_rate / kFrameSize) {
Reset();
- frame_size_ = static_cast<int>(sample_rate / static_cast<float>(kFrameRate));
-
speech_input_minimum_length_us_ =
static_cast<int64_t>(1.7 * Time::kMicrosecondsPerSecond);
speech_input_complete_silence_length_us_ =
@@ -36,8 +37,8 @@
// Set the default configuration for Push To Talk mode.
EnergyEndpointerParams ep_config;
- ep_config.set_frame_period(1.0f / static_cast<float>(kFrameRate));
- ep_config.set_frame_duration(1.0f / static_cast<float>(kFrameRate));
+ ep_config.set_frame_period(1.0f / static_cast<float>(frame_rate_));
+ ep_config.set_frame_duration(1.0f / static_cast<float>(frame_rate_));
ep_config.set_endpoint_margin(0.2f);
ep_config.set_onset_window(0.15f);
ep_config.set_speech_on_window(0.4f);
@@ -92,6 +93,7 @@
EpStatus Endpointer::ProcessAudio(
const ShellAudioBus& audio_bus, float* rms_out) {
DCHECK_EQ(audio_bus.channels(), 1);
+
const size_t num_samples = audio_bus.frames();
const int16_t* audio_data = NULL;
@@ -111,19 +113,17 @@
EpStatus ep_status = EP_PRE_SPEECH;
- // Process the input data in blocks of frame_size_, dropping any incomplete
+ // Process the input data in blocks of kFrameSize, dropping any incomplete
// frames at the end (which is ok since typically the caller will be recording
// audio in multiples of our frame size).
int sample_index = 0;
- while (static_cast<size_t>(sample_index + frame_size_) <= num_samples) {
+ while (static_cast<size_t>(sample_index + kFrameSize) <= num_samples) {
// Have the endpointer process the frame.
- energy_endpointer_.ProcessAudioFrame(audio_frame_time_us_,
- audio_data + sample_index,
- frame_size_,
- rms_out);
- sample_index += frame_size_;
- audio_frame_time_us_ += (frame_size_ * Time::kMicrosecondsPerSecond) /
- sample_rate_;
+ energy_endpointer_.ProcessAudioFrame(
+ audio_frame_time_us_, audio_data + sample_index, kFrameSize, rms_out);
+ sample_index += kFrameSize;
+ audio_frame_time_us_ +=
+ (kFrameSize * Time::kMicrosecondsPerSecond) / sample_rate_;
// Get the status of the endpointer.
int64_t ep_time;
diff --git a/src/cobalt/speech/endpointer/endpointer.h b/src/cobalt/speech/endpointer/endpointer.h
index b8d46f5..f6c818f 100644
--- a/src/cobalt/speech/endpointer/endpointer.h
+++ b/src/cobalt/speech/endpointer/endpointer.h
@@ -100,6 +100,8 @@
return speech_input_complete_;
}
+ int sample_rate() const { return sample_rate_; }
+
// RMS background noise level in dB.
float NoiseLevelDb() const { return energy_endpointer_.GetNoiseLevelDb(); }
@@ -147,7 +149,8 @@
bool speech_input_complete_;
EnergyEndpointer energy_endpointer_;
int sample_rate_;
- int32_t frame_size_;
+ // 1 frame = (1 / frame_rate_) second of audio.
+ int frame_rate_;
};
} // namespace speech
diff --git a/src/cobalt/speech/endpointer_delegate.cc b/src/cobalt/speech/endpointer_delegate.cc
new file mode 100644
index 0000000..a3d0444
--- /dev/null
+++ b/src/cobalt/speech/endpointer_delegate.cc
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#include "cobalt/speech/endpointer_delegate.h"
+
+#include "base/time.h"
+
+namespace cobalt {
+namespace speech {
+
+namespace {
+const int kEndPointerEstimationTimeInMillisecond = 300;
+// If used in noisy conditions, the endpointer should be started and run in the
+// EnvironmentEstimation mode, for at least 200ms, before switching to
+// UserInputMode.
+COMPILE_ASSERT(kEndPointerEstimationTimeInMillisecond >= 200,
+ in_environment_estimation_mode_for_at_least_200ms);
+} // namespace
+
+EndPointerDelegate::EndPointerDelegate(int sample_rate)
+ : endpointer_(sample_rate),
+ num_samples_recorded_(0),
+ is_first_time_sound_started_(false) {}
+
+EndPointerDelegate::~EndPointerDelegate() {}
+
+void EndPointerDelegate::Start() {
+ num_samples_recorded_ = 0;
+ is_first_time_sound_started_ = false;
+
+ endpointer_.StartSession();
+ endpointer_.SetEnvironmentEstimationMode();
+}
+
+void EndPointerDelegate::Stop() { endpointer_.EndSession(); }
+
+bool EndPointerDelegate::IsFirstTimeSoundStarted(
+ const ShellAudioBus& audio_bus) {
+ if (is_first_time_sound_started_) {
+ return false;
+ }
+
+ num_samples_recorded_ += static_cast<int>(audio_bus.frames());
+ if (endpointer_.IsEstimatingEnvironment() &&
+ num_samples_recorded_ * 1000 / endpointer_.sample_rate() >
+ kEndPointerEstimationTimeInMillisecond) {
+ // Switch to user input mode.
+ endpointer_.SetUserInputMode();
+ }
+
+ endpointer_.ProcessAudio(audio_bus, NULL);
+ int64_t ep_time;
+ EpStatus status = endpointer_.Status(&ep_time);
+ if (status == EP_POSSIBLE_ONSET) {
+ is_first_time_sound_started_ = true;
+ }
+
+ return is_first_time_sound_started_;
+}
+
+} // namespace speech
+} // namespace cobalt
diff --git a/src/cobalt/speech/endpointer_delegate.h b/src/cobalt/speech/endpointer_delegate.h
new file mode 100644
index 0000000..8a3aafa
--- /dev/null
+++ b/src/cobalt/speech/endpointer_delegate.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef COBALT_SPEECH_ENDPOINTER_DELEGATE_H_
+#define COBALT_SPEECH_ENDPOINTER_DELEGATE_H_
+
+#include "cobalt/speech/endpointer/endpointer.h"
+#include "media/base/audio_bus.h"
+
+namespace cobalt {
+namespace speech {
+
+// Delegate of endpointer for detecting the first time sound started in one
+// speech session (from start speaking to end of speaking).
+class EndPointerDelegate {
+ public:
+ typedef ::media::ShellAudioBus ShellAudioBus;
+
+ explicit EndPointerDelegate(int sample_rate);
+ ~EndPointerDelegate();
+
+ // Start endpointer session for sound processing.
+ void Start();
+ // Stop endpointer session.
+ void Stop();
+
+ // Return true if it is the first time that the sound started.
+ bool IsFirstTimeSoundStarted(const ShellAudioBus& audio_bus);
+
+ private:
+ // Used for detecting sound start event.
+ Endpointer endpointer_;
+ // Used for recording the number of samples before notifying that it is the
+ // first time the sound started. The |endpointer_| should be started and run
+ // in the EnvironmentEstimation mode if used in noisy conditions for at least
+ // 200ms before switching to UserInputMode.
+ int num_samples_recorded_;
+
+ // Record if it is the first time that the sound started.
+ bool is_first_time_sound_started_;
+};
+
+} // namespace speech
+} // namespace cobalt
+
+#endif // COBALT_SPEECH_ENDPOINTER_DELEGATE_H_
diff --git a/src/cobalt/speech/mic.h b/src/cobalt/speech/mic.h
deleted file mode 100644
index 506632a..0000000
--- a/src/cobalt/speech/mic.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef COBALT_SPEECH_MIC_H_
-#define COBALT_SPEECH_MIC_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "media/base/shell_audio_bus.h"
-
-namespace cobalt {
-namespace speech {
-
-// An abstract class is used for interacting platform specific microphone.
-class Mic {
- public:
- typedef ::media::ShellAudioBus ShellAudioBus;
- typedef base::Callback<void(scoped_ptr<ShellAudioBus>)> DataReceivedCallback;
- typedef base::Callback<void(void)> CompletionCallback;
- typedef base::Callback<void(void)> ErrorCallback;
-
- virtual ~Mic() {}
-
- static scoped_ptr<Mic> Create(int sample_rate,
- const DataReceivedCallback& data_received,
- const CompletionCallback& completion,
- const ErrorCallback& error);
-
- // Multiple calls to Start/Stop are allowed, the implementation should take
- // care of multiple calls. The Start/Stop methods are required to be called in
- // the same thread.
- // Start microphone to receive voice.
- virtual void Start() = 0;
- // Stop microphone from receiving voice.
- virtual void Stop() = 0;
-
- protected:
- Mic(int sample_rate, const DataReceivedCallback& data_received,
- const CompletionCallback& completion, const ErrorCallback& error)
- : sample_rate_(sample_rate),
- data_received_callback_(data_received),
- completion_callback_(completion),
- error_callback_(error) {}
-
- int sample_rate_;
- const DataReceivedCallback data_received_callback_;
- const CompletionCallback completion_callback_;
- const ErrorCallback error_callback_;
-};
-
-std::string GetSpeechAPIKey();
-
-} // namespace speech
-} // namespace cobalt
-
-#endif // COBALT_SPEECH_MIC_H_
diff --git a/src/cobalt/speech/mic_linux.cc b/src/cobalt/speech/mic_linux.cc
deleted file mode 100644
index d7f6809..0000000
--- a/src/cobalt/speech/mic_linux.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-#include "cobalt/speech/mic.h"
-
-namespace cobalt {
-namespace speech {
-
-class MicLinux : public Mic {
- public:
- MicLinux(int sample_rate, const DataReceivedCallback& data_received,
- const CompletionCallback& completion, const ErrorCallback& error)
- : Mic(sample_rate, data_received, completion, error) {}
-
- void Start() OVERRIDE { NOTIMPLEMENTED(); }
- void Stop() OVERRIDE { NOTIMPLEMENTED(); }
-};
-
-// static
-scoped_ptr<Mic> Mic::Create(int sample_rate,
- const DataReceivedCallback& data_received,
- const CompletionCallback& completion,
- const ErrorCallback& error) {
- return make_scoped_ptr<Mic>(
- new MicLinux(sample_rate, data_received, completion, error));
-}
-
-std::string GetSpeechAPIKey() { return ""; }
-
-} // namespace speech
-} // namespace cobalt
diff --git a/src/cobalt/speech/mic_starboard.cc b/src/cobalt/speech/mic_starboard.cc
deleted file mode 100644
index c818dab..0000000
--- a/src/cobalt/speech/mic_starboard.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-#include "cobalt/speech/mic.h"
-
-namespace cobalt {
-namespace speech {
-
-class MicStarboard : public Mic {
- public:
- MicStarboard(int sample_rate, const DataReceivedCallback& data_received,
- const CompletionCallback& completion, const ErrorCallback& error)
- : Mic(sample_rate, data_received, completion, error) {}
-
- void Start() OVERRIDE { NOTIMPLEMENTED(); }
- void Stop() OVERRIDE { NOTIMPLEMENTED(); }
-};
-
-// static
-scoped_ptr<Mic> Mic::Create(int sample_rate,
- const DataReceivedCallback& data_received,
- const CompletionCallback& completion,
- const ErrorCallback& error) {
- return make_scoped_ptr<Mic>(
- new MicStarboard(sample_rate, data_received, completion, error));
-}
-
-std::string GetSpeechAPIKey() { return ""; }
-
-} // namespace speech
-} // namespace cobalt
diff --git a/src/cobalt/speech/mic_win.cc b/src/cobalt/speech/mic_win.cc
deleted file mode 100644
index 80c49fc..0000000
--- a/src/cobalt/speech/mic_win.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-#include "cobalt/speech/mic.h"
-
-namespace cobalt {
-namespace speech {
-
-class MicWin : public Mic {
- public:
- MicWin(int sample_rate, const DataReceivedCallback& data_received,
- const CompletionCallback& completion, const ErrorCallback& error)
- : Mic(sample_rate, data_received, completion, error) {}
-
- void Start() OVERRIDE { NOTIMPLEMENTED(); }
- void Stop() OVERRIDE { NOTIMPLEMENTED(); }
-};
-
-// static
-scoped_ptr<Mic> Mic::Create(int sample_rate,
- const DataReceivedCallback& data_received,
- const CompletionCallback& completion,
- const ErrorCallback& error) {
- return make_scoped_ptr<Mic>(
- new MicWin(sample_rate, data_received, completion, error));
-}
-
-std::string GetSpeechAPIKey() { return ""; }
-
-} // namespace speech
-} // namespace cobalt
diff --git a/src/cobalt/speech/microphone.h b/src/cobalt/speech/microphone.h
new file mode 100644
index 0000000..3b9e6ae
--- /dev/null
+++ b/src/cobalt/speech/microphone.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef COBALT_SPEECH_MICROPHONE_H_
+#define COBALT_SPEECH_MICROPHONE_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+
+namespace cobalt {
+namespace speech {
+
+// An abstract class is used for interacting platform specific microphone.
+class Microphone {
+ public:
+ virtual ~Microphone() {}
+
+ // Opens microphone port and starts recording audio.
+ virtual bool Open() = 0;
+ // Reads audio data from microphone. The return value is the bytes that were
+ // read from microphone. Negative value indicates a read error. |data_size| is
+ // the requested read bytes.
+ virtual int Read(char* out_data, int data_size) = 0;
+ // Closes microphone port and stops recording audio.
+ virtual bool Close() = 0;
+ // Returns the minimum requested bytes per microphone read.
+ virtual int MinMicrophoneReadInBytes() = 0;
+ // Returns true if the microphone is valid.
+ virtual bool IsValid() = 0;
+
+ protected:
+ Microphone() {}
+};
+
+} // namespace speech
+} // namespace cobalt
+
+#endif // COBALT_SPEECH_MICROPHONE_H_
diff --git a/src/cobalt/speech/microphone_fake.cc b/src/cobalt/speech/microphone_fake.cc
new file mode 100644
index 0000000..7ee601c
--- /dev/null
+++ b/src/cobalt/speech/microphone_fake.cc
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#include "cobalt/speech/microphone_fake.h"
+
+#if defined(ENABLE_FAKE_MICROPHONE)
+
+#include <algorithm>
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/rand_util.h"
+#include "starboard/file.h"
+#include "starboard/memory.h"
+#include "starboard/time.h"
+
+namespace cobalt {
+namespace speech {
+
+namespace {
+const int kMaxBufferSize = 512 * 1024;
+const int kMinMicrophoneReadInBytes = 1024;
+// The possiblity of microphone creation failed is 1/20.
+const int kCreationRange = 20;
+// The possiblity of microphone open failed is 1/20.
+const int kOpenRange = 20;
+// The possiblity of microphone read failed is 1/200.
+const int kReadRange = 200;
+// The possiblity of microphone close failed is 1/20.
+const int kCloseRange = 20;
+const int kFailureNumber = 5;
+
+bool ShouldFail(int range) {
+ return base::RandGenerator(range) == kFailureNumber;
+}
+
+} // namespace
+
+MicrophoneFake::MicrophoneFake()
+ : Microphone(),
+ file_length_(-1),
+ read_index_(0),
+ is_valid_(!ShouldFail(kCreationRange)) {
+ if (!is_valid_) {
+ SB_DLOG(WARNING) << "Mocking microphone creation failed.";
+ return;
+ }
+
+ FilePath audio_files_path;
+ SB_CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &audio_files_path));
+ audio_files_path = audio_files_path.Append(FILE_PATH_LITERAL("cobalt"))
+ .Append(FILE_PATH_LITERAL("speech"))
+ .Append(FILE_PATH_LITERAL("testdata"));
+
+ file_util::FileEnumerator file_enumerator(audio_files_path,
+ false /* Not recursive */,
+ file_util::FileEnumerator::FILES);
+ for (FilePath next = file_enumerator.Next(); !next.empty();
+ next = file_enumerator.Next()) {
+ file_paths_.push_back(next);
+ }
+}
+
+bool MicrophoneFake::Open() {
+ if (ShouldFail(kOpenRange)) {
+ SB_DLOG(WARNING) << "Mocking microphone open failed.";
+ return false;
+ }
+
+ SB_DCHECK(file_paths_.size() != 0);
+ uint64 random_index = base::RandGenerator(file_paths_.size());
+ starboard::ScopedFile file(file_paths_[random_index].value().c_str(),
+ kSbFileOpenOnly | kSbFileRead, NULL, NULL);
+ SB_DCHECK(file.IsValid());
+ int file_buffer_size =
+ std::min(static_cast<int>(file.GetSize()), kMaxBufferSize);
+ SB_DCHECK(file_buffer_size > 0);
+ file_buffer_.reset(new char[file_buffer_size]);
+ int read_bytes = file.ReadAll(file_buffer_.get(), file_buffer_size);
+ if (read_bytes < 0) {
+ return false;
+ }
+
+ file_length_ = read_bytes;
+ return true;
+}
+
+int MicrophoneFake::Read(char* out_data, int data_size) {
+ if (ShouldFail(kReadRange)) {
+ SB_DLOG(WARNING) << "Mocking microphone read failed.";
+ return -1;
+ }
+
+ int copy_bytes = std::min(file_length_ - read_index_, data_size);
+ SbMemoryCopy(out_data, file_buffer_.get() + read_index_, copy_bytes);
+ read_index_ += copy_bytes;
+ if (read_index_ == file_length_) {
+ read_index_ = 0;
+ }
+
+ return copy_bytes;
+}
+
+bool MicrophoneFake::Close() {
+ file_buffer_.reset();
+ file_length_ = -1;
+ read_index_ = 0;
+
+ if (ShouldFail(kCloseRange)) {
+ SB_DLOG(WARNING) << "Mocking microphone close failed.";
+ return false;
+ }
+
+ return true;
+}
+
+int MicrophoneFake::MinMicrophoneReadInBytes() {
+ return kMinMicrophoneReadInBytes;
+}
+
+} // namespace speech
+} // namespace cobalt
+
+#endif // defined(ENABLE_FAKE_MICROPHONE)
diff --git a/src/cobalt/speech/microphone_fake.h b/src/cobalt/speech/microphone_fake.h
new file mode 100644
index 0000000..dd17c1c
--- /dev/null
+++ b/src/cobalt/speech/microphone_fake.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef COBALT_SPEECH_MICROPHONE_FAKE_H_
+#define COBALT_SPEECH_MICROPHONE_FAKE_H_
+
+#include "cobalt/speech/speech_configuration.h"
+
+#if defined(ENABLE_FAKE_MICROPHONE)
+
+#include <string>
+#include <vector>
+
+#include "base/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "cobalt/speech/microphone.h"
+
+namespace cobalt {
+namespace speech {
+
+// Fake microphone to mock the speech input by reading from the pre-recorded
+// audio.
+class MicrophoneFake : public Microphone {
+ public:
+ MicrophoneFake();
+ ~MicrophoneFake() SB_OVERRIDE {}
+
+ bool Open() SB_OVERRIDE;
+ int Read(char* out_data, int data_size) SB_OVERRIDE;
+ bool Close() SB_OVERRIDE;
+ int MinMicrophoneReadInBytes() SB_OVERRIDE;
+ bool IsValid() SB_OVERRIDE { return is_valid_; }
+
+ private:
+ std::vector<FilePath> file_paths_;
+ scoped_array<char> file_buffer_;
+ int file_length_;
+ int read_index_;
+ bool is_valid_;
+};
+
+} // namespace speech
+} // namespace cobalt
+
+#endif // defined(ENABLE_FAKE_MICROPHONE)
+#endif // COBALT_SPEECH_MICROPHONE_FAKE_H_
diff --git a/src/cobalt/speech/microphone_manager.cc b/src/cobalt/speech/microphone_manager.cc
new file mode 100644
index 0000000..7b491d9
--- /dev/null
+++ b/src/cobalt/speech/microphone_manager.cc
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+#include "cobalt/speech/microphone_manager.h"
+
+#if defined(ENABLE_FAKE_MICROPHONE)
+#include "cobalt/speech/microphone_fake.h"
+#endif // defined(ENABLE_FAKE_MICROPHONE)
+#if defined(SB_USE_SB_MICROPHONE)
+#include "cobalt/speech/microphone_starboard.h"
+#endif // defined(SB_USE_SB_MICROPHONE)
+#include "cobalt/speech/speech_recognition_error.h"
+
+namespace cobalt {
+namespace speech {
+
+namespace {
+// Size of an audio buffer.
+const int kBufferSizeInBytes = 8 * 1024;
+// The frequency which we read the data from devices.
+const float kMicReadRateInHertz = 60.0f;
+} // namespace
+
+MicrophoneManager::MicrophoneManager(int sample_rate,
+ const DataReceivedCallback& data_received,
+ const CompletionCallback& completion,
+ const ErrorCallback& error,
+ bool enable_fake_microphone)
+ : sample_rate_(sample_rate),
+ data_received_callback_(data_received),
+ completion_callback_(completion),
+ error_callback_(error),
+#if defined(ENABLE_FAKE_MICROPHONE)
+ enable_fake_microphone_(enable_fake_microphone),
+#endif // defined(ENABLE_FAKE_MICROPHONE)
+ state_(kStopped),
+ thread_("microphone_thread") {
+ UNREFERENCED_PARAMETER(sample_rate_);
+#if defined(ENABLE_FAKE_MICROPHONE)
+ UNREFERENCED_PARAMETER(enable_fake_microphone_);
+#else
+ UNREFERENCED_PARAMETER(enable_fake_microphone);
+#endif // defined(ENABLE_FAKE_MICROPHONE)
+ thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
+}
+
+MicrophoneManager::~MicrophoneManager() {
+ thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&MicrophoneManager::DestroyInternal, base::Unretained(this)));
+}
+
+void MicrophoneManager::Open() {
+ thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&MicrophoneManager::OpenInternal, base::Unretained(this)));
+}
+
+void MicrophoneManager::Close() {
+ thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&MicrophoneManager::CloseInternal, base::Unretained(this)));
+}
+
+bool MicrophoneManager::CreateIfNecessary() {
+ DCHECK(thread_.message_loop_proxy()->BelongsToCurrentThread());
+
+ if (microphone_) {
+ return true;
+ }
+
+#if defined(SB_USE_SB_MICROPHONE)
+#if defined(ENABLE_FAKE_MICROPHONE)
+ if (enable_fake_microphone_) {
+ microphone_.reset(new MicrophoneFake());
+ } else {
+ microphone_.reset(
+ new MicrophoneStarboard(sample_rate_, kBufferSizeInBytes));
+ }
+#else
+ microphone_.reset(new MicrophoneStarboard(sample_rate_, kBufferSizeInBytes));
+#endif // defined(ENABLE_FAKE_MICROPHONE)
+#endif // defined(SB_USE_SB_MICROPHONE)
+
+ if (microphone_ && microphone_->IsValid()) {
+ state_ = kStopped;
+ return true;
+ } else {
+ DLOG(WARNING) << "Microphone creation failed.";
+ microphone_.reset();
+ state_ = kError;
+ error_callback_.Run(new SpeechRecognitionError(
+ SpeechRecognitionError::kAudioCapture, "No microphone available."));
+ return false;
+ }
+}
+
+void MicrophoneManager::OpenInternal() {
+ DCHECK(thread_.message_loop_proxy()->BelongsToCurrentThread());
+
+ // Try to create a valid microphone if necessary.
+ if (state_ == kStarted || !CreateIfNecessary()) {
+ return;
+ }
+
+ DCHECK(microphone_);
+ if (!microphone_->Open()) {
+ state_ = kError;
+ error_callback_.Run(new SpeechRecognitionError(
+ SpeechRecognitionError::kAborted, "Microphone open failed."));
+ return;
+ }
+
+ poll_mic_events_timer_.emplace();
+ // Setup a timer to poll for input events.
+ poll_mic_events_timer_->Start(
+ FROM_HERE, base::TimeDelta::FromMicroseconds(static_cast<int64>(
+ base::Time::kMicrosecondsPerSecond / kMicReadRateInHertz)),
+ this, &MicrophoneManager::Read);
+ state_ = kStarted;
+}
+
+void MicrophoneManager::CloseInternal() {
+ DCHECK(thread_.message_loop_proxy()->BelongsToCurrentThread());
+
+ if (state_ == kStopped) {
+ return;
+ }
+
+ if (poll_mic_events_timer_) {
+ poll_mic_events_timer_->Stop();
+ }
+
+ if (microphone_) {
+ if (!microphone_->Close()) {
+ state_ = kError;
+ error_callback_.Run(new SpeechRecognitionError(
+ SpeechRecognitionError::kAborted, "Microphone close failed."));
+ return;
+ }
+ completion_callback_.Run();
+ state_ = kStopped;
+ }
+}
+
+void MicrophoneManager::Read() {
+ DCHECK(thread_.message_loop_proxy()->BelongsToCurrentThread());
+
+ DCHECK(state_ == kStarted);
+ DCHECK(microphone_);
+ DCHECK(microphone_->MinMicrophoneReadInBytes() <= kBufferSizeInBytes);
+
+ static int16_t samples[kBufferSizeInBytes / sizeof(int16_t)];
+ int read_bytes =
+ microphone_->Read(reinterpret_cast<char*>(samples), kBufferSizeInBytes);
+ if (read_bytes > 0) {
+ size_t frames = read_bytes / sizeof(int16_t);
+ scoped_ptr<ShellAudioBus> output_audio_bus(new ShellAudioBus(
+ 1, frames, ShellAudioBus::kInt16, ShellAudioBus::kInterleaved));
+ output_audio_bus->Assign(ShellAudioBus(1, frames, samples));
+ data_received_callback_.Run(output_audio_bus.Pass());
+ } else if (read_bytes < 0) {
+ state_ = kError;
+ error_callback_.Run(new SpeechRecognitionError(
+ SpeechRecognitionError::kAborted, "Microphone read failed."));
+ poll_mic_events_timer_->Stop();
+ }
+}
+
+void MicrophoneManager::DestroyInternal() {
+ DCHECK(thread_.message_loop_proxy()->BelongsToCurrentThread());
+
+ microphone_.reset();
+ state_ = kStopped;
+}
+
+} // namespace speech
+} // namespace cobalt
diff --git a/src/cobalt/speech/microphone_manager.h b/src/cobalt/speech/microphone_manager.h
new file mode 100644
index 0000000..e91ca8c
--- /dev/null
+++ b/src/cobalt/speech/microphone_manager.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#ifndef COBALT_SPEECH_MICROPHONE_MANAGER_H_
+#define COBALT_SPEECH_MICROPHONE_MANAGER_H_
+
+#include "cobalt/speech/speech_configuration.h"
+
+#include "base/callback.h"
+#include "base/optional.h"
+#include "base/threading/thread.h"
+#include "base/timer.h"
+#include "cobalt/dom/event.h"
+#include "cobalt/speech/microphone.h"
+#include "media/base/shell_audio_bus.h"
+
+namespace cobalt {
+namespace speech {
+
+// This class is used for microphone creation, control and destruction. It has
+// a self-managed poller to fetch audio data from microphone.
+class MicrophoneManager {
+ public:
+ typedef ::media::ShellAudioBus ShellAudioBus;
+ typedef base::Callback<void(scoped_ptr<ShellAudioBus>)> DataReceivedCallback;
+ typedef base::Callback<void(void)> CompletionCallback;
+ typedef base::Callback<void(const scoped_refptr<dom::Event>&)> ErrorCallback;
+
+ MicrophoneManager(int sample_rate, const DataReceivedCallback& data_received,
+ const CompletionCallback& completion,
+ const ErrorCallback& error, bool enable_fake_microphone);
+
+ ~MicrophoneManager();
+
+ // Open microphone to receive voice and start a timer to fetch audio data from
+ // microphone.
+ void Open();
+ // Close microphone and stop the timer from receiving audio data.
+ void Close();
+
+ private:
+ enum State { kStarted, kStopped, kError };
+
+ // Returns true if the creation succeeded or the microphone is already a valid
+ // one.
+ bool CreateIfNecessary();
+ void OpenInternal();
+ void CloseInternal();
+ void DestroyInternal();
+
+ // Timer callback for fetching audio data.
+ void Read();
+
+ int sample_rate_;
+ const DataReceivedCallback data_received_callback_;
+ const CompletionCallback completion_callback_;
+ const ErrorCallback error_callback_;
+
+ scoped_ptr<Microphone> microphone_;
+#if defined(ENABLE_FAKE_MICROPHONE)
+ bool enable_fake_microphone_;
+#endif // defined(ENABLE_FAKE_MICROPHONE)
+
+ // Microphone state.
+ State state_;
+ // Repeat timer to poll mic events.
+ base::optional<base::RepeatingTimer<MicrophoneManager> >
+ poll_mic_events_timer_;
+ // Microphone thread.
+ base::Thread thread_;
+};
+
+} // namespace speech
+} // namespace cobalt
+
+#endif // COBALT_SPEECH_MICROPHONE_MANAGER_H_
diff --git a/src/cobalt/speech/microphone_starboard.cc b/src/cobalt/speech/microphone_starboard.cc
new file mode 100644
index 0000000..676c0aa
--- /dev/null
+++ b/src/cobalt/speech/microphone_starboard.cc
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#include "cobalt/speech/microphone_starboard.h"
+
+#if defined(SB_USE_SB_MICROPHONE)
+
+#include "starboard/log.h"
+
+namespace cobalt {
+namespace speech {
+
+namespace {
+// The maximum of microphones which can be supported. Currently only supports
+// one microphone.
+const int kNumberOfMicrophones = 1;
+} // namespace
+
+MicrophoneStarboard::MicrophoneStarboard(int sample_rate, int buffer_size_bytes)
+ : Microphone(),
+ min_microphone_read_in_bytes_(-1),
+ microphone_(kSbMicrophoneInvalid) {
+ SbMicrophoneInfo info[kNumberOfMicrophones];
+ int microphone_num = SbMicrophoneGetAvailable(info, kNumberOfMicrophones);
+
+ // Loop all the available microphones and create a valid one.
+ for (int index = 0; index < microphone_num; ++index) {
+ if (!SbMicrophoneIsSampleRateSupported(info[index].id, sample_rate)) {
+ continue;
+ }
+
+ microphone_ =
+ SbMicrophoneCreate(info[index].id, sample_rate, buffer_size_bytes);
+ if (!SbMicrophoneIsValid(microphone_)) {
+ continue;
+ }
+
+ // Created a microphone successfully.
+ min_microphone_read_in_bytes_ = info[index].min_read_size;
+ return;
+ }
+}
+
+MicrophoneStarboard::~MicrophoneStarboard() {
+ SbMicrophoneDestroy(microphone_);
+}
+
+bool MicrophoneStarboard::Open() {
+ SB_DCHECK(SbMicrophoneIsValid(microphone_));
+ return SbMicrophoneOpen(microphone_);
+}
+
+int MicrophoneStarboard::Read(char* out_data, int data_size) {
+ SB_DCHECK(SbMicrophoneIsValid(microphone_));
+ return SbMicrophoneRead(microphone_, out_data, data_size);
+}
+
+bool MicrophoneStarboard::Close() {
+ SB_DCHECK(SbMicrophoneIsValid(microphone_));
+ return SbMicrophoneClose(microphone_);
+}
+
+} // namespace speech
+} // namespace cobalt
+
+#endif // defined(SB_USE_SB_MICROPHONE)
diff --git a/src/cobalt/speech/microphone_starboard.h b/src/cobalt/speech/microphone_starboard.h
new file mode 100644
index 0000000..9df841a
--- /dev/null
+++ b/src/cobalt/speech/microphone_starboard.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef COBALT_SPEECH_MICROPHONE_STARBOARD_H_
+#define COBALT_SPEECH_MICROPHONE_STARBOARD_H_
+
+#include "cobalt/speech/speech_configuration.h"
+
+#if defined(SB_USE_SB_MICROPHONE)
+
+#include "cobalt/speech/microphone.h"
+#include "starboard/microphone.h"
+
+namespace cobalt {
+namespace speech {
+
+class MicrophoneStarboard : public Microphone {
+ public:
+ MicrophoneStarboard(int sample_rate, int buffer_size_bytes);
+ ~MicrophoneStarboard() OVERRIDE;
+
+ bool Open() OVERRIDE;
+ int Read(char* out_data, int data_size) OVERRIDE;
+ bool Close() OVERRIDE;
+ int MinMicrophoneReadInBytes() OVERRIDE {
+ return min_microphone_read_in_bytes_;
+ }
+ bool IsValid() OVERRIDE { return SbMicrophoneIsValid(microphone_); }
+
+ private:
+ // Minimum requested bytes per microphone read.
+ int min_microphone_read_in_bytes_;
+ SbMicrophone microphone_;
+};
+
+} // namespace speech
+} // namespace cobalt
+
+#endif // defined(SB_USE_SB_MICROPHONE)
+#endif // COBALT_SPEECH_MICROPHONE_STARBOARD_H_
diff --git a/src/cobalt/speech/speech.gyp b/src/cobalt/speech/speech.gyp
index eb0ffcb..aa933d3 100644
--- a/src/cobalt/speech/speech.gyp
+++ b/src/cobalt/speech/speech.gyp
@@ -30,6 +30,8 @@
'audio_encoder_flac.h',
'chunked_byte_buffer.cc',
'chunked_byte_buffer.h',
+ 'endpointer_delegate.cc',
+ 'endpointer_delegate.h',
'endpointer/endpointer.cc',
'endpointer/endpointer.h',
@@ -41,7 +43,10 @@
'google_streaming_api.pb.cc',
'google_streaming_api.pb.h',
'google_streaming_api.pb.proto',
- 'mic.h',
+ 'microphone.h',
+ 'microphone_manager.cc',
+ 'microphone_manager.h',
+ 'speech_configuration.h',
'speech_recognition.cc',
'speech_recognition.h',
'speech_recognition_alternative.cc',
@@ -73,14 +78,38 @@
'conditions': [
['OS=="starboard"', {
'sources': [
- 'mic_starboard.cc',
+ 'microphone_starboard.cc',
+ 'microphone_starboard.h',
],
}],
- ['OS!="starboard" and actual_target_arch in ["linux", "ps3", "win"]', {
+ ['OS=="starboard" and enable_fake_microphone == 1', {
'sources': [
- 'mic_<(actual_target_arch).cc',
+ 'microphone_fake.cc',
+ 'microphone_fake.h',
],
+ 'defines': [
+ 'ENABLE_FAKE_MICROPHONE',
+ ],
+ 'direct_dependent_settings': {
+ 'defines': [ 'ENABLE_FAKE_MICROPHONE', ],
+ },
}],
+ ['cobalt_copy_test_data == 1', {
+ 'actions': [
+ {
+ 'action_name': 'speech_copy_test_data',
+ 'variables': {
+ 'input_files': [
+ '<(DEPTH)/cobalt/speech/testdata/',
+ ],
+ 'output_dir': 'cobalt/speech/testdata/',
+ },
+ 'includes': [ '../build/copy_test_data.gypi' ],
+ },
+ ],
+ }
+
+ ],
],
},
{
diff --git a/src/cobalt/speech/speech_configuration.h b/src/cobalt/speech/speech_configuration.h
new file mode 100644
index 0000000..97ab76f
--- /dev/null
+++ b/src/cobalt/speech/speech_configuration.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#ifndef COBALT_SPEECH_SPEECH_CONFIGURATION_H_
+#define COBALT_SPEECH_SPEECH_CONFIGURATION_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_STARBOARD)
+#include "starboard/configuration.h"
+#if SB_HAS(MICROPHONE) && SB_VERSION(2)
+#define SB_USE_SB_MICROPHONE 1
+#endif // SB_HAS(MICROPHONE) && SB_VERSION(2)
+#endif // defined(OS_STARBOARD)
+
+#endif // COBALT_SPEECH_SPEECH_CONFIGURATION_H_
diff --git a/src/cobalt/speech/speech_recognition.cc b/src/cobalt/speech/speech_recognition.cc
index 761b2e5..8ea7c49 100644
--- a/src/cobalt/speech/speech_recognition.cc
+++ b/src/cobalt/speech/speech_recognition.cc
@@ -31,7 +31,9 @@
->fetcher_factory()
->network_module(),
base::Bind(&SpeechRecognition::OnEventAvailable,
- base::Unretained(this)))),
+ base::Unretained(this)),
+ base::polymorphic_downcast<dom::DOMSettings*>(settings)
+ ->enable_fake_microphone())),
config_("" /*lang*/, false /*continuous*/, false /*interim_results*/,
1 /*max alternatives*/) {}
diff --git a/src/cobalt/speech/speech_recognition_manager.cc b/src/cobalt/speech/speech_recognition_manager.cc
index e531a77..114d374 100644
--- a/src/cobalt/speech/speech_recognition_manager.cc
+++ b/src/cobalt/speech/speech_recognition_manager.cc
@@ -17,6 +17,7 @@
#include "cobalt/speech/speech_recognition_manager.h"
#include "base/bind.h"
+#include "cobalt/base/tokens.h"
#include "cobalt/dom/dom_exception.h"
namespace cobalt {
@@ -28,7 +29,8 @@
} // namespace
SpeechRecognitionManager::SpeechRecognitionManager(
- network::NetworkModule* network_module, const EventCallback& event_callback)
+ network::NetworkModule* network_module, const EventCallback& event_callback,
+ bool enable_fake_microphone)
: ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
weak_this_(weak_ptr_factory_.GetWeakPtr()),
main_message_loop_(base::MessageLoopProxy::current()),
@@ -37,13 +39,15 @@
recognizer_(network_module,
base::Bind(&SpeechRecognitionManager::OnRecognizerEvent,
base::Unretained(this)))),
- ALLOW_THIS_IN_INITIALIZER_LIST(mic_(Mic::Create(
+ ALLOW_THIS_IN_INITIALIZER_LIST(microphone_manager_(
kSampleRate, base::Bind(&SpeechRecognitionManager::OnDataReceived,
base::Unretained(this)),
base::Bind(&SpeechRecognitionManager::OnDataCompletion,
base::Unretained(this)),
base::Bind(&SpeechRecognitionManager::OnMicError,
- base::Unretained(this))))),
+ base::Unretained(this)),
+ enable_fake_microphone)),
+ endpointer_delegate_(kSampleRate),
state_(kStopped) {}
SpeechRecognitionManager::~SpeechRecognitionManager() { Stop(); }
@@ -61,7 +65,8 @@
}
recognizer_.Start(config, kSampleRate);
- mic_->Start();
+ microphone_manager_.Open();
+ endpointer_delegate_.Start();
state_ = kStarted;
}
@@ -74,9 +79,11 @@
return;
}
- mic_->Stop();
+ endpointer_delegate_.Stop();
+ microphone_manager_.Close();
recognizer_.Stop();
state_ = kStopped;
+ event_callback_.Run(new dom::Event(base::Tokens::soundend()));
}
void SpeechRecognitionManager::Abort() {
@@ -88,9 +95,11 @@
return;
}
- mic_->Stop();
+ endpointer_delegate_.Stop();
+ microphone_manager_.Close();
recognizer_.Stop();
state_ = kAborted;
+ event_callback_.Run(new dom::Event(base::Tokens::soundend()));
}
void SpeechRecognitionManager::OnDataReceived(
@@ -105,6 +114,9 @@
// Stop recognizing if in the abort state.
if (state_ != kAborted) {
+ if (endpointer_delegate_.IsFirstTimeSoundStarted(*audio_bus)) {
+ event_callback_.Run(new dom::Event(base::Tokens::soundstart()));
+ }
recognizer_.RecognizeAudio(audio_bus.Pass(), false);
}
}
@@ -125,7 +137,7 @@
size_t dummy_frames =
static_cast<size_t>(kSampleRate * kAudioPacketDurationInSeconds);
scoped_ptr<ShellAudioBus> dummy_audio_bus(new ShellAudioBus(
- 1, dummy_frames, ShellAudioBus::kInt16, ShellAudioBus::kPlanar));
+ 1, dummy_frames, ShellAudioBus::kInt16, ShellAudioBus::kInterleaved));
dummy_audio_bus->ZeroAllFrames();
recognizer_.RecognizeAudio(dummy_audio_bus.Pass(), true);
}
@@ -147,22 +159,23 @@
}
}
-void SpeechRecognitionManager::OnMicError() {
+void SpeechRecognitionManager::OnMicError(
+ const scoped_refptr<dom::Event>& event) {
if (!main_message_loop_->BelongsToCurrentThread()) {
// Called from mic thread.
main_message_loop_->PostTask(
FROM_HERE,
- base::Bind(&SpeechRecognitionManager::OnMicError, weak_this_));
+ base::Bind(&SpeechRecognitionManager::OnMicError, weak_this_, event));
return;
}
- event_callback_.Run(
- scoped_refptr<SpeechRecognitionError>(new SpeechRecognitionError(
- SpeechRecognitionError::kAborted, "Mic Disconnected.")));
+ event_callback_.Run(event);
- // An error is occured in Mic, so stopping the recognizer.
+ // An error is occured in Mic, so stop the energy endpointer and recognizer.
+ endpointer_delegate_.Stop();
recognizer_.Stop();
state_ = kAborted;
+ event_callback_.Run(new dom::Event(base::Tokens::soundend()));
}
} // namespace speech
diff --git a/src/cobalt/speech/speech_recognition_manager.h b/src/cobalt/speech/speech_recognition_manager.h
index 852ede2..9367a10 100644
--- a/src/cobalt/speech/speech_recognition_manager.h
+++ b/src/cobalt/speech/speech_recognition_manager.h
@@ -21,7 +21,9 @@
#include "cobalt/network/network_module.h"
#include "cobalt/script/exception_state.h"
-#include "cobalt/speech/mic.h"
+#include "cobalt/speech/endpointer_delegate.h"
+#include "cobalt/speech/microphone_manager.h"
+#include "cobalt/speech/speech_configuration.h"
#include "cobalt/speech/speech_recognition_config.h"
#include "cobalt/speech/speech_recognition_error.h"
#include "cobalt/speech/speech_recognition_event.h"
@@ -42,7 +44,8 @@
typedef base::Callback<bool(const scoped_refptr<dom::Event>&)> EventCallback;
SpeechRecognitionManager(network::NetworkModule* network_module,
- const EventCallback& event_callback);
+ const EventCallback& event_callback,
+ bool enable_fake_microphone);
~SpeechRecognitionManager();
// Start/Stop speech recognizer and microphone. Multiple calls would be
@@ -62,7 +65,7 @@
// Callbacks from mic.
void OnDataReceived(scoped_ptr<ShellAudioBus> audio_bus);
void OnDataCompletion();
- void OnMicError();
+ void OnMicError(const scoped_refptr<dom::Event>& event);
// Callbacks from recognizer.
void OnRecognizerEvent(const scoped_refptr<dom::Event>& event);
@@ -76,7 +79,12 @@
// Callback for sending dom events if available.
EventCallback event_callback_;
SpeechRecognizer recognizer_;
- scoped_ptr<Mic> mic_;
+
+ MicrophoneManager microphone_manager_;
+
+ // Delegate of endpointer which is used for detecting sound energy.
+ EndPointerDelegate endpointer_delegate_;
+
State state_;
};
diff --git a/src/cobalt/speech/speech_recognizer.cc b/src/cobalt/speech/speech_recognizer.cc
index d5c1ce1..bbb3049 100644
--- a/src/cobalt/speech/speech_recognizer.cc
+++ b/src/cobalt/speech/speech_recognizer.cc
@@ -25,11 +25,16 @@
#include "cobalt/loader/fetcher_factory.h"
#include "cobalt/network/network_module.h"
#include "cobalt/speech/google_streaming_api.pb.h"
-#include "cobalt/speech/mic.h"
+#include "cobalt/speech/microphone.h"
+#include "cobalt/speech/speech_configuration.h"
#include "cobalt/speech/speech_recognition_error.h"
#include "net/base/escape.h"
#include "net/url_request/url_fetcher.h"
+#if defined(SB_USE_SB_MICROPHONE)
+#include "starboard/system.h"
+#endif // defined(SB_USE_SB_MICROPHONE)
+
namespace cobalt {
namespace speech {
@@ -75,16 +80,23 @@
SpeechRecognitionResultList::SpeechRecognitionResults results;
for (int i = 0; i < event.result_size(); ++i) {
SpeechRecognitionResult::SpeechRecognitionAlternatives alternatives;
- const proto::SpeechRecognitionResult& kProtoResult = event.result(i);
- for (int j = 0; j < kProtoResult.alternative_size(); ++j) {
- const proto::SpeechRecognitionAlternative& kAlternative =
- kProtoResult.alternative(j);
+ const proto::SpeechRecognitionResult& proto_result = event.result(i);
+ for (int j = 0; j < proto_result.alternative_size(); ++j) {
+ const proto::SpeechRecognitionAlternative& proto_alternative =
+ proto_result.alternative(j);
+ float confidence = 0.0f;
+ if (proto_alternative.has_confidence()) {
+ confidence = proto_alternative.confidence();
+ } else if (proto_result.has_stability()) {
+ confidence = proto_result.stability();
+ }
scoped_refptr<SpeechRecognitionAlternative> alternative(
- new SpeechRecognitionAlternative(kAlternative.transcript(),
- kAlternative.confidence()));
+ new SpeechRecognitionAlternative(proto_alternative.transcript(),
+ confidence));
alternatives.push_back(alternative);
}
- bool final = kProtoResult.has_final() && kProtoResult.final();
+
+ bool final = proto_result.has_final() && proto_result.final();
scoped_refptr<SpeechRecognitionResult> recognition_result(
new SpeechRecognitionResult(alternatives, final));
results.push_back(recognition_result);
@@ -139,19 +151,32 @@
event_callback.Run(error_event);
}
+bool IsResponseCodeSuccess(int response_code) {
+ // NetFetcher only considers success to be if the network request
+ // was successful *and* we get a 2xx response back.
+ // TODO: 304s are unexpected since we don't enable the HTTP cache,
+ // meaning we don't add the If-Modified-Since header to our request.
+ // However, it's unclear what would happen if we did, so DCHECK.
+ DCHECK_NE(response_code, 304) << "Unsupported status code";
+ return response_code / 100 == 2;
+}
+
} // namespace
SpeechRecognizer::SpeechRecognizer(network::NetworkModule* network_module,
const EventCallback& event_callback)
: network_module_(network_module),
- thread_("speech_recognizer"),
started_(false),
- event_callback_(event_callback) {
+ event_callback_(event_callback),
+ thread_("speech_recognizer") {
thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
}
SpeechRecognizer::~SpeechRecognizer() {
Stop();
+ // Stopping the thread here to ensure that StopInternal has completed before
+ // we finish running the destructor.
+ thread_.Stop();
}
void SpeechRecognizer::Start(const SpeechRecognitionConfig& config,
@@ -182,23 +207,31 @@
const net::URLFetcher* source, scoped_ptr<std::string> download_data) {
DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
+ const net::URLRequestStatus& status = source->GetStatus();
+ const int response_code = source->GetResponseCode();
+
if (source == downstream_fetcher_.get()) {
- chunked_byte_buffer_.Append(*download_data);
- while (chunked_byte_buffer_.HasChunks()) {
- scoped_ptr<std::vector<uint8_t> > chunk =
- chunked_byte_buffer_.PopChunk().Pass();
+ if (status.is_success() && IsResponseCodeSuccess(response_code)) {
+ chunked_byte_buffer_.Append(*download_data);
+ while (chunked_byte_buffer_.HasChunks()) {
+ scoped_ptr<std::vector<uint8_t> > chunk =
+ chunked_byte_buffer_.PopChunk().Pass();
- proto::SpeechRecognitionEvent event;
- if (!event.ParseFromString(std::string(chunk->begin(), chunk->end()))) {
- DLOG(WARNING) << "Parse proto string error.";
- return;
- }
+ proto::SpeechRecognitionEvent event;
+ if (!event.ParseFromString(std::string(chunk->begin(), chunk->end()))) {
+ DLOG(WARNING) << "Parse proto string error.";
+ return;
+ }
- if (event.status() == proto::SpeechRecognitionEvent::STATUS_SUCCESS) {
- ProcessAndFireSuccessEvent(ProcessProtoSuccessResults(event));
- } else {
- ProcessAndFireErrorEvent(event, event_callback_);
+ if (event.status() == proto::SpeechRecognitionEvent::STATUS_SUCCESS) {
+ ProcessAndFireSuccessEvent(ProcessProtoSuccessResults(event));
+ } else {
+ ProcessAndFireErrorEvent(event, event_callback_);
+ }
}
+ } else {
+ event_callback_.Run(new SpeechRecognitionError(
+ SpeechRecognitionError::kNetwork, "Network response failure."));
}
}
}
@@ -206,7 +239,7 @@
void SpeechRecognizer::OnURLFetchComplete(const net::URLFetcher* source) {
DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
UNREFERENCED_PARAMETER(source);
- started_ = false;
+ // no-op.
}
void SpeechRecognizer::StartInternal(const SpeechRecognitionConfig& config,
@@ -243,7 +276,19 @@
up_url = AppendQueryParameter(up_url, "client", kClient);
up_url = AppendQueryParameter(up_url, "pair", pair);
up_url = AppendQueryParameter(up_url, "output", "pb");
- up_url = AppendQueryParameter(up_url, "key", GetSpeechAPIKey());
+
+ const char* speech_api_key = NULL;
+#if defined(SB_USE_SB_MICROPHONE)
+ const int kSpeechApiKeyLength = 100;
+ char buffer[kSpeechApiKeyLength] = {0};
+ bool result = SbSystemGetProperty(kSbSystemPropertySpeechApiKey, buffer,
+ SB_ARRAY_SIZE_INT(buffer));
+ SB_DCHECK(result);
+ speech_api_key = result ? buffer : "";
+#else
+ speech_api_key = "";
+#endif
+ up_url = AppendQueryParameter(up_url, "key", speech_api_key);
// Language is required. If no language is specified, use the system language.
if (!config.lang.empty()) {
diff --git a/src/cobalt/speech/speech_recognizer.h b/src/cobalt/speech/speech_recognizer.h
index 90e5dcd..1bff9f9 100644
--- a/src/cobalt/speech/speech_recognizer.h
+++ b/src/cobalt/speech/speech_recognizer.h
@@ -77,8 +77,6 @@
// This is used for creating fetchers.
network::NetworkModule* network_module_;
- // Speech recognizer is operating in its own thread.
- base::Thread thread_;
// Track the start/stop state of speech recognizer.
bool started_;
@@ -93,6 +91,8 @@
ChunkedByteBuffer chunked_byte_buffer_;
// Used for accumulating final results.
SpeechRecognitionResults final_results_;
+ // Speech recognizer is operating in its own thread.
+ base::Thread thread_;
};
} // namespace speech
diff --git a/src/cobalt/speech/testdata/audio1.raw b/src/cobalt/speech/testdata/audio1.raw
new file mode 100644
index 0000000..5ebf79d
--- /dev/null
+++ b/src/cobalt/speech/testdata/audio1.raw
Binary files differ
diff --git a/src/cobalt/speech/testdata/audio2.raw b/src/cobalt/speech/testdata/audio2.raw
new file mode 100644
index 0000000..35413b7
--- /dev/null
+++ b/src/cobalt/speech/testdata/audio2.raw
Binary files differ
diff --git a/src/cobalt/speech/testdata/audio3.raw b/src/cobalt/speech/testdata/audio3.raw
new file mode 100644
index 0000000..c503c9e
--- /dev/null
+++ b/src/cobalt/speech/testdata/audio3.raw
Binary files differ
diff --git a/src/cobalt/speech/testdata/quit.raw b/src/cobalt/speech/testdata/quit.raw
new file mode 100644
index 0000000..a01dfc4
--- /dev/null
+++ b/src/cobalt/speech/testdata/quit.raw
Binary files differ
diff --git a/src/cobalt/trace_event/json_file_outputter.cc b/src/cobalt/trace_event/json_file_outputter.cc
index f17f2d3..c515057 100644
--- a/src/cobalt/trace_event/json_file_outputter.cc
+++ b/src/cobalt/trace_event/json_file_outputter.cc
@@ -18,12 +18,38 @@
#include <string>
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
+#include "base/command_line.h"
+#endif
#include "base/logging.h"
#include "base/platform_file.h"
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
+#include "base/string_piece.h"
+#include "cobalt/trace_event/switches.h"
+#endif
namespace cobalt {
namespace trace_event {
+// Returns true if and only if log_timed_trace == "on", and
+// ENABLE_DEBUG_COMMAND_LINE_SWITCHES is set.
+bool ShouldLogTimedTrace() {
+ bool isTimedTraceSet = false;
+
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
+
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kLogTimedTrace) &&
+ command_line->GetSwitchValueASCII(switches::kLogTimedTrace) ==
+ "on") {
+ isTimedTraceSet = true;
+ }
+
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
+
+ return isTimedTraceSet;
+}
+
JSONFileOutputter::JSONFileOutputter(const FilePath& output_path)
: output_path_(output_path),
output_trace_event_call_count_(0),
@@ -72,6 +98,13 @@
return;
}
+ if (ShouldLogTimedTrace()) {
+ // These markers assist in locating the trace data in the log, and can be
+ // used by scripts to help extract the trace data.
+ LOG(INFO) << "BEGIN_TRACELOG_MARKER" << base::StringPiece(buffer, length)
+ << "END_TRACELOG_MARKER";
+ }
+
int count = base::WritePlatformFileAtCurrentPos(file_, buffer, length);
if (count < 0) {
Close();
diff --git a/src/cobalt/trace_event/switches.cc b/src/cobalt/trace_event/switches.cc
new file mode 100644
index 0000000..6cf65e6
--- /dev/null
+++ b/src/cobalt/trace_event/switches.cc
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#include "cobalt/trace_event/switches.h"
+
+namespace cobalt {
+namespace trace_event {
+namespace switches {
+
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
+// If this flag is set, then the contents of the timed_trace is sent to the log
+// such that it can be collected by examining console output. This may be
+// useful on devices where it is difficult to gain access to files written by
+// Cobalt. log_timed_trace: on | off.
+const char kLogTimedTrace[] = "log_timed_trace";
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
+
+} // namespace switches
+} // namespace trace_event
+} // namespace cobalt
diff --git a/src/cobalt/trace_event/switches.h b/src/cobalt/trace_event/switches.h
new file mode 100644
index 0000000..98fc0ec
--- /dev/null
+++ b/src/cobalt/trace_event/switches.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef COBALT_TRACE_EVENT_SWITCHES_H_
+#define COBALT_TRACE_EVENT_SWITCHES_H_
+
+namespace cobalt {
+namespace trace_event {
+namespace switches {
+
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
+extern const char kLogTimedTrace[];
+#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
+
+} // namespace switches
+} // namespace trace_event
+} // namespace cobalt
+
+#endif // COBALT_TRACE_EVENT_SWITCHES_H_
diff --git a/src/cobalt/trace_event/trace_event.gyp b/src/cobalt/trace_event/trace_event.gyp
index 75d5c82..4e4279e 100644
--- a/src/cobalt/trace_event/trace_event.gyp
+++ b/src/cobalt/trace_event/trace_event.gyp
@@ -27,6 +27,8 @@
'scoped_event_parser_trace.h',
'scoped_trace_to_file.cc',
'scoped_trace_to_file.h',
+ 'switches.cc',
+ 'switches.h',
],
'dependencies': [
'<(DEPTH)/base/base.gyp:base',
diff --git a/src/media/base/sbplayer_pipeline.cc b/src/media/base/sbplayer_pipeline.cc
index b9d2262..64497b8 100644
--- a/src/media/base/sbplayer_pipeline.cc
+++ b/src/media/base/sbplayer_pipeline.cc
@@ -201,8 +201,6 @@
scoped_refptr<SbPlayerSetBoundsHelper> set_bounds_helper_;
- bool flushing_;
-
// The following member variables can be accessed from WMPI thread but all
// modifications to them happens on the pipeline thread. So any access of
// them from the WMPI thread and any modification to them on the pipeline
@@ -232,7 +230,6 @@
has_video_(false),
audio_read_in_progress_(false),
video_read_in_progress_(false),
- flushing_(false),
set_bounds_helper_(new SbPlayerSetBoundsHelper),
suspended_(false) {}
@@ -327,19 +324,17 @@
seek_cb.Run(PIPELINE_ERROR_INVALID_STATE);
}
+ player_->PrepareForSeek();
+
DCHECK(seek_cb_.is_null());
DCHECK(!seek_cb.is_null());
- flushing_ = true;
-
if (audio_read_in_progress_ || video_read_in_progress_) {
message_loop_->PostTask(
FROM_HERE, base::Bind(&SbPlayerPipeline::Seek, this, time, seek_cb));
return;
}
- player_->PrepareForSeek();
-
{
base::AutoLock auto_lock(lock_);
seek_cb_ = seek_cb;
@@ -637,7 +632,6 @@
DCHECK(message_loop_->BelongsToCurrentThread());
if (status == PIPELINE_OK) {
- flushing_ = false;
player_->Seek(seek_time_);
}
}
@@ -682,7 +676,6 @@
video_read_in_progress_ = false;
}
if (!seek_cb_.is_null()) {
- buffering_state_cb_.Run(kPrerollCompleted);
PipelineStatusCB seek_cb;
{
base::AutoLock auto_lock(lock_);
@@ -718,10 +711,6 @@
return;
}
- if (flushing_) {
- return;
- }
-
if (type == DemuxerStream::AUDIO) {
if (audio_read_in_progress_) {
return;
diff --git a/src/media/base/starboard_player.cc b/src/media/base/starboard_player.cc
index ce5197c..2708468 100644
--- a/src/media/base/starboard_player.cc
+++ b/src/media/base/starboard_player.cc
@@ -40,6 +40,7 @@
ticket_(SB_PLAYER_INITIAL_TICKET),
volume_(1.0),
paused_(true),
+ seek_pending_(false),
state_(kPlaying) {
DCHECK(audio_config.IsValidConfig());
DCHECK(video_config.IsValidConfig());
@@ -131,6 +132,8 @@
void StarboardPlayer::PrepareForSeek() {
DCHECK(message_loop_->BelongsToCurrentThread());
++ticket_;
+ SbPlayerSetPause(player_, true);
+ seek_pending_ = true;
}
void StarboardPlayer::Seek(base::TimeDelta time) {
@@ -154,6 +157,10 @@
++ticket_;
SbPlayerSeek(player_, TimeDeltaToSbMediaTime(time), ticket_);
+ seek_pending_ = false;
+ if (!paused_) {
+ SbPlayerSetPause(player_, false);
+ }
}
void StarboardPlayer::SetVolume(float volume) {
@@ -174,8 +181,10 @@
DCHECK(message_loop_->BelongsToCurrentThread());
DCHECK(SbPlayerIsValid(player_));
- SbPlayerSetPause(player_, pause);
paused_ = pause;
+ if (!seek_pending_) {
+ SbPlayerSetPause(player_, pause);
+ }
}
void StarboardPlayer::GetInfo(uint32* video_frames_decoded,
diff --git a/src/media/base/starboard_player.h b/src/media/base/starboard_player.h
index 0f71acb..2d9dc58 100644
--- a/src/media/base/starboard_player.h
+++ b/src/media/base/starboard_player.h
@@ -131,6 +131,7 @@
int ticket_;
float volume_;
bool paused_;
+ bool seek_pending_;
DecoderBufferCache decoder_buffer_cache_;
// The following variables can be accessed from GetInfo(), which can be called
diff --git a/src/nb/atomic.h b/src/nb/atomic.h
new file mode 100644
index 0000000..9bd5c61
--- /dev/null
+++ b/src/nb/atomic.h
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ */
+
+#ifndef NB_ATOMIC_H_
+#define NB_ATOMIC_H_
+
+#include "starboard/mutex.h"
+#include "starboard/types.h"
+
+namespace nb {
+
+// Provides atomic types like integer and float. Some types like atomic_int32_t
+// are likely to be hardware accelerated for your platform.
+//
+// Never use the parent types like atomic<T>, atomic_number<T> or
+// atomic_integral<T> and instead use the fully qualified classes like
+// atomic_int32_t, atomic_pointer<T*>, etc.
+//
+// Note on template instantiation, avoid using the parent type and instead
+// use the fully qualified type.
+// BAD:
+// template<typename T>
+// void Foo(const atomic<T>& value);
+// GOOD:
+// template<typename atomic_t>
+// void Foo(const atomic_t& vlaue);
+
+// Atomic Pointer class. Instantiate as atomic_pointer<void*>
+// for void* pointer types.
+template<typename T>
+class atomic_pointer;
+
+// Atomic bool class.
+class atomic_bool;
+
+// Atomic int32 class
+class atomic_int32_t;
+
+// Atomic int64 class.
+class atomic_int64_t;
+
+// Atomic float class.
+class atomic_float;
+
+// Atomic double class.
+class atomic_double;
+
+///////////////////////////////////////////////////////////////////////////////
+// Class hiearchy.
+///////////////////////////////////////////////////////////////////////////////
+
+// Base functionality for atomic types. Defines exchange(), load(),
+// store(), compare_exhange_weak(), compare_exchange_strong()
+template <typename T>
+class atomic;
+
+// Subtype of atomic<T> for numbers likes float and integer types but not bool.
+// Adds fetch_add() and fetch_sub().
+template <typename T>
+class atomic_number;
+
+// Subtype of atomic_number<T> for integer types like int32 and int64. Adds
+// increment and decrement.
+template <typename T>
+class atomic_integral;
+
+///////////////////////////////////////////////////////////////////////////////
+// Implimentation.
+///////////////////////////////////////////////////////////////////////////////
+
+// Similar to C++11 std::atomic<T>.
+// atomic<T> may be instantiated with any TriviallyCopyable type T.
+// atomic<T> is neither copyable nor movable.
+template <typename T>
+class atomic {
+ public:
+ typedef T ValueType;
+
+ // C++11 forbids a copy constructor for std::atomic<T>, it also forbids
+ // a move operation.
+ atomic() : value_() {}
+ explicit atomic(T v) : value_(v) {}
+
+ // Checks whether the atomic operations on all objects of this type
+ // are lock-free.
+ // Returns true if the atomic operations on the objects of this type
+ // are lock-free, false otherwise.
+ //
+ // All atomic types may be implemented using mutexes or other locking
+ // operations, rather than using the lock-free atomic CPU instructions.
+ // atomic types are also allowed to be sometimes lock-free, e.g. if only
+ // aligned memory accesses are naturally atomic on a given architecture,
+ // misaligned objects of the same type have to use locks.
+ //
+ // See also std::atomic<T>::is_lock_free().
+ bool is_lock_free() const { return false; }
+ bool is_lock_free() const volatile { return false; }
+
+ // Atomically replaces the value of the atomic object
+ // and returns the value held previously.
+ // See also std::atomic<T>::exchange().
+ T exchange(T new_val) {
+ T old_value;
+ {
+ starboard::ScopedLock lock(mutex_);
+ old_value = value_;
+ value_ = new_val;
+ }
+ return old_value;
+ }
+
+ // Atomically obtains the value of the atomic object.
+ // See also std::atomic<T>::load().
+ T load() const {
+ starboard::ScopedLock lock(mutex_);
+ return value_;
+ }
+
+ // Stores the value. See std::atomic<T>::store(...)
+ void store(T val) {
+ starboard::ScopedLock lock(mutex_);
+ value_ = val;
+ }
+
+ // compare_exchange_strong(...) sets the new value if and only if
+ // *expected_value matches what is stored internally.
+ // If this succeeds then true is returned and *expected_value == new_value.
+ // Otherwise If there is a mismatch then false is returned and
+ // *expected_value is set to the internal value.
+ // Inputs:
+ // new_value: Attempt to set the value to this new value.
+ // expected_value: A test condition for success. If the actual value
+ // matches the expected_value then the swap will succeed.
+ //
+ // See also std::atomic<T>::compare_exchange_strong(...).
+ bool compare_exchange_strong(T* expected_value, T new_value) {
+ // Save original value so that its local. This hints to the compiler
+ // that test_val doesn't have aliasing issues and should result in
+ // more optimal code inside of the lock.
+ const T test_val = *expected_value;
+ starboard::ScopedLock lock(mutex_);
+ if (test_val == value_) {
+ value_ = new_value;
+ return true;
+ } else {
+ *expected_value = value_;
+ return false;
+ }
+ }
+
+ // Weak version of this function is documented to be faster, but has allows
+ // weaker memory ordering and therefore will sometimes have a false negative:
+ // The value compared will actually be equal but the return value from this
+ // function indicates otherwise.
+ // By default, the function delegates to compare_exchange_strong(...).
+ //
+ // See also std::atomic<T>::compare_exchange_weak(...).
+ bool compare_exchange_weak(T* expected_value, T new_value) {
+ return compare_exchange_strong(expected_value, new_value);
+ }
+
+ protected:
+ T value_;
+ starboard::Mutex mutex_;
+};
+
+// A subclass of atomic<T> that adds fetch_add(...) and fetch_sub(...).
+template <typename T>
+class atomic_number : public atomic<T> {
+ public:
+ typedef atomic<T> Super;
+ typedef T ValueType;
+
+ atomic_number() : Super() {}
+ explicit atomic_number(T v) : Super(v) {}
+
+ // Returns the previous value before the input value was added.
+ // See also std::atomic<T>::fetch_add(...).
+ T fetch_add(T val) {
+ T old_val;
+ {
+ starboard::ScopedLock lock(this->mutex_);
+ old_val = this->value_;
+ this->value_ += val;
+ }
+ return old_val;
+ }
+
+ // Returns the value before the operation was applied.
+ // See also std::atomic<T>::fetch_sub(...).
+ T fetch_sub(T val) {
+ T old_val;
+ {
+ starboard::ScopedLock lock(this->mutex_);
+ old_val = this->value_;
+ this->value_ -= val;
+ }
+ return old_val;
+ }
+};
+
+// A subclass to classify Atomic Integers. Adds increment and decrement
+// functions.
+template <typename T>
+class atomic_integral : public atomic_number<T> {
+ public:
+ typedef atomic_number<T> Super;
+
+ atomic_integral() : Super() {}
+ explicit atomic_integral(T v) : Super(v) {}
+
+ T increment() { return this->fetch_add(T(1)); }
+ T decrement() { return this->fetch_sub(T(1)); }
+};
+
+// atomic_pointer class.
+template <typename T>
+class atomic_pointer : public atomic<T> {
+ public:
+ typedef atomic<T> Super;
+ atomic_pointer() : Super() {}
+ explicit atomic_pointer(T initial_val) : Super(initial_val) {}
+};
+
+// Simple atomic bool class. This could be optimized for speed using
+// compiler intrinsics for concurrent integer modification.
+class atomic_bool : public atomic<bool> {
+ public:
+ typedef atomic<bool> Super;
+ atomic_bool() : Super() {}
+ explicit atomic_bool(bool initial_val) : Super(initial_val) {}
+};
+
+// Simple atomic int class. This could be optimized for speed using
+// compiler intrinsics for concurrent integer modification.
+class atomic_int32_t : public atomic_integral<int32_t> {
+ public:
+ typedef atomic_integral<int32_t> Super;
+ atomic_int32_t() : Super() {}
+ explicit atomic_int32_t(int32_t initial_val) : Super(initial_val) {}
+};
+
+// Simple atomic int class. This could be optimized for speed using
+// compiler intrinsics for concurrent integer modification.
+class atomic_int64_t : public atomic_integral<int64_t> {
+ public:
+ typedef atomic_integral<int64_t> Super;
+ atomic_int64_t() : Super() {}
+ explicit atomic_int64_t(int64_t initial_val) : Super(initial_val) {}
+};
+
+class atomic_float : public atomic_number<float> {
+ public:
+ typedef atomic_number<float> Super;
+ atomic_float() : Super() {}
+ explicit atomic_float(float initial_val) : Super(initial_val) {}
+};
+
+class atomic_double : public atomic_number<double> {
+ public:
+ typedef atomic_number<double> Super;
+ atomic_double() : Super() {}
+ explicit atomic_double(double initial_val) : Super(initial_val) {}
+};
+
+} // namespace nb
+
+#endif // NB_ATOMIC_H_
diff --git a/src/nb/atomic_test.cc b/src/nb/atomic_test.cc
new file mode 100644
index 0000000..fc76703
--- /dev/null
+++ b/src/nb/atomic_test.cc
@@ -0,0 +1,317 @@
+/*
+ * 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.
+ */
+
+#include "nb/atomic.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "nb/test_thread.h"
+#include "starboard/configuration.h"
+#include "starboard/mutex.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace nb {
+namespace {
+
+///////////////////////////////////////////////////////////////////////////////
+// Boilerplate for test setup.
+///////////////////////////////////////////////////////////////////////////////
+
+// Defines a typelist for all atomic types.
+typedef ::testing::Types<atomic_int32_t, atomic_int64_t,
+ atomic_float, atomic_double,
+ atomic_bool,
+ atomic_pointer<int*> > AllAtomicTypes;
+
+// Defines a typelist for just atomic number types.
+typedef ::testing::Types<atomic_int32_t, atomic_int64_t,
+ atomic_float, atomic_double> AtomicNumberTypes;
+
+// Defines test type that will be instantiated using each type in
+// AllAtomicTypes type list.
+template <typename T>
+class AtomicTest : public ::testing::Test {};
+TYPED_TEST_CASE(AtomicTest, AllAtomicTypes); // Registration.
+
+// Defines test type that will be instantiated using each type in
+// AtomicNumberTypes type list.
+template <typename T>
+class AtomicNumberTest : public ::testing::Test {};
+TYPED_TEST_CASE(AtomicNumberTest, AtomicNumberTypes); // Registration.
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Singlethreaded tests.
+///////////////////////////////////////////////////////////////////////////////
+
+// Tests default constructor and single-argument constructor.
+TYPED_TEST(AtomicTest, Constructors) {
+ typedef TypeParam AtomicT;
+ typedef typename AtomicT::ValueType T;
+
+ const T zero(0);
+ const T one = zero + 1; // Allows AtomicPointer<T*>.
+
+ AtomicT atomic_default;
+
+ // Tests that default value is zero.
+ ASSERT_EQ(atomic_default.load(), zero);
+ AtomicT atomic_val(one);
+ ASSERT_EQ(one, atomic_val.load());
+}
+
+// Tests load() and exchange().
+TYPED_TEST(AtomicTest, Load_Exchange_SingleThread) {
+ typedef TypeParam AtomicT;
+ typedef typename AtomicT::ValueType T;
+
+ const T zero(0);
+ const T one = zero + 1; // Allows AtomicPointer<T*>.
+
+ AtomicT atomic;
+ ASSERT_EQ(atomic.load(), zero); // Default is 0.
+ ASSERT_EQ(zero, atomic.exchange(one)); // Old value was 0.
+
+ // Tests that AtomicType has const get function.
+ const AtomicT& const_atomic = atomic;
+ ASSERT_EQ(one, const_atomic.load());
+}
+
+// Tests compare_exchange_strong().
+TYPED_TEST(AtomicNumberTest, CompareExchangeStrong_SingleThread) {
+ typedef TypeParam AtomicT;
+ typedef typename AtomicT::ValueType T;
+
+ const T zero(0);
+ const T one = zero + 1; // Allows AtomicPointer<T*>.
+
+ AtomicT atomic;
+ ASSERT_EQ(atomic.load(), zero); // Default is 0.
+ T expected_value = zero;
+ // Should succeed.
+ ASSERT_TRUE(atomic.compare_exchange_strong(&expected_value,
+ one)); // New value.
+
+ ASSERT_EQ(zero, expected_value);
+ ASSERT_EQ(one, atomic.load()); // Expect that value was set.
+
+ expected_value = zero;
+ // Asserts that when the expected and actual value is mismatched that the
+ // compare_exchange_strong() fails.
+ ASSERT_FALSE(atomic.compare_exchange_strong(&expected_value, // Mismatched.
+ zero)); // New value.
+
+ // Failed and this means that expected_value should be set to what the
+ // internal value was. In this case, one.
+ ASSERT_EQ(expected_value, one);
+ ASSERT_EQ(one, atomic.load());
+
+ ASSERT_TRUE(atomic.compare_exchange_strong(&expected_value, // Matches.
+ zero));
+ ASSERT_EQ(expected_value, one);
+}
+
+// Tests atomic fetching and adding.
+TYPED_TEST(AtomicNumberTest, FetchAdd_SingleThread) {
+ typedef TypeParam AtomicT;
+ typedef typename AtomicT::ValueType T;
+
+ const T zero(0);
+ const T one = zero + 1; // Allows atomic_pointer<T*>.
+ const T two = zero + 2;
+
+ AtomicT atomic;
+ ASSERT_EQ(atomic.load(), zero); // Default is 0.
+ ASSERT_EQ(zero, atomic.fetch_add(one)); // Prev value was 0.
+ ASSERT_EQ(one, atomic.load()); // Now value is this.
+ ASSERT_EQ(one, atomic.fetch_add(one)); // Prev value was 1.
+ ASSERT_EQ(two, atomic.exchange(one)); // Old value was 2.
+}
+
+// Tests atomic fetching and subtracting.
+TYPED_TEST(AtomicNumberTest, FetchSub_SingleThread) {
+ typedef TypeParam AtomicT;
+ typedef typename AtomicT::ValueType T;
+
+ const T zero(0);
+ const T one = zero + 1; // Allows AtomicPointer<T*>.
+ const T two = zero + 2;
+ const T neg_two(zero-2);
+
+ AtomicT atomic;
+ ASSERT_EQ(atomic.load(), zero); // Default is 0.
+ atomic.exchange(two);
+ ASSERT_EQ(two, atomic.fetch_sub(one)); // Prev value was 2.
+ ASSERT_EQ(one, atomic.load()); // New value.
+ ASSERT_EQ(one, atomic.fetch_sub(one)); // Prev value was one.
+ ASSERT_EQ(zero, atomic.load()); // New 0.
+ ASSERT_EQ(zero, atomic.fetch_sub(two));
+ ASSERT_EQ(neg_two, atomic.load()); // 0-2 = -2
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Multithreaded tests.
+///////////////////////////////////////////////////////////////////////////////
+
+// A thread that will execute compare_exhange_strong() and write out a result
+// to a shared output.
+template <typename AtomicT>
+class CompareExchangeThread : public TestThread {
+ public:
+ typedef typename AtomicT::ValueType T;
+ CompareExchangeThread(int start_num,
+ int end_num,
+ AtomicT* atomic_value,
+ std::vector<T>* output,
+ starboard::Mutex* output_mutex)
+ : start_num_(start_num), end_num_(end_num),
+ atomic_value_(atomic_value), output_(output),
+ output_mutex_(output_mutex) {
+ }
+
+ virtual void Run() {
+ std::vector<T> output_buffer;
+ output_buffer.reserve(end_num_ - start_num_);
+ for (int i = start_num_; i < end_num_; ++i) {
+ T new_value = T(i);
+ while (true) {
+ if (std::rand() % 3 == 0) {
+ // 1 in 3 chance of yeilding.
+ // Attempt to cause more contention by giving other threads a chance
+ // to run.
+ SbThreadYield();
+ }
+
+ const T prev_value = atomic_value_->load();
+ T expected_value = prev_value;
+ const bool success =
+ atomic_value_->compare_exchange_strong(&expected_value,
+ new_value);
+ if (success) {
+ output_buffer.push_back(prev_value);
+ break;
+ }
+ }
+ }
+
+ // Lock the output to append this output buffer.
+ starboard::ScopedLock lock(*output_mutex_);
+ output_->insert(output_->end(),
+ output_buffer.begin(),
+ output_buffer.end());
+ }
+ private:
+ const int start_num_;
+ const int end_num_;
+ AtomicT*const atomic_value_;
+ std::vector<T>*const output_;
+ starboard::Mutex*const output_mutex_;
+};
+
+// Tests Atomic<T>::compare_exchange_strong(). Each thread has a unique
+// sequential range [0,1,2,3 ... ), [5,6,8, ...) that it will generate.
+// The numbers are sequentially written to the shared Atomic type and then
+// exposed to other threads:
+//
+// Generates [0,1,2,...,n/2)
+// +------+ Thread A <--------+ (Write Exchanged Value)
+// | |
+// | compare_exchange() +---> exchanged? ---+
+// +----> +------------+ +----+ v
+// | AtomicType | Output vector
+// +----> +------------+ +----+ ^
+// | compare_exchange() +---> exchanged? ---+
+// | |
+// +------+ Thread B <--------+
+// Generates [n/2,n/2+1,...,n)
+//
+// By repeatedly calling atomic<T>::compare_exchange_strong() by each of the
+// threads, each will see the previous value of the shared variable when their
+// exchange (atomic swap) operation is successful. If all of the swapped out
+// values are recombined then it will form the original generated sequence from
+// all threads.
+//
+// TEST PHASE
+// sort( output vector ) AND TEST THAT
+// output vector Contains [0,1,2,...,n)
+//
+// The test passes when the output array is tested that it contains every
+// expected generated number from all threads. If compare_exchange_strong() is
+// written incorrectly for an atomic type then the output array will have
+// duplicates or otherwise not be equal to the expected natural number set.
+TYPED_TEST(AtomicNumberTest, Test_CompareExchange_MultiThreaded) {
+ typedef TypeParam AtomicT;
+ typedef typename AtomicT::ValueType T;
+
+ static const int kNumElements = 1000;
+ static const int kNumThreads = 4;
+
+ AtomicT atomic_value(T(-1));
+ std::vector<TestThread*> threads;
+ std::vector<T> output_values;
+ starboard::Mutex output_mutex;
+
+ for (int i = 0; i < kNumThreads; ++i) {
+ const int start_num = (kNumElements * i) / kNumThreads;
+ const int end_num = (kNumElements * (i + 1)) / kNumThreads;
+ threads.push_back(
+ new CompareExchangeThread<AtomicT>(
+ start_num, // defines the number range to generate.
+ end_num,
+ &atomic_value,
+ &output_values,
+ &output_mutex));
+ }
+
+ // These threads will generate unique numbers in their range and then
+ // write them to the output array.
+ for (int i = 0; i < kNumThreads; ++i) {
+ threads[i]->Start();
+ }
+
+ for (int i = 0; i < kNumThreads; ++i) {
+ threads[i]->Join();
+ }
+ // Cleanup threads.
+ for (int i = 0; i < kNumThreads; ++i) {
+ delete threads[i];
+ }
+ threads.clear();
+
+ // Final value needs to be written out. The last thread to join doesn't
+ // know it's the last and therefore the final value in the shared
+ // has not be pushed to the output array.
+ output_values.push_back(atomic_value.load());
+ std::sort(output_values.begin(), output_values.end());
+
+ // We expect the -1 value because it was the explicit initial value of the
+ // shared atomic.
+ ASSERT_EQ(T(-1), output_values[0]);
+ ASSERT_EQ(T(0), output_values[1]);
+ output_values.erase(output_values.begin()); // Chop off the -1 at the front.
+
+ // Finally, assert that the output array is equal to the natural numbers
+ // after it has been sorted.
+ ASSERT_EQ(output_values.size(), kNumElements);
+ // All of the elements should be equal too.
+ for (int i = 0; i < output_values.size(); ++i) {
+ ASSERT_EQ(output_values[i], T(i));
+ }
+}
+
+} // namespace
+} // namespace nb
diff --git a/src/nb/nb.gyp b/src/nb/nb.gyp
index 3780eb9..f87d42a 100644
--- a/src/nb/nb.gyp
+++ b/src/nb/nb.gyp
@@ -24,6 +24,7 @@
'allocator.h',
'allocator_decorator.cc',
'allocator_decorator.h',
+ 'atomic.h',
'fixed_no_free_allocator.cc',
'fixed_no_free_allocator.h',
'memory_pool.cc',
@@ -38,6 +39,7 @@
'scoped_ptr.h',
'thread_collision_warner.cc',
'thread_collision_warner.h',
+ 'thread_local_object.h',
],
'dependencies': [
@@ -60,9 +62,11 @@
'target_name': 'nb_test',
'type': '<(gtest_target_type)',
'sources': [
+ 'atomic_test.cc',
'fixed_no_free_allocator_test.cc',
'reuse_allocator_test.cc',
'run_all_unittests.cc',
+ 'test_thread.h',
'thread_local_object_test.cc',
],
'dependencies': [
diff --git a/src/nb/test_thread.h b/src/nb/test_thread.h
new file mode 100644
index 0000000..0ea5768
--- /dev/null
+++ b/src/nb/test_thread.h
@@ -0,0 +1,73 @@
+// 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.
+
+#ifndef NB_TEST_THREAD_H_
+#define NB_TEST_THREAD_H_
+
+#include "starboard/configuration.h"
+#include "starboard/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace nb {
+
+// TestThread that is a bare bones class wrapper around Starboard
+// thread. Subclasses must override Run().
+class TestThread {
+ public:
+ TestThread() : thread_(kSbThreadInvalid) {}
+ virtual ~TestThread() {}
+
+ // Subclasses should override the Run method.
+ virtual void Run() = 0;
+
+ // Calls SbThreadCreate() with default parameters.
+ void Start() {
+ SbThreadEntryPoint entry_point = ThreadEntryPoint;
+
+ thread_ = SbThreadCreate(
+ 0, // default stack_size.
+ kSbThreadNoPriority, // default priority.
+ kSbThreadNoAffinity, // default affinity.
+ true, // joinable.
+ "TestThread",
+ entry_point,
+ this);
+
+ if (kSbThreadInvalid == thread_) {
+ ADD_FAILURE_AT(__FILE__, __LINE__) << "Invalid thread.";
+ }
+ return;
+ }
+
+ void Join() {
+ if (!SbThreadJoin(thread_, NULL)) {
+ ADD_FAILURE_AT(__FILE__, __LINE__) << "Could not join thread.";
+ }
+ }
+
+ private:
+ static void* ThreadEntryPoint(void* ptr) {
+ TestThread* this_ptr = static_cast<TestThread*>(ptr);
+ this_ptr->Run();
+ return NULL;
+ }
+
+ SbThread thread_;
+
+ SB_DISALLOW_COPY_AND_ASSIGN(TestThread);
+};
+
+} // namespace nb.
+
+#endif // NB_TEST_THREAD_H_
diff --git a/src/nb/thread_local_object.h b/src/nb/thread_local_object.h
index 4b6a7ab..a303f5a 100644
--- a/src/nb/thread_local_object.h
+++ b/src/nb/thread_local_object.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BASE_THREADING_THREAD_LOCAL_OBJECT_H_
-#define BASE_THREADING_THREAD_LOCAL_OBJECT_H_
+#ifndef NB_THREAD_LOCAL_OBJECT_H_
+#define NB_THREAD_LOCAL_OBJECT_H_
#include <set>
@@ -24,7 +24,7 @@
#include "starboard/mutex.h"
#include "starboard/thread.h"
-namespace base {
+namespace nb {
// Like base::ThreadLocalPointer<T> but destroys objects. This is important
// for using ThreadLocalObjects that aren't tied to a singleton, or for
@@ -75,12 +75,14 @@
// Thread Local Objects are destroyed after this call.
~ThreadLocalObject() {
CheckCurrentThreadAllowedToDestruct();
- SB_DCHECK(entry_set_.size() < 2)
+ if (SB_DLOG_IS_ON(FATAL)) {
+ SB_DCHECK(entry_set_.size() < 2)
<< "Logic error: Some threads may still be accessing the objects that "
<< "are about to be destroyed. Only one object is expected and that "
<< "should be for the main thread. The caller should ensure that "
<< "other threads that access this object are externally "
<< "synchronized.";
+ }
// No locking is done because the entries should not be accessed by
// different threads while this object is shutting down. If access is
// occuring then the caller has a race condition, external to this class.
@@ -209,6 +211,6 @@
SB_DISALLOW_COPY_AND_ASSIGN(ThreadLocalObject<Type>);
};
-} // namespace base
+} // namespace nb
-#endif // BASE_THREADING_THREAD_LOCAL_H_
+#endif // NB_THREAD_LOCAL_OBJECT_H_
diff --git a/src/nb/thread_local_object_test.cc b/src/nb/thread_local_object_test.cc
index 000c6f4..9fce6d6 100644
--- a/src/nb/thread_local_object_test.cc
+++ b/src/nb/thread_local_object_test.cc
@@ -15,172 +15,31 @@
#include <map>
#include <string>
+#include "nb/test_thread.h"
+#include "nb/atomic.h"
#include "nb/thread_local_object.h"
#include "nb/scoped_ptr.h"
#include "starboard/mutex.h"
#include "starboard/thread.h"
-
#include "testing/gtest/include/gtest/gtest.h"
-namespace base {
+namespace nb {
namespace {
-// Similar to C++11 std::atomic<T>.
-// Atomic<T> may be instantiated with any TriviallyCopyable type T.
-// Atomic<T> is neither copyable nor movable.
-// TODO: Lift this class out into the library.
-template <typename T>
-class Atomic {
- public:
- // C++11 forbids a copy constructor for std::atomic<T>, it also forbids
- // a move operation.
- Atomic() : value_() {}
- explicit Atomic(T v) : value_(v) {}
-
- // Checks whether the atomic operations on all objects of this type
- // are lock-free.
- // Returns true if the atomic operations on the objects of this type
- // are lock-free, false otherwise.
- //
- // All atomic types may be implemented using mutexes or other locking
- // operations, rather than using the lock-free atomic CPU instructions.
- // Atomic types are also allowed to be sometimes lock-free, e.g. if only
- // aligned memory accesses are naturally atomic on a given architecture,
- // misaligned objects of the same type have to use locks.
- bool is_lock_free() const { return false; }
- bool is_lock_free() const volatile { return false; }
-
- // Atomically replaces the value of the atomic object
- // and returns the value held previously.
- T Swap(T new_val) {
- int old_value = -1;
- {
- starboard::ScopedLock lock(mutex_);
- old_value = value_;
- value_ = new_val;
- }
- return old_value;
- }
-
- // Atomically obtains the value of the atomic object.
- T Get() const {
- starboard::ScopedLock lock(mutex_);
- return value_;
- }
-
- // Returns the new updated value after the operation has been applied.
- T Add(T val) {
- starboard::ScopedLock lock(mutex_);
- value_ += val;
- return value_;
- }
-
- // TrySwap(...) sets the new value if and only if "expected_old_value"
- // matches the actual value during the atomic assignment operation. If this
- // succeeds then true is returned. If there is a mismatch then the value is
- // left unchanged and false is returned.
- // Inputs:
- // new_value: Attempt to set the value to this new value.
- // expected_old_value: A test condition for success. If the actual value
- // matches the expected_old_value then the swap will succeed.
- // optional_actual_value: If non-null, then the actual value at the time
- // of the attempted operation is set to this value.
- bool TrySwap(T new_value, T expected_old_value,
- T* optional_actual_value) {
- starboard::ScopedLock lock(mutex_);
- if (optional_actual_value) {
- *optional_actual_value = value_;
- }
- if (expected_old_value == value_) {
- value_ = new_value;
- return true;
- }
- return false;
- }
-
- private:
- T value_;
- starboard::Mutex mutex_;
-};
-
-// Simple atomic int class. This could be optimized for speed using
-// compiler intrinsics for concurrent integer modification.
-class AtomicInt : public Atomic<int> {
- public:
- AtomicInt() : Atomic<int>(0) {}
- explicit AtomicInt(int initial_val) : Atomic<int>(initial_val) {}
- void Increment() { Add(1); }
- void Decrement() { Add(-1); }
-};
-
-// Simple atomic bool class. This could be optimized for speed using
-// compiler intrinsics for concurrent integer modification.
-class AtomicBool : public Atomic<bool> {
- public:
- AtomicBool() : Atomic<bool>(false) {}
- explicit AtomicBool(bool initial_val) : Atomic<bool>(initial_val) {}
-};
-
-// AbstractTestThread that is a bare bones class wrapper around Starboard
-// thread. Subclasses must override Run().
-// TODO: Move this to nplb/thread_helpers.h
-class AbstractTestThread {
- public:
- explicit AbstractTestThread() : thread_(kSbThreadInvalid) {}
- virtual ~AbstractTestThread() {}
-
- // Subclasses should override the Run method.
- virtual void Run() = 0;
-
- // Calls SbThreadCreate() with default parameters.
- void Start() {
- SbThreadEntryPoint entry_point = ThreadEntryPoint;
-
- thread_ = SbThreadCreate(
- 0, // default stack_size.
- kSbThreadNoPriority, // default priority.
- kSbThreadNoAffinity, // default affinity.
- true, // joinable.
- "AbstractTestThread",
- entry_point,
- this);
-
- if (kSbThreadInvalid == thread_) {
- ADD_FAILURE_AT(__FILE__, __LINE__) << "Invalid thread.";
- }
- return;
- }
-
- void Join() {
- if (!SbThreadJoin(thread_, NULL)) {
- ADD_FAILURE_AT(__FILE__, __LINE__) << "Could not join thread.";
- }
- }
-
- private:
- static void* ThreadEntryPoint(void* ptr) {
- AbstractTestThread* this_ptr = static_cast<AbstractTestThread*>(ptr);
- this_ptr->Run();
- return NULL;
- }
-
- SbThread thread_;
-};
-
// Simple class that counts the number of instances alive.
struct CountsInstances {
- CountsInstances() { s_instances_.Increment(); }
- ~CountsInstances() { s_instances_.Decrement(); }
- static AtomicInt s_instances_;
- static int NumInstances() { return s_instances_.Get(); }
- static void ResetNumInstances() { s_instances_.Swap(0); }
+ CountsInstances() { s_instances_.increment(); }
+ ~CountsInstances() { s_instances_.decrement(); }
+ static atomic_int32_t s_instances_;
+ static int NumInstances() { return s_instances_.load(); }
+ static void ResetNumInstances() { s_instances_.exchange(0); }
};
-AtomicInt CountsInstances::s_instances_(0);
+nb::atomic_int32_t CountsInstances::s_instances_(0);
// A simple thread that just creates the an object from the supplied
// ThreadLocalObject<T> and then exits.
template <typename TYPE>
-class CreateThreadLocalObjectThenExit : public AbstractTestThread {
+class CreateThreadLocalObjectThenExit : public TestThread {
public:
explicit CreateThreadLocalObjectThenExit(
ThreadLocalObject<TYPE>* tlo) : tlo_(tlo) {}
@@ -196,7 +55,7 @@
// A simple thread that just deletes the object supplied on a thread and then
// exists.
template <typename TYPE>
-class DestroyTypeOnThread : public AbstractTestThread {
+class DestroyTypeOnThread : public TestThread {
public:
explicit DestroyTypeOnThread(TYPE* ptr)
: ptr_(ptr) {}
@@ -285,7 +144,7 @@
nb::scoped_ptr<TLO> tlo(new TLO);
{
- AbstractTestThread* thread =
+ TestThread* thread =
new CreateThreadLocalObjectThenExit<CountsInstances>(tlo.get());
thread->Start();
thread->Join();
@@ -318,7 +177,7 @@
// Thread will simply create the thread local object (CountsInstances)
// and then return.
- nb::scoped_ptr<AbstractTestThread> thread_ptr(
+ nb::scoped_ptr<TestThread> thread_ptr(
new CreateThreadLocalObjectThenExit<CountsInstances>(tlo));
thread_ptr->Start(); // Object is now created.
thread_ptr->Join(); // ...then destroyed.
@@ -342,5 +201,4 @@
}
} // anonymous namespace
-} // namespace base
-
+} // nb namespace
diff --git a/src/starboard/audio_sink.h b/src/starboard/audio_sink.h
index 59f507b..790741a 100644
--- a/src/starboard/audio_sink.h
+++ b/src/starboard/audio_sink.h
@@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// An interface to output raw audio data.
+// Module Overview: Starboard Audio Sink API
+//
+// Provides an interface to output raw audio data.
#ifndef STARBOARD_AUDIO_SINK_H_
#define STARBOARD_AUDIO_SINK_H_
@@ -69,37 +71,49 @@
// --- Functions -------------------------------------------------------------
-// Returns whether the given audio sink handle is valid.
+// Indicates whether the given audio sink handle is valid.
+//
+// |audio_sink|: The audio sink handle to check.
SB_EXPORT bool SbAudioSinkIsValid(SbAudioSink audio_sink);
// Creates an audio sink for the specified |channels| and
-// |sampling_frequency_hz|, acquiring all resources needed to operate it, and
-// returning an opaque handle to it.
-//
-// |frame_buffers| is an array of pointers to sample data. If the sink is
-// operating in interleaved mode, the array contains only one element, which is
-// an array containing |frames_per_channel| * |channels| samples. If the sink
-// is operating in planar mode, the number of elements in the array will be the
-// same as |channels|, each of the elements will be an array of
-// |frames_per_channel| samples. The caller has to ensure that |frame_buffers|
-// is valid until SbAudioSinkDestroy is called.
-//
-// |update_source_status_func| cannot be NULL. The audio sink will call it on
-// an internal thread to query the status of the source.
-//
-// |consume_frames_func| cannot be NULL. The audio sink will call it on an
-// internal thread to report consumed frames.
-//
-// |context| will be passed back into all callbacks, and is generally used to
-// point at a class or struct that contains state associated with the audio
-// sink.
-//
-// The audio sink will start to call |update_source_status_func| immediately
-// after SbAudioSinkCreate is called, even before it returns. The caller has
-// to ensure that the above callbacks returns meaningful values in this case.
+// |sampling_frequency_hz|, acquires all resources needed to operate the
+// audio sink, and returns an opaque handle to the audio sink.
//
// If the particular platform doesn't support the requested audio sink, the
// function returns kSbAudioSinkInvalid without calling any of the callbacks.
+//
+// |channels|: The number of audio channels, such as left and right channels
+// in stereo audio.
+// |sampling_frequency_hz|: The sample frequency of the audio data being
+// streamed. For example, 22,000 Hz means 22,000 sample elements represents
+// one second of audio data.
+// |audio_sample_type|: The type of each sample of the audio data --
+// |int16|, |float32|, etc.
+// |audio_frame_storage_type|: Indicates whether frames are interleaved or
+// planar.
+// |frame_buffers|: An array of pointers to sample data.
+// - If the sink is operating in interleaved mode, the array contains only
+// one element, which is an array containing (|frames_per_channel| *
+// |channels|) samples.
+// - If the sink is operating in planar mode, the number of elements in the
+// array is the same as |channels|, and each element is an array of
+// |frames_per_channel| samples. The caller has to ensure that
+// |frame_buffers| is valid until SbAudioSinkDestroy is called.
+// |frames_per_channel|: The size of the frame buffers, in units of the
+// number of samples per channel. The frame, in this case, represents a
+// group of samples at the same media time, one for each channel.
+// |update_source_status_func|: The audio sink calls this function on an
+// internal thread to query the status of the source. The value cannot be NULL.
+// |consume_frames_func|: The audio sink calls this function on an internal
+// thread to report consumed frames. The value cannot be NULL.
+// |context|: A value that is passed back to all callbacks and is generally
+// used to point at a class or struct that contains state associated with the
+// audio sink.
+// |update_source_status_func|: A function that the audio sink starts to call
+// immediately after SbAudioSinkCreate is called, even before it returns.
+// The caller has to ensure that the callback functions above return
+// meaningful values in this case.
SB_EXPORT SbAudioSink
SbAudioSinkCreate(int channels,
int sampling_frequency_hz,
@@ -111,32 +125,36 @@
SbAudioSinkConsumeFramesFunc consume_frames_func,
void* context);
-// Destroys |audio_sink|, freeing all associated resources. It will wait until
-// all callbacks in progress is finished before returning. Upon returning of
-// this function, no callbacks passed into SbAudioSinkCreate will be called
-// further. This function can be called on any thread but cannot be called
+// Destroys |audio_sink|, freeing all associated resources. Before
+// returning, the function waits until all callbacks that are in progress
+// have finished. After the function returns, no further calls are made
+// callbacks passed into SbAudioSinkCreate. In addition, you can not pass
+// |audio_sink| to any other SbAudioSink functions after SbAudioSinkDestroy
+// has been called on it.
+//
+// This function can be called on any thread. However, it cannot be called
// within any of the callbacks passed into SbAudioSinkCreate.
-// It is not allowed to pass |audio_sink| into any other SbAudioSink function
-// once SbAudioSinkDestroy has been called on it.
+//
+// |audio_sink|: The audio sink to destroy.
SB_EXPORT void SbAudioSinkDestroy(SbAudioSink audio_sink);
-// Returns the maximum channel supported on the platform.
+// Returns the maximum number of channels supported on the platform. For
+// example, the number would be |2| if the platform only supports stereo.
SB_EXPORT int SbAudioSinkGetMaxChannels();
-// Returns the nearest supported sample rate of |sampling_frequency_hz|. On
-// platforms that don't support all sample rates, it is the caller's
+// Returns the supported sample rate closest to |sampling_frequency_hz|.
+// On platforms that don't support all sample rates, it is the caller's
// responsibility to resample the audio frames into the supported sample rate
// returned by this function.
SB_EXPORT int SbAudioSinkGetNearestSupportedSampleFrequency(
int sampling_frequency_hz);
-// Returns true if the particular SbMediaAudioSampleType is supported on this
-// platform.
+// Indicates whether |audio_sample_type| is supported on this platform.
SB_EXPORT bool SbAudioSinkIsAudioSampleTypeSupported(
SbMediaAudioSampleType audio_sample_type);
-// Returns true if the particular SbMediaAudioFrameStorageType is supported on
-// this platform.
+// Indicates whether |audio_frame_storage_type| is supported on this
+// platform.
SB_EXPORT bool SbAudioSinkIsAudioFrameStorageTypeSupported(
SbMediaAudioFrameStorageType audio_frame_storage_type);
diff --git a/src/starboard/client_porting/eztime/eztime.gyp b/src/starboard/client_porting/eztime/eztime.gyp
index 009c29f..70f51e6 100644
--- a/src/starboard/client_porting/eztime/eztime.gyp
+++ b/src/starboard/client_porting/eztime/eztime.gyp
@@ -32,9 +32,9 @@
'target_name': 'eztime_test',
'type': '<(gtest_target_type)',
'sources': [
+ '<(DEPTH)/starboard/common/test_main.cc',
'test_constants.h',
'eztime_test.cc',
- '<(DEPTH)/starboard/nplb/main.cc',
],
'dependencies': [
'<(DEPTH)/testing/gmock.gyp:gmock',
diff --git a/src/starboard/nplb/main.cc b/src/starboard/common/test_main.cc
similarity index 100%
rename from src/starboard/nplb/main.cc
rename to src/starboard/common/test_main.cc
diff --git a/src/starboard/creator/ci20/configuration_public.h b/src/starboard/creator/ci20/configuration_public.h
deleted file mode 100644
index cd85a36..0000000
--- a/src/starboard/creator/ci20/configuration_public.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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.
-
-// The Starboard configuration for Creator Ci20 Debian.
-
-// Other source files should never include this header directly, but should
-// include the generic "starboard/configuration.h" instead.
-
-#ifndef STARBOARD_CREATOR_CI20_CONFIGURATION_PUBLIC_H_
-#define STARBOARD_CREATOR_CI20_CONFIGURATION_PUBLIC_H_
-
-// --- Architecture Configuration --------------------------------------------
-
-// Whether the current platform is big endian. SB_IS_LITTLE_ENDIAN will be
-// automatically set based on this.
-#define SB_IS_BIG_ENDIAN 0
-
-// Whether the current platform is an ARM architecture.
-#define SB_IS_ARCH_ARM 0
-
-// Whether the current platform is a MIPS architecture.
-#define SB_IS_ARCH_MIPS 1
-
-// Whether the current platform is a PPC architecture.
-#define SB_IS_ARCH_PPC 0
-
-// Whether the current platform is an x86 architecture.
-#define SB_IS_ARCH_X86 0
-
-// Whether the current platform is a 32-bit architecture.
-#define SB_IS_32_BIT 1
-
-// Whether the current platform is a 64-bit architecture.
-#define SB_IS_64_BIT 0
-
-// Whether the current platform's pointers are 32-bit.
-// Whether the current platform's longs are 32-bit.
-#if SB_IS(32_BIT)
-#define SB_HAS_32_BIT_POINTERS 1
-#define SB_HAS_32_BIT_LONG 1
-#else
-#define SB_HAS_32_BIT_POINTERS 0
-#define SB_HAS_32_BIT_LONG 0
-#endif
-
-// Whether the current platform's pointers are 64-bit.
-// Whether the current platform's longs are 64-bit.
-#if SB_IS(64_BIT)
-#define SB_HAS_64_BIT_POINTERS 1
-#define SB_HAS_64_BIT_LONG 1
-#else
-#define SB_HAS_64_BIT_POINTERS 0
-#define SB_HAS_64_BIT_LONG 0
-#endif
-
-// Configuration parameters that allow the application to make some general
-// compile-time decisions with respect to the the number of cores likely to be
-// available on this platform. For a definitive measure, the application should
-// still call SbSystemGetNumberOfProcessors at runtime.
-
-// Whether the current platform is expected to have many cores (> 6), or a
-// wildly varying number of cores.
-#define SB_HAS_MANY_CORES 0
-
-// Whether the current platform is expected to have exactly 1 core.
-#define SB_HAS_1_CORE 0
-
-// Whether the current platform is expected to have exactly 2 cores.
-#define SB_HAS_2_CORES 1
-
-// Whether the current platform is expected to have exactly 4 cores.
-#define SB_HAS_4_CORES 0
-
-// Whether the current platform is expected to have exactly 6 cores.
-#define SB_HAS_6_CORES 0
-
-// Whether the current platform's thread scheduler will automatically balance
-// threads between cores, as opposed to systems where threads will only ever run
-// on the specifically pinned core.
-#define SB_HAS_CROSS_CORE_SCHEDULER 1
-
-#include "starboard/creator/shared/configuration_public.h"
-
-#endif // STARBOARD_CREATOR_CI20_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/creator/ci20directfb/README.md b/src/starboard/creator/ci20directfb/README.md
new file mode 100644
index 0000000..e0c1251
--- /dev/null
+++ b/src/starboard/creator/ci20directfb/README.md
@@ -0,0 +1,4 @@
+# Setting up Starboard to use DirectFB on a Creator Ci20
+
+See `starboard/raspi/directfb/README.md`. The steps for getting directfb
+running on the Ci20 are identical.
diff --git a/src/starboard/creator/ci20/atomic_public.h b/src/starboard/creator/ci20directfb/atomic_public.h
similarity index 79%
copy from src/starboard/creator/ci20/atomic_public.h
copy to src/starboard/creator/ci20directfb/atomic_public.h
index 3b48d2e..2a182e7 100644
--- a/src/starboard/creator/ci20/atomic_public.h
+++ b/src/starboard/creator/ci20directfb/atomic_public.h
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef STARBOARD_CREATOR_CI20_ATOMIC_PUBLIC_H_
-#define STARBOARD_CREATOR_CI20_ATOMIC_PUBLIC_H_
+#ifndef STARBOARD_CREATOR_CI20DIRECTFB_ATOMIC_PUBLIC_H_
+#define STARBOARD_CREATOR_CI20DIRECTFB_ATOMIC_PUBLIC_H_
#include "starboard/linux/shared/atomic_public.h"
-#endif // STARBOARD_CREATOR_CI20_ATOMIC_PUBLIC_H_
+#endif // STARBOARD_CREATOR_CI20DIRECTFB_ATOMIC_PUBLIC_H_
diff --git a/src/starboard/creator/ci20directfb/configuration_public.h b/src/starboard/creator/ci20directfb/configuration_public.h
new file mode 100644
index 0000000..651c203
--- /dev/null
+++ b/src/starboard/creator/ci20directfb/configuration_public.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef STARBOARD_CREATOR_CI20DIRECTFB_CONFIGURATION_PUBLIC_H_
+#define STARBOARD_CREATOR_CI20DIRECTFB_CONFIGURATION_PUBLIC_H_
+
+#include "starboard/creator/shared/configuration_public.h"
+
+// Indicates whether or not the given platform supports rendering of NV12
+// textures. These textures typically originate from video decoders.
+#undef SB_HAS_NV12_TEXTURE_SUPPORT
+#define SB_HAS_NV12_TEXTURE_SUPPORT 0
+
+// This configuration supports the blitter API (implemented via DirectFB).
+#undef SB_HAS_BLITTER
+#define SB_HAS_BLITTER 1
+
+// Unfortunately, DirectFB does not support bilinear filtering. According to
+// http://osdir.com/ml/graphics.directfb.user/2008-06/msg00028.html, "smooth
+// scaling is not supported in conjunction with blending", and we need blending
+// more.
+#undef SB_HAS_BILINEAR_FILTERING_SUPPORT
+#define SB_HAS_BILINEAR_FILTERING_SUPPORT 0
+
+// DirectFB's only 32-bit RGBA color format is word-order ARGB. This translates
+// to byte-order ARGB for big endian platforms and byte-order BGRA for
+// little-endian platforms.
+#undef SB_PREFERRED_RGBA_BYTE_ORDER
+#if SB_IS(BIG_ENDIAN)
+#define SB_PREFERRED_RGBA_BYTE_ORDER SB_PREFERRED_RGBA_BYTE_ORDER_ARGB
+#else
+#define SB_PREFERRED_RGBA_BYTE_ORDER SB_PREFERRED_RGBA_BYTE_ORDER_BGRA
+#endif
+
+#endif // STARBOARD_CREATOR_CI20DIRECTFB_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/creator/ci20directfb/gyp_configuration.gypi b/src/starboard/creator/ci20directfb/gyp_configuration.gypi
new file mode 100644
index 0000000..8d8c263
--- /dev/null
+++ b/src/starboard/creator/ci20directfb/gyp_configuration.gypi
@@ -0,0 +1,45 @@
+# 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.
+
+{
+ 'variables': {
+ 'platform_libraries': [
+ '-ldirectfb',
+ '-ldirect',
+ ],
+ 'gl_type': 'none',
+ },
+
+ 'target_defaults': {
+ 'default_configuration': 'creator-ci20directfb_debug',
+ 'configurations': {
+ 'creator-ci20directfb_debug': {
+ 'inherit_from': ['debug_base'],
+ },
+ 'creator-ci20directfb_devel': {
+ 'inherit_from': ['devel_base'],
+ },
+ 'creator-ci20directfb_qa': {
+ 'inherit_from': ['qa_base'],
+ },
+ 'creator-ci20directfb_gold': {
+ 'inherit_from': ['gold_base'],
+ },
+ }, # end of configurations
+ },
+
+ 'includes': [
+ '../shared/gyp_configuration.gypi',
+ ],
+}
diff --git a/src/starboard/creator/ci20directfb/gyp_configuration.py b/src/starboard/creator/ci20directfb/gyp_configuration.py
new file mode 100644
index 0000000..4e712f5
--- /dev/null
+++ b/src/starboard/creator/ci20directfb/gyp_configuration.py
@@ -0,0 +1,32 @@
+# 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.
+"""Starboard Creator Ci20 DirectFB platform configuration for gyp_cobalt."""
+
+import logging
+import os
+import sys
+
+# Import the shared Creator platform configuration.
+sys.path.append(
+ os.path.realpath(
+ os.path.join(os.path.dirname(__file__), os.pardir, 'shared')))
+import gyp_configuration # pylint: disable=import-self,g-import-not-at-top
+
+
+def CreatePlatformConfig():
+ try:
+ return gyp_configuration.PlatformConfig('creator-ci20directfb')
+ except RuntimeError as e:
+ logging.critical(e)
+ return None
diff --git a/src/starboard/creator/ci20directfb/main.cc b/src/starboard/creator/ci20directfb/main.cc
new file mode 100644
index 0000000..68d7761
--- /dev/null
+++ b/src/starboard/creator/ci20directfb/main.cc
@@ -0,0 +1,29 @@
+// 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.
+
+#include "starboard/configuration.h"
+#include "starboard/shared/directfb/application_directfb.h"
+#include "starboard/shared/signal/crash_signals.h"
+#include "starboard/shared/signal/suspend_signals.h"
+
+int main(int argc, char** argv) {
+ tzset();
+ starboard::shared::signal::InstallCrashSignalHandlers();
+ starboard::shared::signal::InstallSuspendSignalHandlers();
+ starboard::ApplicationDirectFB application;
+ int result = application.Run(argc, argv);
+ starboard::shared::signal::UninstallSuspendSignalHandlers();
+ starboard::shared::signal::UninstallCrashSignalHandlers();
+ return result;
+}
diff --git a/src/starboard/creator/ci20/starboard_platform.gyp b/src/starboard/creator/ci20directfb/starboard_platform.gyp
similarity index 84%
copy from src/starboard/creator/ci20/starboard_platform.gyp
copy to src/starboard/creator/ci20directfb/starboard_platform.gyp
index c6a9f11..b695c91 100644
--- a/src/starboard/creator/ci20/starboard_platform.gyp
+++ b/src/starboard/creator/ci20directfb/starboard_platform.gyp
@@ -25,14 +25,14 @@
'target_name': 'starboard_platform',
'type': 'static_library',
'sources': [
- '<(DEPTH)/starboard/creator/ci20/configuration_public.h',
- '<(DEPTH)/starboard/creator/ci20/system_get_property.cc',
+ '<(DEPTH)/starboard/creator/ci20directfb/configuration_public.h',
+ '<(DEPTH)/starboard/creator/ci20directfb/main.cc',
+ '<(DEPTH)/starboard/creator/ci20directfb/system_get_property.cc',
'<(DEPTH)/starboard/linux/shared/atomic_public.h',
'<(DEPTH)/starboard/linux/shared/system_get_connection_type.cc',
'<(DEPTH)/starboard/linux/shared/system_get_device_type.cc',
'<(DEPTH)/starboard/linux/shared/system_get_path.cc',
'<(DEPTH)/starboard/linux/shared/system_has_capability.cc',
- '<(DEPTH)/starboard/linux/x64x11/main.cc',
'<(DEPTH)/starboard/shared/alsa/alsa_audio_sink_type.cc',
'<(DEPTH)/starboard/shared/alsa/alsa_audio_sink_type.h',
'<(DEPTH)/starboard/shared/alsa/alsa_util.cc',
@@ -41,6 +41,43 @@
'<(DEPTH)/starboard/shared/alsa/audio_sink_get_nearest_supported_sample_frequency.cc',
'<(DEPTH)/starboard/shared/alsa/audio_sink_is_audio_frame_storage_type_supported.cc',
'<(DEPTH)/starboard/shared/alsa/audio_sink_is_audio_sample_type_supported.cc',
+ '<(DEPTH)/starboard/shared/directfb/application_directfb.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_blit_rect_to_rect.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_create_context.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_create_default_device.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_create_pixel_data.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_create_render_target_surface.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_create_surface_from_pixel_data.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_create_swap_chain_from_window.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_destroy_context.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_destroy_device.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_destroy_pixel_data.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_destroy_surface.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_destroy_swap_chain.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_download_surface_pixels.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_fill_rect.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_flip_swap_chain.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_flush_context.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_get_max_contexts.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_get_pixel_data_pitch_in_bytes.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_get_pixel_data_pointer.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_get_render_target_from_surface.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_get_render_target_from_swap_chain.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_get_surface_info.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_internal.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_is_pixel_format_supported_by_download_surface_pixels.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_is_pixel_format_supported_by_pixel_data.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_is_surface_format_supported_by_render_target_surface.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_set_blending.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_set_color.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_set_modulate_blits_with_color.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_set_render_target.cc',
+ '<(DEPTH)/starboard/shared/directfb/blitter_set_scissor.cc',
+ '<(DEPTH)/starboard/shared/directfb/window_create.cc',
+ '<(DEPTH)/starboard/shared/directfb/window_destroy.cc',
+ '<(DEPTH)/starboard/shared/directfb/window_get_platform_handle.cc',
+ '<(DEPTH)/starboard/shared/directfb/window_get_size.cc',
+ '<(DEPTH)/starboard/shared/directfb/window_internal.cc',
'<(DEPTH)/starboard/shared/dlmalloc/memory_allocate_aligned_unchecked.cc',
'<(DEPTH)/starboard/shared/dlmalloc/memory_allocate_unchecked.cc',
'<(DEPTH)/starboard/shared/dlmalloc/memory_free.cc',
@@ -210,6 +247,8 @@
'<(DEPTH)/starboard/shared/starboard/audio_sink/audio_sink_is_valid.cc',
'<(DEPTH)/starboard/shared/starboard/audio_sink/stub_audio_sink_type.cc',
'<(DEPTH)/starboard/shared/starboard/audio_sink/stub_audio_sink_type.h',
+ '<(DEPTH)/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc',
+ '<(DEPTH)/starboard/shared/starboard/blitter_blit_rects_to_rects.cc',
'<(DEPTH)/starboard/shared/starboard/directory_can_open.cc',
'<(DEPTH)/starboard/shared/starboard/event_cancel.cc',
'<(DEPTH)/starboard/shared/starboard/event_schedule.cc',
@@ -275,12 +314,9 @@
'<(DEPTH)/starboard/shared/stub/system_get_used_gpu_memory.cc',
'<(DEPTH)/starboard/shared/stub/system_hide_splash_screen.cc',
'<(DEPTH)/starboard/shared/stub/system_raise_platform_error.cc',
- '<(DEPTH)/starboard/shared/x11/application_x11.cc',
- '<(DEPTH)/starboard/shared/x11/window_create.cc',
- '<(DEPTH)/starboard/shared/x11/window_destroy.cc',
- '<(DEPTH)/starboard/shared/x11/window_get_platform_handle.cc',
- '<(DEPTH)/starboard/shared/x11/window_get_size.cc',
- '<(DEPTH)/starboard/shared/x11/window_internal.cc',
+ ],
+ 'include_dirs': [
+ '<(sysroot)/mipsel-r2-hard/usr/include/directfb',
],
'defines': [
# This must be defined when building Starboard, and must not when
diff --git a/src/starboard/creator/ci20/system_get_property.cc b/src/starboard/creator/ci20directfb/system_get_property.cc
similarity index 95%
copy from src/starboard/creator/ci20/system_get_property.cc
copy to src/starboard/creator/ci20directfb/system_get_property.cc
index 8a7a795..51ca55f 100644
--- a/src/starboard/creator/ci20/system_get_property.cc
+++ b/src/starboard/creator/ci20directfb/system_get_property.cc
@@ -20,7 +20,7 @@
namespace {
const char* kFriendlyName = "Creator Ci20";
-const char* kPlatformName = "Creator Ci20 JZ4780";
+const char* kPlatformName = "DirectFB; Creator Ci20 JZ4780";
bool CopyStringAndTestIfSuccess(char* out_value,
int value_length,
@@ -47,6 +47,7 @@
case kSbSystemPropertyModelName:
case kSbSystemPropertyModelYear:
case kSbSystemPropertyNetworkOperatorName:
+ case kSbSystemPropertySpeechApiKey:
return false;
case kSbSystemPropertyFriendlyName:
diff --git a/src/starboard/creator/ci20/thread_types_public.h b/src/starboard/creator/ci20directfb/thread_types_public.h
similarity index 77%
copy from src/starboard/creator/ci20/thread_types_public.h
copy to src/starboard/creator/ci20directfb/thread_types_public.h
index ec9eedf..b531032 100644
--- a/src/starboard/creator/ci20/thread_types_public.h
+++ b/src/starboard/creator/ci20directfb/thread_types_public.h
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef STARBOARD_CREATOR_CI20_THREAD_TYPES_PUBLIC_H_
-#define STARBOARD_CREATOR_CI20_THREAD_TYPES_PUBLIC_H_
+#ifndef STARBOARD_CREATOR_CI20DIRECTFB_THREAD_TYPES_PUBLIC_H_
+#define STARBOARD_CREATOR_CI20DIRECTFB_THREAD_TYPES_PUBLIC_H_
#include "starboard/linux/shared/thread_types_public.h"
-#endif // STARBOARD_CREATOR_CI20_THREAD_TYPES_PUBLIC_H_
+#endif // STARBOARD_CREATOR_CI20DIRECTFB_THREAD_TYPES_PUBLIC_H_
diff --git a/src/starboard/creator/ci20/atomic_public.h b/src/starboard/creator/ci20x11/atomic_public.h
similarity index 80%
rename from src/starboard/creator/ci20/atomic_public.h
rename to src/starboard/creator/ci20x11/atomic_public.h
index 3b48d2e..932fe9d 100644
--- a/src/starboard/creator/ci20/atomic_public.h
+++ b/src/starboard/creator/ci20x11/atomic_public.h
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef STARBOARD_CREATOR_CI20_ATOMIC_PUBLIC_H_
-#define STARBOARD_CREATOR_CI20_ATOMIC_PUBLIC_H_
+#ifndef STARBOARD_CREATOR_CI20X11_ATOMIC_PUBLIC_H_
+#define STARBOARD_CREATOR_CI20X11_ATOMIC_PUBLIC_H_
#include "starboard/linux/shared/atomic_public.h"
-#endif // STARBOARD_CREATOR_CI20_ATOMIC_PUBLIC_H_
+#endif // STARBOARD_CREATOR_CI20X11_ATOMIC_PUBLIC_H_
diff --git a/src/starboard/shared/stub/microphone_get_speech_api_key.cc b/src/starboard/creator/ci20x11/configuration_public.h
similarity index 71%
rename from src/starboard/shared/stub/microphone_get_speech_api_key.cc
rename to src/starboard/creator/ci20x11/configuration_public.h
index 98038b4..4c00bad 100644
--- a/src/starboard/shared/stub/microphone_get_speech_api_key.cc
+++ b/src/starboard/creator/ci20x11/configuration_public.h
@@ -12,12 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/microphone.h"
+#ifndef STARBOARD_CREATOR_CI20X11_CONFIGURATION_PUBLIC_H_
+#define STARBOARD_CREATOR_CI20X11_CONFIGURATION_PUBLIC_H_
-#if SB_HAS(MICROPHONE) && SB_VERSION(2)
+#include "starboard/creator/shared/configuration_public.h"
-const char* SbMicrophoneGetSpeechApiKey() {
- return "";
-}
-
-#endif // SB_HAS(MICROPHONE) && SB_VERSION(2)
+#endif // STARBOARD_CREATOR_CI20X11_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/creator/ci20x11/gyp_configuration.gypi b/src/starboard/creator/ci20x11/gyp_configuration.gypi
new file mode 100644
index 0000000..a2ea1b8
--- /dev/null
+++ b/src/starboard/creator/ci20x11/gyp_configuration.gypi
@@ -0,0 +1,48 @@
+# 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.
+
+{
+ 'variables': {
+ 'platform_libraries': [
+ '-lEGL',
+ '-lGLESv2',
+ '-lX11',
+ '-lXcomposite',
+ '-lXext',
+ '-lXrender',
+ ],
+ },
+
+ 'target_defaults': {
+ 'default_configuration': 'creator-ci20x11_debug',
+ 'configurations': {
+ 'creator-ci20x11_debug': {
+ 'inherit_from': ['debug_base'],
+ },
+ 'creator-ci20x11_devel': {
+ 'inherit_from': ['devel_base'],
+ },
+ 'creator-ci20x11_qa': {
+ 'inherit_from': ['qa_base'],
+ },
+ 'creator-ci20x11_gold': {
+ 'inherit_from': ['gold_base'],
+ },
+ }, # end of configurations
+ },
+
+ 'includes': [
+ '../shared/gyp_configuration.gypi',
+ ],
+}
diff --git a/src/starboard/creator/ci20x11/gyp_configuration.py b/src/starboard/creator/ci20x11/gyp_configuration.py
new file mode 100644
index 0000000..1c062df
--- /dev/null
+++ b/src/starboard/creator/ci20x11/gyp_configuration.py
@@ -0,0 +1,32 @@
+# 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.
+"""Starboard Creator Ci20 X11 platform configuration for gyp_cobalt."""
+
+import logging
+import os
+import sys
+
+# Import the shared Creator platform configuration.
+sys.path.append(
+ os.path.realpath(
+ os.path.join(os.path.dirname(__file__), os.pardir, 'shared')))
+import gyp_configuration # pylint: disable=import-self,g-import-not-at-top
+
+
+def CreatePlatformConfig():
+ try:
+ return gyp_configuration.PlatformConfig('creator-ci20x11')
+ except RuntimeError as e:
+ logging.critical(e)
+ return None
diff --git a/src/starboard/creator/ci20/main.cc b/src/starboard/creator/ci20x11/main.cc
similarity index 100%
rename from src/starboard/creator/ci20/main.cc
rename to src/starboard/creator/ci20x11/main.cc
diff --git a/src/starboard/creator/ci20/starboard_platform.gyp b/src/starboard/creator/ci20x11/starboard_platform.gyp
similarity index 97%
rename from src/starboard/creator/ci20/starboard_platform.gyp
rename to src/starboard/creator/ci20x11/starboard_platform.gyp
index c6a9f11..bab02c6 100644
--- a/src/starboard/creator/ci20/starboard_platform.gyp
+++ b/src/starboard/creator/ci20x11/starboard_platform.gyp
@@ -25,14 +25,15 @@
'target_name': 'starboard_platform',
'type': 'static_library',
'sources': [
- '<(DEPTH)/starboard/creator/ci20/configuration_public.h',
- '<(DEPTH)/starboard/creator/ci20/system_get_property.cc',
+ '<(DEPTH)/starboard/creator/ci20x11/atomic_public.h',
+ '<(DEPTH)/starboard/creator/ci20x11/configuration_public.h',
+ '<(DEPTH)/starboard/creator/ci20x11/main.cc',
+ '<(DEPTH)/starboard/creator/ci20x11/system_get_property.cc',
'<(DEPTH)/starboard/linux/shared/atomic_public.h',
'<(DEPTH)/starboard/linux/shared/system_get_connection_type.cc',
'<(DEPTH)/starboard/linux/shared/system_get_device_type.cc',
'<(DEPTH)/starboard/linux/shared/system_get_path.cc',
'<(DEPTH)/starboard/linux/shared/system_has_capability.cc',
- '<(DEPTH)/starboard/linux/x64x11/main.cc',
'<(DEPTH)/starboard/shared/alsa/alsa_audio_sink_type.cc',
'<(DEPTH)/starboard/shared/alsa/alsa_audio_sink_type.h',
'<(DEPTH)/starboard/shared/alsa/alsa_util.cc',
@@ -226,8 +227,8 @@
'<(DEPTH)/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc',
'<(DEPTH)/starboard/shared/starboard/media/media_is_output_protected.cc',
'<(DEPTH)/starboard/shared/starboard/media/media_set_output_protection.cc',
- '<(DEPTH)/starboard/shared/starboard/media/mime_parser.cc',
- '<(DEPTH)/starboard/shared/starboard/media/mime_parser.h',
+ '<(DEPTH)/starboard/shared/starboard/media/mime_type.cc',
+ '<(DEPTH)/starboard/shared/starboard/media/mime_type.h',
'<(DEPTH)/starboard/shared/starboard/new.cc',
'<(DEPTH)/starboard/shared/starboard/player/filter/audio_decoder_internal.h',
'<(DEPTH)/starboard/shared/starboard/player/filter/audio_renderer_internal.cc',
diff --git a/src/starboard/creator/ci20/system_get_property.cc b/src/starboard/creator/ci20x11/system_get_property.cc
similarity index 97%
rename from src/starboard/creator/ci20/system_get_property.cc
rename to src/starboard/creator/ci20x11/system_get_property.cc
index 8a7a795..9d71165 100644
--- a/src/starboard/creator/ci20/system_get_property.cc
+++ b/src/starboard/creator/ci20x11/system_get_property.cc
@@ -47,6 +47,7 @@
case kSbSystemPropertyModelName:
case kSbSystemPropertyModelYear:
case kSbSystemPropertyNetworkOperatorName:
+ case kSbSystemPropertySpeechApiKey:
return false;
case kSbSystemPropertyFriendlyName:
diff --git a/src/starboard/creator/ci20/thread_types_public.h b/src/starboard/creator/ci20x11/thread_types_public.h
similarity index 79%
rename from src/starboard/creator/ci20/thread_types_public.h
rename to src/starboard/creator/ci20x11/thread_types_public.h
index ec9eedf..7437a70 100644
--- a/src/starboard/creator/ci20/thread_types_public.h
+++ b/src/starboard/creator/ci20x11/thread_types_public.h
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef STARBOARD_CREATOR_CI20_THREAD_TYPES_PUBLIC_H_
-#define STARBOARD_CREATOR_CI20_THREAD_TYPES_PUBLIC_H_
+#ifndef STARBOARD_CREATOR_CI20X11_THREAD_TYPES_PUBLIC_H_
+#define STARBOARD_CREATOR_CI20X11_THREAD_TYPES_PUBLIC_H_
#include "starboard/linux/shared/thread_types_public.h"
-#endif // STARBOARD_CREATOR_CI20_THREAD_TYPES_PUBLIC_H_
+#endif // STARBOARD_CREATOR_CI20X11_THREAD_TYPES_PUBLIC_H_
diff --git a/src/starboard/creator/shared/configuration_public.h b/src/starboard/creator/shared/configuration_public.h
index 8144c15..3574948 100644
--- a/src/starboard/creator/shared/configuration_public.h
+++ b/src/starboard/creator/shared/configuration_public.h
@@ -17,8 +17,78 @@
#ifndef STARBOARD_CREATOR_SHARED_CONFIGURATION_PUBLIC_H_
#define STARBOARD_CREATOR_SHARED_CONFIGURATION_PUBLIC_H_
+// --- Architecture Configuration --------------------------------------------
+
+// Whether the current platform is big endian. SB_IS_LITTLE_ENDIAN will be
+// automatically set based on this.
+#define SB_IS_BIG_ENDIAN 0
+
+// Whether the current platform is an ARM architecture.
+#define SB_IS_ARCH_ARM 0
+
+// Whether the current platform is a MIPS architecture.
+#define SB_IS_ARCH_MIPS 1
+
+// Whether the current platform is a PPC architecture.
+#define SB_IS_ARCH_PPC 0
+
+// Whether the current platform is an x86 architecture.
+#define SB_IS_ARCH_X86 0
+
+// Whether the current platform is a 32-bit architecture.
+#define SB_IS_32_BIT 1
+
+// Whether the current platform is a 64-bit architecture.
+#define SB_IS_64_BIT 0
+
+// Whether the current platform's pointers are 32-bit.
+// Whether the current platform's longs are 32-bit.
+#if SB_IS(32_BIT)
+#define SB_HAS_32_BIT_POINTERS 1
+#define SB_HAS_32_BIT_LONG 1
+#else
+#define SB_HAS_32_BIT_POINTERS 0
+#define SB_HAS_32_BIT_LONG 0
+#endif
+
+// Whether the current platform's pointers are 64-bit.
+// Whether the current platform's longs are 64-bit.
+#if SB_IS(64_BIT)
+#define SB_HAS_64_BIT_POINTERS 1
+#define SB_HAS_64_BIT_LONG 1
+#else
+#define SB_HAS_64_BIT_POINTERS 0
+#define SB_HAS_64_BIT_LONG 0
+#endif
+
+// Configuration parameters that allow the application to make some general
+// compile-time decisions with respect to the the number of cores likely to be
+// available on this platform. For a definitive measure, the application should
+// still call SbSystemGetNumberOfProcessors at runtime.
+
+// Whether the current platform is expected to have many cores (> 6), or a
+// wildly varying number of cores.
+#define SB_HAS_MANY_CORES 0
+
+// Whether the current platform is expected to have exactly 1 core.
+#define SB_HAS_1_CORE 0
+
+// Whether the current platform is expected to have exactly 2 cores.
+#define SB_HAS_2_CORES 1
+
+// Whether the current platform is expected to have exactly 4 cores.
+#define SB_HAS_4_CORES 0
+
+// Whether the current platform is expected to have exactly 6 cores.
+#define SB_HAS_6_CORES 0
+
+// Whether the current platform's thread scheduler will automatically balance
+// threads between cores, as opposed to systems where threads will only ever run
+// on the specifically pinned core.
+#define SB_HAS_CROSS_CORE_SCHEDULER 1
+
// The API version implemented by this platform.
-#define SB_API_VERSION 1
+#define SB_API_VERSION 2
// --- System Header Configuration -------------------------------------------
@@ -49,6 +119,9 @@
// Whether the current platform provides the standard header float.h.
#define SB_HAS_FLOAT_H 1
+// Whether the current platform has microphone supported.
+#define SB_HAS_MICROPHONE 0
+
// Type detection for wchar_t.
#if defined(__WCHAR_MAX__) && \
(__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff)
@@ -68,10 +141,8 @@
// --- Architecture Configuration --------------------------------------------
-// On the current version of Raspbian, real time thread scheduling seems to be
-// broken in that higher priority threads do not always have priority over lower
-// priority threads. It looks like the thread created last will always have the
-// highest priority.
+// On default Linux, you must be a superuser in order to set real time
+// scheduling on threads.
#define SB_HAS_THREAD_PRIORITY_SUPPORT 0
// --- Attribute Configuration -----------------------------------------------
diff --git a/src/starboard/creator/ci20/gyp_configuration.gypi b/src/starboard/creator/shared/gyp_configuration.gypi
similarity index 86%
rename from src/starboard/creator/ci20/gyp_configuration.gypi
rename to src/starboard/creator/shared/gyp_configuration.gypi
index 045e41c..c6cb2f2 100644
--- a/src/starboard/creator/ci20/gyp_configuration.gypi
+++ b/src/starboard/creator/shared/gyp_configuration.gypi
@@ -19,7 +19,7 @@
'enable_webdriver': 0,
'in_app_dial%': 0,
- 'gl_type': 'system_gles2',
+ 'gl_type%': 'system_gles3',
'image_cache_size_in_bytes': 32 * 1024 * 1024,
'scratch_surface_cache_size_in_bytes' : 0,
@@ -39,6 +39,16 @@
'-U__linux__',
'--sysroot=<(sysroot)',
'-EL',
+
+ # Suppress some warnings that will be hard to fix.
+ '-Wno-unused-local-typedefs',
+ '-Wno-unused-result',
+ '-Wno-deprecated-declarations',
+ '-Wno-missing-field-initializers',
+ '-Wno-comment',
+ '-Wno-narrowing',
+ '-Wno-unknown-pragmas',
+ '-Wno-type-limits', # TODO: We should actually look into these.
],
'linker_flags': [
'--sysroot=<(sysroot)',
@@ -87,16 +97,10 @@
'-lavformat',
'-lavresample',
'-lavutil',
- '-lEGL',
- '-lGLESv2',
'-lm',
'-lpthread',
'-lpulse',
'-lrt',
- '-lX11',
- '-lXcomposite',
- '-lXext',
- '-lXrender',
],
'conditions': [
['cobalt_fastbuild==0', {
@@ -129,21 +133,6 @@
'-std=gnu++11',
'-Wno-literal-suffix',
],
- 'default_configuration': 'creator-ci20_debug',
- 'configurations': {
- 'creator-ci20_debug': {
- 'inherit_from': ['debug_base'],
- },
- 'creator-ci20_devel': {
- 'inherit_from': ['devel_base'],
- },
- 'creator-ci20_qa': {
- 'inherit_from': ['qa_base'],
- },
- 'creator-ci20_gold': {
- 'inherit_from': ['gold_base'],
- },
- }, # end of configurations
'target_conditions': [
['cobalt_code==1', {
'cflags': [
diff --git a/src/starboard/creator/ci20/gyp_configuration.py b/src/starboard/creator/shared/gyp_configuration.py
similarity index 73%
rename from src/starboard/creator/ci20/gyp_configuration.py
rename to src/starboard/creator/shared/gyp_configuration.py
index 10bb683..373a70e 100644
--- a/src/starboard/creator/ci20/gyp_configuration.py
+++ b/src/starboard/creator/shared/gyp_configuration.py
@@ -11,7 +11,7 @@
# 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.
-"""Starboard ci20 platform configuration for gyp_cobalt."""
+"""Starboard Creator Ci20 platform configuration for gyp_cobalt."""
import logging
import os
@@ -20,19 +20,11 @@
import config.starboard
-def CreatePlatformConfig():
- try:
- return _PlatformConfig('creator-ci20')
- except RuntimeError as e:
- logging.critical(e)
- return None
-
-
-class _PlatformConfig(config.starboard.PlatformConfigStarboard):
+class PlatformConfig(config.starboard.PlatformConfigStarboard):
"""Starboard ci20 platform configuration."""
def __init__(self, platform):
- super(_PlatformConfig, self).__init__(platform)
+ super(PlatformConfig, self).__init__(platform)
def _GetCi20Home(self):
try:
@@ -46,16 +38,16 @@
def GetVariables(self, configuration):
ci20_home = self._GetCi20Home()
- sysroot = os.path.join(ci20_home, 'mips-mti-linux-gnu', '2016.05-03',
- 'sysroot')
+ relative_sysroot = os.path.join('mips-mti-linux-gnu', '2016.05-03',
+ 'sysroot')
+ sysroot = os.path.join(ci20_home, relative_sysroot)
if not os.path.isdir(sysroot):
logging.critical(
- 'ci20 builds require '
- '$CI20_HOME/mips-mti-linux-gnu/2016.05-03/sysroot to be a valid '
- 'directory.')
+ 'ci20 builds require $CI20_HOME/%s to be a valid directory.',
+ relative_sysroot)
sys.exit(1)
- variables = super(_PlatformConfig, self).GetVariables(configuration)
+ variables = super(PlatformConfig, self).GetVariables(configuration)
variables.update({
'clang': 0,
'sysroot': sysroot,
diff --git a/src/starboard/drm.h b/src/starboard/drm.h
index 26d99a9..f7f4544 100644
--- a/src/starboard/drm.h
+++ b/src/starboard/drm.h
@@ -12,8 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Definitions that allow for DRM support, common between Player and Decoder
-// interfaces.
+// Module Overview: Starboard DRM module
+//
+// Provides definitions that allow for DRM support, which are common
+// between Player and Decoder interfaces.
#ifndef STARBOARD_DRM_H_
#define STARBOARD_DRM_H_
@@ -104,26 +106,30 @@
// --- Functions -------------------------------------------------------------
-// Returns whether the |drm_system| is a valid SbDrmSystem.
+// Indicates whether |drm_system| is a valid SbDrmSystem.
static SB_C_FORCE_INLINE bool SbDrmSystemIsValid(SbDrmSystem drm) {
return drm != kSbDrmSystemInvalid;
}
-// Creates a new |key_system| DRM system that can be used when constructing an
-// SbPlayer or an SbDecoder. |key_system| should be in fhe form of
-// "com.example.somesystem" as suggested by
-// https://w3c.github.io/encrypted-media/#key-system. All letters in
-// |key_system| should be in lower case and will be matched exactly with known
-// DRM key systems of the platform.
-// |context| will be passed when any callback parameters of this function are
-// called.
-// |update_request_callback| is a callback that will be called every time after
-// SbDrmGenerateSessionUpdateRequest() is called.
-// |session_updated_callback| is a callback that will be called every time
-// after SbDrmUpdateSession() is called.
-// Please refer to the document of SbDrmGenerateSessionUpdateRequest() and
+// Creates a new DRM system that can be used when constructing an SbPlayer
+// or an SbDecoder.
+//
+// This function returns kSbDrmSystemInvalid if |key_system| is unsupported.
+//
+// Also see the documentation of SbDrmGenerateSessionUpdateRequest() and
// SbDrmUpdateSession() for more details.
-// Returns kSbDrmSystemInvalid if the |key_system| is unsupported.
+//
+// |key_system|: The DRM key system to be created. The value should be in the
+// form of "com.example.somesystem" as suggested by
+// https://w3c.github.io/encrypted-media/#key-system. All letters in the value
+// should be lowercase and will be matched exactly with known DRM key systems
+// of the platform.
+// |context|: A value passed when any of this function's callback parameters
+// are called.
+// |update_request_callback|: A function that is called every time after
+// SbDrmGenerateSessionUpdateRequest() is called.
+// |session_updated_callback|: A function that is called every time after
+// SbDrmUpdateSession() is called.
SB_EXPORT SbDrmSystem
SbDrmCreateSystem(const char* key_system,
void* context,
@@ -132,15 +138,28 @@
// 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. Calls
-// |update_request_callback| with |context| and either a populated request, or
-// NULL |session_id| if an error occured. |context| may be used to distinguish
-// callbacks from multiple concurrent calls to
-// SbDrmGenerateSessionUpdateRequest(), and/or to route callbacks back to an
-// object instance.
+// |type|, extracted from the media stream, in |drm_system|'s key system.
//
-// Callbacks may called from another thread or from the current thread before
-// this function returns.
+// This function calls |drm_system|'s |update_request_callback| function,
+// which is defined when the DRM system is created by SbDrmCreateSystem. When
+// calling that function, this function either sends |context| (also from
+// |SbDrmCreateSystem|) and a populated request, or it sends NULL |session_id|
+// if an error occurred.
+//
+// |drm_system|'s |context| may be used to distinguish callbacks from
+// multiple concurrent calls to SbDrmGenerateSessionUpdateRequest(), and/or
+// to route callbacks back to an object instance.
+//
+// Callbacks may be called either from the current thread before this function
+// returns or from another thread.
+//
+// |drm_system|: The DRM system that defines the key system used for the
+// session update request payload as well as the callback function that is
+// called as a result of the function being called.
+// |type|: The case-sensitive type of the session update request payload.
+// |initialization_data|: The data for which the session update request payload
+// is created.
+// |initialization_data_size|: The size of the session update request payload.
SB_EXPORT void SbDrmGenerateSessionUpdateRequest(
SbDrmSystem drm_system,
const char* type,
@@ -155,26 +174,28 @@
// and/or to route callbacks back to an object instance.
//
// Once the session is successfully updated, an SbPlayer or SbDecoder associated
-// with that system will be able to decrypt samples encrypted.
+// with that DRM key system will be able to decrypt encrypted samples.
//
-// |session_updated_callback| may called from another thread or from the current
-// thread before this function returns.
+// |drm_system|'s |session_updated_callback| may called either from the
+// current thread before this function returns or from another thread.
SB_EXPORT void SbDrmUpdateSession(SbDrmSystem drm_system,
const void* key,
int key_size,
const void* session_id,
int session_id_size);
-// Clear any internal states/resources related to the particular |session_id|.
+// Clear any internal states/resources related to the specified |session_id|.
SB_EXPORT void SbDrmCloseSession(SbDrmSystem drm_system,
const void* session_id,
int session_id_size);
-// Gets the number of keys installed in the given |drm_system| system.
+// Returns the number of keys installed in |drm_system|.
+//
+// |drm_system|: The system for which the number of installed keys is retrieved.
SB_EXPORT int SbDrmGetKeyCount(SbDrmSystem drm_system);
-// Gets the |out_key|, |out_key_size|, and |out_status| for key with |index| in
-// the given |drm_system| system. Returns whether a key is installed at |index|.
+// Gets |out_key|, |out_key_size|, and |out_status| for the key with |index|
+// in |drm_system|. Returns whether a key is installed at |index|.
// If not, the output parameters, which all must not be NULL, will not be
// modified.
SB_EXPORT bool SbDrmGetKeyStatus(SbDrmSystem drm_system,
@@ -186,17 +207,21 @@
SbDrmKeyStatus* out_status);
// Removes all installed keys for |drm_system|. Any outstanding session update
-// requests will also be invalidated.
+// requests are also invalidated.
+//
+// |drm_system|: The DRM system for which keys should be removed.
SB_EXPORT void SbDrmRemoveAllKeys(SbDrmSystem drm_system);
-// Destroys |drm_system|, which implicitly removes all keys installed in it, and
+// Destroys |drm_system|, which implicitly removes all keys installed in it and
// invalidates all outstanding session update requests. A DRM system cannot be
// destroyed unless any associated SbPlayer or SbDecoder has first been
// destroyed.
//
-// All callbacks are guaranteed to be finished when this function returns. So
-// calling this function from a callback passed to SbDrmCreateSystem() will
-// result in deadlock.
+// All callbacks are guaranteed to be finished when this function returns.
+// As a result, if this function is called from a callback that is passed
+// to SbDrmCreateSystem(), a deadlock will occur.
+//
+// |drm_system|: The DRM system to be destroyed.
SB_EXPORT void SbDrmDestroySystem(SbDrmSystem drm_system);
#ifdef __cplusplus
diff --git a/src/starboard/linux/shared/configuration_public.h b/src/starboard/linux/shared/configuration_public.h
index 20643e6..0e1efaa 100644
--- a/src/starboard/linux/shared/configuration_public.h
+++ b/src/starboard/linux/shared/configuration_public.h
@@ -24,7 +24,7 @@
#define STARBOARD_LINUX_SHARED_CONFIGURATION_PUBLIC_H_
// The API version implemented by this platform.
-#define SB_API_VERSION 1
+#define SB_API_VERSION 2
// --- System Header Configuration -------------------------------------------
@@ -55,6 +55,9 @@
// Whether the current platform provides the standard header float.h.
#define SB_HAS_FLOAT_H 1
+// Whether the current platform has microphone supported.
+#define SB_HAS_MICROPHONE 0
+
// Type detection for wchar_t.
#if defined(__WCHAR_MAX__) && \
(__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff)
diff --git a/src/starboard/linux/x64directfb/starboard_platform.gyp b/src/starboard/linux/x64directfb/starboard_platform.gyp
index f89ae85..2419586 100644
--- a/src/starboard/linux/x64directfb/starboard_platform.gyp
+++ b/src/starboard/linux/x64directfb/starboard_platform.gyp
@@ -265,8 +265,8 @@
'<(DEPTH)/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc',
'<(DEPTH)/starboard/shared/starboard/media/media_is_output_protected.cc',
'<(DEPTH)/starboard/shared/starboard/media/media_set_output_protection.cc',
- '<(DEPTH)/starboard/shared/starboard/media/mime_parser.cc',
- '<(DEPTH)/starboard/shared/starboard/media/mime_parser.h',
+ '<(DEPTH)/starboard/shared/starboard/media/mime_type.cc',
+ '<(DEPTH)/starboard/shared/starboard/media/mime_type.h',
'<(DEPTH)/starboard/shared/starboard/new.cc',
'<(DEPTH)/starboard/shared/starboard/player/filter/audio_decoder_internal.h',
'<(DEPTH)/starboard/shared/starboard/player/filter/audio_renderer_internal.cc',
diff --git a/src/starboard/linux/x64directfb/system_get_property.cc b/src/starboard/linux/x64directfb/system_get_property.cc
index b1529fe..1d20f7f 100644
--- a/src/starboard/linux/x64directfb/system_get_property.cc
+++ b/src/starboard/linux/x64directfb/system_get_property.cc
@@ -47,6 +47,7 @@
case kSbSystemPropertyModelName:
case kSbSystemPropertyModelYear:
case kSbSystemPropertyNetworkOperatorName:
+ case kSbSystemPropertySpeechApiKey:
return false;
case kSbSystemPropertyFriendlyName:
diff --git a/src/starboard/linux/x64x11/starboard_platform.gyp b/src/starboard/linux/x64x11/starboard_platform.gyp
index 6f9e3f8..a208bfc 100644
--- a/src/starboard/linux/x64x11/starboard_platform.gyp
+++ b/src/starboard/linux/x64x11/starboard_platform.gyp
@@ -226,8 +226,8 @@
'<(DEPTH)/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc',
'<(DEPTH)/starboard/shared/starboard/media/media_is_output_protected.cc',
'<(DEPTH)/starboard/shared/starboard/media/media_set_output_protection.cc',
- '<(DEPTH)/starboard/shared/starboard/media/mime_parser.cc',
- '<(DEPTH)/starboard/shared/starboard/media/mime_parser.h',
+ '<(DEPTH)/starboard/shared/starboard/media/mime_type.cc',
+ '<(DEPTH)/starboard/shared/starboard/media/mime_type.h',
'<(DEPTH)/starboard/shared/starboard/new.cc',
'<(DEPTH)/starboard/shared/starboard/player/filter/audio_decoder_internal.h',
'<(DEPTH)/starboard/shared/starboard/player/filter/audio_renderer_internal.cc',
diff --git a/src/starboard/linux/x64x11/starboard_platform_tests.gyp b/src/starboard/linux/x64x11/starboard_platform_tests.gyp
new file mode 100644
index 0000000..0250125
--- /dev/null
+++ b/src/starboard/linux/x64x11/starboard_platform_tests.gyp
@@ -0,0 +1,41 @@
+# 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.
+{
+ 'targets': [
+ {
+ 'target_name': 'starboard_platform_tests',
+ 'type': '<(gtest_target_type)',
+ 'sources': [
+ '<(DEPTH)/starboard/common/test_main.cc',
+ '<(DEPTH)/starboard/shared/starboard/media/mime_type_test.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/starboard/starboard.gyp:starboard',
+ '<(DEPTH)/testing/gmock.gyp:gmock',
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ ],
+ },
+ {
+ 'target_name': 'starboard_platform_tests_deploy',
+ 'type': 'none',
+ 'dependencies': [
+ '<(DEPTH)/<(starboard_path)/starboard_platform_tests.gyp:starboard_platform_tests',
+ ],
+ 'variables': {
+ 'executable_name': 'starboard_platform_tests',
+ },
+ 'includes': [ '../../build/deploy.gypi' ],
+ },
+ ],
+}
diff --git a/src/starboard/linux/x64x11/system_get_property.cc b/src/starboard/linux/x64x11/system_get_property.cc
index cffaa35..b72747d 100644
--- a/src/starboard/linux/x64x11/system_get_property.cc
+++ b/src/starboard/linux/x64x11/system_get_property.cc
@@ -47,6 +47,7 @@
case kSbSystemPropertyModelName:
case kSbSystemPropertyModelYear:
case kSbSystemPropertyNetworkOperatorName:
+ case kSbSystemPropertySpeechApiKey:
return false;
case kSbSystemPropertyFriendlyName:
diff --git a/src/starboard/microphone.h b/src/starboard/microphone.h
index 9ca8816..7e43451 100644
--- a/src/starboard/microphone.h
+++ b/src/starboard/microphone.h
@@ -85,6 +85,9 @@
// Microphone max supported sampling rate.
int max_sample_rate_hz;
+
+ // The minimum read size required for each read from microphone.
+ int min_read_size;
} SbMicrophoneInfo;
// An opaque handle to an implementation-private structure representing a
@@ -102,9 +105,11 @@
// Gets all currently-available microphone information and the results are
// stored in |out_info_array|. |info_array_size| is the size of
// |out_info_array|.
-// Return value is the number of the available microphones. A negative return
-// value indicates that either the |info_array_size| is too small or an internal
-// error is occurred.
+// Returns the number of the available microphones. A negative return
+// value indicates that an internal error has occurred. If the number of
+// available microphones is larger than |info_array_size|, |out_info_array| will
+// be filled up with as many available microphones as possible and the actual
+// number of available microphones will be returned.
SB_EXPORT int SbMicrophoneGetAvailable(SbMicrophoneInfo* out_info_array,
int info_array_size);
@@ -153,7 +158,9 @@
// an error. This function should be called frequently, otherwise microphone
// only buffers |buffer_size| bytes which is configured in |SbMicrophoneCreate|
// and the new audio data will be thrown out. No audio data will be read from a
-// stopped microphone.
+// stopped microphone. If |audio_data_size| is smaller than |min_read_size| of
+// |SbMicrophoneInfo|, the extra audio data which is already read from device
+// will be discarded.
SB_EXPORT int SbMicrophoneRead(SbMicrophone microphone,
void* out_audio_data,
int audio_data_size);
@@ -163,12 +170,6 @@
// read will be thrown away.
SB_EXPORT void SbMicrophoneDestroy(SbMicrophone microphone);
-// Returns the Google Speech API key. The platform manufacturer is responsible
-// for registering a Google Speech API key for their products. In the API
-// Console (http://developers.google.com/console), you are able to enable the
-// Speech APIs and generate a Speech API key.
-SB_EXPORT const char* SbMicrophoneGetSpeechApiKey();
-
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/src/starboard/nplb/microphone_get_available_test.cc b/src/starboard/nplb/microphone_get_available_test.cc
index 14a7ed0..232995b 100644
--- a/src/starboard/nplb/microphone_get_available_test.cc
+++ b/src/starboard/nplb/microphone_get_available_test.cc
@@ -32,14 +32,16 @@
SbMicrophoneInfo info_array[kMaxNumberOfMicrophone];
if (SbMicrophoneGetAvailable(info_array, kMaxNumberOfMicrophone) > 0) {
int available_microphones = SbMicrophoneGetAvailable(info_array, 0);
- EXPECT_LE(available_microphones, 0);
+ EXPECT_GT(available_microphones, 0);
}
}
TEST(SbMicrophoneGetAvailableTest, RainyDayNegativeNumberOfMicrophone) {
SbMicrophoneInfo info_array[kMaxNumberOfMicrophone];
- int available_microphones = SbMicrophoneGetAvailable(info_array, -10);
- EXPECT_LT(available_microphones, 0);
+ if (SbMicrophoneGetAvailable(info_array, kMaxNumberOfMicrophone) > 0) {
+ int available_microphones = SbMicrophoneGetAvailable(info_array, -10);
+ EXPECT_GT(available_microphones, 0);
+ }
}
TEST(SbMicrophoneGetAvailableTest, RainyDayNULLInfoArray) {
@@ -47,7 +49,7 @@
if (SbMicrophoneGetAvailable(info_array, kMaxNumberOfMicrophone) > 0) {
int available_microphones =
SbMicrophoneGetAvailable(NULL, kMaxNumberOfMicrophone);
- EXPECT_LT(available_microphones, 0);
+ EXPECT_GT(available_microphones, 0);
}
}
diff --git a/src/starboard/nplb/microphone_get_speech_api_key_test.cc b/src/starboard/nplb/microphone_get_speech_api_key_test.cc
deleted file mode 100644
index 67b5347..0000000
--- a/src/starboard/nplb/microphone_get_speech_api_key_test.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.
-
-#include "starboard/microphone.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace starboard {
-namespace nplb {
-
-#if SB_HAS(MICROPHONE) && SB_VERSION(2)
-
-TEST(SbMicrophoneGetSpeechApiKeyTest, SunnyDay) {
- const char* speech_api_key = SbMicrophoneGetSpeechApiKey();
-
- ASSERT_NE(speech_api_key, static_cast<const char*>(NULL));
- EXPECT_NE(speech_api_key[0], '\0');
-}
-
-#endif // SB_HAS(MICROPHONE) && SB_VERSION(2)
-
-} // namespace nplb
-} // namespace starboard
diff --git a/src/starboard/nplb/microphone_read_test.cc b/src/starboard/nplb/microphone_read_test.cc
index 6f80656..7df0260 100644
--- a/src/starboard/nplb/microphone_read_test.cc
+++ b/src/starboard/nplb/microphone_read_test.cc
@@ -35,16 +35,41 @@
info_array[0].id, info_array[0].max_sample_rate_hz, kBufferSize);
ASSERT_TRUE(SbMicrophoneIsValid(microphone));
- bool success = SbMicrophoneOpen(microphone);
- ASSERT_TRUE(success);
+ ASSERT_TRUE(SbMicrophoneOpen(microphone));
- void* audio_data[1024];
+ int requested_bytes = info_array[0].min_read_size;
+ std::vector<uint8_t> audio_data(requested_bytes, 0);
int read_bytes =
- SbMicrophoneRead(microphone, audio_data, sizeof(audio_data));
+ SbMicrophoneRead(microphone, &audio_data[0], audio_data.size());
EXPECT_GE(read_bytes, 0);
- success = SbMicrophoneClose(microphone);
- EXPECT_TRUE(success);
+ EXPECT_TRUE(SbMicrophoneClose(microphone));
+ SbMicrophoneDestroy(microphone);
+ }
+}
+
+TEST(SbMicrophoneReadTest, SunnyDayReadIsLargerThanMinReadSize) {
+ SbMicrophoneInfo info_array[kMaxNumberOfMicrophone];
+ int available_microphones =
+ SbMicrophoneGetAvailable(info_array, kMaxNumberOfMicrophone);
+ EXPECT_GE(available_microphones, 0);
+
+ if (available_microphones != 0) {
+ ASSERT_TRUE(SbMicrophoneIsSampleRateSupported(
+ info_array[0].id, info_array[0].max_sample_rate_hz));
+ SbMicrophone microphone = SbMicrophoneCreate(
+ info_array[0].id, info_array[0].max_sample_rate_hz, kBufferSize);
+ ASSERT_TRUE(SbMicrophoneIsValid(microphone));
+
+ ASSERT_TRUE(SbMicrophoneOpen(microphone));
+
+ int requested_bytes = info_array[0].min_read_size;
+ std::vector<uint8_t> audio_data(requested_bytes * 2, 0);
+ int read_bytes =
+ SbMicrophoneRead(microphone, &audio_data[0], audio_data.size());
+ EXPECT_GE(read_bytes, 0);
+
+ EXPECT_TRUE(SbMicrophoneClose(microphone));
SbMicrophoneDestroy(microphone);
}
}
@@ -62,22 +87,19 @@
info_array[0].id, info_array[0].max_sample_rate_hz, kBufferSize);
ASSERT_TRUE(SbMicrophoneIsValid(microphone));
- bool success = SbMicrophoneOpen(microphone);
- EXPECT_TRUE(success);
+ EXPECT_TRUE(SbMicrophoneOpen(microphone));
SbThreadSleep(50 * kSbTimeMillisecond);
- success = SbMicrophoneClose(microphone);
- EXPECT_TRUE(success);
+ EXPECT_TRUE(SbMicrophoneClose(microphone));
+ EXPECT_TRUE(SbMicrophoneOpen(microphone));
- success = SbMicrophoneOpen(microphone);
- EXPECT_TRUE(success);
-
- void* audio_data[16 * 1024];
+ int requested_bytes = info_array[0].min_read_size;
+ std::vector<uint8_t> audio_data(requested_bytes, 0);
int read_bytes =
- SbMicrophoneRead(microphone, audio_data, sizeof(audio_data));
+ SbMicrophoneRead(microphone, &audio_data[0], audio_data.size());
EXPECT_GE(read_bytes, 0);
- EXPECT_LT(read_bytes, sizeof(audio_data));
+ EXPECT_LT(read_bytes, audio_data.size());
SbMicrophoneDestroy(microphone);
}
@@ -96,14 +118,12 @@
info_array[0].id, info_array[0].max_sample_rate_hz, kBufferSize);
ASSERT_TRUE(SbMicrophoneIsValid(microphone));
- bool success = SbMicrophoneOpen(microphone);
- ASSERT_TRUE(success);
+ ASSERT_TRUE(SbMicrophoneOpen(microphone));
int read_bytes = SbMicrophoneRead(microphone, NULL, 0);
EXPECT_EQ(read_bytes, 0);
- success = SbMicrophoneClose(microphone);
- EXPECT_TRUE(success);
+ EXPECT_TRUE(SbMicrophoneClose(microphone));
SbMicrophoneDestroy(microphone);
}
}
@@ -121,14 +141,38 @@
info_array[0].id, info_array[0].max_sample_rate_hz, kBufferSize);
ASSERT_TRUE(SbMicrophoneIsValid(microphone));
- bool success = SbMicrophoneOpen(microphone);
- ASSERT_TRUE(success);
+ ASSERT_TRUE(SbMicrophoneOpen(microphone));
int read_bytes = SbMicrophoneRead(microphone, NULL, 1024);
EXPECT_LE(read_bytes, 0);
- success = SbMicrophoneClose(microphone);
- EXPECT_TRUE(success);
+ EXPECT_TRUE(SbMicrophoneClose(microphone));
+ SbMicrophoneDestroy(microphone);
+ }
+}
+
+TEST(SbMicrophoneReadTest, RainyDayAudioBufferSizeIsSmallerThanMinReadSize) {
+ SbMicrophoneInfo info_array[kMaxNumberOfMicrophone];
+ int available_microphones =
+ SbMicrophoneGetAvailable(info_array, kMaxNumberOfMicrophone);
+ EXPECT_GE(available_microphones, 0);
+
+ if (available_microphones != 0) {
+ ASSERT_TRUE(SbMicrophoneIsSampleRateSupported(
+ info_array[0].id, info_array[0].max_sample_rate_hz));
+ SbMicrophone microphone = SbMicrophoneCreate(
+ info_array[0].id, info_array[0].max_sample_rate_hz, kBufferSize);
+ ASSERT_TRUE(SbMicrophoneIsValid(microphone));
+
+ ASSERT_TRUE(SbMicrophoneOpen(microphone));
+
+ int requested_bytes = info_array[0].min_read_size;
+ std::vector<uint8_t> audio_data(requested_bytes / 2, 0);
+ int read_bytes =
+ SbMicrophoneRead(microphone, &audio_data[0], audio_data.size());
+ EXPECT_GE(read_bytes, 0);
+
+ EXPECT_TRUE(SbMicrophoneClose(microphone));
SbMicrophoneDestroy(microphone);
}
}
@@ -146,10 +190,12 @@
info_array[0].id, info_array[0].max_sample_rate_hz, kBufferSize);
ASSERT_TRUE(SbMicrophoneIsValid(microphone));
- void* audio_data[1024];
+ int requested_bytes = info_array[0].min_read_size;
+ std::vector<uint8_t> audio_data(requested_bytes, 0);
int read_bytes =
- SbMicrophoneRead(microphone, audio_data, sizeof(audio_data));
- EXPECT_EQ(read_bytes, 0);
+ SbMicrophoneRead(microphone, &audio_data[0], audio_data.size());
+ // An error should have occurred because open was not called.
+ EXPECT_LT(read_bytes, 0);
SbMicrophoneDestroy(microphone);
}
@@ -168,26 +214,24 @@
info_array[0].id, info_array[0].max_sample_rate_hz, kBufferSize);
ASSERT_TRUE(SbMicrophoneIsValid(microphone));
- bool success = SbMicrophoneOpen(microphone);
- EXPECT_TRUE(success);
+ EXPECT_TRUE(SbMicrophoneOpen(microphone));
+ EXPECT_TRUE(SbMicrophoneClose(microphone));
- success = SbMicrophoneClose(microphone);
- EXPECT_TRUE(success);
-
- void* audio_data[1024];
+ int requested_bytes = info_array[0].min_read_size;
+ std::vector<uint8_t> audio_data(requested_bytes, 0);
int read_bytes =
- SbMicrophoneRead(microphone, audio_data, sizeof(audio_data));
- // No data can be read.
- EXPECT_EQ(read_bytes, 0);
+ SbMicrophoneRead(microphone, &audio_data[0], audio_data.size());
+ // An error should have occurred because the microphone was closed.
+ EXPECT_LT(read_bytes, 0);
SbMicrophoneDestroy(microphone);
}
}
TEST(SbMicrophoneReadTest, RainyDayMicrophoneIsInvalid) {
- void* audio_data[1024];
+ std::vector<uint8_t> audio_data(1024, 0);
int read_bytes =
- SbMicrophoneRead(kSbMicrophoneInvalid, audio_data, sizeof(audio_data));
+ SbMicrophoneRead(kSbMicrophoneInvalid, &audio_data[0], audio_data.size());
EXPECT_LT(read_bytes, 0);
}
diff --git a/src/starboard/nplb/nplb.gyp b/src/starboard/nplb/nplb.gyp
index 437cc92..43143c2 100644
--- a/src/starboard/nplb/nplb.gyp
+++ b/src/starboard/nplb/nplb.gyp
@@ -21,6 +21,7 @@
'target_name': 'nplb',
'type': '<(gtest_target_type)',
'sources': [
+ '<(DEPTH)/starboard/common/test_main.cc',
'atomic_test.cc',
'audio_sink_create_test.cc',
'audio_sink_destroy_test.cc',
@@ -107,7 +108,6 @@
'log_raw_dump_stack_test.cc',
'log_raw_test.cc',
'log_test.cc',
- 'main.cc',
'memory_align_to_page_size_test.cc',
'memory_allocate_aligned_test.cc',
'memory_allocate_test.cc',
@@ -125,7 +125,6 @@
'microphone_create_test.cc',
'microphone_destroy_test.cc',
'microphone_get_available_test.cc',
- 'microphone_get_speech_api_key_test.cc',
'microphone_is_sample_rate_supported_test.cc',
'microphone_open_test.cc',
'microphone_read_test.cc',
diff --git a/src/starboard/nplb/system_get_property_test.cc b/src/starboard/nplb/system_get_property_test.cc
index de94895..ef4078f 100644
--- a/src/starboard/nplb/system_get_property_test.cc
+++ b/src/starboard/nplb/system_get_property_test.cc
@@ -70,6 +70,9 @@
BasicTest(kSbSystemPropertyChipsetModelNumber, false, true, __LINE__);
BasicTest(kSbSystemPropertyFirmwareVersion, false, true, __LINE__);
BasicTest(kSbSystemPropertyNetworkOperatorName, false, true, __LINE__);
+#if SB_VERSION(2)
+ BasicTest(kSbSystemPropertySpeechApiKey, false, true, __LINE__);
+#endif // SB_VERSION(2)
if (IsCEDevice(SbSystemGetDeviceType())) {
BasicTest(kSbSystemPropertyBrandName, true, true, __LINE__);
diff --git a/src/starboard/raspi/1/starboard_platform.gyp b/src/starboard/raspi/1/starboard_platform.gyp
index b866ee7..7e51179 100644
--- a/src/starboard/raspi/1/starboard_platform.gyp
+++ b/src/starboard/raspi/1/starboard_platform.gyp
@@ -233,8 +233,8 @@
'<(DEPTH)/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc',
'<(DEPTH)/starboard/shared/starboard/media/media_is_output_protected.cc',
'<(DEPTH)/starboard/shared/starboard/media/media_set_output_protection.cc',
- '<(DEPTH)/starboard/shared/starboard/media/mime_parser.cc',
- '<(DEPTH)/starboard/shared/starboard/media/mime_parser.h',
+ '<(DEPTH)/starboard/shared/starboard/media/mime_type.cc',
+ '<(DEPTH)/starboard/shared/starboard/media/mime_type.h',
'<(DEPTH)/starboard/shared/starboard/new.cc',
'<(DEPTH)/starboard/shared/starboard/player/filter/audio_decoder_internal.h',
'<(DEPTH)/starboard/shared/starboard/player/filter/audio_renderer_internal.cc',
diff --git a/src/starboard/raspi/1/system_get_property.cc b/src/starboard/raspi/1/system_get_property.cc
index 6b5cee9..50f9d92 100644
--- a/src/starboard/raspi/1/system_get_property.cc
+++ b/src/starboard/raspi/1/system_get_property.cc
@@ -47,6 +47,7 @@
case kSbSystemPropertyModelName:
case kSbSystemPropertyModelYear:
case kSbSystemPropertyNetworkOperatorName:
+ case kSbSystemPropertySpeechApiKey:
return false;
case kSbSystemPropertyFriendlyName:
diff --git a/src/starboard/raspi/directfb/README.md b/src/starboard/raspi/directfb/README.md
index 4d9d9be..a4b4ec7 100644
--- a/src/starboard/raspi/directfb/README.md
+++ b/src/starboard/raspi/directfb/README.md
@@ -31,7 +31,7 @@
## Modifications to /etc/directfbrc
-Open or create 'etc/directfbrc' (as root) and add the lines:
+Open or create '/etc/directfbrc' (as root) and add the lines:
graphics-vt
hardware
diff --git a/src/starboard/raspi/shared/configuration_public.h b/src/starboard/raspi/shared/configuration_public.h
index 15c18ca..0db1522 100644
--- a/src/starboard/raspi/shared/configuration_public.h
+++ b/src/starboard/raspi/shared/configuration_public.h
@@ -18,7 +18,7 @@
#define STARBOARD_RASPI_SHARED_CONFIGURATION_PUBLIC_H_
// The API version implemented by this platform.
-#define SB_API_VERSION 1
+#define SB_API_VERSION 2
// --- System Header Configuration -------------------------------------------
@@ -49,6 +49,9 @@
// Whether the current platform provides the standard header float.h.
#define SB_HAS_FLOAT_H 1
+// Whether the current platform has microphone supported.
+#define SB_HAS_MICROPHONE 0
+
// Type detection for wchar_t.
#if defined(__WCHAR_MAX__) && \
(__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff)
diff --git a/src/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc b/src/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc
index 9bfd9a7..0f417fd 100644
--- a/src/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc
+++ b/src/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc
@@ -16,10 +16,10 @@
#include "starboard/character.h"
#include "starboard/log.h"
-#include "starboard/shared/starboard/media/mime_parser.h"
+#include "starboard/shared/starboard/media/mime_type.h"
#include "starboard/string.h"
-using starboard::shared::starboard::media::MimeParser;
+using starboard::shared::starboard::media::MimeType;
SbMediaSupportType SbMediaCanPlayMimeAndKeySystem(const char* mime,
const char* key_system) {
@@ -37,27 +37,32 @@
return kSbMediaSupportTypeNotSupported;
}
}
- MimeParser parser(mime);
- if (!parser.is_valid()) {
+ MimeType mime_type(mime);
+ if (!mime_type.is_valid()) {
SB_DLOG(WARNING) << mime << " is not a valid mime type";
return kSbMediaSupportTypeNotSupported;
}
- if (parser.mime() == "application/octet-stream") {
+ int codecs_index = mime_type.GetParamIndexByName("codecs");
+ if (codecs_index != MimeType::kInvalidParamIndex && codecs_index != 0) {
+ SB_DLOG(WARNING) << mime << " is not a valid mime type";
+ return kSbMediaSupportTypeNotSupported;
+ }
+ if (mime_type.type() == "application" &&
+ mime_type.subtype() == "octet-stream") {
return kSbMediaSupportTypeProbably;
}
- if (parser.mime() == "audio/mp4") {
+ if (mime_type.type() == "audio" && mime_type.subtype() == "mp4") {
return kSbMediaSupportTypeProbably;
}
- if (parser.mime() == "video/mp4") {
+ if (mime_type.type() == "video" && mime_type.subtype() == "mp4") {
return kSbMediaSupportTypeProbably;
}
#if SB_HAS(MEDIA_WEBM_VP9_SUPPORT)
- if (parser.mime() == "video/webm") {
- if (!parser.HasParam("codecs")) {
+ if (mime_type.type() == "video" && mime_type.subtype() == "webm") {
+ if (codecs_index == MimeType::kInvalidParamIndex) {
return kSbMediaSupportTypeMaybe;
}
- std::string codecs = parser.GetParam("codecs");
- if (codecs == "vp9") {
+ if (mime_type.GetParamStringValue(0) == "vp9") {
return kSbMediaSupportTypeProbably;
}
return kSbMediaSupportTypeNotSupported;
diff --git a/src/starboard/shared/starboard/media/mime_parser.cc b/src/starboard/shared/starboard/media/mime_parser.cc
deleted file mode 100644
index 7db734a..0000000
--- a/src/starboard/shared/starboard/media/mime_parser.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// 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.
-
-#include "starboard/shared/starboard/media/mime_parser.h"
-
-#include <vector>
-
-#include "starboard/character.h"
-#include "starboard/log.h"
-#include "starboard/string.h"
-
-namespace starboard {
-namespace shared {
-namespace starboard {
-namespace media {
-
-namespace {
-
-void ToLower(std::string* string) {
- SB_DCHECK(string);
- for (size_t i = 0; i < string->size(); ++i) {
- (*string)[i] = SbCharacterToLower((*string)[i]);
- }
-}
-
-void Trim(std::string* string) {
- SB_DCHECK(string);
- while (!string->empty() && SbCharacterIsSpace(*string->rbegin())) {
- string->resize(string->size() - 1);
- }
- while (!string->empty() && SbCharacterIsSpace(*string->begin())) {
- string->erase(string->begin());
- }
-}
-
-bool IsSeparator(char ch, std::string separator) {
- if (separator.empty()) {
- return SbCharacterIsSpace(ch);
- }
- return separator.find(ch) != separator.npos;
-}
-
-// For any given string, split it into substrings separated by any character in
-// the |separator| string. If |separator| is empty string, treat any white
-// space as separators.
-std::vector<std::string> SplitString(std::string string,
- std::string separator = "") {
- std::vector<std::string> result;
- while (!string.empty()) {
- Trim(&string);
- if (string.empty()) {
- break;
- }
- bool added = false;
- for (size_t i = 0; i < string.size(); ++i) {
- if (IsSeparator(string[i], separator)) {
- result.push_back(string.substr(0, i));
- Trim(&result.back());
- string = string.substr(i + 1);
- added = true;
- break;
- }
- }
- if (!added) {
- Trim(&string);
- result.push_back(string);
- break;
- }
- }
- return result;
-}
-
-} // namespace
-
-MimeParser::MimeParser(std::string mime_with_params) {
- Trim(&mime_with_params);
- ToLower(&mime_with_params);
-
- std::vector<std::string> splits = SplitString(mime_with_params, ";");
- if (splits.empty()) {
- return; // It is invalid, leave |mime_| as empty.
- }
- mime_ = splits[0];
- // Mime is in the form of "video/mp4".
- if (SplitString(mime_, "/").size() != 2) {
- mime_.clear();
- return;
- }
- splits.erase(splits.begin());
-
- while (!splits.empty()) {
- std::string params = *splits.begin();
- splits.erase(splits.begin());
-
- // Param is in the form of 'name=value' or 'name="value"'.
- std::vector<std::string> name_and_value = SplitString(params, "=");
- if (name_and_value.size() != 2) {
- mime_.clear();
- return;
- }
- std::string name = name_and_value[0];
- std::string value = name_and_value[1];
-
- if (value.size() >= 2 && value[0] == '\"' &&
- value[value.size() - 1] == '\"') {
- value.erase(value.begin());
- value.resize(value.size() - 1);
- Trim(&value);
- }
-
- params_[name] = value;
- }
-}
-
-bool MimeParser::HasParam(const std::string& name) const {
- return params_.find(name) != params_.end();
-}
-
-std::string MimeParser::GetParam(const std::string& name) const {
- std::map<std::string, std::string>::const_iterator iter = params_.find(name);
- if (iter == params_.end()) {
- return "";
- }
- return iter->second;
-}
-
-} // namespace media
-} // namespace starboard
-} // namespace shared
-} // namespace starboard
diff --git a/src/starboard/shared/starboard/media/mime_parser.h b/src/starboard/shared/starboard/media/mime_parser.h
deleted file mode 100644
index b896b2d..0000000
--- a/src/starboard/shared/starboard/media/mime_parser.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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.
-
-#ifndef STARBOARD_SHARED_STARBOARD_MEDIA_MIME_PARSER_H_
-#define STARBOARD_SHARED_STARBOARD_MEDIA_MIME_PARSER_H_
-
-#include <map>
-#include <string>
-
-#include "starboard/shared/internal_only.h"
-
-namespace starboard {
-namespace shared {
-namespace starboard {
-namespace media {
-
-// This class can be used to parse media mime types with params. For example,
-// the following mime type 'video/mp4; codecs="avc1.4d401e"; width=640' will be
-// parsed into:
-// mime => video/mp4
-// param: codecs => avc1.4d401e
-// param: width => 640
-class MimeParser {
- public:
- explicit MimeParser(std::string mime_with_params);
-
- bool is_valid() const { return !mime_.empty(); }
- const std::string& mime() const { return mime_; }
-
- bool HasParam(const std::string& name) const;
- std::string GetParam(const std::string& name) const;
-
- private:
- std::string mime_;
- std::map<std::string, std::string> params_;
-};
-
-} // namespace media
-} // namespace starboard
-} // namespace shared
-} // namespace starboard
-
-#endif // STARBOARD_SHARED_STARBOARD_MEDIA_MIME_PARSER_H_
diff --git a/src/starboard/shared/starboard/media/mime_type.cc b/src/starboard/shared/starboard/media/mime_type.cc
new file mode 100644
index 0000000..d77b2d5
--- /dev/null
+++ b/src/starboard/shared/starboard/media/mime_type.cc
@@ -0,0 +1,217 @@
+// 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.
+
+#include "starboard/shared/starboard/media/mime_type.h"
+
+#include "starboard/character.h"
+#include "starboard/log.h"
+#include "starboard/string.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace media {
+
+namespace {
+
+typedef std::vector<std::string> Strings;
+
+MimeType::ParamType GetParamTypeByValue(const std::string& value) {
+ int count;
+ int i;
+ if (SbStringScanF(value.c_str(), "%d%n", &i, &count) == 1 &&
+ count == value.size()) {
+ return MimeType::kParamTypeInteger;
+ }
+ float f;
+ if (SbStringScanF(value.c_str(), "%g%n", &f, &count) == 1 &&
+ count == value.size()) {
+ return MimeType::kParamTypeFloat;
+ }
+ return MimeType::kParamTypeString;
+}
+
+bool ContainsSpace(const std::string& str) {
+ for (size_t i = 0; i < str.size(); ++i) {
+ if (SbCharacterIsSpace(str[i])) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Trim(std::string* str) {
+ while (!str->empty() && SbCharacterIsSpace(*str->begin())) {
+ str->erase(str->begin());
+ }
+ while (!str->empty() && SbCharacterIsSpace(*str->rbegin())) {
+ str->resize(str->size() - 1);
+ }
+}
+
+Strings SplitAndTrim(const std::string& str, char ch) {
+ Strings result;
+ size_t pos = 0;
+
+ for (;;) {
+ size_t next = str.find(ch, pos);
+ result.push_back(str.substr(pos, next - pos));
+ Trim(&result.back());
+ if (next == str.npos) {
+ break;
+ }
+ pos = next + 1;
+ }
+
+ return result;
+}
+
+} // namespace
+
+const int MimeType::kInvalidParamIndex = -1;
+
+MimeType::MimeType(const std::string& content_type) : is_valid_(false) {
+ Strings components = SplitAndTrim(content_type, ';');
+
+ SB_DCHECK(!components.empty());
+
+ // 1. Verify if there is a valid type/subtype in the very beginning.
+ if (ContainsSpace(components.front())) {
+ return;
+ }
+
+ std::vector<std::string> type_and_container =
+ SplitAndTrim(components.front(), '/');
+ if (type_and_container.size() != 2 || type_and_container[0].empty() ||
+ type_and_container[1].empty()) {
+ return;
+ }
+ type_ = type_and_container[0];
+ subtype_ = type_and_container[1];
+ components.erase(components.begin());
+
+ // 2. Verify the parameters have valid formats, we want to be strict here.
+ for (Strings::iterator iter = components.begin(); iter != components.end();
+ ++iter) {
+ std::vector<std::string> name_and_value = SplitAndTrim(*iter, '=');
+ if (name_and_value.size() != 2 || name_and_value[0].empty() ||
+ name_and_value[1].empty()) {
+ return;
+ }
+ Param param;
+ if (name_and_value[1].size() > 2 && name_and_value[1][0] == '\"' &&
+ *name_and_value[1].rbegin() == '\"') {
+ param.type = kParamTypeString;
+ param.value = name_and_value[1].substr(1, name_and_value[1].size() - 2);
+ } else {
+ param.type = GetParamTypeByValue(name_and_value[1]);
+ param.value = name_and_value[1];
+ }
+ param.name = name_and_value[0];
+ params_.push_back(param);
+ }
+
+ is_valid_ = true;
+}
+
+int MimeType::GetParamCount() const {
+ SB_DCHECK(is_valid());
+
+ return static_cast<int>(params_.size());
+}
+
+MimeType::ParamType MimeType::GetParamType(int index) const {
+ SB_DCHECK(is_valid());
+ SB_DCHECK(index < GetParamCount());
+
+ return params_[index].type;
+}
+
+const std::string& MimeType::GetParamName(int index) const {
+ SB_DCHECK(is_valid());
+ SB_DCHECK(index < GetParamCount());
+
+ return params_[index].name;
+}
+
+int MimeType::GetParamIntValue(int index) const {
+ SB_DCHECK(is_valid());
+ SB_DCHECK(index < GetParamCount());
+ SB_DCHECK(GetParamType(index) == kParamTypeInteger);
+
+ int i;
+ SbStringScanF(params_[index].value.c_str(), "%d", &i);
+ return i;
+}
+
+float MimeType::GetParamFloatValue(int index) const {
+ SB_DCHECK(is_valid());
+ SB_DCHECK(index < GetParamCount());
+ SB_DCHECK(GetParamType(index) == kParamTypeInteger ||
+ GetParamType(index) == kParamTypeFloat);
+
+ float f;
+ SbStringScanF(params_[index].value.c_str(), "%g", &f);
+
+ return f;
+}
+
+const std::string& MimeType::GetParamStringValue(int index) const {
+ SB_DCHECK(is_valid());
+ SB_DCHECK(index < GetParamCount());
+
+ return params_[index].value;
+}
+
+int MimeType::GetParamIntValue(const char* name, int default_value) const {
+ int index = GetParamIndexByName(name);
+ if (index != kInvalidParamIndex) {
+ return GetParamIntValue(index);
+ }
+ return default_value;
+}
+
+float MimeType::GetParamFloatValue(const char* name,
+ float default_value) const {
+ int index = GetParamIndexByName(name);
+ if (index != kInvalidParamIndex) {
+ return GetParamFloatValue(index);
+ }
+ return default_value;
+}
+
+const std::string& MimeType::GetParamStringValue(
+ const char* name,
+ const std::string& default_value) const {
+ int index = GetParamIndexByName(name);
+ if (index != kInvalidParamIndex) {
+ return GetParamStringValue(index);
+ }
+ return default_value;
+}
+
+int MimeType::GetParamIndexByName(const char* name) const {
+ for (size_t i = 0; i < params_.size(); ++i) {
+ if (SbStringCompareNoCase(params_[i].name.c_str(), name) == 0) {
+ return static_cast<int>(i);
+ }
+ }
+ return kInvalidParamIndex;
+}
+
+} // namespace media
+} // namespace starboard
+} // namespace shared
+} // namespace starboard
diff --git a/src/starboard/shared/starboard/media/mime_type.h b/src/starboard/shared/starboard/media/mime_type.h
new file mode 100644
index 0000000..eb5b2f2
--- /dev/null
+++ b/src/starboard/shared/starboard/media/mime_type.h
@@ -0,0 +1,95 @@
+// 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.
+
+#ifndef STARBOARD_SHARED_STARBOARD_MEDIA_MIME_TYPE_H_
+#define STARBOARD_SHARED_STARBOARD_MEDIA_MIME_TYPE_H_
+
+#include <string>
+#include <vector>
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace media {
+
+// This class can be used to parse a content type for media in the form of
+// "type/subtype; param1=value1; param2="value2". For example, the content type
+// "video/webm; codecs="vp9"; width=1920; height=1080; framerate=59.96" will be
+// parsed into:
+// type: video
+// subtype: webm
+// codecs: vp9
+// width: 1920
+// height: 1080
+// framerate: 59.96
+//
+// The following are the restrictions on the components:
+// 1. Type/subtype has to be in the very beginning.
+// 2. String values may be double quoted.
+// 3. Numeric values cannot be double quoted.
+class MimeType {
+ public:
+ enum ParamType {
+ kParamTypeInteger,
+ kParamTypeFloat,
+ kParamTypeString,
+ };
+
+ static const int kInvalidParamIndex;
+
+ explicit MimeType(const std::string& content_type);
+
+ bool is_valid() const { return is_valid_; }
+
+ const std::string& type() const { return type_; }
+ const std::string& subtype() const { return subtype_; }
+
+ int GetParamIndexByName(const char* name) const;
+ int GetParamCount() const;
+ ParamType GetParamType(int index) const;
+ const std::string& GetParamName(int index) const;
+
+ int GetParamIntValue(int index) const;
+ float GetParamFloatValue(int index) const;
+ const std::string& GetParamStringValue(int index) const;
+
+ int GetParamIntValue(const char* name, int default_value) const;
+ float GetParamFloatValue(const char* name, float default_value) const;
+ const std::string& GetParamStringValue(
+ const char* name,
+ const std::string& default_value) const;
+
+ private:
+ struct Param {
+ ParamType type;
+ std::string name;
+ std::string value;
+ };
+
+ // Use std::vector as the number of components are usually small and we'd like
+ // to keep the order of components.
+ typedef std::vector<Param> Params;
+
+ bool is_valid_;
+ std::string type_;
+ std::string subtype_;
+ Params params_;
+};
+
+} // namespace media
+} // namespace starboard
+} // namespace shared
+} // namespace starboard
+
+#endif // STARBOARD_SHARED_STARBOARD_MEDIA_MIME_TYPE_H_
diff --git a/src/starboard/shared/starboard/media/mime_type_test.cc b/src/starboard/shared/starboard/media/mime_type_test.cc
new file mode 100644
index 0000000..44d0371
--- /dev/null
+++ b/src/starboard/shared/starboard/media/mime_type_test.cc
@@ -0,0 +1,269 @@
+// 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.
+
+#include "starboard/shared/starboard/media/mime_type.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace media {
+namespace {
+
+TEST(MimeTypeTest, EmptyString) {
+ MimeType mime_type("");
+ EXPECT_FALSE(mime_type.is_valid());
+}
+
+// Valid mime type must have a type/subtype without space in between.
+TEST(MimeTypeTest, InvalidType) {
+ {
+ MimeType mime_type("video");
+ EXPECT_FALSE(mime_type.is_valid());
+ }
+
+ {
+ MimeType mime_type("video/");
+ EXPECT_FALSE(mime_type.is_valid());
+ }
+
+ {
+ MimeType mime_type("/mp4");
+ EXPECT_FALSE(mime_type.is_valid());
+ }
+
+ {
+ MimeType mime_type("video /mp4");
+ EXPECT_FALSE(mime_type.is_valid());
+ }
+
+ {
+ MimeType mime_type("video/ mp4");
+ EXPECT_FALSE(mime_type.is_valid());
+ }
+
+ {
+ MimeType mime_type("video / mp4");
+ EXPECT_FALSE(mime_type.is_valid());
+ }
+}
+
+TEST(MimeTypeTest, ValidContentTypeWithTypeAndSubtypeOnly) {
+ {
+ MimeType mime_type("video/mp4");
+ EXPECT_TRUE(mime_type.is_valid());
+ EXPECT_EQ("video", mime_type.type());
+ EXPECT_EQ("mp4", mime_type.subtype());
+ }
+
+ {
+ MimeType mime_type("audio/mp4");
+ EXPECT_TRUE(mime_type.is_valid());
+ }
+
+ {
+ MimeType mime_type("abc/xyz");
+ EXPECT_TRUE(mime_type.is_valid());
+ }
+}
+
+TEST(MimeTypeTest, TypeNotAtBeginning) {
+ {
+ MimeType mime_type(";video/mp4");
+ EXPECT_FALSE(mime_type.is_valid());
+ }
+
+ {
+ MimeType mime_type("codecs=\"abc\"; audio/mp4");
+ EXPECT_FALSE(mime_type.is_valid());
+ }
+}
+
+TEST(MimeTypeTest, EmptyComponent) {
+ {
+ MimeType mime_type("video/mp4;");
+ EXPECT_FALSE(mime_type.is_valid());
+ }
+
+ {
+ MimeType mime_type("video/mp4;;");
+ EXPECT_FALSE(mime_type.is_valid());
+ }
+
+ {
+ MimeType mime_type("audio/mp4; codecs=\"abc\";");
+ EXPECT_FALSE(mime_type.is_valid());
+ }
+}
+
+TEST(MimeTypeTest, ValidContentTypeWithParams) {
+ {
+ MimeType mime_type("video/mp4; name=123");
+ EXPECT_TRUE(mime_type.is_valid());
+ }
+
+ {
+ MimeType mime_type("audio/mp4;codecs=\"abc\"");
+ EXPECT_TRUE(mime_type.is_valid());
+ }
+
+ {
+ MimeType mime_type(" audio/mp4 ; codecs = \"abc\" ");
+ EXPECT_TRUE(mime_type.is_valid());
+ }
+}
+
+TEST(MimeTypeTest, GetParamIndexByName) {
+ MimeType mime_type("video/mp4; name=123");
+ EXPECT_EQ(MimeType::kInvalidParamIndex,
+ mime_type.GetParamIndexByName("video"));
+ EXPECT_EQ(MimeType::kInvalidParamIndex, mime_type.GetParamIndexByName("mp4"));
+ EXPECT_EQ(0, mime_type.GetParamIndexByName("name"));
+}
+
+TEST(MimeTypeTest, ParamCount) {
+ {
+ MimeType mime_type("video/mp4");
+ EXPECT_EQ(0, mime_type.GetParamCount());
+ }
+
+ {
+ MimeType mime_type("video/mp4; width=1920");
+ EXPECT_EQ(1, mime_type.GetParamCount());
+ }
+
+ {
+ MimeType mime_type("video/mp4; width=1920; height=1080");
+ EXPECT_EQ(2, mime_type.GetParamCount());
+ }
+}
+
+TEST(MimeTypeTest, GetParamType) {
+ {
+ MimeType mime_type("video/mp4; name0=123; name1=1.2; name2=xyz");
+ EXPECT_EQ(MimeType::kParamTypeInteger, mime_type.GetParamType(0));
+ EXPECT_EQ(MimeType::kParamTypeFloat, mime_type.GetParamType(1));
+ EXPECT_EQ(MimeType::kParamTypeString, mime_type.GetParamType(2));
+ }
+
+ {
+ MimeType mime_type("video/mp4; name0=\"123\"; name1=\"abc\"");
+ EXPECT_EQ(MimeType::kParamTypeString, mime_type.GetParamType(0));
+ EXPECT_EQ(MimeType::kParamTypeString, mime_type.GetParamType(1));
+ }
+
+ {
+ MimeType mime_type("video/mp4; name1=\" abc \"");
+ EXPECT_EQ(MimeType::kParamTypeString, mime_type.GetParamType(0));
+ }
+}
+
+TEST(MimeTypeTest, GetParamName) {
+ {
+ MimeType mime_type("video/mp4; name0=123; name1=1.2; name2=xyz");
+ EXPECT_EQ("name0", mime_type.GetParamName(0));
+ EXPECT_EQ("name1", mime_type.GetParamName(1));
+ EXPECT_EQ("name2", mime_type.GetParamName(2));
+ }
+}
+
+TEST(MimeTypeTest, GetParamIntValueWithIndex) {
+ {
+ MimeType mime_type("video/mp4; name=123");
+ EXPECT_EQ(123, mime_type.GetParamIntValue(0));
+ }
+
+ {
+ MimeType mime_type("video/mp4; width=1920; height=1080");
+ EXPECT_EQ(1920, mime_type.GetParamIntValue(0));
+ EXPECT_EQ(1080, mime_type.GetParamIntValue(1));
+ }
+
+ {
+ MimeType mime_type("audio/mp4; channels=6");
+ EXPECT_EQ(6, mime_type.GetParamIntValue(0));
+ }
+}
+
+TEST(MimeTypeTest, GetParamFloatValueWithIndex) {
+ {
+ MimeType mime_type("video/mp4; name0=123; name1=123.4");
+ EXPECT_FLOAT_EQ(123., mime_type.GetParamFloatValue(0));
+ EXPECT_FLOAT_EQ(123.4, mime_type.GetParamFloatValue(1));
+ }
+}
+
+TEST(MimeTypeTest, GetParamStringValueWithIndex) {
+ {
+ MimeType mime_type("video/mp4; name0=123; name1=abc; name2=\"xyz\"");
+ EXPECT_EQ("123", mime_type.GetParamStringValue(0));
+ EXPECT_EQ("abc", mime_type.GetParamStringValue(1));
+ EXPECT_EQ("xyz", mime_type.GetParamStringValue(2));
+ }
+
+ {
+ MimeType mime_type("video/mp4; name=\" xyz \"");
+ EXPECT_EQ(" xyz ", mime_type.GetParamStringValue(0));
+ }
+}
+
+TEST(MimeTypeTest, GetParamIntValueWithName) {
+ {
+ MimeType mime_type("video/mp4; name=123");
+ EXPECT_EQ(123, mime_type.GetParamIntValue("name", 0));
+ EXPECT_EQ(6, mime_type.GetParamIntValue("channels", 6));
+ }
+
+ {
+ MimeType mime_type("video/mp4; width=1920; height=1080");
+ EXPECT_EQ(1920, mime_type.GetParamIntValue("width", 0));
+ EXPECT_EQ(1080, mime_type.GetParamIntValue("height", 0));
+ }
+
+ {
+ MimeType mime_type("audio/mp4; channels=6");
+ EXPECT_EQ(6, mime_type.GetParamIntValue("channels", 0));
+ }
+}
+
+TEST(MimeTypeTest, GetParamFloatValueWithName) {
+ {
+ MimeType mime_type("video/mp4; name0=123; name1=123.4");
+ EXPECT_FLOAT_EQ(123.f, mime_type.GetParamFloatValue("name0", 0.f));
+ EXPECT_FLOAT_EQ(123.4f, mime_type.GetParamFloatValue("name1", 0.f));
+ EXPECT_FLOAT_EQ(59.96f, mime_type.GetParamFloatValue("framerate", 59.96f));
+ }
+}
+
+TEST(MimeTypeTest, GetParamStringValueWithName) {
+ {
+ MimeType mime_type("video/mp4; name0=123; name1=abc; name2=\"xyz\"");
+ EXPECT_EQ("123", mime_type.GetParamStringValue("name0", ""));
+ EXPECT_EQ("abc", mime_type.GetParamStringValue("name1", ""));
+ EXPECT_EQ("xyz", mime_type.GetParamStringValue("name2", ""));
+ EXPECT_EQ("h263", mime_type.GetParamStringValue("codecs", "h263"));
+ }
+
+ {
+ MimeType mime_type("video/mp4; name=\" xyz \"");
+ EXPECT_EQ(" xyz ", mime_type.GetParamStringValue("name", ""));
+ }
+}
+
+} // namespace
+} // namespace media
+} // namespace starboard
+} // namespace shared
+} // namespace starboard
diff --git a/src/starboard/starboard.gyp b/src/starboard/starboard.gyp
index 5677568..b89ff1a 100644
--- a/src/starboard/starboard.gyp
+++ b/src/starboard/starboard.gyp
@@ -60,26 +60,13 @@
'window.h',
],
'dependencies': [
+ '<(DEPTH)/<(starboard_path)/starboard_platform.gyp:starboard_platform',
'common/common.gyp:common',
],
+ 'export_dependent_settings': [
+ '<(DEPTH)/<(starboard_path)/starboard_platform.gyp:starboard_platform',
+ ],
'conditions': [
- ['starboard_path == ""', {
- # TODO: Make starboard_path required. This legacy condition is only
- # here to support semi-starboard platforms while they still exist.
- 'dependencies': [
- '<(DEPTH)/starboard/<(target_arch)/starboard_platform.gyp:starboard_platform',
- ],
- 'export_dependent_settings': [
- '<(DEPTH)/starboard/<(target_arch)/starboard_platform.gyp:starboard_platform',
- ],
- }, {
- 'dependencies': [
- '<(DEPTH)/<(starboard_path)/starboard_platform.gyp:starboard_platform',
- ],
- 'export_dependent_settings': [
- '<(DEPTH)/<(starboard_path)/starboard_platform.gyp:starboard_platform',
- ],
- }],
['final_executable_type=="shared_library"', {
'all_dependent_settings': {
'target_conditions': [
diff --git a/src/starboard/starboard_all.gyp b/src/starboard/starboard_all.gyp
index b97230b..1eb3b02 100644
--- a/src/starboard/starboard_all.gyp
+++ b/src/starboard/starboard_all.gyp
@@ -16,6 +16,9 @@
# Starboard project.
{
+ 'variables': {
+ 'has_platform_tests%' : '<!(python -c "import os.path; print os.path.isfile(\'<(starboard_path)/starboard_platform_tests.gyp\') & 1 | 0")',
+ },
'targets': [
{
# Note that this target must be in a separate GYP file from starboard.gyp,
@@ -31,6 +34,13 @@
'<(DEPTH)/starboard/nplb/nplb.gyp:*',
'<(DEPTH)/starboard/starboard.gyp:*',
],
+ 'conditions': [
+ ['has_platform_tests==1', {
+ 'dependencies': [
+ '<(DEPTH)/<(starboard_path)/starboard_platform_tests.gyp:starboard_platform_tests',
+ ],
+ }],
+ ],
},
],
}
diff --git a/src/starboard/stub/starboard_platform.gyp b/src/starboard/stub/starboard_platform.gyp
index bfacb36..63ca705 100644
--- a/src/starboard/stub/starboard_platform.gyp
+++ b/src/starboard/stub/starboard_platform.gyp
@@ -102,7 +102,6 @@
'<(DEPTH)/starboard/shared/stub/microphone_create.cc',
'<(DEPTH)/starboard/shared/stub/microphone_destroy.cc',
'<(DEPTH)/starboard/shared/stub/microphone_get_available.cc',
- '<(DEPTH)/starboard/shared/stub/microphone_get_speech_api_key.cc',
'<(DEPTH)/starboard/shared/stub/microphone_is_sample_rate_supported.cc',
'<(DEPTH)/starboard/shared/stub/microphone_open.cc',
'<(DEPTH)/starboard/shared/stub/microphone_read.cc',
diff --git a/src/starboard/system.h b/src/starboard/system.h
index c52a4e1..667cd1a 100644
--- a/src/starboard/system.h
+++ b/src/starboard/system.h
@@ -94,6 +94,14 @@
// A universally-unique ID for the current user.
kSbSystemPropertyPlatformUuid,
+
+#if SB_VERSION(2)
+ // The Google Speech API key. The platform manufacturer is responsible
+ // for registering a Google Speech API key for their products. In the API
+ // Console (http://developers.google.com/console), you are able to enable the
+ // Speech APIs and generate a Speech API key.
+ kSbSystemPropertySpeechApiKey,
+#endif // SB_VERSION(2)
} SbSystemPropertyId;
// Enumeration of device types.
diff --git a/src/starboard/time_zone.h b/src/starboard/time_zone.h
index ce67d09..25ac711 100644
--- a/src/starboard/time_zone.h
+++ b/src/starboard/time_zone.h
@@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Access to the system time zone information.
+// Module Overview: Starboard Time Zone module
+//
+// Provides access to the system time zone information.
#ifndef STARBOARD_TIME_ZONE_H_
#define STARBOARD_TIME_ZONE_H_
@@ -24,7 +26,7 @@
extern "C" {
#endif
-// The number of minutes west of the Greenwich Prime Meridian, NOT including any
+// The number of minutes west of the Greenwich Prime Meridian, NOT including
// Daylight Savings Time adjustments.
//
// For example: PST/PDT is 480 minutes (28800 seconds, 8 hours).
@@ -34,7 +36,7 @@
SB_EXPORT SbTimeZone SbTimeZoneGetCurrent();
// Gets the three-letter code of the current timezone in standard time,
-// regardless of current DST status. (e.g. "PST")
+// regardless of current Daylight Savings Time status. (e.g. "PST")
SB_EXPORT const char* SbTimeZoneGetName();
// Gets the three-letter code of the current timezone in Daylight Savings Time,
diff --git a/src/third_party/libjpeg/jmemnobs.c b/src/third_party/libjpeg/jmemnobs.c
index a360de8..935ef6e 100644
--- a/src/third_party/libjpeg/jmemnobs.c
+++ b/src/third_party/libjpeg/jmemnobs.c
@@ -23,7 +23,7 @@
#if defined(NEED_STARBOARD_MEMORY)
#include "starboard/memory.h"
#define malloc SbMemoryAllocate
-#define free SbMemoryFree
+#define free SbMemoryDeallocate
#elif !defined(HAVE_STDLIB_H) /* <stdlib.h> should declare malloc(),free() */
extern void * malloc JPP((size_t size));
extern void free JPP((void *ptr));
diff --git a/src/third_party/libpng/pngmem.c b/src/third_party/libpng/pngmem.c
index d19179d..1b4b88f 100644
--- a/src/third_party/libpng/pngmem.c
+++ b/src/third_party/libpng/pngmem.c
@@ -24,7 +24,7 @@
#if defined(STARBOARD)
# include "starboard/memory.h"
# define malloc SbMemoryAllocate
-# define free SbMemoryFree
+# define free SbMemoryDeallocate
#endif
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
diff --git a/src/third_party/openssl/openssl/crypto/LPdir_starboard.c b/src/third_party/openssl/openssl/crypto/LPdir_starboard.c
index f663a95..5daa624 100644
--- a/src/third_party/openssl/openssl/crypto/LPdir_starboard.c
+++ b/src/third_party/openssl/openssl/crypto/LPdir_starboard.c
@@ -52,7 +52,7 @@
(*ctx)->dir = SbDirectoryOpen(directory, NULL);
if (!SbDirectoryIsValid((*ctx)->dir)) {
- SbMemoryFree(*ctx);
+ SbMemoryDeallocate(*ctx);
*ctx = NULL;
return NULL;
}
@@ -70,7 +70,7 @@
{
if (ctx != NULL && *ctx != NULL) {
bool result = SbDirectoryClose((*ctx)->dir);
- SbMemoryFree(*ctx);
+ SbMemoryDeallocate(*ctx);
return (result ? 1 : 0);
}
return 0;
diff --git a/src/third_party/sqlite/amalgamation/sqlite3.c b/src/third_party/sqlite/amalgamation/sqlite3.c
index 25aa93a..5a56cc5 100644
--- a/src/third_party/sqlite/amalgamation/sqlite3.c
+++ b/src/third_party/sqlite/amalgamation/sqlite3.c
@@ -14473,7 +14473,7 @@
#if defined(STARBOARD)
#include "starboard/memory.h"
#define malloc SbMemoryAllocate
-#define free SbMemoryFree
+#define free SbMemoryDeallocate
#define realloc SbMemoryReallocate
#endif
diff --git a/src/third_party/zlib/zutil.c b/src/third_party/zlib/zutil.c
index bf2e3cc..fd3a67b 100644
--- a/src/third_party/zlib/zutil.c
+++ b/src/third_party/zlib/zutil.c
@@ -301,7 +301,7 @@
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
{
SB_UNREFERENCED_PARAMETER(opaque);
- SbMemoryFree(ptr);
+ SbMemoryDeallocate(ptr);
}
#endif /* STARBOARD */