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, &current_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, &current_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 */