Cleanup merge conflicts after merging Cobalt 24 support

Change-Id: I802473fd11c1f83f490c1845063b360bfcc763f8
diff --git a/LICENSE b/LICENSE
index d645695..6b2e4a9 100644
--- a/LICENSE
+++ b/LICENSE
@@ -200,3 +200,82 @@
    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.
+
+----------------------------------------------------------------------
+
+UNICODE LICENSE V3
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright © 2016-2023 Unicode, Inc.
+
+NOTICE TO USER: Carefully read the following legal agreement. BY
+DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
+SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
+TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
+DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of data files and any associated documentation (the "Data Files") or
+software and any associated documentation (the "Software") to deal in the
+Data Files or Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, and/or sell
+copies of the Data Files or Software, and to permit persons to whom the
+Data Files or Software are furnished to do so, provided that either (a)
+this copyright and permission notice appear with all copies of the Data
+Files or Software, or (b) this copyright and permission notice appear in
+associated Documentation.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
+THIRD PARTY RIGHTS.
+
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
+BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
+FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall
+not be used in advertising or otherwise to promote the sale, use or other
+dealings in these Data Files or Software without prior written
+authorization of the copyright holder.
+
+----------------------------------------------------------------------
+
+ICU License - ICU 1.8.1 to ICU 57.1
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1995-2016 International Business Machines Corporation and others
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, and/or sell copies of the Software, and to permit persons
+to whom the Software is furnished to do so, provided that the above
+copyright notice(s) and this permission notice appear in all copies of
+the Software and that both the above copyright notice(s) and this
+permission notice appear in supporting documentation.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
+SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in this Software without prior written authorization
+of the copyright holder.
+
+All trademarks and registered trademarks mentioned herein are the
+property of their respective owners.
diff --git a/NOTICE b/NOTICE
index 09628ff..5dd1ec8 100644
--- a/NOTICE
+++ b/NOTICE
@@ -24,3 +24,10 @@
 Copyright 2017 The Cobalt Authors. All Rights Reserved.
 Licensed under the Apache License, Version 2.0
 See https://cobalt.googlesource.com/cobalt/+/master/src/AUTHORS for the list of Cobalt authors.
+
+Code from ICU is:
+Copyright 2016-2023 Unicode, Inc.
+and
+Copyright (c) 1995-2016 International Business Machines Corporation and others
+All rights reserved.
+Licensed under UNICODE LICENSE V3 and the ICU License from https://github.com/unicode-org/icu/blob/main/LICENSE
diff --git a/plugin/Cobalt.conf.in b/plugin/Cobalt.conf.in
index 0bd2ef7..e8a1690 100644
--- a/plugin/Cobalt.conf.in
+++ b/plugin/Cobalt.conf.in
@@ -19,7 +19,11 @@
 advertisingid.add("ifa_type", "@PLUGIN_COBALT_IFA_TYPE@")
 advertisingid.add("lmt", "@PLUGIN_COBALT_LIMIT_AD_TRACKING@")
 
-if boolean("@advertisingid@"):
+if (
+    "@PLUGIN_COBALT_ADVERTISING_ID@" or
+    "@PLUGIN_COBALT_IFA_TYPE@" or
+    "@PLUGIN_COBALT_LIMIT_AD_TRACKING@"
+):
     configuration.add("advertisingid", advertisingid)
 
 systemproperties = JSON()
diff --git a/plugin/CobaltImplementation.cpp b/plugin/CobaltImplementation.cpp
index 3be1428..a9ea8bb 100644
--- a/plugin/CobaltImplementation.cpp
+++ b/plugin/CobaltImplementation.cpp
@@ -258,6 +258,7 @@
       Block();
       SbRdkQuit();
       Wait(Thread::BLOCKED | Thread::STOPPED | Thread::STOPPING, Core::infinite);
+      std::quick_exit(0);
     }
 
     uint32_t Configure(PluginHost::IShell* service) {
diff --git a/plugin/CobaltJsonRpc.cpp b/plugin/CobaltJsonRpc.cpp
index 2125e64..6a70cd7 100644
--- a/plugin/CobaltJsonRpc.cpp
+++ b/plugin/CobaltJsonRpc.cpp
@@ -23,10 +23,6 @@
 #include "Cobalt.h"
 #include "Module.h"
 
-#ifndef SYSLOG_GLOBAL
-#define SYSLOG_GLOBAL(CATEGORY, PARAMETERS) SYSLOG(CATEGORY, PARAMETERS)
-#endif /* SYSLOG_GLOBAL */
-
 namespace WPEFramework {
 namespace Plugin {
 
@@ -210,14 +206,14 @@
   Exchange::IDictionary *dict(
     _cobalt->QueryInterface<Exchange::IDictionary>());
   if (dict == nullptr) {
-    SYSLOG_GLOBAL(Logging::Error, (_T("IDictionary is not implemented")));
+    SYSLOG(Logging::Error, (_T("IDictionary is not implemented")));
   } else {
     std::string json;
     if (!dict->Get("settings", "accessibility", json)) {
-      SYSLOG_GLOBAL(Logging::Error, (_T("Cannot get 'accessibility' setting")));
+      SYSLOG(Logging::Error, (_T("Cannot get 'accessibility' setting")));
     }
     else if (!response.FromString(json)) {
-      SYSLOG_GLOBAL(Logging::Error, (_T("Cannot convert to JSON object")));
+      SYSLOG(Logging::Error, (_T("Cannot convert to JSON object")));
     }
     else {
       result = Core::ERROR_NONE;
@@ -243,14 +239,14 @@
     Exchange::IDictionary *dict(
       _cobalt->QueryInterface<Exchange::IDictionary>());
     if (dict == nullptr) {
-      SYSLOG_GLOBAL(Logging::Error, (_T("IDictionary is not implemented")));
+      SYSLOG(Logging::Error, (_T("IDictionary is not implemented")));
     } else {
       std::string json;
       if (!param.ToString(json)) {
-        SYSLOG_GLOBAL(Logging::Error, (_T("Cannot convert to string")));
+        SYSLOG(Logging::Error, (_T("Cannot convert to string")));
       }
       else if (!dict->Set("settings", "accessibility", json)) {
-        SYSLOG_GLOBAL(Logging::Error, (_T("Cannot set 'accessibility' setting")));
+        SYSLOG(Logging::Error, (_T("Cannot set 'accessibility' setting")));
       }
       else {
         result = Core::ERROR_NONE;
diff --git a/plugin/Module.h b/plugin/Module.h
index f0d8629..ec9c6d5 100644
--- a/plugin/Module.h
+++ b/plugin/Module.h
@@ -24,5 +24,9 @@
 #include <core/core.h>
 #include <plugins/plugins.h>
 
+#if !defined(THUNDER_VERSION) && defined(THUNDER_VERSION_MAJOR)
+#define THUNDER_VERSION THUNDER_VERSION_MAJOR
+#endif
+
 #undef EXTERNAL
 #define EXTERNAL
diff --git a/src/third_party/starboard/rdk/arm/configuration_constants.cc b/src/third_party/starboard/rdk/arm/configuration_constants.cc
index b0fb96e..024605a 100644
--- a/src/third_party/starboard/rdk/arm/configuration_constants.cc
+++ b/src/third_party/starboard/rdk/arm/configuration_constants.cc
@@ -158,8 +158,6 @@
 // The maximum number of users that can be signed in at the same time.
 const uint32_t kSbUserMaxSignedIn = 1;
 
-#if SB_API_VERSION >= 14
 // Defines maximum space in bytes the cache directory kSbSystemPathCacheDirectory can
 // use. The default value is 24MiB.
 const uint32_t kSbMaxSystemPathCacheDirectorySize = 24 << 20;  // 24MiB
-#endif //SB_API_VERSION >= 14
diff --git a/src/third_party/starboard/rdk/arm/toolchain/BUILD.gn b/src/third_party/starboard/rdk/arm/toolchain/BUILD.gn
index 84ef703..37c77e6 100644
--- a/src/third_party/starboard/rdk/arm/toolchain/BUILD.gn
+++ b/src/third_party/starboard/rdk/arm/toolchain/BUILD.gn
@@ -30,15 +30,14 @@
 
 import("//third_party/starboard/rdk/shared/build/rdk_toolchain.gni")
 
-rdk_gcc_toolchain("host") {
-  envprefix = "BUILD_"
-  extra_ldflags = ""
-  toolchain_args = {
-    current_os = "linux"
-    current_cpu = "x86"
-  }
-}
-
 rdk_gcc_toolchain("target") {
   envprefix = ""
 }
+
+rdk_gcc_toolchain("native_target") {
+  envprefix = ""
+  toolchain_args = {
+    is_starboard = false
+    is_native_target_build = true
+  }
+}
diff --git a/src/third_party/starboard/rdk/arm64/configuration_constants.cc b/src/third_party/starboard/rdk/arm64/configuration_constants.cc
index b0fb96e..024605a 100644
--- a/src/third_party/starboard/rdk/arm64/configuration_constants.cc
+++ b/src/third_party/starboard/rdk/arm64/configuration_constants.cc
@@ -158,8 +158,6 @@
 // The maximum number of users that can be signed in at the same time.
 const uint32_t kSbUserMaxSignedIn = 1;
 
-#if SB_API_VERSION >= 14
 // Defines maximum space in bytes the cache directory kSbSystemPathCacheDirectory can
 // use. The default value is 24MiB.
 const uint32_t kSbMaxSystemPathCacheDirectorySize = 24 << 20;  // 24MiB
-#endif //SB_API_VERSION >= 14
diff --git a/src/third_party/starboard/rdk/arm64/toolchain/BUILD.gn b/src/third_party/starboard/rdk/arm64/toolchain/BUILD.gn
index da593cb..37c77e6 100644
--- a/src/third_party/starboard/rdk/arm64/toolchain/BUILD.gn
+++ b/src/third_party/starboard/rdk/arm64/toolchain/BUILD.gn
@@ -30,15 +30,14 @@
 
 import("//third_party/starboard/rdk/shared/build/rdk_toolchain.gni")
 
-rdk_gcc_toolchain("host") {
-  envprefix = "BUILD_"
-  extra_ldflags = ""
-  toolchain_args = {
-    current_os = "linux"
-    current_cpu = "x64"
-  }
-}
-
 rdk_gcc_toolchain("target") {
   envprefix = ""
 }
+
+rdk_gcc_toolchain("native_target") {
+  envprefix = ""
+  toolchain_args = {
+    is_starboard = false
+    is_native_target_build = true
+  }
+}
diff --git a/src/third_party/starboard/rdk/rpi/configuration_constants.cc b/src/third_party/starboard/rdk/rpi/configuration_constants.cc
index 6602c64..2b70460 100644
--- a/src/third_party/starboard/rdk/rpi/configuration_constants.cc
+++ b/src/third_party/starboard/rdk/rpi/configuration_constants.cc
@@ -33,8 +33,6 @@
 
 #include "starboard/configuration_constants.h"
 
-#if SB_API_VERSION >= 12
-
 // Determines the threshhold of allocation size that should be done with mmap
 // (if available), rather than allocated within the core heap.
 const size_t kSbDefaultMmapThreshold = 256 * 1024U;
@@ -161,9 +159,5 @@
 // The maximum number of users that can be signed in at the same time.
 const uint32_t kSbUserMaxSignedIn = 1;
 
-#endif  // SB_API_VERSION >= 12
-
-#if SB_API_VERSION >= 14
 // The maximum size the cache directory is allowed to use in bytes.
 const uint32_t kSbMaxSystemPathCacheDirectorySize = 24 << 20;  // 24MiB
-#endif  // SB_API_VERSION >= 14
diff --git a/src/third_party/starboard/rdk/rpi/toolchain/BUILD.gn b/src/third_party/starboard/rdk/rpi/toolchain/BUILD.gn
index 84ef703..37c77e6 100644
--- a/src/third_party/starboard/rdk/rpi/toolchain/BUILD.gn
+++ b/src/third_party/starboard/rdk/rpi/toolchain/BUILD.gn
@@ -30,15 +30,14 @@
 
 import("//third_party/starboard/rdk/shared/build/rdk_toolchain.gni")
 
-rdk_gcc_toolchain("host") {
-  envprefix = "BUILD_"
-  extra_ldflags = ""
-  toolchain_args = {
-    current_os = "linux"
-    current_cpu = "x86"
-  }
-}
-
 rdk_gcc_toolchain("target") {
   envprefix = ""
 }
+
+rdk_gcc_toolchain("native_target") {
+  envprefix = ""
+  toolchain_args = {
+    is_starboard = false
+    is_native_target_build = true
+  }
+}
diff --git a/src/third_party/starboard/rdk/shared/BUILD.gn b/src/third_party/starboard/rdk/shared/BUILD.gn
index 6dfbcbd..0f8d33e 100644
--- a/src/third_party/starboard/rdk/shared/BUILD.gn
+++ b/src/third_party/starboard/rdk/shared/BUILD.gn
@@ -33,8 +33,7 @@
 declare_args() {
   rdk_enable_securityagent = true
   rdk_enable_ocdm = true
-  rdk_enable_cryptography = true
-  rdk_enable_cbcs = false
+  rdk_enable_rfc_api = false
 }
 
 pkg_config("glib") {
@@ -64,11 +63,9 @@
   ]
 }
 
-if (rdk_enable_cryptography) {
-  pkg_config("cryptography") {
-    packages = [ "WPEFrameworkCryptography" ]
-    defines = [ "HAS_CRYPTOGRAPHY=1" ]
-  }
+pkg_config("cryptography") {
+  packages = [ "WPEFrameworkCryptography" ]
+  defines = [ "HAS_CRYPTOGRAPHY=1" ]
 }
 
 if (rdk_enable_securityagent) {
@@ -88,48 +85,20 @@
 static_library("starboard_platform") {
   check_includes = false
 
+  # has_pedantic_warnings = true
+
   defines = []
 
   sources = [
     # Shared sources
     "//starboard/shared/gles/system_gles2.cc",
-    "//starboard/shared/iso/character_is_alphanumeric.cc",
-    "//starboard/shared/iso/character_is_digit.cc",
-    "//starboard/shared/iso/character_is_hex_digit.cc",
-    "//starboard/shared/iso/character_is_space.cc",
-    "//starboard/shared/iso/character_is_upper.cc",
-    "//starboard/shared/iso/character_to_lower.cc",
-    "//starboard/shared/iso/character_to_upper.cc",
     "//starboard/shared/iso/directory_close.cc",
     "//starboard/shared/iso/directory_get_next.cc",
     "//starboard/shared/iso/directory_open.cc",
-    "//starboard/shared/iso/double_absolute.cc",
-    "//starboard/shared/iso/double_exponent.cc",
-    "//starboard/shared/iso/double_floor.cc",
-    "//starboard/shared/iso/double_is_finite.cc",
-    "//starboard/shared/iso/double_is_nan.cc",
     "//starboard/shared/iso/memory_allocate_unchecked.cc",
-    "//starboard/shared/iso/memory_compare.cc",
-    "//starboard/shared/iso/memory_copy.cc",
-    "//starboard/shared/iso/memory_find_byte.cc",
     "//starboard/shared/iso/memory_free.cc",
-    "//starboard/shared/iso/memory_move.cc",
     "//starboard/shared/iso/memory_reallocate_unchecked.cc",
-    "//starboard/shared/iso/memory_set.cc",
-    "//starboard/shared/iso/string_compare.cc",
-    "//starboard/shared/iso/string_compare_all.cc",
-    "//starboard/shared/iso/string_find_character.cc",
-    "//starboard/shared/iso/string_find_last_character.cc",
-    "//starboard/shared/iso/string_find_string.cc",
-    "//starboard/shared/iso/string_get_length.cc",
-    "//starboard/shared/iso/string_get_length_wide.cc",
-    "//starboard/shared/iso/string_parse_double.cc",
-    "//starboard/shared/iso/string_parse_signed_integer.cc",
-    "//starboard/shared/iso/string_parse_uint64.cc",
-    "//starboard/shared/iso/string_parse_unsigned_integer.cc",
     "//starboard/shared/iso/string_scan.cc",
-    "//starboard/shared/iso/system_binary_search.cc",
-    "//starboard/shared/iso/system_sort.cc",
     "//starboard/shared/libevent/socket_waiter_add.cc",
     "//starboard/shared/libevent/socket_waiter_create.cc",
     "//starboard/shared/libevent/socket_waiter_destroy.cc",
@@ -144,7 +113,6 @@
     "//starboard/shared/linux/socket_get_interface_address.cc",
     "//starboard/shared/linux/system_get_random_data.cc",
     "//starboard/shared/linux/system_get_stack.cc",
-    "//starboard/shared/linux/system_get_total_cpu_memory.cc",
     "//starboard/shared/linux/system_get_used_cpu_memory.cc",
     "//starboard/shared/linux/system_is_debugger_attached.cc",
     "//starboard/shared/linux/thread_get_id.cc",
@@ -211,7 +179,6 @@
     "//starboard/shared/posix/storage_write_record.cc",
     "//starboard/shared/posix/string_compare_no_case.cc",
     "//starboard/shared/posix/string_compare_no_case_n.cc",
-    "//starboard/shared/posix/string_compare_wide.cc",
     "//starboard/shared/posix/string_format.cc",
     "//starboard/shared/posix/string_format_wide.cc",
     "//starboard/shared/posix/system_break_into_debugger.cc",
@@ -226,7 +193,6 @@
     "//starboard/shared/posix/time_get_now.cc",
     "//starboard/shared/posix/time_is_time_thread_now_supported.cc",
     "//starboard/shared/posix/time_zone_get_current.cc",
-    "//starboard/shared/posix/time_zone_get_name.cc",
     "//starboard/shared/pthread/condition_variable_broadcast.cc",
     "//starboard/shared/pthread/condition_variable_create.cc",
     "//starboard/shared/pthread/condition_variable_destroy.cc",
@@ -298,24 +264,16 @@
     "//starboard/shared/starboard/log_mutex.cc",
     "//starboard/shared/starboard/log_raw_format.cc",
     "//starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc",
-    "//starboard/shared/starboard/media/media_get_audio_configuration_5_1.cc",
     "//starboard/shared/starboard/media/media_get_audio_output_count_single_audio_output.cc",
-    "//starboard/shared/starboard/media/mime_type.cc",
     "//starboard/shared/starboard/memory.cc",
     "//starboard/shared/starboard/queue_application.cc",
-    "//starboard/shared/starboard/string_concat.cc",
-    "//starboard/shared/starboard/string_concat_wide.cc",
-    "//starboard/shared/starboard/string_copy.cc",
-    "//starboard/shared/starboard/string_copy_wide.cc",
     "//starboard/shared/starboard/string_duplicate.cc",
     "//starboard/shared/starboard/system_get_random_uint64.cc",
     "//starboard/shared/starboard/system_request_blur.cc",
     "//starboard/shared/starboard/system_request_focus.cc",
     "//starboard/shared/starboard/system_request_freeze.cc",
-    "//starboard/shared/starboard/system_request_pause.cc",
     "//starboard/shared/starboard/system_request_reveal.cc",
     "//starboard/shared/starboard/system_request_stop.cc",
-    "//starboard/shared/starboard/system_request_unpause.cc",
     "//starboard/shared/starboard/system_supports_resume.cc",
     "//starboard/shared/starboard/window_set_default_options.cc",
     "//starboard/shared/stub/decode_target_get_info.cc",
@@ -331,8 +289,6 @@
     "//starboard/shared/stub/microphone_is_sample_rate_supported.cc",
     "//starboard/shared/stub/microphone_open.cc",
     "//starboard/shared/stub/microphone_read.cc",
-    "//starboard/shared/stub/system_get_total_gpu_memory.cc",
-    "//starboard/shared/stub/system_get_used_gpu_memory.cc",
     "//starboard/shared/stub/system_hide_splash_screen.cc",
     "//starboard/shared/stub/system_raise_platform_error.cc",
     "//starboard/shared/stub/system_symbolize.cc",
@@ -376,6 +332,7 @@
     "main_rdk.cc",
     "media/gst_media_utils.cc",
     "media/media_get_audio_buffer_budget.cc",
+    "media/media_get_audio_configuration.cc",
     "media/media_get_buffer_alignment.cc",
     "media/media_get_buffer_allocation_unit.cc",
     "media/media_get_buffer_garbage_collection_duration_threshold.cc",
@@ -396,6 +353,7 @@
     "platform_service.h",
     "player/player_create.cc",
     "player/player_destroy.cc",
+    "player/player_get_audio_configuration.cc",
     "player/player_get_current_frame.cc",
     "player/player_get_info.cc",
     "player/player_get_maximum_number_of_samples_per_write.cc",
@@ -414,7 +372,6 @@
     "speech/speech_synthesis_is_supported.cc",
     "speech/speech_synthesis_speak.cc",
     "system/system_egl.cc",
-    "system/system_get_connection_type.cc",
     "system/system_get_device_type.cc",
     "system/system_get_extensions.cc",
     "system/system_get_path.cc",
@@ -422,8 +379,11 @@
     "system/system_has_capability.cc",
     "system/system_network_is_disconnected.cc",
     "system/system_request_conceal.cc",
-    "system/system_request_suspend.cc",
     "system/system_sign_with_certification_secret_key.cc",
+    "system/system_get_total_cpu_memory.cc",
+    "system/system_get_total_gpu_memory.cc",
+    "system/system_get_used_gpu_memory.cc",
+    "time_zone_get_name.cc",
     "window/window_create.cc",
     "window/window_destroy.cc",
     "window/window_get_diagonal_size_in_inches.cc",
@@ -435,13 +395,9 @@
   if (target_platform == "rdk-rpi") {
     sources -= [
       "//starboard/shared/gles/system_gles2.cc",
-      "//starboard/shared/starboard/media/media_get_audio_configuration_5_1.cc",
-      "//starboard/shared/starboard/media/media_get_audio_output_count_single_audio_output.cc",
     ]
     sources += [
       "//starboard/raspi/shared/system_gles2.cc",
-      "//starboard/shared/starboard/media/media_get_audio_output_count_single_audio_output.cc",
-      "//starboard/shared/starboard/media/media_get_audio_configuration_stereo_only.cc",
     ]
   }
 
@@ -465,18 +421,17 @@
     ":glib",
     ":gstreamer",
     ":wpeframework",
+    ":cryptography",
   ]
 
-  if (rdk_enable_cryptography) {
-    configs += [
-      ":cryptography",
-    ]
+  if (rdk_enable_rfc_api) {
     libs += [
       "rfcapi",
     ]
     cflags += [
       "-I=/usr/include/wdmp-c",
     ]
+    defines = [ "HAS_RFC_API=1" ]
   }
 
   if (rdk_enable_securityagent) {
@@ -487,10 +442,6 @@
     configs += [ ":ocdm" ]
   }
 
-  if (rdk_enable_cbcs) {
-    defines += [ "ENABLE_CBCS=1" ]
-  }
-
   public_deps = [
     "//starboard:starboard_headers_only",
     "//starboard/common",
@@ -502,7 +453,10 @@
   ]
 
   if (sb_is_evergreen_compatible) {
-    public_deps += [ "//starboard/elf_loader:evergreen_config" ]
+    public_deps += [
+      "//starboard/elf_loader:constants",
+      "//starboard/elf_loader:evergreen_config"
+    ]
     deps += [ "//third_party/crashpad/wrapper" ]
   } else {
     deps += [ "//third_party/crashpad/wrapper:wrapper_stub" ]
diff --git a/src/third_party/starboard/rdk/shared/accessibility_get_caption_settings.cc b/src/third_party/starboard/rdk/shared/accessibility_get_caption_settings.cc
index bfcdfb1..65817c8 100644
--- a/src/third_party/starboard/rdk/shared/accessibility_get_caption_settings.cc
+++ b/src/third_party/starboard/rdk/shared/accessibility_get_caption_settings.cc
@@ -34,7 +34,6 @@
 
 #include "third_party/starboard/rdk/shared/rdkservices.h"
 
-#if SB_API_VERSION >= 12 || SB_HAS(CAPTIONS)
 bool SbAccessibilityGetCaptionSettings(
     SbAccessibilityCaptionSettings* caption_settings) {
   if (!caption_settings ||
@@ -45,4 +44,3 @@
 
   return third_party::starboard::rdk::shared::Accessibility::GetCaptionSettings(caption_settings);
 }
-#endif  // SB_API_VERSION >= 12 || SB_HAS(CAPTIONS)
diff --git a/src/third_party/starboard/rdk/shared/accessibility_set_captions_enabled.cc b/src/third_party/starboard/rdk/shared/accessibility_set_captions_enabled.cc
index 2297a47..5b7faa7 100644
--- a/src/third_party/starboard/rdk/shared/accessibility_set_captions_enabled.cc
+++ b/src/third_party/starboard/rdk/shared/accessibility_set_captions_enabled.cc
@@ -30,8 +30,6 @@
 #include "starboard/accessibility.h"
 #include "starboard/configuration.h"
 
-#if SB_API_VERSION >= 12 || SB_HAS(CAPTIONS)
 bool SbAccessibilitySetCaptionsEnabled(bool enabled) {
   return false;
 }
-#endif  // SB_API_VERSION >= 12 || SB_HAS(CAPTIONS)
diff --git a/src/third_party/starboard/rdk/shared/application_rdk.cc b/src/third_party/starboard/rdk/shared/application_rdk.cc
index 164a19b..cbfa0f7 100644
--- a/src/third_party/starboard/rdk/shared/application_rdk.cc
+++ b/src/third_party/starboard/rdk/shared/application_rdk.cc
@@ -45,6 +45,7 @@
 #include <sys/eventfd.h>
 #include <sys/timerfd.h>
 #include <unistd.h>
+#include <malloc.h>
 
 namespace third_party {
 namespace starboard {
@@ -95,8 +96,14 @@
   }
 }
 
+#if SB_API_VERSION >= 15
+Application::Application(SbEventHandleCallback sb_event_handle_callback)
+  : QueueApplication(sb_event_handle_callback)
+#else
 Application::Application()
-  : input_handler_(new EssInput)
+  : QueueApplication()
+#endif
+  , input_handler_(new EssInput)
   , hang_monitor_(new HangMonitor("Application")) {
   essos_context_recycle_ = !!getenv("COBALT_ESSOS_CONTEXT_DESTROY");
   BuildEssosContext();
@@ -133,6 +140,8 @@
   using ::starboard::shared::starboard::media::MimeSupportabilityCache;
   MimeSupportabilityCache::GetInstance()->SetCacheEnabled(true);
   KeySystemSupportabilityCache::GetInstance()->SetCacheEnabled(true);
+
+  ScheduleMemoryUsageCheck();
 }
 
 void Application::Teardown() {
@@ -246,15 +255,9 @@
 }
 
 void Application::Inject(Event* e) {
-#if SB_API_VERSION >= 13
   if (e && e->event && e->event->type == kSbEventTypeFreeze) {
     player::ForceStop();
   }
-#else
-  if (e && e->event && e->event->type == kSbEventTypeSuspend) {
-    player::ForceStop();
-  }
-#endif
 
   QueueApplication::Inject(e);
 }
@@ -388,6 +391,48 @@
   }, nullptr, 0);
 }
 
+void Application::ReleaseMemory() {
+  Inject(new Event(kSbEventTypeLowMemory, NULL, [](void*) {
+    malloc_trim(0);
+  }));
+}
+
+void Application::ScheduleMemoryUsageCheck(SbTime delay) {
+  SbEventSchedule([](void* data) {
+    SbTime back_off_timeout = Application::Get()->CheckMemoryUsage();
+    if (back_off_timeout && back_off_timeout != kSbTimeMax)
+      Application::Get()->ScheduleMemoryUsageCheck(back_off_timeout);
+  }, nullptr, delay);
+}
+
+SbTime Application::CheckMemoryUsage() {
+  static const int64_t kCPUMemoryPressureLimit = ([]() -> int64_t {
+    const char* env = std::getenv("COBALT_CPU_MEM_PRESSURE_IN_MB");
+    int64_t limit_in_mb = SB_INT64_C(400);
+    if( env ) {
+      int64_t t = strtol(env, nullptr, 0);
+      if ( t >= 0 )
+        limit_in_mb = t;
+    }
+    int64_t total_in_bytes = SbSystemGetTotalCPUMemory();
+    return std::min(total_in_bytes, limit_in_mb * 1024 * 1024);
+  })();
+
+  if (!kCPUMemoryPressureLimit)
+    return kSbTimeMax;
+
+  int64_t usage_in_bytes = SbSystemGetUsedCPUMemory();
+  if (kCPUMemoryPressureLimit < usage_in_bytes) {
+    SB_LOG(INFO) << "Triggering memory pressure event. Current CPU mem. usage: "
+                 << uint64_t(usage_in_bytes / 1024) << " kb, pressure limit: "
+                 << uint64_t(kCPUMemoryPressureLimit / 1024) << " kb.";
+    ReleaseMemory();
+    return 5 * kSbTimeSecond;
+  }
+
+  return kSbTimeSecond;
+}
+
 }  // namespace shared
 }  // namespace rdk
 }  // namespace starboard
diff --git a/src/third_party/starboard/rdk/shared/application_rdk.h b/src/third_party/starboard/rdk/shared/application_rdk.h
index 909ee89..1bd3dda 100644
--- a/src/third_party/starboard/rdk/shared/application_rdk.h
+++ b/src/third_party/starboard/rdk/shared/application_rdk.h
@@ -53,7 +53,11 @@
 
 class Application : public ::starboard::shared::starboard::QueueApplication {
  public:
+#if SB_API_VERSION >= 15
+  explicit Application(SbEventHandleCallback sb_event_handle_callback);
+#else
   Application();
+#endif  // SB_API_VERSION >= 15
   ~Application() override;
 
   static third_party::starboard::rdk::shared::Application* Get() {
@@ -100,6 +104,10 @@
   void BuildEssosContext();
   void FatalError();
 
+  void ScheduleMemoryUsageCheck(SbTime delay = kSbTimeSecond);
+  SbTime CheckMemoryUsage();
+  void ReleaseMemory();
+
   static EssTerminateListener terminateListener;
   static EssKeyListener keyListener;
   static EssSettingsListener settingsListener;
diff --git a/src/third_party/starboard/rdk/shared/audio_sink/gstreamer_audio_sink_type.cc b/src/third_party/starboard/rdk/shared/audio_sink/gstreamer_audio_sink_type.cc
index e1b5787..c78d6b1 100644
--- a/src/third_party/starboard/rdk/shared/audio_sink/gstreamer_audio_sink_type.cc
+++ b/src/third_party/starboard/rdk/shared/audio_sink/gstreamer_audio_sink_type.cc
@@ -128,7 +128,7 @@
   GstElement* audiosink_{nullptr};
   GMainLoop* mainloop_{nullptr};
   GMainContext* main_loop_context_{nullptr};
-  guint source_id_{0};
+  int source_id_{-1};
   bool destroying_{false};
   bool enough_data_{false};
   std::string file_name_;
@@ -193,7 +193,7 @@
   appsrc_ = gst_element_factory_make("appsrc", "source");
   GstAppSrcCallbacks callbacks = {&GStreamerAudioSink::AppSrcNeedData,
                                   &GStreamerAudioSink::AppSrcEnoughData,
-                                  nullptr};
+                                  nullptr, nullptr};
   gst_app_src_set_callbacks(GST_APP_SRC(appsrc_), &callbacks, this, nullptr);
   gst_app_src_set_max_bytes(GST_APP_SRC(appsrc_),
                             kFramesPerRequest * GetBytesPerFrame());
diff --git a/src/third_party/starboard/rdk/shared/build/linux/BUILD.gn b/src/third_party/starboard/rdk/shared/build/linux/BUILD.gn
new file mode 100644
index 0000000..f07772e
--- /dev/null
+++ b/src/third_party/starboard/rdk/shared/build/linux/BUILD.gn
@@ -0,0 +1,49 @@
+# Copyright 2023 The Cobalt Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Copyright 2021 The Cobalt Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//third_party/starboard/rdk/shared/build/rdk_toolchain.gni")
+
+rdk_gcc_toolchain("x86") {
+  envprefix = "BUILD_"
+  extra_ldflags = ""
+  toolchain_args = {
+    current_os = "linux"
+    current_cpu = "x86"
+  }
+}
+
+rdk_gcc_toolchain("x64") {
+  envprefix = "BUILD_"
+  extra_ldflags = ""
+  toolchain_args = {
+    current_os = "linux"
+    current_cpu = "x64"
+  }
+}
diff --git a/src/third_party/starboard/rdk/shared/build/rdk_toolchain.gni b/src/third_party/starboard/rdk/shared/build/rdk_toolchain.gni
index f533c5d..8f60930 100644
--- a/src/third_party/starboard/rdk/shared/build/rdk_toolchain.gni
+++ b/src/third_party/starboard/rdk/shared/build/rdk_toolchain.gni
@@ -58,7 +58,7 @@
       if (defined(invoker.toolchain_args)) {
         forward_variables_from(invoker.toolchain_args, "*")
       }
-#      is_clang = false
+      is_clang = false
     }
   }
 }
diff --git a/src/third_party/starboard/rdk/shared/configuration.cc b/src/third_party/starboard/rdk/shared/configuration.cc
index 46edac4..070344c 100644
--- a/src/third_party/starboard/rdk/shared/configuration.cc
+++ b/src/third_party/starboard/rdk/shared/configuration.cc
@@ -30,8 +30,8 @@
 
 #include "third_party/starboard/rdk/shared/configuration.h"
 
-#include "cobalt/extension/configuration.h"
 #include "starboard/common/configuration_defaults.h"
+#include "starboard/extension/configuration.h"
 
 #include "third_party/starboard/rdk/shared/libcobalt.h"
 
@@ -76,6 +76,7 @@
     &::starboard::common::CobaltRasterizerTypeDefault,
     &::starboard::common::CobaltEnableJitDefault,
     &::starboard::common::CobaltFallbackSplashScreenTopicsDefault,
+    &::starboard::common::CobaltCanStoreCompiledJavascriptDefault,
 };
 
 }  // namespace
diff --git a/src/third_party/starboard/rdk/shared/drm/drm_system_ocdm.cc b/src/third_party/starboard/rdk/shared/drm/drm_system_ocdm.cc
index 6a67de6..f33c652 100644
--- a/src/third_party/starboard/rdk/shared/drm/drm_system_ocdm.cc
+++ b/src/third_party/starboard/rdk/shared/drm/drm_system_ocdm.cc
@@ -334,6 +334,11 @@
                                  const char url[],
                                  const uint8_t challenge[],
                                  const uint16_t challenge_length) {
+  if (challenge_length == 0) {
+    Session::OnError(ocdm_session, user_data, "Empty challenge");
+    return;
+  }
+
   Session* session = static_cast<Session*>(user_data);
   std::string id;
   int ticket;
@@ -750,28 +755,31 @@
   if ( !g_ocdmGetMetricSystemData )
     return nullptr;
 
-  int i = 1;
-  do {
-    uint32_t buffer_length =  i * 4 * 1024;
+  const int kMaxRetry = 5;
+  for (int i = 0; i < kMaxRetry; ++i) {
+    uint32_t buffer_length =  ( 1 << i ) * 4 * 1024;
 
     std::vector<uint8_t> tmp;
     tmp.resize(buffer_length);
 
-    auto rc = g_ocdmGetMetricSystemData(ocdm_system_, &buffer_length, tmp.data());
-    if ( rc == ERROR_BUFFER_TOO_SMALL && ++i <= 4 ) {
-      continue;
-    }
+    const uint32_t kBufferTooSmallErrorCode = 4; // ERROR_BUFFER_TOO_SMALL
 
+    auto rc = g_ocdmGetMetricSystemData(ocdm_system_, &buffer_length, tmp.data());
     if ( rc == ERROR_NONE ) {
       uint16_t out_length = (((buffer_length * 8) / 6) + 4) * sizeof(TCHAR);
       metrics_.resize(out_length, '\0');
       out_length = WPEFramework::Core::URL::Base64Encode(tmp.data(), buffer_length, reinterpret_cast<char*>(metrics_.data()), out_length, false);
       metrics_.resize(out_length);
-    }  else  {
-      SB_LOG(ERROR) << "Failed to get drm metrics, rc = " << rc;
+    } else if ( rc == kBufferTooSmallErrorCode && i < (kMaxRetry - 1) ) {
+      SB_LOG(INFO) << "GetMetrics: buffer is too small, rc = " << rc << ", i = " << i;
+      continue;
+    } else {
+      metrics_.resize(0);
+      SB_LOG(ERROR) << "GetMetrics: failed, rc = " << rc;
     }
 
-  } while(false);
+    break;
+  }
 
   *size = static_cast<int>(metrics_.size());
   return metrics_.data();
diff --git a/src/third_party/starboard/rdk/shared/drm/gst_decryptor_ocdm.cc b/src/third_party/starboard/rdk/shared/drm/gst_decryptor_ocdm.cc
index 0f47544..3c4642a 100644
--- a/src/third_party/starboard/rdk/shared/drm/gst_decryptor_ocdm.cc
+++ b/src/third_party/starboard/rdk/shared/drm/gst_decryptor_ocdm.cc
@@ -24,6 +24,7 @@
 
 #include <gst/gst.h>
 #include <gst/base/gstbasetransform.h>
+#include <gst/base/gstbytereader.h>
 
 #include <opencdm/open_cdm.h>
 
@@ -130,9 +131,26 @@
         gst_buffer_unmap(key, &map_info);
       }
 
+      uint32_t total_clear = 0;
+      uint32_t total_encrypted = 0;
+      GstMapInfo sample_map;
+      if (gst_buffer_map(subsamples, &sample_map, GST_MAP_READ)) {
+        GstByteReader* reader = gst_byte_reader_new(sample_map.data, sample_map.size);
+        for (uint32_t i = 0; i < subsample_count; ++i) {
+          uint16_t clear = 0;
+          uint32_t encrypted = 0;
+          gst_byte_reader_get_uint16_be(reader, &clear);
+          gst_byte_reader_get_uint32_be(reader, &encrypted);
+          total_clear += clear;
+          total_encrypted += encrypted;
+        }
+        gst_byte_reader_free(reader);
+        gst_buffer_unmap(subsamples, &sample_map);
+      }
+
       GST_TRACE_OBJECT(self, "buf=(%" GST_PTR_FORMAT "), "
-                       "subsample_count=%u, subsamples=(%p), iv=(%p), key=(%p : %s)",
-                       buffer, subsample_count, subsamples, iv, key, md5sum);
+                       "subsample_count=%u, subsamples=(%p), clear=%u, encrypted=%u, iv=(%p), key=(%p : %s)",
+                       buffer, subsample_count, subsamples, total_clear, total_encrypted, iv, key, md5sum);
 
       g_free(md5sum);
     }
@@ -230,7 +248,7 @@
     }
 
     if ( rc != 0 ) {
-      if ( rc == ERROR_INVALID_SESSION ) {
+      if ( rc == (int)ERROR_INVALID_SESSION ) {
         GST_DEBUG_OBJECT(self, "Invalid session. Probably due to player shutdown.");
         return GST_BASE_TRANSFORM_FLOW_DROPPED;
       }
@@ -432,14 +450,6 @@
 
   const GValue* value = nullptr;
 
-#if !(defined(ENABLE_CBCS) && ENABLE_CBCS)
-  const char* cipher_mode = gst_structure_get_string(info, "cipher-mode");
-  if ( g_strcmp0(cipher_mode, "cbcs") == 0 ) {
-    GST_ELEMENT_ERROR (self, STREAM, DECRYPT, ("Decryption failed"), ("Unsupported chipher-mode = %s", cipher_mode));
-    goto exit;
-  }
-#endif
-
   value = gst_structure_get_value(info, "kid");
   if (!value) {
     GST_ELEMENT_ERROR (self, STREAM, DECRYPT_NOKEY, ("No key ID available for encrypted sample"), (NULL));
diff --git a/src/third_party/starboard/rdk/shared/ess_input.cc b/src/third_party/starboard/rdk/shared/ess_input.cc
index 86feef8..24926e1 100644
--- a/src/third_party/starboard/rdk/shared/ess_input.cc
+++ b/src/third_party/starboard/rdk/shared/ess_input.cc
@@ -355,6 +355,9 @@
     case KEY_KPLEFTPAREN:
      return kSbKeyLaunchThisApplication;
 
+    case KEY_F8:
+     return kSbKeyMicrophone;
+
     case KEY_UNKNOWN:
       break;
   }
@@ -398,61 +401,6 @@
   return kSbKeyModifiersNone;
 }
 
-bool IsYouTubeCompliantKey(SbKey key) {
-  // Returns true if `key` is supported by YouTube apps.
-  // See 'Remote keys requirements' from
-  //  https://developers.google.com/youtube/living-room/certification/software-certification-2023#remote-keys-and-events
-  // section:
-  // '8.1.2 Device remote keys not implemented by the YouTube application or reserved for device system functions MUST NOT dispatch any key event or key code.'
-  switch (key) {
-    case kSbKeyLeft:
-    case kSbKeyRight:
-    case kSbKeyUp:
-    case kSbKeyDown:
-    case kSbKeyReturn:
-    case kSbKeyEscape:
-    case kSbKeyPlay:
-    case kSbKeyPause:
-    case kSbKeyMediaPlayPause:
-    case kSbKeyMediaStop:
-    case kSbKeyMediaFastForward:
-    case kSbKeyMediaRewind:
-    case kSbKeySpace:
-    case kSbKeyBackspace:
-    case kSbKeyDelete:
-    case kSbKeyBrowserSearch:
-    case kSbKeyMicrophone:
-    case kSbKeyMediaPrevTrack:
-    case kSbKeyMediaNextTrack:
-    case kSbKeySubtitle:
-    case kSbKeyRed:
-    case kSbKeyGreen:
-    case kSbKeyYellow:
-    case kSbKeyBlue:
-    case kSbKeyLaunchThisApplication:
-    case kSbKey0:
-    case kSbKey1:
-    case kSbKey2:
-    case kSbKey3:
-    case kSbKey4:
-    case kSbKey5:
-    case kSbKey6:
-    case kSbKey7:
-    case kSbKey8:
-    case kSbKey9:
-    case kSbKeyChannelUp:
-    case kSbKeyChannelDown:
-    case kSbKeyLast:
-    case kSbKeyMediaAudioTrack:
-    case kSbKeyInfo:
-    case kSbKeyGuide:
-      return true;
-    default:
-      break;
-  }
-  return false;
-}
-
 }  // namespace
 
 EssInput::EssInput() : key_repeat_interval_(kKeyHoldTime) {
@@ -464,21 +412,13 @@
 
 void EssInput::CreateKey(unsigned int key, SbInputEventType type, unsigned int modifiers, bool repeatable) {
   SbKey sb_key = KeyCodeToSbKey(key);
-  if (sb_key == kSbKeyUnknown) {
-    DeleteRepeatKey();
-    return;
-  }
-
-  if (!IsYouTubeCompliantKey(sb_key)) {
-    DeleteRepeatKey();
-    return;
-  }
+  // if (sb_key == kSbKeyUnknown) {
+  //   DeleteRepeatKey();
+  //   return;
+  // }
 
   SbInputData* data = new SbInputData();
   memset(data, 0, sizeof(*data));
-#if SB_API_VERSION < 13
-  data->timestamp = SbTimeGetMonotonicNow();
-#endif
   data->type = type;
   data->device_type = kSbInputDeviceTypeRemote;
   data->device_id = 1;  // kKeyboardDeviceId;
diff --git a/src/third_party/starboard/rdk/shared/hang_detector.cc b/src/third_party/starboard/rdk/shared/hang_detector.cc
index 74c5708..c3a5130 100644
--- a/src/third_party/starboard/rdk/shared/hang_detector.cc
+++ b/src/third_party/starboard/rdk/shared/hang_detector.cc
@@ -39,7 +39,11 @@
 
 namespace {
 
-const uint32_t kMaxExpirationCount = 6;
+#if defined(COBALT_BUILD_TYPE_GOLD)
+const int32_t kMaxExpirationCount = 6;
+#else
+const int32_t kMaxExpirationCount = 18;
+#endif
 
 pid_t get_tid() {
 #ifdef SYS_gettid
diff --git a/src/third_party/starboard/rdk/shared/libcobalt.cc b/src/third_party/starboard/rdk/shared/libcobalt.cc
index 2fde63e..088d005 100644
--- a/src/third_party/starboard/rdk/shared/libcobalt.cc
+++ b/src/third_party/starboard/rdk/shared/libcobalt.cc
@@ -61,83 +61,39 @@
     Application::Get()->Link(link);
   }
 
-  void RequestSuspend() {
+  void RequestFreeze() {
     starboard::ScopedLock lock(mutex_);
     WaitForApp(lock);
     starboard::Semaphore sem;
-#if SB_API_VERSION >= 13
     Application::Get()->Freeze(
       &sem,
       [](void* ctx) {
         reinterpret_cast<starboard::Semaphore*>(ctx)->Put();
       });
-#else
-    Application::Get()->Suspend(
-      &sem,
-      [](void* ctx) {
-        reinterpret_cast<starboard::Semaphore*>(ctx)->Put();
-      });
-#endif
     sem.Take();
   }
 
-  void RequestResume() {
+  void RequestFocus() {
     starboard::ScopedLock lock(mutex_);
     WaitForApp(lock);
     starboard::Semaphore sem;
-#if SB_API_VERSION >= 13
     Application::Get()->Focus(
       &sem,
       [](void* ctx) {
         reinterpret_cast<starboard::Semaphore*>(ctx)->Put();
       });
-#else
-    Application::Get()->Unpause(
-      &sem,
-      [](void* ctx) {
-        reinterpret_cast<starboard::Semaphore*>(ctx)->Put();
-      });
-#endif
     sem.Take();
   }
 
-  void RequestPause() {
+  void RequestBlur() {
     starboard::ScopedLock lock(mutex_);
     WaitForApp(lock);
     starboard::Semaphore sem;
-#if SB_API_VERSION >= 13
     Application::Get()->Blur(
       &sem,
       [](void* ctx) {
         reinterpret_cast<starboard::Semaphore*>(ctx)->Put();
       });
-#else
-    Application::Get()->Pause(
-      &sem,
-      [](void* ctx) {
-        reinterpret_cast<starboard::Semaphore*>(ctx)->Put();
-      });
-#endif
-    sem.Take();
-  }
-
-  void RequestUnpause() {
-    starboard::ScopedLock lock(mutex_);
-    WaitForApp(lock);
-    starboard::Semaphore sem;
-#if SB_API_VERSION >= 13
-    Application::Get()->Focus(
-      &sem,
-      [](void* ctx) {
-        reinterpret_cast<starboard::Semaphore*>(ctx)->Put();
-      });
-#else
-    Application::Get()->Unpause(
-      &sem,
-      [](void* ctx) {
-        reinterpret_cast<starboard::Semaphore*>(ctx)->Put();
-      });
-#endif
     sem.Take();
   }
 
@@ -200,11 +156,7 @@
     }
 
     if (should_invoke_default) {
-#if SB_API_VERSION >= 13
       Application::Get()->Conceal(NULL, NULL);
-#else
-      Application::Get()->Suspend(NULL, NULL);
-#endif
     }
   }
 
@@ -279,19 +231,19 @@
 }
 
 void SbRdkSuspend() {
-  GetContext()->RequestSuspend();
+  GetContext()->RequestFreeze();
 }
 
 void SbRdkResume() {
-  GetContext()->RequestResume();
+  GetContext()->RequestFocus();
 }
 
 void SbRdkPause() {
-  GetContext()->RequestPause();
+  GetContext()->RequestBlur();
 }
 
 void SbRdkUnpause() {
-  GetContext()->RequestUnpause();
+  GetContext()->RequestFocus();
 }
 
 void SbRdkQuit() {
diff --git a/src/third_party/starboard/rdk/shared/main_rdk.cc b/src/third_party/starboard/rdk/shared/main_rdk.cc
index b7c5be9..8333a6c 100644
--- a/src/third_party/starboard/rdk/shared/main_rdk.cc
+++ b/src/third_party/starboard/rdk/shared/main_rdk.cc
@@ -32,6 +32,7 @@
 #include <gst/gst.h>
 
 #include <signal.h>
+#include <sys/resource.h>
 
 #include "starboard/configuration.h"
 #include "starboard/shared/signal/crash_signals.h"
@@ -41,6 +42,10 @@
 
 #if SB_IS(EVERGREEN_COMPATIBLE)
 #include "third_party/crashpad/wrapper/wrapper.h"
+#include "starboard/common/paths.h"
+#include "starboard/elf_loader/elf_loader_constants.h"
+#include "starboard/shared/starboard/command_line.h"
+#include "starboard/shared/starboard/starboard_switches.h"
 #endif
 
 namespace third_party {
@@ -55,7 +60,8 @@
 }
 
 static void InstallStopSignalHandlers() {
-  struct sigaction action = {0};
+  struct sigaction action;
+  memset (&action, 0, sizeof (action));
   action.sa_handler = RequestStop;
   action.sa_flags = 0;
   ::sigemptyset(&action.sa_mask);
@@ -73,10 +79,21 @@
 }  // namespace starboard
 }  // namespace third_party
 
+#if SB_API_VERSION >= 15
+int SbRunStarboardMain(int argc, char** argv, SbEventHandleCallback callback) {
+  third_party::starboard::rdk::shared::Application application(callback);
+  int result = application.Run(argc, argv);
+  return result;
+}
+#endif  // SB_API_VERSION >= 15
 
 extern "C" SB_EXPORT_PLATFORM int main(int argc, char** argv) {
   tzset();
 
+  rlimit stack_size;
+  stack_size.rlim_cur = 512 * 1024;
+  setrlimit(RLIMIT_STACK, &stack_size);
+
   GError* error = NULL;
   gst_init_check(NULL, NULL, &error);
   g_free(error);
@@ -85,13 +102,27 @@
   third_party::starboard::rdk::shared::InstallStopSignalHandlers();
 
 #if SB_IS(EVERGREEN_COMPATIBLE)
-  third_party::crashpad::wrapper::InstallCrashpadHandler(true);
+  auto command_line = starboard::shared::starboard::CommandLine(argc, argv);
+  auto evergreen_content_path =
+    command_line.GetSwitchValue(starboard::elf_loader::kEvergreenContent);
+  std::string ca_certificates_path = evergreen_content_path.empty()
+    ? starboard::common::GetCACertificatesPath()
+    : starboard::common::GetCACertificatesPath(evergreen_content_path);
+  if (ca_certificates_path.empty()) {
+    SB_LOG(ERROR) << "Failed to get CA certificates path. Skip crashpad handler setup.";
+  } else {
+    third_party::crashpad::wrapper::InstallCrashpadHandler(true, ca_certificates_path);
+  }
 #endif
 
   int result = 0;
   {
+#if SB_API_VERSION >= 15
+    result = SbRunStarboardMain(argc, argv, SbEventHandle);
+#else
     third_party::starboard::rdk::shared::Application application;
     result = application.Run(argc, argv);
+#endif
   }
 
   third_party::starboard::rdk::shared::UninstallStopSignalHandlers();
diff --git a/src/third_party/starboard/rdk/shared/media/gst_media_utils.cc b/src/third_party/starboard/rdk/shared/media/gst_media_utils.cc
index 934c5c8..0389442 100644
--- a/src/third_party/starboard/rdk/shared/media/gst_media_utils.cc
+++ b/src/third_party/starboard/rdk/shared/media/gst_media_utils.cc
@@ -185,7 +185,12 @@
 }
 
 std::vector<std::string> CodecToGstCaps(SbMediaAudioCodec codec,
-                                        const SbMediaAudioSampleInfo* info) {
+#if SB_API_VERSION >= 15
+    const SbMediaAudioStreamInfo* info
+#else   // SB_API_VERSION >= 15
+    const SbMediaAudioSampleInfo* info
+#endif
+) {
   switch (codec) {
     default:
     case kSbMediaAudioCodecNone:
diff --git a/src/third_party/starboard/rdk/shared/media/gst_media_utils.h b/src/third_party/starboard/rdk/shared/media/gst_media_utils.h
index fd8bb06..b343906 100644
--- a/src/third_party/starboard/rdk/shared/media/gst_media_utils.h
+++ b/src/third_party/starboard/rdk/shared/media/gst_media_utils.h
@@ -32,7 +32,12 @@
 bool GstRegistryHasElementForMediaType(SbMediaAudioCodec codec);
 std::vector<std::string> CodecToGstCaps(
     SbMediaAudioCodec codec,
-    const SbMediaAudioSampleInfo* info = nullptr);
+#if SB_API_VERSION >= 15
+    const SbMediaAudioStreamInfo* info = nullptr
+#else   // SB_API_VERSION >= 15
+    const SbMediaAudioSampleInfo* info = nullptr
+#endif
+);
 std::vector<std::string> CodecToGstCaps(SbMediaVideoCodec codec);
 
 }  // namespace media
diff --git a/src/third_party/starboard/rdk/shared/media/media_get_audio_buffer_budget.cc b/src/third_party/starboard/rdk/shared/media/media_get_audio_buffer_budget.cc
index 0883d70..8e97e61 100644
--- a/src/third_party/starboard/rdk/shared/media/media_get_audio_buffer_budget.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_get_audio_buffer_budget.cc
@@ -33,8 +33,6 @@
 
 #include "starboard/common/log.h"
 
-#if SB_API_VERSION >= 10
 int SbMediaGetAudioBufferBudget() {
   return 5 * 1024 * 1024;
 }
-#endif  // SB_API_VERSION >= 10
diff --git a/src/third_party/starboard/rdk/shared/system/system_request_suspend.cc b/src/third_party/starboard/rdk/shared/media/media_get_audio_configuration.cc
similarity index 76%
rename from src/third_party/starboard/rdk/shared/system/system_request_suspend.cc
rename to src/third_party/starboard/rdk/shared/media/media_get_audio_configuration.cc
index bd28584..fa47943 100644
--- a/src/third_party/starboard/rdk/shared/system/system_request_suspend.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_get_audio_configuration.cc
@@ -1,3 +1,4 @@
+//
 // Copyright 2020 Comcast Cable Communications Management, LLC
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +15,7 @@
 //
 // SPDX-License-Identifier: Apache-2.0
 //
-// Copyright 2017 The Cobalt Authors. All Rights Reserved.
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -28,13 +29,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "starboard/system.h"
+#include "starboard/media.h"
 
-#include "third_party/starboard/rdk/shared/libcobalt.h"
+#include "third_party/starboard/rdk/shared/rdkservices.h"
 
-#if SB_API_VERSION < 13
-void SbSystemRequestSuspend() {
-  // Route through conceal request. cobalt-plugin will call Suspend.
-  SbRdkRequestConceal();
+bool SbMediaGetAudioConfiguration(
+    int output_index,
+    SbMediaAudioConfiguration* out_configuration) {
+  return third_party::starboard::rdk::shared::DeviceInfo::GetAudioConfiguration(output_index, out_configuration);
 }
-#endif  // SB_API_VERSION < 13
diff --git a/src/third_party/starboard/rdk/shared/media/media_get_buffer_alignment.cc b/src/third_party/starboard/rdk/shared/media/media_get_buffer_alignment.cc
index e27ba16..30025d6 100644
--- a/src/third_party/starboard/rdk/shared/media/media_get_buffer_alignment.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_get_buffer_alignment.cc
@@ -33,11 +33,6 @@
 
 #include "starboard/common/log.h"
 
-#if SB_API_VERSION >= 14
-  int SbMediaGetBufferAlignment() {
-#else  // SB_API_VERSION >= 14
-  int SbMediaGetBufferAlignment(SbMediaType type) {
-    SB_UNREFERENCED_PARAMETER(type);
-#endif  // SB_API_VERSION >= 10
+int SbMediaGetBufferAlignment() {
     return 1;
 }
diff --git a/src/third_party/starboard/rdk/shared/media/media_get_buffer_allocation_unit.cc b/src/third_party/starboard/rdk/shared/media/media_get_buffer_allocation_unit.cc
index 8b0ce01..e046cc8 100644
--- a/src/third_party/starboard/rdk/shared/media/media_get_buffer_allocation_unit.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_get_buffer_allocation_unit.cc
@@ -33,8 +33,6 @@
 
 #include "starboard/common/log.h"
 
-#if SB_API_VERSION >= 10
 int SbMediaGetBufferAllocationUnit() {
   return 1 * 1024 * 1024;
 }
-#endif  // SB_API_VERSION >= 10
diff --git a/src/third_party/starboard/rdk/shared/media/media_get_buffer_garbage_collection_duration_threshold.cc b/src/third_party/starboard/rdk/shared/media/media_get_buffer_garbage_collection_duration_threshold.cc
index 9de47e0..4aa55ea 100644
--- a/src/third_party/starboard/rdk/shared/media/media_get_buffer_garbage_collection_duration_threshold.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_get_buffer_garbage_collection_duration_threshold.cc
@@ -33,8 +33,6 @@
 
 #include "starboard/common/log.h"
 
-#if SB_API_VERSION >= 10
 SbTime SbMediaGetBufferGarbageCollectionDurationThreshold() {
   return 170 * kSbTimeSecond;
 }
-#endif  // SB_API_VERSION >= 10
diff --git a/src/third_party/starboard/rdk/shared/media/media_get_buffer_padding.cc b/src/third_party/starboard/rdk/shared/media/media_get_buffer_padding.cc
index 242ba1d..c9a9df7 100644
--- a/src/third_party/starboard/rdk/shared/media/media_get_buffer_padding.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_get_buffer_padding.cc
@@ -14,13 +14,6 @@
 // SPDX-License-Identifier: Apache-2.0
 #include "starboard/media.h"
 
-#include "starboard/common/log.h"
-
-#if SB_API_VERSION >= 14
-  int SbMediaGetBufferPadding() {
-#else   // SB_API_VERSION >= 14
-  int SbMediaGetBufferPadding(SbMediaType type) {
-    SB_UNREFERENCED_PARAMETER(type);
-#endif  // SB_API_VERSION >= 14
+int SbMediaGetBufferPadding() {
     return 0;
 }
diff --git a/src/third_party/starboard/rdk/shared/media/media_get_buffer_storage_type.cc b/src/third_party/starboard/rdk/shared/media/media_get_buffer_storage_type.cc
index 58bed81..87456fd 100644
--- a/src/third_party/starboard/rdk/shared/media/media_get_buffer_storage_type.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_get_buffer_storage_type.cc
@@ -33,8 +33,6 @@
 
 #include "starboard/common/log.h"
 
-#if SB_API_VERSION >= 10
 SbMediaBufferStorageType SbMediaGetBufferStorageType() {
   return kSbMediaBufferStorageTypeMemory;
 }
-#endif  // SB_API_VERSION >= 10
diff --git a/src/third_party/starboard/rdk/shared/media/media_get_initial_buffer_capacity.cc b/src/third_party/starboard/rdk/shared/media/media_get_initial_buffer_capacity.cc
index fe673e0..9b86ca5 100644
--- a/src/third_party/starboard/rdk/shared/media/media_get_initial_buffer_capacity.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_get_initial_buffer_capacity.cc
@@ -17,8 +17,6 @@
 
 #include "starboard/common/log.h"
 
-#if SB_API_VERSION >= 10
 int SbMediaGetInitialBufferCapacity() {
   return 21 * 1024 * 1024;
 }
-#endif  // SB_API_VERSION >= 10
diff --git a/src/third_party/starboard/rdk/shared/media/media_get_max_buffer_capacity.cc b/src/third_party/starboard/rdk/shared/media/media_get_max_buffer_capacity.cc
index e4dea0c..ec383a7 100644
--- a/src/third_party/starboard/rdk/shared/media/media_get_max_buffer_capacity.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_get_max_buffer_capacity.cc
@@ -17,7 +17,6 @@
 
 #include "starboard/common/log.h"
 
-#if SB_API_VERSION >= 10
 int SbMediaGetMaxBufferCapacity(SbMediaVideoCodec codec,
                                 int resolution_width,
                                 int resolution_height,
@@ -45,4 +44,3 @@
   // must be larger than sum of 8k video budget and non-video budget.
   return 360 * 1024 * 1024;
 }
-#endif  // SB_API_VERSION >= 10
diff --git a/src/third_party/starboard/rdk/shared/media/media_get_progressive_buffer_budget.cc b/src/third_party/starboard/rdk/shared/media/media_get_progressive_buffer_budget.cc
index 933e8f1..2fca5fe 100644
--- a/src/third_party/starboard/rdk/shared/media/media_get_progressive_buffer_budget.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_get_progressive_buffer_budget.cc
@@ -18,7 +18,6 @@
 
 #include "starboard/common/log.h"
 
-#if SB_API_VERSION >= 10
 int SbMediaGetProgressiveBufferBudget(SbMediaVideoCodec codec,
                                       int resolution_width,
                                       int resolution_height,
@@ -29,4 +28,3 @@
   SB_UNREFERENCED_PARAMETER(bits_per_pixel);
   return 12 * 1024 * 1024;
 }
-#endif  // SB_API_VERSION >= 10
diff --git a/src/third_party/starboard/rdk/shared/media/media_get_video_buffer_budget.cc b/src/third_party/starboard/rdk/shared/media/media_get_video_buffer_budget.cc
index 496c2ea..ba5c00c 100644
--- a/src/third_party/starboard/rdk/shared/media/media_get_video_buffer_budget.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_get_video_buffer_budget.cc
@@ -16,7 +16,6 @@
 
 #include "starboard/common/log.h"
 
-#if SB_API_VERSION >= 10
 int SbMediaGetVideoBufferBudget(SbMediaVideoCodec codec,
                                 int resolution_width,
                                 int resolution_height,
@@ -50,4 +49,3 @@
   // lower than 8k (7680x4320).
   return 300 * 1024 * 1024;
 }
-#endif  // SB_API_VERSION >= 10
diff --git a/src/third_party/starboard/rdk/shared/media/media_is_buffer_pool_allocate_on_demand.cc b/src/third_party/starboard/rdk/shared/media/media_is_buffer_pool_allocate_on_demand.cc
index 1989f92..58e6a2d 100644
--- a/src/third_party/starboard/rdk/shared/media/media_is_buffer_pool_allocate_on_demand.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_is_buffer_pool_allocate_on_demand.cc
@@ -18,8 +18,6 @@
 
 #include "starboard/common/log.h"
 
-#if SB_API_VERSION >= 10
 bool SbMediaIsBufferPoolAllocateOnDemand() {
   return true;
 }
-#endif  // SB_API_VERSION >= 10
diff --git a/src/third_party/starboard/rdk/shared/media/media_is_buffer_using_memory_pool.cc b/src/third_party/starboard/rdk/shared/media/media_is_buffer_using_memory_pool.cc
index 0f1f0e9..c3baa24 100644
--- a/src/third_party/starboard/rdk/shared/media/media_is_buffer_using_memory_pool.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_is_buffer_using_memory_pool.cc
@@ -16,8 +16,6 @@
 // SPDX-License-Identifier: Apache-2.0
 #include "starboard/media.h"
 
-#if SB_API_VERSION >= 10
 bool SbMediaIsBufferUsingMemoryPool() {
   return true;
 }
-#endif  // SB_API_VERSION >= 10
diff --git a/src/third_party/starboard/rdk/shared/media/media_is_supported.cc b/src/third_party/starboard/rdk/shared/media/media_is_supported.cc
index 930d5db..d6512ee 100644
--- a/src/third_party/starboard/rdk/shared/media/media_is_supported.cc
+++ b/src/third_party/starboard/rdk/shared/media/media_is_supported.cc
@@ -31,11 +31,8 @@
 
 #include <string>
 
-#if SB_API_VERSION >= 13
-#include "starboard/shared/starboard/media/media_support_internal.h"
-#endif
-
 #include "starboard/media.h"
+#include "starboard/shared/starboard/media/media_support_internal.h"
 
 #include "third_party/starboard/rdk/shared/drm/drm_system_ocdm.h"
 
@@ -62,13 +59,8 @@
     case kSbMediaVideoCodecVc1:
       return {};
 
-#if SB_API_VERSION < 11
-    case kSbMediaVideoCodecVp10:
-      return {{"video/webm"}};
-#else   // SB_API_VERSION < 11
     case kSbMediaVideoCodecAv1:
       return {};
-#endif  // SB_API_VERSION < 11
 
     case kSbMediaVideoCodecVp8:
     case kSbMediaVideoCodecVp9:
diff --git a/src/third_party/starboard/rdk/shared/platform_configuration/BUILD.gn b/src/third_party/starboard/rdk/shared/platform_configuration/BUILD.gn
index db89e5e..1727d9d 100644
--- a/src/third_party/starboard/rdk/shared/platform_configuration/BUILD.gn
+++ b/src/third_party/starboard/rdk/shared/platform_configuration/BUILD.gn
@@ -60,6 +60,9 @@
 
     cflags_cc += [
       "-std=gnu++14",
+      "-Wno-literal-suffix",
+      # Generated by Audio Renderer and Audio Sink implementations.
+      "-Wno-reorder",
     ]
 
     if (is_qa || is_gold) {
@@ -131,15 +134,31 @@
     "-Wextra",
     "-Wunreachable-code",
   ]
+  if (!is_clang) {
+    cflags += [
+      "-Wno-expansion-to-defined",
+    ]
+  }
 }
 
 config("no_pedantic_warnings") {
   if (!is_clang) {
+    cflags = [
+      "-Wno-conversion",
+      "-Wno-deprecated-declarations",
+      "-Wno-ignored-qualifiers",
+      "-Wno-multichar",
+      "-Wno-sign-conversion",
+      "-Wno-unused-function",
+      "-Wno-unused-local-typedefs",
+      "-Wno-unused-parameter",
+      "-Wno-unused-variable",
+      "-Wno-unused-but-set-variable",
+    ]
     cflags_cc = [
-      "-Wno-literal-suffix",
       "-Wno-deprecated-copy",
       "-Wno-invalid-offsetof",
-      "-Wno-ignored-qualifiers",
+      "-Wno-literal-suffix",
       "-Wno-pessimizing-move",
     ]
   } else {
diff --git a/src/third_party/starboard/rdk/shared/platform_configuration/configuration.gni b/src/third_party/starboard/rdk/shared/platform_configuration/configuration.gni
index 3def42b..a1885b8 100644
--- a/src/third_party/starboard/rdk/shared/platform_configuration/configuration.gni
+++ b/src/third_party/starboard/rdk/shared/platform_configuration/configuration.gni
@@ -32,8 +32,9 @@
 
 cobalt_font_package = "limited"
 final_executable_type = "shared_library"
+starboard_level_final_executable_type = "shared_library"
 
-sb_api_version = 14
+sb_api_version = 15
 sb_filter_based_player = false
 gl_type = "system_gles2"
 
@@ -43,6 +44,9 @@
 no_pedantic_warnings_config_path =
   "//third_party/starboard/rdk/shared/platform_configuration:no_pedantic_warnings"
 
+pedantic_warnings_config_path =
+  "//third_party/starboard/rdk/shared/platform_configuration:pedantic_warnings"
+
 speed_config_path =
   "//third_party/starboard/rdk/shared/platform_configuration:speed"
 
diff --git a/src/third_party/starboard/rdk/shared/platform_service.cc b/src/third_party/starboard/rdk/shared/platform_service.cc
index a530e5d..d606bb4 100644
--- a/src/third_party/starboard/rdk/shared/platform_service.cc
+++ b/src/third_party/starboard/rdk/shared/platform_service.cc
@@ -33,11 +33,11 @@
 #include <memory>
 #include <string>
 
-#include "cobalt/extension/platform_service.h"
 #include "starboard/common/log.h"
 #include "starboard/common/string.h"
 #include "starboard/configuration.h"
 #include "starboard/shared/starboard/application.h"
+#include "starboard/extension/platform_service.h"
 
 #include "third_party/starboard/rdk/shared/firebolt/firebolt.h"
 #include "third_party/starboard/rdk/shared/log_override.h"
diff --git a/src/third_party/starboard/rdk/shared/player/player_create.cc b/src/third_party/starboard/rdk/shared/player/player_create.cc
index 70d056b..36bdeb6 100644
--- a/src/third_party/starboard/rdk/shared/player/player_create.cc
+++ b/src/third_party/starboard/rdk/shared/player/player_create.cc
@@ -48,9 +48,17 @@
     return kSbPlayerInvalid;
   }
 
-  auto *max_video_capabilities = creation_param->video_sample_info.max_video_capabilities;
-  auto audio_codec = creation_param->audio_sample_info.codec;
-  auto video_codec = creation_param->video_sample_info.codec;
+  #if SB_API_VERSION >= 15
+  const auto& audio_info = creation_param->audio_stream_info;
+  const auto& video_info = creation_param->video_stream_info;
+  #else
+  const auto& audio_info = creation_param->audio_sample_info;
+  const auto& video_info = creation_param->video_sample_info;
+  #endif
+
+  auto *max_video_capabilities = video_info.max_video_capabilities;
+  auto audio_codec = audio_info.codec;
+  auto video_codec = video_info.codec;
   auto drm_system  = creation_param->drm_system;
   auto output_mode = creation_param->output_mode;
 
@@ -81,7 +89,7 @@
   }
 
   std::unique_ptr<SbPlayerPrivate> player { new SbPlayerPrivate(
-      window, video_codec, audio_codec, drm_system, creation_param->audio_sample_info,
+      window, video_codec, audio_codec, drm_system, audio_info,
       max_video_capabilities,
       sample_deallocate_func, decoder_status_func, player_status_func,
       player_error_func, context, output_mode, provider) };
diff --git a/src/third_party/starboard/rdk/shared/system/system_request_suspend.cc b/src/third_party/starboard/rdk/shared/player/player_get_audio_configuration.cc
similarity index 72%
copy from src/third_party/starboard/rdk/shared/system/system_request_suspend.cc
copy to src/third_party/starboard/rdk/shared/player/player_get_audio_configuration.cc
index bd28584..5366f77 100644
--- a/src/third_party/starboard/rdk/shared/system/system_request_suspend.cc
+++ b/src/third_party/starboard/rdk/shared/player/player_get_audio_configuration.cc
@@ -1,3 +1,4 @@
+//
 // Copyright 2020 Comcast Cable Communications Management, LLC
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +15,7 @@
 //
 // SPDX-License-Identifier: Apache-2.0
 //
-// Copyright 2017 The Cobalt Authors. All Rights Reserved.
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -28,13 +29,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "starboard/system.h"
+#include "starboard/player.h"
+#include "starboard/media.h"
 
-#include "third_party/starboard/rdk/shared/libcobalt.h"
+#include "third_party/starboard/rdk/shared/player/player_internal.h"
 
-#if SB_API_VERSION < 13
-void SbSystemRequestSuspend() {
-  // Route through conceal request. cobalt-plugin will call Suspend.
-  SbRdkRequestConceal();
+#if SB_API_VERSION >= 15
+
+bool SbPlayerGetAudioConfiguration(
+    SbPlayer player,
+    int index,
+    SbMediaAudioConfiguration* out_audio_configuration) {
+  return SbMediaGetAudioConfiguration(index, out_audio_configuration);
 }
-#endif  // SB_API_VERSION < 13
+
+#endif  // SB_API_VERSION >= 15
diff --git a/src/third_party/starboard/rdk/shared/player/player_get_info.cc b/src/third_party/starboard/rdk/shared/player/player_get_info.cc
index e60239b..b4f0324 100644
--- a/src/third_party/starboard/rdk/shared/player/player_get_info.cc
+++ b/src/third_party/starboard/rdk/shared/player/player_get_info.cc
@@ -32,12 +32,16 @@
 #include "starboard/player.h"
 #include "third_party/starboard/rdk/shared/player/player_internal.h"
 
-#if SB_API_VERSION >= 10
-void SbPlayerGetInfo2(SbPlayer player, SbPlayerInfo2* out_player_info) {
+#if SB_API_VERSION >= 15
+void SbPlayerGetInfo(SbPlayer player, SbPlayerInfo* out_player_info) {
+  if (player == kSbPlayerInvalid)
+    return;
   player->player_->GetInfo(out_player_info);
 }
-#else
-void SbPlayerGetInfo(SbPlayer /*player*/, SbPlayerInfo* /*out_player_info*/) {
-  SB_NOTIMPLEMENTED();
+#else   // SB_API_VERSION >= 15
+void SbPlayerGetInfo2(SbPlayer player, SbPlayerInfo2* out_player_info) {
+  if (player == kSbPlayerInvalid)
+    return;
+  player->player_->GetInfo(out_player_info);
 }
-#endif  // SB_API_VERSION >= 10
+#endif  // SB_API_VERSION >= 15
diff --git a/src/third_party/starboard/rdk/shared/player/player_get_maximum_number_of_samples_per_write.cc b/src/third_party/starboard/rdk/shared/player/player_get_maximum_number_of_samples_per_write.cc
index 33126e3..ffa7fcd 100644
--- a/src/third_party/starboard/rdk/shared/player/player_get_maximum_number_of_samples_per_write.cc
+++ b/src/third_party/starboard/rdk/shared/player/player_get_maximum_number_of_samples_per_write.cc
@@ -33,9 +33,9 @@
 
 #include "third_party/starboard/rdk/shared/player/player_internal.h"
 
-#if SB_API_VERSION >= 10
 int SbPlayerGetMaximumNumberOfSamplesPerWrite(SbPlayer player,
                                               SbMediaType /*sample_type*/) {
+  if (player == kSbPlayerInvalid)
+    return 0;
   return player->MaxNumberOfSamplesPerWrite();
 }
-#endif  // SB_API_VERSION >= 10
diff --git a/src/third_party/starboard/rdk/shared/player/player_internal.cc b/src/third_party/starboard/rdk/shared/player/player_internal.cc
index d3aeab1..daeabd4 100644
--- a/src/third_party/starboard/rdk/shared/player/player_internal.cc
+++ b/src/third_party/starboard/rdk/shared/player/player_internal.cc
@@ -21,13 +21,15 @@
 #include <math.h>
 
 #include <glib.h>
+#include <gst/gst.h>
 #include <gst/app/gstappsrc.h>
+#include <gst/audio/audio.h>
 #include <gst/audio/streamvolume.h>
 #include <gst/base/gstbytewriter.h>
-#include <gst/gst.h>
 #include <gst/base/gstflowcombiner.h>
 #include <gst/video/video.h>
 #include <gst/base/gstbasetransform.h>
+#include <gst/base/gstbaseparse.h>
 
 #include <map>
 #include <string>
@@ -43,6 +45,7 @@
 #include "starboard/time.h"
 #include "starboard/memory.h"
 #include "starboard/drm.h"
+#include "starboard/common/log.h"
 #include "third_party/starboard/rdk/shared/media/gst_media_utils.h"
 #include "third_party/starboard/rdk/shared/hang_detector.h"
 #include "third_party/starboard/rdk/shared/drm/gst_decryptor_ocdm.h"
@@ -73,14 +76,13 @@
 GST_DEBUG_CATEGORY(cobalt_gst_player_debug);
 #define GST_CAT_DEFAULT cobalt_gst_player_debug
 
-#if !defined(GST_HAS_HDR_SUPPORT)
-#if GST_CHECK_VERSION(1, 18, 0) || (defined(__has_include) &&  __has_include("gstreamer-1.0/gst/video/video-hdr.h"))
+#if !defined(GST_HAS_HDR_SUPPORT) && GST_CHECK_VERSION(1, 18, 0)
 #define GST_HAS_HDR_SUPPORT 1
 #endif
-#endif
 
 static void PrintGstCaps(GstCaps* caps);
 static GstElement* CreatePayloader();
+static GstElement* CreateGstElement(const gchar* factory_name, const gchar* name_format, ...) G_GNUC_PRINTF (2, 3);
 
 static GSourceFuncs SourceFunctions = {
     // prepare
@@ -114,14 +116,9 @@
   return flag->value;
 }
 
-bool isRialtoEnabled()
-{
+bool isRialtoEnabled() {
   static bool is_rialto_enabled = false;
-#if __GNUC__ < 10
-  static volatile gsize init = 0;
-#else
   static gsize init = 0;
-#endif
 
   if (g_once_init_enter (&init)) {
     GstElementFactory *factory = gst_element_factory_find("rialtomsevideosink");
@@ -138,11 +135,7 @@
 
 bool enableNativeAudio() {
   static bool enable_native_audio = false;
-#if __GNUC__ < 10
-  static volatile gsize init = 0;
-#else
   static gsize init = 0;
-#endif
 
   if (g_once_init_enter (&init)) {
     GstElementFactory* factory = gst_element_factory_find("brcmaudiosink");
@@ -423,6 +416,7 @@
   gst_app_src_set_emit_signals(GST_APP_SRC(appsrc), FALSE);
   gst_app_src_set_callbacks(GST_APP_SRC(appsrc), callbacks, user_data, nullptr);
   gst_app_src_set_max_bytes(GST_APP_SRC(appsrc), max_bytes);
+  gst_base_src_set_format(GST_BASE_SRC(appsrc), GST_FORMAT_TIME);
 
   GstCobaltSrc* src = GST_COBALT_SRC(element);
   gchar* name = g_strdup_printf("src_%u", src->priv->pad_number);
@@ -437,7 +431,7 @@
   }
 
   if (decryptor) {
-    GST_DEBUG("Injecting decryptor element %" GST_PTR_FORMAT, decryptor);
+    GST_DEBUG_OBJECT(element, "Injecting decryptor element %" GST_PTR_FORMAT, decryptor);
 
     gst_bin_add(GST_BIN(element), decryptor);
     gst_element_sync_state_with_parent(decryptor);
@@ -446,7 +440,7 @@
   }
 
   if (payloader) {
-    GST_DEBUG("Injecting payloader element %" GST_PTR_FORMAT, payloader);
+    GST_DEBUG_OBJECT(element, "Injecting payloader element %" GST_PTR_FORMAT, payloader);
 
     if (GST_IS_BASE_TRANSFORM(payloader)) {
       gst_base_transform_set_in_place(GST_BASE_TRANSFORM(payloader), TRUE);
@@ -496,45 +490,6 @@
       return GST_PAD_PROBE_OK;
     }, msg, [](gpointer data) { gst_message_unref(GST_MESSAGE(data)); });
 
-#if GST_CHECK_VERSION(1,18,0)
-  gst_pad_add_probe (
-    pad, GST_PAD_PROBE_TYPE_EVENT_BOTH,
-    [](GstPad * pad, GstPadProbeInfo * info, gpointer data) -> GstPadProbeReturn {
-      GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
-      GstSegment *segment = reinterpret_cast<GstSegment*>(data);
-      switch ( GST_EVENT_TYPE(event) ) {
-        case GST_EVENT_SEEK:
-          break;
-        case GST_EVENT_SEGMENT: {
-          const GstSegment *src = nullptr;
-          gst_event_parse_segment(event, &src);
-          gst_segment_copy_into(src, segment);
-          // fallthrough
-        }
-        default:
-          return GST_PAD_PROBE_OK;
-      };
-      gdouble rate = 1.0;
-      GstSeekFlags flags = GST_SEEK_FLAG_NONE;
-      gst_event_parse_seek (event, &rate, NULL, &flags, NULL, NULL, NULL, NULL);
-      if ( !!(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) ) {
-        gdouble rate_multiplier = rate / segment->rate;
-        GstEvent *rate_change_event =
-          gst_event_new_instant_rate_change(rate_multiplier, (GstSegmentFlags)flags);
-        gst_event_set_seqnum (rate_change_event, gst_event_get_seqnum (event));
-        GstPad *peer_pad = gst_pad_get_peer(pad);
-        GST_DEBUG("Sending instant rate change pad: %" GST_PTR_FORMAT ", event: %" GST_PTR_FORMAT ", rate_multiplier: %.2f",
-                  peer_pad, rate_change_event, rate_multiplier);
-        if ( gst_pad_send_event (peer_pad, rate_change_event) != TRUE )
-          GST_PAD_PROBE_INFO_FLOW_RETURN(info) = GST_FLOW_NOT_SUPPORTED;
-        gst_object_unref(peer_pad);
-        gst_event_unref(event);
-        return GST_PAD_PROBE_HANDLED;
-      }
-      return GST_PAD_PROBE_OK;
-    }, gst_segment_new(), reinterpret_cast<GDestroyNotify>(gst_segment_free));
-#endif
-
   // Allocation query can stall streaming thread if sent during pre-roll.
   // Drop the query since we don't use proposed allocation anyway.
   gst_pad_add_probe (
@@ -542,7 +497,7 @@
     [](GstPad * pad, GstPadProbeInfo * info, gpointer data) -> GstPadProbeReturn {
       GstQuery* query = GST_PAD_PROBE_INFO_QUERY(info);
       if (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION) {
-        GST_DEBUG_OBJECT(pad, "Drop allocation query");
+        GST_TRACE_OBJECT(pad, "Drop allocation query");
         return GST_PAD_PROBE_DROP;
       }
       return GST_PAD_PROBE_OK;
@@ -747,11 +702,7 @@
     case kSbMediaTransferId12BitBt2020:
       return GST_VIDEO_TRANSFER_BT2020_12;
     case kSbMediaTransferIdSmpteSt2084:
-#if GST_CHECK_VERSION(1, 18, 0)
       return GST_VIDEO_TRANSFER_SMPTE2084;
-#else
-      return GST_VIDEO_TRANSFER_SMPTE_ST_2084;
-#endif
     case kSbMediaTransferIdAribStdB67:
       return GST_VIDEO_TRANSFER_ARIB_STD_B67;
     case kSbMediaTransferIdUnspecified:
@@ -799,9 +750,8 @@
     GST_DEBUG ("Setting \"colorimetry\" to %s", tmp);
     g_free (tmp);
   }
-#if GST_CHECK_VERSION(1, 18, 0)
   GstVideoMasteringDisplayInfo mastering_display_info;
-  gst_video_mastering_display_info_init (&mastering_display_info);//  gst_video_mastering_display_metadata_init (&mastering_display_metadata);
+  gst_video_mastering_display_info_init (&mastering_display_info);
 
   mastering_display_info.display_primaries[0].x = (guint16)(color_metadata.mastering_metadata.primary_r_chromaticity_x * 50000);
   mastering_display_info.display_primaries[0].y = (guint16)(color_metadata.mastering_metadata.primary_r_chromaticity_y * 50000);
@@ -819,41 +769,11 @@
   gst_caps_set_simple (caps, "mastering-display-info", G_TYPE_STRING, tmp, NULL);
   GST_DEBUG ("Setting \"mastering-display-info\" to %s", tmp);
   g_free (tmp);
-#else
-  GstVideoMasteringDisplayMetadata mastering_display_metadata;
-  gst_video_mastering_display_metadata_init (&mastering_display_metadata);
-  mastering_display_metadata.Rx = color_metadata.mastering_metadata.primary_r_chromaticity_x;
-  mastering_display_metadata.Ry = color_metadata.mastering_metadata.primary_r_chromaticity_y;
-  mastering_display_metadata.Gx = color_metadata.mastering_metadata.primary_g_chromaticity_x;
-  mastering_display_metadata.Gy = color_metadata.mastering_metadata.primary_g_chromaticity_y;
-  mastering_display_metadata.Bx = color_metadata.mastering_metadata.primary_b_chromaticity_x;
-  mastering_display_metadata.By = color_metadata.mastering_metadata.primary_b_chromaticity_y;
-  mastering_display_metadata.Wx = color_metadata.mastering_metadata.white_point_chromaticity_x;
-  mastering_display_metadata.Wy = color_metadata.mastering_metadata.white_point_chromaticity_y;
-  mastering_display_metadata.max_luma = color_metadata.mastering_metadata.luminance_max;
-  mastering_display_metadata.min_luma = color_metadata.mastering_metadata.luminance_min;
-
-  if (gst_video_mastering_display_metadata_has_primaries(&mastering_display_metadata) &&
-      gst_video_mastering_display_metadata_has_luminance(&mastering_display_metadata) ) {
-    gchar *tmp =
-      gst_video_mastering_display_metadata_to_caps_string
-      (&mastering_display_metadata);
-    gst_caps_set_simple (caps, "mastering-display-metadata", G_TYPE_STRING, tmp, NULL);
-    GST_DEBUG ("Setting \"mastering-display-metadata\" to %s", tmp);
-    g_free (tmp);
-  }
-#endif
   if (color_metadata.max_cll && color_metadata.max_fall) {
     GstVideoContentLightLevel content_light_level;
-#if GST_CHECK_VERSION(1, 18, 0)
     content_light_level.max_content_light_level = color_metadata.max_cll;
     content_light_level.max_frame_average_light_level = color_metadata.max_fall;
     gchar *tmp = gst_video_content_light_level_to_string(&content_light_level);
-#else
-    content_light_level.maxCLL = color_metadata.max_cll;
-    content_light_level.maxFALL = color_metadata.max_fall;
-    gchar *tmp = gst_video_content_light_level_to_caps_string(&content_light_level);
-#endif
     gst_caps_set_simple (caps, "content-light-level", G_TYPE_STRING, tmp, NULL);
     GST_DEBUG ("setting \"content-light-level\" to %s", tmp);
     g_free (tmp);
@@ -867,7 +787,11 @@
   return memcmp(&lhs, &rhs, sizeof(SbMediaColorMetadata));
 }
 
+#if SB_API_VERSION >= 15
+static void AddVideoInfoToGstCaps(const SbMediaVideoStreamInfo& info, GstCaps* caps) {
+#else
 static void AddVideoInfoToGstCaps(const SbMediaVideoSampleInfo& info, GstCaps* caps) {
+#endif
   AddColorMetadataToGstCaps(caps, info.color_metadata);
   gst_caps_set_simple (caps,
     "width", G_TYPE_INT, info.frame_width,
@@ -881,17 +805,18 @@
   }
 }
 
-static void PrintPositionPerSink(GstElement* element)
+static void PrintPositionPerSink(GstElement* element, GstDebugLevel level)
 {
 #ifndef GST_DISABLE_GST_DEBUG
-  if (gst_debug_category_get_threshold(GST_CAT_DEFAULT) < GST_LEVEL_INFO)
+  if (gst_debug_category_get_threshold(GST_CAT_DEFAULT) < level)
     return;
 #endif
 
-  auto fold_func = [](const GValue *vitem, GValue*, gpointer) -> gboolean {
+  auto fold_func = [](const GValue *vitem, GValue*, gpointer data) -> gboolean {
+    GstDebugLevel level = (GstDebugLevel)GPOINTER_TO_INT(data);
     GstObject *item = GST_OBJECT(g_value_get_object (vitem));
     if (GST_IS_BIN (item)) {
-      PrintPositionPerSink(GST_ELEMENT(item));
+      PrintPositionPerSink(GST_ELEMENT(item), level);
     }
     else if (GST_IS_BASE_SINK(item)) {
       GstElement* el = GST_ELEMENT(item);
@@ -901,7 +826,8 @@
         gst_query_parse_position(query, 0, &position);
       }
       gst_query_unref(query);
-      GST_INFO("Position from %s : %" GST_TIME_FORMAT, GST_ELEMENT_NAME(el), GST_TIME_ARGS(position));
+      GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, level, el,
+        "Position from %s : %" GST_TIME_FORMAT, GST_ELEMENT_NAME(el), GST_TIME_ARGS(position));
     }
     return TRUE;
   };
@@ -912,7 +838,7 @@
   bool keep_going = true;
   while (keep_going) {
     GstIteratorResult ires;
-    ires = gst_iterator_fold (iter, fold_func, NULL, NULL);
+    ires = gst_iterator_fold (iter, fold_func, NULL, GINT_TO_POINTER(level));
     switch (ires) {
       case GST_ITERATOR_RESYNC:
         gst_iterator_resync (iter);
@@ -937,12 +863,7 @@
 
 static GstElement* CreatePayloader() {
   static GstElementFactory* factory = nullptr;
-#if __GNUC__ < 10
-  static volatile gsize init = 0;
-#else
   static gsize init = 0;
-#endif
-
 
   if (g_once_init_enter (&init)) {
     factory = gst_element_factory_find("svppay");
@@ -950,13 +871,26 @@
   }
 
   if (!factory) {
-    GST_WARNING("svppay not found");
+    GST_DEBUG("svppay not found");
     return nullptr;
   }
 
   return gst_element_factory_create(factory, nullptr);
 }
 
+
+static GstElement* CreateGstElement(const gchar* factory_name, const gchar* name_format, ...) {
+  GstElement *result;
+  gchar *name;
+  va_list args;
+  va_start(args, name_format);
+  name = g_strdup_vprintf(name_format, args);
+  va_end(args);
+  result = gst_element_factory_make(factory_name, name);
+  g_free(name);
+  return result;
+}
+
 }  // namespace
 
 // ********************************* Player ******************************** //
@@ -1147,7 +1081,11 @@
              SbMediaVideoCodec video_codec,
              SbMediaAudioCodec audio_codec,
              SbDrmSystem drm_system,
-             const SbMediaAudioSampleInfo& audio_sample_info,
+#if SB_API_VERSION >= 15
+             const SbMediaAudioStreamInfo& audio_info,
+#else   // SB_API_VERSION >= 15
+             const SbMediaAudioSampleInfo& audio_info,
+#endif
              const char* max_video_capabilities,
              SbPlayerDeallocateSampleFunc sample_deallocate_func,
              SbPlayerDecoderStatusFunc decoder_status_func,
@@ -1166,11 +1104,17 @@
   void SetVolume(double volume) override;
   void Seek(SbTime seek_to_timestamp, int ticket) override;
   bool SetRate(double rate) override;
+#if SB_API_VERSION >= 15
+  void GetInfo(SbPlayerInfo* info) override;
+#else   // SB_API_VERSION >= 15
   void GetInfo(SbPlayerInfo2* info) override;
+#endif
   void SetBounds(int zindex, int x, int y, int w, int h) override;
 
   GstElement* GetPipeline() const { return pipeline_;  }
   bool IsValid() const { return SbThreadIsValid(playback_thread_); }
+  bool HasMaxVideoCaps() const { return !max_video_capabilities_.empty(); }
+  void AudioConfigurationChanged();
 
  private:
   enum class State {
@@ -1179,8 +1123,23 @@
     kInitialPreroll,
     kPrerollAfterSeek,
     kPresenting,
+    kEnded,
   };
 
+  static const char* PrivatePlayerStateToStr(State state) {
+#define CASE(x) case x: return #x
+    switch(state) {
+        CASE(State::kNull);
+        CASE(State::kInitial);
+        CASE(State::kInitialPreroll);
+        CASE(State::kPrerollAfterSeek);
+        CASE(State::kPresenting);
+        CASE(State::kEnded);
+    }
+#undef CASE
+    return "unknown";
+  }
+
   enum MediaTimestampIndex {
     kAudioIndex,
     kVideoIndex,
@@ -1298,21 +1257,33 @@
   SbTime MinTimestamp(MediaType* origin) const;
 
   void DecoderNeedsData(::starboard::ScopedLock&, MediaType media) const {
-    int need_data = static_cast<int>(media);
-    if (media != MediaType::kNone && (decoder_state_data_ & need_data) == need_data) {
-      GST_LOG("Already sent 'kSbPlayerDecoderStateNeedsData', ignoring new request");
+    SB_DCHECK(media != MediaType::kNone);
+
+    int need_data = static_cast<int>(media) & ~decoder_state_data_;
+    if (need_data == 0) {
+      GST_LOG_OBJECT(pipeline_, "Already sent 'kSbPlayerDecoderStateNeedsData' for media type: %d, ignoring new request", static_cast<int>(media));
       return;
     }
-    if (media != MediaType::kNone && (eos_data_ & need_data) == need_data) {
-      GST_LOG("Stream(%d) already ended, ignoring needs data request", need_data);
+    if ((eos_data_ & need_data) == need_data) {
+      GST_LOG_OBJECT(pipeline_, "Stream(%d) already ended, ignoring needs data request", need_data);
       return;
     }
+
     decoder_state_data_ |= need_data;
+
+#if 0
+    if ((need_data & static_cast<int>(MediaType::kAudio)) != 0)
+      decoder_status_func_(player_, context_, kSbMediaTypeAudio, kSbPlayerDecoderStateNeedsData, ticket_);
+    if ((need_data & static_cast<int>(MediaType::kVideo)) != 0)
+      decoder_status_func_(player_, context_, kSbMediaTypeVideo, kSbPlayerDecoderStateNeedsData, ticket_);
+#else
     DispatchOnWorkerThread(new DecoderStatusTask(
       decoder_status_func_, player_, ticket_, context_,
-      kSbPlayerDecoderStateNeedsData, media));
+      kSbPlayerDecoderStateNeedsData, static_cast<MediaType>(need_data)));
+#endif
   }
 
+  gboolean HandleBusMessage(GstBus* bus, GstMessage* message);
   void HandleApplicationMessage(GstBus* bus, GstMessage* message);
   void WritePendingSamples();
   void CheckBuffering(gint64 position);
@@ -1320,13 +1291,13 @@
   void SchedulePlayingStateUpdate();
   void AddBufferingProbe(GstClockTime target, int ticket);
   void HandleInititialSeek(::starboard::ScopedLock&);
+  void DidEnd();
 
   SbPlayer player_;
   SbWindow window_;
   SbMediaVideoCodec video_codec_;
   SbMediaAudioCodec audio_codec_;
   SbDrmSystem drm_system_;
-  const SbMediaAudioSampleInfo audio_sample_info_;
   std::string max_video_capabilities_;
   SbPlayerDeallocateSampleFunc sample_deallocate_func_;
   SbPlayerDecoderStatusFunc decoder_status_func_;
@@ -1343,7 +1314,7 @@
   GstElement* pipeline_{nullptr};
   int source_setup_id_{-1};
   int bus_watch_id_{-1};
-  SbThread playback_thread_;
+  SbThread playback_thread_ { kSbThreadInvalid };
   ::starboard::Mutex mutex_;
   ::starboard::Mutex source_setup_mutex_;
   ::starboard::Mutex seek_mutex_;
@@ -1420,6 +1391,25 @@
       gst_object_unref(pipeline);
     }
   }
+
+  bool CanCreate(const char* max_video_capabilities) {
+    #if !defined(COBALT_BUILD_TYPE_GOLD)
+    bool has_max_video_caps_set = (max_video_capabilities && *max_video_capabilities);
+    ::starboard::ScopedLock lock(mutex_);
+    for(const auto& p: players_) {
+      if (p->HasMaxVideoCaps() == has_max_video_caps_set)
+        return false;
+    }
+    #endif
+    return true;
+  }
+
+  void AudioConfigurationChanged() {
+    ::starboard::ScopedLock lock(mutex_);
+    for(const auto& p: players_) {
+      p->AudioConfigurationChanged();
+    }
+  }
 };
 SB_ONCE_INITIALIZE_FUNCTION(PlayerRegistry, GetPlayerRegistry);
 
@@ -1428,7 +1418,11 @@
                        SbMediaVideoCodec video_codec,
                        SbMediaAudioCodec audio_codec,
                        SbDrmSystem drm_system,
-                       const SbMediaAudioSampleInfo& audio_sample_info,
+#if SB_API_VERSION >= 15
+                       const SbMediaAudioStreamInfo& audio_info,
+#else   // SB_API_VERSION >= 15
+                       const SbMediaAudioSampleInfo& audio_info,
+#endif
                        const char* max_video_capabilities,
                        SbPlayerDeallocateSampleFunc sample_deallocate_func,
                        SbPlayerDecoderStatusFunc decoder_status_func,
@@ -1442,7 +1436,6 @@
       video_codec_(video_codec),
       audio_codec_(audio_codec),
       drm_system_(drm_system),
-      audio_sample_info_(audio_sample_info),
       sample_deallocate_func_(sample_deallocate_func),
       decoder_status_func_(decoder_status_func),
       player_status_func_(player_status_func),
@@ -1466,18 +1459,20 @@
     GstState state, pending;
     GstStateChangeReturn result = gst_element_get_state(player.pipeline_, &state, &pending, 0);
     gint64 position = player.GetPosition();
-    GST_INFO("Player state: %s (pending: %s, result: %s), position: %" GST_TIME_FORMAT "",
-             gst_element_state_get_name(state),
-             gst_element_state_get_name(pending),
-             gst_element_state_change_return_get_name(result),
-             GST_TIME_ARGS(position));
+    GST_INFO_OBJECT(
+      player.pipeline_,
+      "Player state: %s (pending: %s, result: %s), position: %" GST_TIME_FORMAT "",
+      gst_element_state_get_name(state),
+      gst_element_state_get_name(pending),
+      gst_element_state_change_return_get_name(result),
+      GST_TIME_ARGS(position));
     player.hang_monitor_.Reset();
     return G_SOURCE_CONTINUE;
   }, this, nullptr);
   hang_monitor_source_id_ = g_source_attach(src, main_loop_context_);
   g_source_unref(src);
 
-  GST_INFO("Creating player with max capabilities: %s",
+  GST_INFO_OBJECT(pipeline_,"Creating player with max capabilities: '%s'",
            max_video_capabilities);
 
   GstElementFactory* src_factory = gst_element_factory_find("cobaltsrc");
@@ -1488,7 +1483,10 @@
     gst_object_unref(src_factory);
   }
 
-  pipeline_ = gst_element_factory_make("playbin", "media_pipeline");
+  static int player_id = 0;
+  player_id++;
+
+  pipeline_ = CreateGstElement("playbin", "media-pipeline-%d", player_id);
 
   unsigned flagAudio = getGstPlayFlag("audio");
   unsigned flagVideo = getGstPlayFlag("video");
@@ -1523,15 +1521,15 @@
   bus_watch_id_ = gst_bus_add_watch(bus, &PlayerImpl::BusMessageCallback, this);
   gst_object_unref(bus);
 
-  video_appsrc_ = gst_element_factory_make("appsrc", "vidsrc");
-  audio_appsrc_ = gst_element_factory_make("appsrc", "audsrc");
+  video_appsrc_ = CreateGstElement("appsrc", "vidsrc-%d", player_id);
+  audio_appsrc_ = CreateGstElement("appsrc", "audsrc-%d", player_id);
 
   GstElement* playsink = (gst_bin_get_by_name(GST_BIN(pipeline_), "playsink"));
   if (playsink) {
     g_object_set(G_OBJECT(playsink), "send-event-mode", 0, nullptr);
     g_object_unref(playsink);
   } else {
-    GST_WARNING("No playsink ?!?!?");
+    GST_WARNING_OBJECT(pipeline_, "No playsink ?!?!?");
   }
 
   if (drm_system_) {
@@ -1545,6 +1543,9 @@
   ChangePipelineState(GST_STATE_READY);
   g_main_context_pop_thread_default(main_loop_context_);
 
+  if (gst_element_get_state(pipeline_, nullptr, nullptr, 0) == GST_STATE_CHANGE_FAILURE)
+    return;
+
   playback_thread_ =
       SbThreadCreate(0, kSbThreadPriorityRealTime, kSbThreadNoAffinity, true,
                      "playback_thread", &PlayerImpl::ThreadEntryPoint, this);
@@ -1592,31 +1593,32 @@
   }
   g_main_loop_unref(main_loop_);
   g_main_context_unref(main_loop_context_);
+  GST_INFO_OBJECT(pipeline_, "BYE BYE player");
   g_object_unref(pipeline_);
-  GST_INFO("BYE BYE player");
 }
 
 // static
 gboolean PlayerImpl::BusMessageCallback(GstBus* bus,
                                         GstMessage* message,
                                         gpointer user_data) {
-  SB_UNREFERENCED_PARAMETER(bus);
-
   PlayerImpl* self = static_cast<PlayerImpl*>(user_data);
+  return self->HandleBusMessage(bus, message);
+}
+
+gboolean PlayerImpl::HandleBusMessage(GstBus* bus, GstMessage* message) {
   GST_TRACE("%d", SbThreadGetId());
+  GST_LOG_OBJECT(pipeline_, "Got GST message '%s' from '%s'", GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC_NAME(message));
 
   switch (GST_MESSAGE_TYPE(message)) {
     case GST_MESSAGE_APPLICATION: {
-      self->HandleApplicationMessage(bus, message);
+      HandleApplicationMessage(bus, message);
       break;
     }
 
     case GST_MESSAGE_EOS:
-      if (GST_MESSAGE_SRC(message) == GST_OBJECT(self->pipeline_)) {
-        GST_INFO("EOS");
-        self->DispatchOnWorkerThread(new PlayerStatusTask(
-            self->player_status_func_, self->player_, self->ticket_,
-            self->context_, kSbPlayerStateEndOfStream));
+      if (GST_MESSAGE_SRC(message) == GST_OBJECT(pipeline_)) {
+        GST_INFO_OBJECT(pipeline_, "EOS");
+        DidEnd();
       }
       break;
 
@@ -1626,25 +1628,23 @@
       gst_message_parse_error(message, &err, &debug);
 
       std::string file_name = "cobalt_";
-      file_name += (GST_OBJECT_NAME(self->pipeline_));
+      file_name += (GST_OBJECT_NAME(pipeline_));
       file_name += "_err_";
       file_name += std::to_string(err->code);
-      GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(self->pipeline_),
+      GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(pipeline_),
                                         GST_DEBUG_GRAPH_SHOW_ALL,
                                         file_name.c_str());
 
 
-      bool is_eos = (self->eos_data_ == (int)self->GetBothMediaTypeTakingCodecsIntoAccount());
+      bool is_eos = (eos_data_ == (int)GetBothMediaTypeTakingCodecsIntoAccount());
       if (err->domain == GST_STREAM_ERROR && is_eos) {
-        GST_WARNING("Got stream error. But all streams are ended, so reporting EOS. Error code %d: %s (%s).",
+        GST_WARNING_OBJECT(pipeline_, "Got stream error. But all streams are ended, so reporting EOS. Error code %d: %s (%s).",
           err->code, err->message, debug);
-        self->DispatchOnWorkerThread(new PlayerStatusTask(
-          self->player_status_func_, self->player_, self->ticket_,
-          self->context_, kSbPlayerStateEndOfStream));
+        DidEnd();
       } else {
-        GST_ERROR("Error %d: %s (%s)", err->code, err->message, debug);
-        self->DispatchOnWorkerThread(new PlayerErrorTask(
-          self->player_error_func_, self->player_, self->context_,
+        GST_ERROR_OBJECT(pipeline_, "Error %d: %s (%s)", err->code, err->message, debug);
+        DispatchOnWorkerThread(new PlayerErrorTask(
+          player_error_func_, player_, context_,
           kSbPlayerErrorDecode, err->message));
       }
       g_free(debug);
@@ -1653,7 +1653,7 @@
     }
 
     case GST_MESSAGE_STATE_CHANGED: {
-      if (GST_MESSAGE_SRC(message) == GST_OBJECT(self->pipeline_)) {
+      if (GST_MESSAGE_SRC(message) == GST_OBJECT(pipeline_)) {
         GstState old_state, new_state, pending;
         gst_message_parse_state_changed(message, &old_state, &new_state,
                                         &pending);
@@ -1663,16 +1663,16 @@
                         gst_element_state_get_name(new_state),
                         gst_element_state_get_name(pending));
         std::string file_name = "cobalt_";
-        file_name += (GST_OBJECT_NAME(self->pipeline_));
+        file_name += (GST_OBJECT_NAME(pipeline_));
         file_name += "_";
         file_name += gst_element_state_get_name(old_state);
         file_name += "_";
         file_name += gst_element_state_get_name(new_state);
-        GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(self->pipeline_),
+        GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(pipeline_),
                                           GST_DEBUG_GRAPH_SHOW_ALL,
                                           file_name.c_str());
 
-        if (GST_STATE(self->pipeline_) >= GST_STATE_PAUSED) {
+        if (GST_STATE(pipeline_) >= GST_STATE_PAUSED) {
           int ticket = 0;
           bool is_seek_pending = false;
           bool is_rate_pending = false;
@@ -1680,93 +1680,93 @@
           SbTime pending_seek_pos = kSbTimeMax;
 
           {
-            ::starboard::ScopedLock lock(self->mutex_);
-            ticket = self->ticket_;
-            is_seek_pending = self->is_seek_pending_;
-            is_rate_pending = self->pending_rate_ != .0;
-            pending_seek_pos = self->seek_position_;
-            SB_DCHECK(!is_seek_pending || self->seek_position_ != kSbTimeMax);
-            rate = self->pending_rate_;
+            ::starboard::ScopedLock lock(mutex_);
+            ticket = ticket_;
+            is_seek_pending = is_seek_pending_;
+            is_rate_pending = pending_rate_ != .0;
+            pending_seek_pos = seek_position_;
+            SB_DCHECK(!is_seek_pending || seek_position_ != kSbTimeMax);
+            rate = pending_rate_;
             if (is_seek_pending && is_rate_pending) {
               is_rate_pending = false;
-              self->rate_ = rate;
-              self->pending_rate_ = .0;
+              rate_ = rate;
+              pending_rate_ = .0;
             }
-            if (self->state_ == State::kPrerollAfterSeek ||
-                self->state_ == State::kInitialPreroll) {
-              self->has_oob_write_pending_ |= is_seek_pending;
+            if (state_ == State::kPrerollAfterSeek ||
+                state_ == State::kInitialPreroll) {
+              has_oob_write_pending_ |= is_seek_pending;
             }
           }
 
-          if (self->video_codec_ != kSbMediaVideoCodecNone && !self->pending_bounds_.IsEmpty()) {
-            PendingBounds bounds = self->pending_bounds_;
-            self->pending_bounds_ = {};
-            self->SetBounds(0, bounds.x, bounds.y, bounds.w, bounds.h);
+          if (video_codec_ != kSbMediaVideoCodecNone && !pending_bounds_.IsEmpty()) {
+            PendingBounds bounds = pending_bounds_;
+            pending_bounds_ = {};
+            SetBounds(0, bounds.x, bounds.y, bounds.w, bounds.h);
           }
 
-          if (is_rate_pending && GST_STATE(self->pipeline_) == GST_STATE_PLAYING) {
-            GST_INFO("Sending pending SetRate(rate=%lf)", rate);
-            self->SetRate(rate);
+          if (is_rate_pending && GST_STATE(pipeline_) == GST_STATE_PLAYING) {
+            GST_INFO_OBJECT(pipeline_,"Sending pending SetRate(rate=%lf)", rate);
+            SetRate(rate);
           } else if (is_seek_pending) {
-            GST_INFO("Sending pending Seek(position=%" PRId64 ", ticket=%d)", pending_seek_pos, ticket);
-            self->Seek(pending_seek_pos, ticket);
+            GST_INFO_OBJECT(pipeline_, "Sending pending Seek(position=%" PRId64 ", ticket=%d)", pending_seek_pos, ticket);
+            Seek(pending_seek_pos, ticket);
           }
         }
       }
     } break;
 
     case GST_MESSAGE_ASYNC_DONE: {
-      if (GST_MESSAGE_SRC(message) == GST_OBJECT(self->pipeline_)) {
-        GST_INFO("===> ASYNC-DONE %s %d",
-                 gst_element_state_get_name(GST_STATE(self->pipeline_)),
-                 static_cast<int>(self->state_));
+      if (GST_MESSAGE_SRC(message) == GST_OBJECT(pipeline_)) {
+        GST_INFO_OBJECT(pipeline_, "===> ASYNC-DONE, pipeline state: %s, player state: %s",
+                 gst_element_state_get_name(GST_STATE(pipeline_)),
+                 PrivatePlayerStateToStr(state_));
 
-        ::starboard::Mutex &mutex = self->mutex_;
+        ::starboard::Mutex &mutex = mutex_;
         ::starboard::ScopedLock lock(mutex);
 
-        if (self->state_ == State::kPrerollAfterSeek ||
-            self->state_ == State::kInitialPreroll) {
+        if (state_ == State::kPrerollAfterSeek ||
+            state_ == State::kInitialPreroll) {
 
-          bool is_seek_pending = self->is_seek_pending_;
-          bool has_pending_samples = (self->pending_samples_.empty() == false) || self->has_oob_write_pending_;
+          bool is_seek_pending = is_seek_pending_;
+          bool has_pending_samples = (pending_samples_.empty() == false) || has_oob_write_pending_;
 
           if (!is_seek_pending && has_pending_samples) {
 
-            int prev_has_data = static_cast<int>(self->has_enough_data_);
-            self->has_enough_data_ = static_cast<int>(MediaType::kBoth);
+            int prev_has_data = static_cast<int>(has_enough_data_);
+            has_enough_data_ = static_cast<int>(MediaType::kBoth);
 
             mutex.Release();
-            GST_INFO("===> Writing pending samples");
-            self->WritePendingSamples();
+            GST_INFO_OBJECT(pipeline_, "===> Writing pending samples");
+            WritePendingSamples();
             mutex.Acquire();
 
-            if (self->has_enough_data_ == static_cast<int>(MediaType::kBoth))
-              self->has_enough_data_ = prev_has_data;
-            self->has_oob_write_pending_ = false;
-            self->pending_oob_write_condition_.Broadcast();
+            if (has_enough_data_ == static_cast<int>(MediaType::kBoth))
+              has_enough_data_ = prev_has_data;
+            has_oob_write_pending_ = false;
+            pending_oob_write_condition_.Broadcast();
           }
-          GST_INFO("===> Asuming preroll done");
+          GST_INFO_OBJECT(pipeline_, "===> Asuming preroll done");
 
           // The below code is good but on BRCM the decoder reports old
           // position for some time which makes some YTLB 2020 test failing.
-          // self->seek_position_ = kSbTimeMax;
-          self->DispatchOnWorkerThread(new PlayerStatusTask(
-              self->player_status_func_, self->player_, self->ticket_,
-              self->context_, kSbPlayerStatePresenting));
-          self->state_ = State::kPresenting;
+          // seek_position_ = kSbTimeMax;
+          DispatchOnWorkerThread(new PlayerStatusTask(
+              player_status_func_, player_, ticket_,
+              context_, kSbPlayerStatePresenting));
+          state_ = State::kPresenting;
         }
 
-        self->SchedulePlayingStateUpdate();
+        SchedulePlayingStateUpdate();
       }
     } break;
 
     case GST_MESSAGE_CLOCK_LOST:
-      self->ChangePipelineState(GST_STATE_PAUSED);
-      self->ChangePipelineState(GST_STATE_PLAYING);
+      ChangePipelineState(GST_STATE_PAUSED);
+      ChangePipelineState(GST_STATE_PLAYING);
       break;
 
     case GST_MESSAGE_LATENCY:
-      gst_bin_recalculate_latency(GST_BIN(self->pipeline_));
+      gst_bin_recalculate_latency(GST_BIN(pipeline_));
       break;
 
     case GST_MESSAGE_QOS: {
@@ -1780,22 +1780,20 @@
         GstDebugLevel log_level = GST_LEVEL_DEBUG;
         gst_message_parse_qos_stats(message, &format, &processed, &dropped);
         if (format == GST_FORMAT_BUFFERS) {
-          ::starboard::ScopedLock lock(self->mutex_);
-          if (self->dropped_video_frames_ != static_cast<int>(dropped)) {
+          ::starboard::ScopedLock lock(mutex_);
+          if (dropped_video_frames_ != static_cast<int>(dropped)) {
             log_level = GST_LEVEL_INFO;
-            self->dropped_video_frames_ = static_cast<int>(dropped);
+            dropped_video_frames_ = static_cast<int>(dropped);
           }
         }
         GST_CAT_LEVEL_LOG (
-          GST_CAT_DEFAULT, log_level, NULL,
+          GST_CAT_DEFAULT, log_level, pipeline_,
           "QOS written = %d, processed = %" G_GUINT64_FORMAT ", dropped = %" G_GUINT64_FORMAT,
-          self->total_video_frames_, processed, dropped);
+          total_video_frames_, processed, dropped);
       }
     } break;
 
     default:
-      GST_LOG("Got GST message %s from %s", GST_MESSAGE_TYPE_NAME(message),
-              GST_MESSAGE_SRC_NAME(message));
       break;
   }
 
@@ -1954,12 +1952,13 @@
 // static
 void PlayerImpl::OnVideoBufferUnderflow(PlayerImpl* self)
 {
-  GST_WARNING("Decoder need data state = 0x%x,"
-              " video appsrc level = %lld kb,"
-              " audio appsrc level = %lld kb",
-              self->decoder_state_data_,
-              gst_app_src_get_current_level_bytes(GST_APP_SRC(self->video_appsrc_)) / 1024,
-              gst_app_src_get_current_level_bytes(GST_APP_SRC(self->audio_appsrc_)) / 1024);
+  GST_WARNING_OBJECT(self->pipeline_,
+    "Decoder need data state = 0x%x,"
+    " video appsrc level = %" G_GUINT64_FORMAT " kb,"
+    " audio appsrc level = %" G_GUINT64_FORMAT " kb",
+    self->decoder_state_data_,
+    gst_app_src_get_current_level_bytes(GST_APP_SRC(self->video_appsrc_)) / 1024,
+    gst_app_src_get_current_level_bytes(GST_APP_SRC(self->audio_appsrc_)) / 1024);
 }
 
 // static
@@ -1970,12 +1969,12 @@
     static bool disable_wait_video = !!getenv("COBALT_AML_DISABLE_WAIT_VIDEO");
     bool has_video = (self->video_codec_ != kSbMediaVideoCodecNone);
     if (has_video && g_str_has_prefix(GST_ELEMENT_NAME(element), "amlhalasink") && !disable_wait_video) {
-      g_object_set(element, "wait-video", TRUE, "a-wait-timeout", 4000, nullptr);
+      g_object_set(element, "wait-video", TRUE, "a-wait-timeout", 4000, "disable-xrun", TRUE, nullptr);
     }
     else
     if (has_video && g_str_has_prefix(GST_ELEMENT_NAME(element), "westerossink")) {
       if (g_object_class_find_property(G_OBJECT_GET_CLASS(element), "zoom-mode")) {
-        GST_INFO("Setting westerossink zoom-mode to 0");
+        GST_INFO_OBJECT(pipeline, "Setting westerossink zoom-mode to 0");
         g_object_set(element, "zoom-mode", 0, nullptr);
       }
       g_signal_connect_swapped(
@@ -1988,6 +1987,10 @@
     }
   }
 
+  if (GST_IS_BASE_PARSE(element)) {
+    gst_base_parse_set_pts_interpolation(GST_BASE_PARSE(element), FALSE);
+  }
+
   const gchar *klass_str = gst_element_class_get_metadata(GST_ELEMENT_GET_CLASS(element), "klass");
   if (strstr(klass_str, "Sink")) {
     GObjectClass *oclass = G_OBJECT_GET_CLASS(element);
@@ -2016,7 +2019,7 @@
     src = audio_appsrc_;
   }
 
-  GST_DEBUG_OBJECT(src, "===> %d", SbThreadGetId());
+  GST_INFO_OBJECT(src, "===> %d", SbThreadGetId());
   ::starboard::ScopedLock lock(mutex_);
   if (state_ == State::kPrerollAfterSeek)
     GST_DEBUG_OBJECT(src, "===> Mark EOS with State::kPrerollAfterSeek");
@@ -2026,7 +2029,12 @@
   else
       eos_data_ |= static_cast<int>(MediaType::kAudio);
 
-  gst_app_src_end_of_stream(GST_APP_SRC(src));
+  if (eos_data_ == static_cast<int>(GetBothMediaTypeTakingCodecsIntoAccount())) {
+    if (audio_codec_ != kSbMediaAudioCodecNone)
+      gst_app_src_end_of_stream(GST_APP_SRC(audio_appsrc_));
+    if (video_codec_ != kSbMediaVideoCodecNone)
+      gst_app_src_end_of_stream(GST_APP_SRC(video_appsrc_));
+  }
 }
 
 bool PlayerImpl::WriteSample(SbMediaType sample_type, GstBuffer* buffer, uint64_t serial_id) {
@@ -2102,16 +2110,44 @@
       sample_deallocate_func_(player_, context_, sample_infos[0].buffer);
       return;
   }
-  GstClockTime timestamp = sample_infos[0].timestamp * kSbTimeNanosecondsPerMicrosecond;
+
+#if defined(SB_RDK_ZERO_COPY_SAMPLE_WRITE) && SB_RDK_ZERO_COPY_SAMPLE_WRITE
+  using BufferInfo = std::tuple<SbPlayerDeallocateSampleFunc, SbPlayer, void*, const void*>;
+  GstBuffer* buffer =
+    gst_buffer_new_wrapped_full(
+      static_cast<GstMemoryFlags>(0),
+      const_cast<gpointer> (sample_infos[0].buffer),
+      sample_infos[0].buffer_size,
+      0,
+      sample_infos[0].buffer_size,
+      new BufferInfo(sample_deallocate_func_, player_, context_, sample_infos[0].buffer),
+      [](gpointer data) {
+        BufferInfo &info = *reinterpret_cast<BufferInfo*>(data);
+        auto deallocate_func = std::get<0>(info);
+        auto player = std::get<1>(info);
+        auto* context = std::get<2>(info);
+        const auto* buffer = std::get<3>(info);
+        deallocate_func(player, context, buffer);
+        delete &info;
+      });
+#else
+  G_GNUC_UNUSED gsize sz;
   GstBuffer* buffer =
       gst_buffer_new_allocate(nullptr, sample_infos[0].buffer_size, nullptr);
-  gsize sz = gst_buffer_fill(buffer, 0, sample_infos[0].buffer, sample_infos[0].buffer_size);
+  sz = gst_buffer_fill(buffer, 0, sample_infos[0].buffer, sample_infos[0].buffer_size);
   SB_DCHECK(sz == sample_infos[0].buffer_size);
-  GST_BUFFER_TIMESTAMP(buffer) = timestamp;
   sample_deallocate_func_(player_, context_, sample_infos[0].buffer);
+#endif
+
+  GstClockTime timestamp = sample_infos[0].timestamp * kSbTimeNanosecondsPerMicrosecond;
+  GST_BUFFER_TIMESTAMP(buffer) = timestamp;
 
   if (sample_infos[0].type == kSbMediaTypeVideo) {
+#if SB_API_VERSION >= 15
+    const auto& info = sample_infos[0].video_sample_info.stream_info;
+#else
     const auto& info = sample_infos[0].video_sample_info;
+#endif
     if (frame_width_ != info.frame_width ||
         frame_height_ != info.frame_height ||
         CompareColorMetadata(color_metadata_, info.color_metadata) != 0) {
@@ -2128,15 +2164,21 @@
         gst_caps_unref(gst_caps);
       }
     }
-    if (!info.is_key_frame) {
+    if (!sample_infos[0].video_sample_info.is_key_frame) {
       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
     }
   }
-  else {
+  else if (sample_infos[0].type == kSbMediaTypeAudio) {
     SB_DCHECK (sample_infos[0].type == kSbMediaTypeAudio);
     SB_DCHECK (audio_codec_ != kSbMediaAudioCodecNone);
+
     if ( audio_caps_ == nullptr ) {
-      auto caps = CodecToGstCaps(audio_codec_, &audio_sample_info_);
+#if SB_API_VERSION >= 15
+      const auto& audio_info = sample_infos[0].audio_sample_info.stream_info;
+#else
+      const auto& audio_info = sample_infos[0].audio_sample_info;
+#endif
+      auto caps = CodecToGstCaps(audio_codec_, &audio_info);
       if (!caps.empty() && caps[0].c_str()) {
         GstCaps* gst_caps = gst_caps_from_string(caps[0].c_str());
         PrintGstCaps(gst_caps);
@@ -2145,12 +2187,31 @@
         gst_caps_unref(gst_caps);
       }
     }
+
+#if SB_API_VERSION >= 15
+    const guint64 kMaxGstClockTime = G_MAXUINT64 / G_GUINT64_CONSTANT (2);
+    const auto& info = sample_infos[0].audio_sample_info;
+    guint64 start_clip = 0, end_clip = 0;
+
+    if (info.discarded_duration_from_front)
+      start_clip = (info.discarded_duration_from_front == kSbTimeMax)
+        ? kMaxGstClockTime : info.discarded_duration_from_front * kSbTimeNanosecondsPerMicrosecond;
+
+    if (info.discarded_duration_from_back)
+      end_clip = (info.discarded_duration_from_back == kSbTimeMax)
+        ? kMaxGstClockTime : info.discarded_duration_from_back * kSbTimeNanosecondsPerMicrosecond;
+
+    if (start_clip || end_clip) {
+      gst_buffer_add_audio_clipping_meta(buffer, GST_FORMAT_TIME, start_clip, end_clip);
+      GST_DEBUG_OBJECT(pipeline_, "Add audio clipping, start: %" PRIu64 ", end %" PRIu64, start_clip, end_clip);
+    }
+#endif
   }
 
   RecordTimestamp(sample_type, timestamp);
 
   if (sample_infos[0].drm_info) {
-    GST_LOG("Encounterd encrypted %s sample",
+    GST_LOG_OBJECT(pipeline_, "Encounterd encrypted %s sample",
             sample_type == kSbMediaTypeVideo ? "video" : "audio");
     SB_DCHECK(drm_system_);
 
@@ -2166,7 +2227,7 @@
       (encryption_scheme == kSbDrmEncryptionSchemeAesCtr) ? "cenc" :
       (encryption_scheme == kSbDrmEncryptionSchemeAesCbc  ? "cbcs" : "unknown");
 
-    GST_LOG("Encryption cipher-mode: %s", cipher_mode);
+    GST_LOG_OBJECT(pipeline_, "Encryption cipher-mode: %s", cipher_mode);
 
     key = gst_buffer_new_allocate(
         nullptr, sample_infos[0].drm_info->identifier_size, nullptr);
@@ -2194,12 +2255,12 @@
         if (!gst_byte_writer_put_uint16_be(
               &writer,
               sample_infos[0].drm_info->subsample_mapping[i].clear_byte_count))
-          GST_ERROR("Failed writing clear subsample info at %d", i);
+          GST_ERROR_OBJECT(pipeline_, "Failed writing clear subsample info at %d", i);
         if (!gst_byte_writer_put_uint32_be(&writer,
                                            sample_infos[0]
                                            .drm_info->subsample_mapping[i]
                                            .encrypted_byte_count))
-          GST_ERROR("Failed writing encrypted subsample info at %d", i);
+          GST_ERROR_OBJECT(pipeline_, "Failed writing encrypted subsample info at %d", i);
       }
       subsamples = gst_buffer_new_wrapped(subsamples_raw, subsamples_raw_size);
     }
@@ -2229,7 +2290,7 @@
     gst_buffer_unref(key);
     gst_buffer_unref(subsamples);
   } else {
-    GST_LOG("Encounterd clear %s sample",
+    GST_LOG_OBJECT(pipeline_, "Encounterd clear %s sample",
             sample_type == kSbMediaTypeVideo ? "video" : "audio");
   }
 
@@ -2246,15 +2307,15 @@
         seek_pos_ns =  seek_position_ * kSbTimeNanosecondsPerMicrosecond;
   }
 
-  if (GST_CLOCK_TIME_IS_VALID(seek_pos_ns) && seek_pos_ns > GST_BUFFER_TIMESTAMP(buffer)) {
+  if (GST_CLOCK_TIME_IS_VALID(seek_pos_ns) && GstClockTime(seek_pos_ns) > GST_BUFFER_TIMESTAMP(buffer)) {
     // Set dummy duration to let sink drop out-of-segment samples
     GST_BUFFER_DURATION (buffer) = GST_SECOND / 60;
     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DECODE_ONLY);
   }
 
   if (keep_samples) {
-    GST_INFO("Pending flushing operation. Storing sample");
-    GST_INFO("SampleType:%d %" GST_TIME_FORMAT " id:%" PRIu64 " b:%" GST_PTR_FORMAT,
+    GST_INFO_OBJECT(pipeline_, "Pending flushing operation. Storing sample");
+    GST_INFO_OBJECT(pipeline_, "SampleType:%d %" GST_TIME_FORMAT " id:%" PRIu64 " b:%" GST_PTR_FORMAT,
              sample_type, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)), serial, buffer);
     PendingSample sample(sample_type, buffer, serial);
     buffer= nullptr;
@@ -2268,7 +2329,7 @@
     while(has_oob_write_pending_) {
       const auto kWaitTime = 10 * kSbTimeSecond;
       if (!pending_oob_write_condition_.WaitTimed(kWaitTime)) {
-        GST_ERROR("Pending write took too long, give up");
+        GST_ERROR_OBJECT(pipeline_, "Pending write took too long, give up");
         has_oob_write_pending_ = false;
         break;
       }
@@ -2283,7 +2344,7 @@
     }
 
     if(local_samples.empty()) {
-      GST_WARNING("No pending samples");
+      GST_WARNING_OBJECT(pipeline_, "No pending samples");
       return;
     }
 
@@ -2292,7 +2353,7 @@
     SB_CHECK(sample.Type() == sample_type);
 
     if (serial != sample.SerialID()) {
-      GST_WARNING("Detected out-of-order sample. Expected serial: %" PRIu64 ", sample serial: %" PRIu64 "",
+      GST_WARNING_OBJECT(pipeline_, "Detected out-of-order sample. Expected serial: %" PRIu64 ", sample serial: %" PRIu64 "",
                   serial, sample.SerialID());
     }
 
@@ -2312,7 +2373,7 @@
     }
   }
 
-  GST_TRACE("Wrote sample.");
+  GST_LOG_OBJECT(pipeline_,"Wrote sample.");
 }
 
 void PlayerImpl::SetVolume(double volume) {
@@ -2375,14 +2436,14 @@
       DispatchOnWorkerThread(new PlayerStatusTask(player_status_func_, player_, ticket_,
                                                   context_, kSbPlayerStatePrerolling));
       AddBufferingProbe(position, ticket_);
-      GST_INFO("Successfully changed initial segment, position: %" GST_TIME_FORMAT ", ticket: %d", GST_TIME_ARGS(position), ticket_);
+      GST_INFO_OBJECT(pipeline_, "Successfully changed initial segment, position: %" GST_TIME_FORMAT ", ticket: %d", GST_TIME_ARGS(position), ticket_);
       return;
     }
   }
 #endif
 
   // Else send seek after pre-roll.
-  GST_INFO("Delaying seek.");
+  GST_INFO_OBJECT(pipeline_, "Delaying seek.");
   is_seek_pending_ = true;
 }
 
@@ -2430,7 +2491,7 @@
     }
   }
 
-  GST_DEBUG("Calling seek");
+  GST_DEBUG_OBJECT(pipeline_, "Calling seek");
   DispatchOnWorkerThread(new PlayerStatusTask(player_status_func_, player_,
                                               ticket_, context_,
                                               kSbPlayerStatePrerolling));
@@ -2448,7 +2509,7 @@
       state_ = State::kPresenting;
     }, "Presenting after seek failure"));
   } else {
-    GST_DEBUG("Seek called with success");
+    GST_DEBUG_OBJECT(pipeline_, "Seek called with success");
     DispatchOnWorkerThread(new FunctionTask([this]() {
       state_ = State::kPrerollAfterSeek;
     }, "Preroll after seek"));
@@ -2497,29 +2558,10 @@
     need_instant_rate_change_ = ( rate != 1. );
     mutex_.Release();
 
-#if GST_CHECK_VERSION(1,18,0)
-    static const bool kEnableInstantRateChangeSeek = ([]()->bool {
-      if( !!getenv("COBALT_DISABLE_INSTANT_RATE_CHANGE_SEEK") )
-        return false;
-      if( !!getenv("COBALT_ENABLE_INSTANT_RATE_CHANGE_SEEK") )
-        return true;
-      return false;
-    })();
-    if (kEnableInstantRateChangeSeek) {
-      success = gst_element_seek(
-        pipeline_, rate, GST_FORMAT_TIME,
-        static_cast<GstSeekFlags>(GST_SEEK_FLAG_INSTANT_RATE_CHANGE),
-        GST_SEEK_TYPE_NONE, 0,
-        GST_SEEK_TYPE_NONE, 0);
-    }
-    else
-#endif
-    {
-      GstStructure* s = gst_structure_new(
+    GstStructure* s = gst_structure_new(
         kCustomInstantRateChangeEventName, "rate", G_TYPE_DOUBLE, rate, NULL);
-      success = gst_element_send_event(
+    success = gst_element_send_event(
         pipeline_, gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s));
-    }
 
     mutex_.Acquire();
   }
@@ -2533,25 +2575,22 @@
   return success;
 }
 
+#if SB_API_VERSION >= 15
+void PlayerImpl::GetInfo(SbPlayerInfo* out_player_info) {
+#else   // SB_API_VERSION >= 15
 void PlayerImpl::GetInfo(SbPlayerInfo2* out_player_info) {
-  gint64 duration = 0;
-  if (gst_element_query_duration(pipeline_, GST_FORMAT_TIME, &duration) &&
-      GST_CLOCK_TIME_IS_VALID(duration)) {
-    out_player_info->duration = duration;
-  } else {
-    out_player_info->duration = SB_PLAYER_NO_DURATION;
-  }
+#endif  // SB_API_VERSION >= 15
 
   gint64 position = GetPosition();
 
   CheckBuffering(position);
 
-  GST_TRACE("Position: %" GST_TIME_FORMAT " (Seek to: %" GST_TIME_FORMAT
-            ") Duration: %" GST_TIME_FORMAT,
-            GST_TIME_ARGS(position),
-            GST_TIME_ARGS(seek_position_ * kSbTimeNanosecondsPerMicrosecond),
-            GST_TIME_ARGS(duration));
+  GST_LOG_OBJECT(
+    pipeline_,"Current position: %" GST_TIME_FORMAT " (Seek position: %" GST_TIME_FORMAT ")",
+    GST_TIME_ARGS(position),
+    GST_TIME_ARGS(seek_position_ != kSbTimeMax ? seek_position_ * kSbTimeNanosecondsPerMicrosecond : GST_CLOCK_TIME_NONE));
 
+  out_player_info->duration = SB_PLAYER_NO_DURATION;
   out_player_info->current_media_timestamp =
       GST_CLOCK_TIME_IS_VALID(position)
           ? position / kSbTimeNanosecondsPerMicrosecond
@@ -2570,14 +2609,17 @@
     out_player_info->dropped_video_frames = dropped_video_frames_;
   }
 
-  GST_LOG("Frames dropped: %d, Frames corrupted: %d",
-          out_player_info->dropped_video_frames,
-          out_player_info->corrupted_video_frames);
+  GST_LOG_OBJECT(
+    pipeline_,
+    "Frames dropped: %d, Frames corrupted: %d",
+    out_player_info->dropped_video_frames,
+    out_player_info->corrupted_video_frames);
+
   out_player_info->playback_rate = rate_;
 }
 
 void PlayerImpl::SetBounds(int zindex, int x, int y, int w, int h) {
-  GST_TRACE("Set Bounds: %d %d %d %d %d", zindex, x, y, w, h);
+  GST_TRACE_OBJECT(pipeline_, "Set Bounds: %d %d %d %d %d", zindex, x, y, w, h);
   GstElement* vid_sink = nullptr;
   g_object_get(pipeline_, "video-sink", &vid_sink, nullptr);
   if (vid_sink && g_object_class_find_property(G_OBJECT_GET_CLASS(vid_sink),
@@ -2601,7 +2643,7 @@
   GstState current, pending;
   current = pending = GST_STATE_VOID_PENDING;
   gst_element_get_state(pipeline_, &current, &pending, 0);
-  if ((current == state && pending == GST_STATE_VOID_PENDING) || pending == state) {
+  if (current == state || pending == state) {
     GST_DEBUG_OBJECT(
       pipeline_, "Rejected state change to %s from %s with %s pending",
       gst_element_state_get_name(state),
@@ -2626,7 +2668,7 @@
         GST_INFO_OBJECT(pipeline_, "Ignore state change to playing: invalid min sample ts");
         return false;
       }
-      else if (seek_pos_ns > min_ts) {
+      else if (seek_pos_ns > GstClockTime(min_ts)) {
         GST_INFO_OBJECT(
           pipeline_,
           "Ignore state change to playing: no samples for seek time yet"
@@ -2646,7 +2688,15 @@
   }
   GST_INFO_OBJECT(pipeline_, "Changing state to %s",
                    gst_element_state_get_name(state));
-  return gst_element_set_state(pipeline_, state) != GST_STATE_CHANGE_FAILURE;
+  bool result = gst_element_set_state(pipeline_, state) != GST_STATE_CHANGE_FAILURE;
+  if (!result) {
+    GST_ERROR_OBJECT(
+      pipeline_, "Failed to change pipeline state to %s from %s with %s pending",
+      gst_element_state_get_name(state),
+      gst_element_state_get_name(current),
+      gst_element_state_get_name(pending));
+  }
+  return result;
 }
 
 void PlayerImpl::CheckBuffering(gint64 position) {
@@ -2654,7 +2704,7 @@
     return;
 
   constexpr SbTime kMarginNs =
-      350 * kSbTimeMillisecond * kSbTimeNanosecondsPerMicrosecond;
+      50 * kSbTimeMillisecond * kSbTimeNanosecondsPerMicrosecond;
 
   MediaType origin = MediaType::kNone;
   SbTime min_ts = MinTimestamp(&origin);
@@ -2671,12 +2721,9 @@
       DecoderNeedsData(lock, origin);
       buf_target_min_ts_ = min_ts + kMarginNs;
     }
-
-    PrintPositionPerSink(pipeline_);
-    GST_WARNING("Force setting to PAUSED. Pos: %" GST_TIME_FORMAT
-                " sample:%" GST_TIME_FORMAT,
-                GST_TIME_ARGS(position), GST_TIME_ARGS(min_ts + kMarginNs));
-
+    PrintPositionPerSink(pipeline_, GST_LEVEL_INFO);
+    GST_INFO_OBJECT(pipeline_, "Pause for buffering. Pos: %" GST_TIME_FORMAT
+                ", min ts:%" GST_TIME_FORMAT, GST_TIME_ARGS(position), GST_TIME_ARGS(min_ts));
     ChangePipelineState(GST_STATE_PAUSED);
   } else if (buf_target_min_ts_ != kSbTimeMax && min_ts > buf_target_min_ts_) {
     double rate;
@@ -2689,8 +2736,9 @@
     GstState state, pending;
     gst_element_get_state(pipeline_, &state, &pending, 0);
     if (rate > .0 && state != GST_STATE_PLAYING && pending != GST_STATE_PLAYING) {
-      GST_TRACE("Moving to playing, min_ts = %" GST_TIME_FORMAT " need %" GST_TIME_FORMAT,
-                GST_TIME_ARGS(min_ts), GST_TIME_ARGS(buf_target_min_ts));
+      GST_INFO_OBJECT(
+        pipeline_, "Resuming playback. min_ts: %" GST_TIME_FORMAT ", buff traget: %" GST_TIME_FORMAT,
+        GST_TIME_ARGS(min_ts), GST_TIME_ARGS(buf_target_min_ts));
       ChangePipelineState(GST_STATE_PLAYING);
     }
   }
@@ -2733,13 +2781,14 @@
 
   if (GST_CLOCK_TIME_IS_VALID(cached_position_ns_) &&
       std::abs(position - cached_position_ns_) > GST_SECOND) {
-    PrintPositionPerSink(pipeline_);
-    GST_WARNING("Unexpected position! More than 1 second jump detected: "
+    PrintPositionPerSink(pipeline_, GST_LEVEL_WARNING);
+    GST_WARNING_OBJECT(pipeline_, "Unexpected position! More than 1 second jump detected: "
                 "%" GST_TIME_FORMAT " --> %" GST_TIME_FORMAT "",
                 GST_TIME_ARGS(cached_position_ns_),
                 GST_TIME_ARGS(position));
   }
 
+  PrintPositionPerSink(pipeline_, GST_LEVEL_LOG);
   cached_position_ns_ = position;
   return position;
 }
@@ -2766,16 +2815,16 @@
       auto &prev_ts = prev_timestamps[sample.Type() == kSbMediaTypeVideo ? kVideoIndex : kAudioIndex];
 
       if (prev_ts == sample.Timestamp()) {
-        GST_WARNING("Skipping %" GST_TIME_FORMAT ". Already written.",
+        GST_WARNING_OBJECT(pipeline_, "Skipping %" GST_TIME_FORMAT ". Already written.",
                     GST_TIME_ARGS(prev_ts));
         continue;
       }
 
       GstBuffer* buffer = keep_samples ? sample.CopyBuffer() : sample.TakeBuffer();
-      GST_INFO("Writing pending: SampleType:%d id:%" PRIu64 " b:%" GST_PTR_FORMAT, sample.Type(), sample.SerialID(), buffer);
+      GST_INFO_OBJECT(pipeline_, "Writing pending: SampleType:%d id:%" PRIu64 " b:%" GST_PTR_FORMAT, sample.Type(), sample.SerialID(), buffer);
       prev_ts = GST_BUFFER_TIMESTAMP(buffer);
       if (WriteSample(sample.Type(), buffer, sample.SerialID())) {
-        GST_INFO("Pending sample was written.");
+        GST_INFO_OBJECT(pipeline_, "Pending sample was written.");
       } else {
         gst_buffer_unref(buffer);
       }
@@ -2792,9 +2841,9 @@
         }
       }
       if (keep_samples) {
-        GST_INFO("Stored samples again.");
+        GST_INFO_OBJECT(pipeline_, "Stored samples again.");
       } else {
-        GST_INFO("Seek ticket changed (%d -> %d), dropped local samples.", ticket, ticket_);
+        GST_INFO_OBJECT(pipeline_, "Seek ticket changed (%d -> %d), dropped local samples.", ticket, ticket_);
       }
     }
   }
@@ -2848,7 +2897,7 @@
 void PlayerImpl::HandleApplicationMessage(GstBus* bus, GstMessage* message) {
   const GstStructure* structure = gst_message_get_structure(message);
   if (gst_structure_has_name(structure, "force-stop") && !force_stop_) {
-    GST_INFO("Received force STOP, pipeline = %p!!!", pipeline_);
+    GST_INFO_OBJECT(pipeline_, "Received force STOP, pipeline = %p!!!", pipeline_);
     force_stop_ = true;
     ChangePipelineState(GST_STATE_READY);
     g_signal_handlers_disconnect_by_func(pipeline_, reinterpret_cast<gpointer>(&PlayerImpl::SetupSource), this);
@@ -2862,7 +2911,7 @@
   }
   else if (gst_structure_has_name(structure, kDidReceiveFirstSegmentMsgName)) {
     if (GST_MESSAGE_SRC(message) == GST_OBJECT(audio_appsrc_) || GST_MESSAGE_SRC(message) == GST_OBJECT(video_appsrc_)) {
-      GST_INFO("Received '%s' message from %" GST_PTR_FORMAT, kDidReceiveFirstSegmentMsgName, GST_MESSAGE_SRC(message));
+      GST_INFO_OBJECT(pipeline_, "Received '%s' message from %" GST_PTR_FORMAT, kDidReceiveFirstSegmentMsgName, GST_MESSAGE_SRC(message));
       bool should_set_rate = false;
       double rate = 0.;
       auto type = GST_MESSAGE_SRC(message) == GST_OBJECT(audio_appsrc_) ? MediaType::kAudio : MediaType::kVideo;
@@ -2874,7 +2923,7 @@
       mutex_.Release();
 
       if (should_set_rate) {
-        GST_INFO("Sending pending SetRate(rate=%lf)", rate);
+        GST_INFO_OBJECT(pipeline_, "Sending pending SetRate(rate=%lf)", rate);
         SetRate(rate);
       }
     }
@@ -2883,7 +2932,7 @@
     if (GST_MESSAGE_SRC(message) == GST_OBJECT(audio_appsrc_) || GST_MESSAGE_SRC(message) == GST_OBJECT(video_appsrc_)) {
       int ticket;
       if (gst_structure_get_int(structure, "ticket", &ticket)) {
-        GST_INFO("Received '%s' message from %" GST_PTR_FORMAT, kDidReachBufferingTargetMsgName, GST_MESSAGE_SRC(message));
+        GST_INFO_OBJECT(pipeline_, "Received '%s' message from %" GST_PTR_FORMAT, kDidReachBufferingTargetMsgName, GST_MESSAGE_SRC(message));
         auto type = GST_MESSAGE_SRC(message) == GST_OBJECT(audio_appsrc_) ? MediaType::kAudio : MediaType::kVideo;
         bool should_update_playing_state = false;
         ::starboard::ScopedLock lock(mutex_);
@@ -2908,12 +2957,12 @@
           g_object_set(video_sink, "res-usage", 0x0u, nullptr);
         }
         else {
-          GST_WARNING("'westerossink' has no 'res-usage' property, secondary video may steal decoder");
+          GST_WARNING_OBJECT(pipeline_, "'westerossink' has no 'res-usage' property, secondary video may steal decoder");
         }
         g_object_set(pipeline_, "video-sink", video_sink, nullptr);
       }
       else {
-        GST_DEBUG("Failed to create 'westerossink'");
+        GST_DEBUG_OBJECT(pipeline_, "Failed to create 'westerossink'");
       }
       gst_object_unref(GST_OBJECT(factory));
     }
@@ -2989,7 +3038,8 @@
       buffering_state_ |= static_cast<int>(MediaType::kAudio);
   }
 
-  if (video_appsrc_) {
+  if (video_appsrc_ && video_codec_ != kSbMediaVideoCodecNone) {
+    target +=  10 * 16 * GST_MSECOND;
     if (add_probe(video_appsrc_, target, ticket, buffering_probe_callback) != 0u)
       buffering_state_ |= static_cast<int>(MediaType::kVideo);
   }
@@ -3035,6 +3085,33 @@
   g_source_unref(src);
 }
 
+void PlayerImpl::DidEnd() {
+  if (state_ < State::kPresenting) {
+    DispatchOnWorkerThread(
+      new PlayerStatusTask(
+        player_status_func_, player_, ticket_,
+        context_, kSbPlayerStatePresenting));
+    state_ = State::kPresenting;
+  }
+
+  if (state_ == State::kPresenting) {
+    DispatchOnWorkerThread(
+      new PlayerStatusTask(
+        player_status_func_, player_, ticket_,
+        context_, kSbPlayerStateEndOfStream));
+    state_ = State::kEnded;
+  }
+}
+
+void PlayerImpl::AudioConfigurationChanged() {
+  GST_WARNING_OBJECT(pipeline_, "Emitting an error on audio configuration change.");
+  DispatchOnWorkerThread(
+    new PlayerErrorTask(
+      player_error_func_, player_, context_,
+      kSbPlayerErrorCapabilityChanged, "Audio device capability changed"));
+
+}
+
 }  // namespace
 
 void ForceStop() {
@@ -3042,6 +3119,11 @@
   GetPlayerRegistry()->ForceStop();
 }
 
+void AudioConfigurationChanged() {
+  using third_party::starboard::rdk::shared::player::GetPlayerRegistry;
+  GetPlayerRegistry()->AudioConfigurationChanged();
+}
+
 }  // namespace player
 }  // namespace shared
 }  // namespace rdk
@@ -3055,7 +3137,11 @@
     SbMediaVideoCodec video_codec,
     SbMediaAudioCodec audio_codec,
     SbDrmSystem drm_system,
-    const SbMediaAudioSampleInfo& audio_sample_info,
+#if SB_API_VERSION >= 15
+    const SbMediaAudioStreamInfo& audio_info,
+#else   // SB_API_VERSION >= 15
+    const SbMediaAudioSampleInfo& audio_info,
+#endif
     const char* max_video_capabilities,
     SbPlayerDeallocateSampleFunc sample_deallocate_func,
     SbPlayerDecoderStatusFunc decoder_status_func,
@@ -3063,21 +3149,24 @@
     SbPlayerErrorFunc player_error_func,
     void* context,
     SbPlayerOutputMode output_mode,
-    SbDecodeTargetGraphicsContextProvider* provider)
-    : player_(new PlayerImpl(this,
-                             window,
-                             video_codec,
-                             audio_codec,
-                             drm_system,
-                             audio_sample_info,
-                             max_video_capabilities,
-                             sample_deallocate_func,
-                             decoder_status_func,
-                             player_status_func,
-                             player_error_func,
-                             context,
-                             output_mode,
-                             provider)) {
-  if (  !static_cast<PlayerImpl&>(*player_).IsValid() )
-    player_.reset(nullptr);
+    SbDecodeTargetGraphicsContextProvider* provider) {
+  if ( third_party::starboard::rdk::shared::player::GetPlayerRegistry()->CanCreate(max_video_capabilities) ) {
+    player_.reset(
+      new PlayerImpl(this,
+                     window,
+                     video_codec,
+                     audio_codec,
+                     drm_system,
+                     audio_info,
+                     max_video_capabilities,
+                     sample_deallocate_func,
+                     decoder_status_func,
+                     player_status_func,
+                     player_error_func,
+                     context,
+                     output_mode,
+                     provider));
+    if (  !static_cast<PlayerImpl&>(*player_).IsValid() )
+      player_.reset(nullptr);
+  }
 }
diff --git a/src/third_party/starboard/rdk/shared/player/player_internal.h b/src/third_party/starboard/rdk/shared/player/player_internal.h
index c91ed9c..845031f 100644
--- a/src/third_party/starboard/rdk/shared/player/player_internal.h
+++ b/src/third_party/starboard/rdk/shared/player/player_internal.h
@@ -37,10 +37,17 @@
   virtual void SetVolume(double volume) = 0;
   virtual void Seek(SbTime seek_to_timestamp, int ticket) = 0;
   virtual bool SetRate(double rate) = 0;
+#if SB_API_VERSION >= 15
+  virtual void GetInfo(SbPlayerInfo* info) = 0;
+#else   // SB_API_VERSION >= 15
   virtual void GetInfo(SbPlayerInfo2* info) = 0;
+#endif
   virtual void SetBounds(int zindex, int x, int y, int w, int h) = 0;
 };
 
+void ForceStop();
+void AudioConfigurationChanged();
+
 }  // namespace player
 }  // namespace shared
 }  // namespace rdk
@@ -52,7 +59,11 @@
                   SbMediaVideoCodec video_codec,
                   SbMediaAudioCodec audio_codec,
                   SbDrmSystem drm_system,
-                  const SbMediaAudioSampleInfo& audio_sample_info,
+#if SB_API_VERSION >= 15
+                  const SbMediaAudioStreamInfo& audio_info,
+#else   // SB_API_VERSION >= 15
+                  const SbMediaAudioSampleInfo& audio_info,
+#endif
                   const char* max_video_capabilities,
                   SbPlayerDeallocateSampleFunc sample_deallocate_func,
                   SbPlayerDecoderStatusFunc decoder_status_func,
@@ -67,6 +78,7 @@
     using third_party::starboard::rdk::shared::player::Player;
     return Player::MaxNumberOfSamplesPerWrite();
   }
+
   std::unique_ptr<third_party::starboard::rdk::shared::player::Player> player_;
 };
 
diff --git a/src/third_party/starboard/rdk/shared/player/player_seek.cc b/src/third_party/starboard/rdk/shared/player/player_seek.cc
index 0c1bc19..69ddbce 100644
--- a/src/third_party/starboard/rdk/shared/player/player_seek.cc
+++ b/src/third_party/starboard/rdk/shared/player/player_seek.cc
@@ -33,6 +33,12 @@
 
 #include "third_party/starboard/rdk/shared/player/player_internal.h"
 
+#if SB_API_VERSION >= 15
+void SbPlayerSeek(SbPlayer player, SbTime seek_to_timestamp, int ticket) {
+#else   // SB_API_VERSION >= 15
 void SbPlayerSeek2(SbPlayer player, SbTime seek_to_timestamp, int ticket) {
+#endif  // SB_API_VERSION >= 15
+  if (player == kSbPlayerInvalid)
+    return;
   player->player_->Seek(seek_to_timestamp, ticket);
 }
diff --git a/src/third_party/starboard/rdk/shared/player/player_set_bounds.cc b/src/third_party/starboard/rdk/shared/player/player_set_bounds.cc
index 84c5627..20b9f7b 100644
--- a/src/third_party/starboard/rdk/shared/player/player_set_bounds.cc
+++ b/src/third_party/starboard/rdk/shared/player/player_set_bounds.cc
@@ -39,5 +39,7 @@
                        int y,
                        int width,
                        int height) {
+  if (player == kSbPlayerInvalid)
+    return;
   player->player_->SetBounds(z_index, x, y, width, height);
 }
diff --git a/src/third_party/starboard/rdk/shared/player/player_set_playback_rate.cc b/src/third_party/starboard/rdk/shared/player/player_set_playback_rate.cc
index e5d2083..3923883 100644
--- a/src/third_party/starboard/rdk/shared/player/player_set_playback_rate.cc
+++ b/src/third_party/starboard/rdk/shared/player/player_set_playback_rate.cc
@@ -34,5 +34,7 @@
 #include "third_party/starboard/rdk/shared/player/player_internal.h"
 
 bool SbPlayerSetPlaybackRate(SbPlayer player, double playback_rate) {
+  if (player == kSbPlayerInvalid)
+    return false;
   return player->player_->SetRate(playback_rate);
 }
diff --git a/src/third_party/starboard/rdk/shared/player/player_set_volume.cc b/src/third_party/starboard/rdk/shared/player/player_set_volume.cc
index 0ad39dc..728fae3 100644
--- a/src/third_party/starboard/rdk/shared/player/player_set_volume.cc
+++ b/src/third_party/starboard/rdk/shared/player/player_set_volume.cc
@@ -34,5 +34,7 @@
 #include "third_party/starboard/rdk/shared/player/player_internal.h"
 
 void SbPlayerSetVolume(SbPlayer player, double volume) {
+  if (player == kSbPlayerInvalid)
+    return;
   player->player_->SetVolume(volume);
 }
diff --git a/src/third_party/starboard/rdk/shared/player/player_write_end_of_stream.cc b/src/third_party/starboard/rdk/shared/player/player_write_end_of_stream.cc
index 23fef23..1b78f87 100644
--- a/src/third_party/starboard/rdk/shared/player/player_write_end_of_stream.cc
+++ b/src/third_party/starboard/rdk/shared/player/player_write_end_of_stream.cc
@@ -34,5 +34,7 @@
 #include "third_party/starboard/rdk/shared/player/player_internal.h"
 
 void SbPlayerWriteEndOfStream(SbPlayer player, SbMediaType stream_type) {
+  if (player == kSbPlayerInvalid)
+    return;
   player->player_->MarkEOS(stream_type);
 }
diff --git a/src/third_party/starboard/rdk/shared/player/player_write_sample.cc b/src/third_party/starboard/rdk/shared/player/player_write_sample.cc
index 335b999..8336b8e 100644
--- a/src/third_party/starboard/rdk/shared/player/player_write_sample.cc
+++ b/src/third_party/starboard/rdk/shared/player/player_write_sample.cc
@@ -33,10 +33,17 @@
 
 #include "third_party/starboard/rdk/shared/player/player_internal.h"
 
-void SbPlayerWriteSample2(SbPlayer player,
+#if SB_API_VERSION >= 15
+SB_EXPORT void SbPlayerWriteSamples(
+#else   // SB_API_VERSION >= 15
+SB_EXPORT void SbPlayerWriteSample2(
+#endif  // SB_API_VERSION >= 15
+                          SbPlayer player,
                           SbMediaType sample_type,
                           const SbPlayerSampleInfo* sample_infos,
                           int number_of_sample_infos) {
+  if (player == kSbPlayerInvalid)
+    return;
   player->player_->WriteSample(sample_type, sample_infos,
                                number_of_sample_infos);
 }
diff --git a/src/third_party/starboard/rdk/shared/rdkservices.cc b/src/third_party/starboard/rdk/shared/rdkservices.cc
index d29525e..6355fe5 100644
--- a/src/third_party/starboard/rdk/shared/rdkservices.cc
+++ b/src/third_party/starboard/rdk/shared/rdkservices.cc
@@ -30,22 +30,29 @@
 #include <interfaces/json/JsonData_HDRProperties.h>
 #include <interfaces/json/JsonData_PlayerProperties.h>
 #include <interfaces/json/JsonData_DeviceIdentification.h>
+#include <interfaces/json/JsonData_DeviceInfo.h>
 
 #ifdef HAS_SECURITY_AGENT
 #include <securityagent/securityagent.h>
 #endif
 
 #include "starboard/atomic.h"
+#include "starboard/audio_sink.h"
 #include "starboard/event.h"
+#include "starboard/media.h"
 #include "starboard/once.h"
+#include "starboard/common/atomic.h"
 #include "starboard/common/condition_variable.h"
 #include "starboard/common/mutex.h"
+#include "starboard/common/media.h"
 #include "starboard/accessibility.h"
 #include "starboard/common/file.h"
+#include "starboard/shared/starboard/media/mime_supportability_cache.h"
 
 #include "third_party/starboard/rdk/shared/accessibility_data.h"
 #include "third_party/starboard/rdk/shared/log_override.h"
 #include "third_party/starboard/rdk/shared/application_rdk.h"
+#include "third_party/starboard/rdk/shared/player/player_internal.h"
 
 MODULE_NAME_DECLARATION(BUILD_REFERENCE);
 
@@ -66,6 +73,9 @@
 const char kTTSCallsign[] = "org.rdk.TextToSpeech.1";
 const char kAuthServiceCallsign[] = "org.rdk.AuthService.1";
 
+const char kDeviceInfoCallsign[] = "DeviceInfo.1";
+const char kBluetoothCallsign[] = "org.rdk.Bluetooth.1";
+
 const char kAuthServiceExperienceFile[] = "/opt/www/authService/experience.dat";
 
 const uint32_t kPriviligedRequestErrorCode = -32604U;
@@ -192,6 +202,20 @@
   }
 };
 
+struct VariableTimeout {
+  const uint32_t min_ms;   // milliseconds
+  const uint64_t deadline; // ticks
+  VariableTimeout(uint32_t min, uint32_t max)
+    : min_ms(min), deadline(Core::Time::Now().Ticks() + max * Core::Time::TicksPerMillisecond) {
+  }
+  uint32_t value() const {
+    auto now = Core::Time::Now().Ticks();
+    return (now < deadline)
+      ? std::max(static_cast<uint32_t>((deadline - now) / Core::Time::TicksPerMillisecond), min_ms)
+      : min_ms;
+  }
+};
+
 struct DeviceIdImpl {
   DeviceIdImpl() {
     JsonData::DeviceIdentification::DeviceidentificationData data;
@@ -808,6 +832,7 @@
 private:
   void Refresh();
   void OnUpdated(const Core::JSON::String&);
+  void ForceNeedsRefresh() {  needs_refresh_.store(true); }
 
   ServiceLink display_info_ { kDisplayInfoCallsign };
   ResolutionInfo resolution_info_ { };
@@ -817,16 +842,19 @@
   ::starboard::atomic_bool did_subscribe_ { false };
 };
 
+SB_ONCE_INITIALIZE_FUNCTION(DisplayInfoImpl, GetDisplayInfo);
+
 void DisplayInfoImpl::Refresh() {
   if (!needs_refresh_.load())
     return;
 
+  VariableTimeout timeout(kDefaultTimeoutMs, 1000);
   uint32_t rc;
 
   if (!did_subscribe_.load()) {
     bool old_val = did_subscribe_.exchange(true);
     if (old_val == false) {
-      rc = display_info_.Subscribe<Core::JSON::String>(kDefaultTimeoutMs, "updated", &DisplayInfoImpl::OnUpdated, this);
+      rc = display_info_.Subscribe<Core::JSON::String>(timeout.value(), "updated", &DisplayInfoImpl::OnUpdated, this);
       if (Core::ERROR_UNAVAILABLE == rc || kPriviligedRequestErrorCode == rc) {
         needs_refresh_.store(false);
         SB_LOG(ERROR) << "Failed to subscribe to '" << kDisplayInfoCallsign
@@ -848,7 +876,7 @@
   bool needs_refresh = false;
 
   Core::JSON::String resolution;
-  rc = ServiceLink(kPlayerInfoCallsign).Get(kDefaultTimeoutMs, "resolution", resolution);
+  rc = ServiceLink(kPlayerInfoCallsign).Get(timeout.value(), "resolution", resolution);
   if (Core::ERROR_NONE == rc && resolution.IsSet()) {
     if (resolution.Value().find("Resolution2160") != std::string::npos) {
       resolution_info_ = ResolutionInfo { 3840 , 2160 };
@@ -856,20 +884,20 @@
       resolution_info_ = ResolutionInfo { 1920 , 1080 };
     }
   } else {
-    needs_refresh |= (Core::ERROR_ASYNC_FAILED == rc);
+    needs_refresh |= (Core::ERROR_ASYNC_FAILED == rc || Core::ERROR_TIMEDOUT  == rc);
     resolution_info_ = ResolutionInfo { 1920 , 1080 };
     SB_LOG(ERROR) << "Failed to get 'resolution', rc=" << rc << " ( " << Core::ErrorToString(rc) << " )";
   }
 
   Core::JSON::DecUInt16 widthincentimeters, heightincentimeters;
-  rc = display_info_.Get(kDefaultTimeoutMs, "widthincentimeters", widthincentimeters);
+  rc = display_info_.Get(timeout.value(), "widthincentimeters", widthincentimeters);
   if (Core::ERROR_NONE != rc) {
     needs_refresh |= (Core::ERROR_ASYNC_FAILED == rc);
     widthincentimeters.Clear();
     SB_LOG(ERROR) << "Failed to get 'DisplayInfo.widthincentimeters', rc=" << rc << " ( " << Core::ErrorToString(rc) << " )";
   }
 
-  rc = display_info_.Get(kDefaultTimeoutMs, "heightincentimeters", heightincentimeters);
+  rc = display_info_.Get(timeout.value(), "heightincentimeters", heightincentimeters);
   if (Core::ERROR_NONE != rc) {
     needs_refresh |= (Core::ERROR_ASYNC_FAILED == rc);
     heightincentimeters.Clear();
@@ -888,9 +916,9 @@
 
     HdrTypes types;
 
-    uint32_t rc = display_info_.Get(kDefaultTimeoutMs, method, types);
+    uint32_t rc = display_info_.Get(timeout.value(), method, types);
     if (Core::ERROR_NONE != rc) {
-      needs_refresh |= (Core::ERROR_ASYNC_FAILED == rc);
+      needs_refresh |= (Core::ERROR_ASYNC_FAILED == rc || Core::ERROR_TIMEDOUT  == rc);
       SB_LOG(ERROR) << "Failed to get '" << method << "', rc=" << rc << " ( " << Core::ErrorToString(rc) << " )";
       return 0u;
     }
@@ -926,7 +954,15 @@
 
   hdr_caps_ = tv_caps & stb_caps;
 
-  needs_refresh_.store(needs_refresh);
+  needs_refresh_.store(false);
+
+  if (needs_refresh) {
+    SbEventSchedule([](void* data) {
+      using ::starboard::shared::starboard::media::MimeSupportabilityCache;
+      MimeSupportabilityCache::GetInstance()->ClearCachedMimeSupportabilities();
+      GetDisplayInfo()->ForceNeedsRefresh();
+    }, nullptr, kSbTimeSecond);
+  }
 
   SB_LOG(INFO) << "Display info updated, resolution: "
                << resolution_info_.Width << 'x' << resolution_info_.Height
@@ -940,13 +976,14 @@
   if (needs_refresh_.load() == false) {
     needs_refresh_.store(true);
     SbEventSchedule([](void* data) {
+      using ::starboard::shared::starboard::media::MimeSupportabilityCache;
+      // Clear mime cache until display info is updated
+      MimeSupportabilityCache::GetInstance()->ClearCachedMimeSupportabilities();
       Application::Get()->DisplayInfoChanged();
     }, nullptr, 0);
   }
 }
 
-SB_ONCE_INITIALIZE_FUNCTION(DisplayInfoImpl, GetDisplayInfo);
-
 struct NetworkInfoImpl {
 private:
   ServiceLink network_link_ { kNetworkCallsign };
@@ -1058,12 +1095,10 @@
 
       if (is_connected_.load() != has_connected_interface) {
         is_connected_.store(has_connected_interface);
-#if SB_API_VERSION >= 13
         if (has_connected_interface)
           Application::Get()->InjectOsNetworkConnectedEvent();
         else
           Application::Get()->InjectOsNetworkDisconnectedEvent();
-#endif
       }
     }
 
@@ -1112,6 +1147,291 @@
 
 SB_ONCE_INITIALIZE_FUNCTION(NetworkInfoImpl, GetNetworkInfo);
 
+struct DeviceInfoImpl {
+
+  bool GetAudioConfiguration(int index, SbMediaAudioConfiguration* out_audio_configuration);
+
+  void Teardown() {
+    if (did_subscribe_.load()) {
+      bluetooth_.Unsubscribe(kDefaultTimeoutMs, "onStatusChanged");
+      did_subscribe_.store(false);
+    }
+    device_info_.Teardown();
+    bluetooth_.Teardown();
+    needs_refresh_.store(true);
+  }
+
+private:
+  struct DeviceDetailsData : public Core::JSON::Container {
+    DeviceDetailsData()
+      : Core::JSON::Container() {
+      Init();
+    }
+    DeviceDetailsData(const DeviceDetailsData& other)
+      : Core::JSON::Container()
+      , Name(other.Name)
+      , Devicetype(other.Devicetype) {
+      Init();
+    }
+    DeviceDetailsData& operator=(const DeviceDetailsData& rhs) {
+      Name = rhs.Name;
+      Devicetype = rhs.Devicetype;
+      return *this;
+    }
+    Core::JSON::String Name;
+    Core::JSON::String Devicetype;
+  private:
+    void Init() {
+      Add(_T("name"), &Name);
+      Add(_T("deviceType"), &Devicetype);
+    }
+  };
+
+  struct ConnectedDevicesData : public Core::JSON::Container {
+    ConnectedDevicesData()
+      : Core::JSON::Container() {
+      Add(_T("connectedDevices"), &Connecteddevices);
+    }
+    ConnectedDevicesData(const ConnectedDevicesData&) = delete;
+    ConnectedDevicesData& operator=(const ConnectedDevicesData&) = delete;
+    Core::JSON::ArrayType<DeviceDetailsData> Connecteddevices;
+  };
+
+  struct StatusChangedData : public Core::JSON::Container {
+    StatusChangedData()
+      : Core::JSON::Container() {
+      Init();
+    }
+    StatusChangedData(const StatusChangedData& other)
+      : Core::JSON::Container()
+      , Name(other.Name)
+      , Newstatus(other.Newstatus)
+      , Devicetype(other.Devicetype)
+      , Connected(other.Connected) {
+      Init();
+    }
+    StatusChangedData& operator=(const StatusChangedData& rhs) {
+      Name = rhs.Name;
+      Devicetype = rhs.Devicetype;
+      Newstatus = rhs.Newstatus;
+      Connected = rhs.Connected;
+      return *this;
+    }
+    Core::JSON::String Name;
+    Core::JSON::String Newstatus;
+    Core::JSON::String Devicetype;
+    Core::JSON::Boolean Connected;
+  private:
+    void Init() {
+      Add(_T("name"), &Name);
+      Add(_T("newStatus"), &Newstatus);
+      Add(_T("deviceType"), &Devicetype);
+      Add(_T("connected"), &Connected);
+    }
+  };
+
+  void OnBluetoothStatusChanged(const StatusChangedData&);
+  void Refresh();
+  void ForceNeedsRefresh() {  needs_refresh_.store(true); }
+  void InitAudioConfigurationForAudioPort(const std::string& port_name, SbMediaAudioConfiguration* out);
+
+  static bool IsAudioOutputDeviceType(const std::string& type) {
+    return (strcasestr(type.c_str(), "audio") ||
+            strcasestr(type.c_str(), "headset") ||
+            strcasestr(type.c_str(), "headphones") ||
+            strcasestr(type.c_str(), "loudspeaker") ||
+            strcasestr(type.c_str(), "handsfree"));
+  };
+
+  ServiceLink device_info_ { kDeviceInfoCallsign };
+  ServiceLink bluetooth_ { kBluetoothCallsign };
+
+  ::starboard::atomic_bool did_subscribe_ { false };
+  ::starboard::atomic_bool needs_refresh_ { true };
+  ::starboard::atomic_bool has_bluetooth_audio_connected_ { false };
+  ::starboard::Mutex mutex_;
+
+  std::vector<SbMediaAudioConfiguration> audio_configurations_;
+
+  static constexpr SbMediaAudioConnector kAudioConnectorUnknown = static_cast<SbMediaAudioConnector>(0);
+};
+
+SB_ONCE_INITIALIZE_FUNCTION(DeviceInfoImpl, GetDeviceInfo);
+
+void DeviceInfoImpl::InitAudioConfigurationForAudioPort(const std::string& port_name, SbMediaAudioConfiguration* audio_configuration)
+{
+  if (!audio_configuration)
+    return;
+
+  const auto& connectorType = [](const std::string& name) {
+    if (strncasecmp(name.c_str(), "hdmi", 4) == 0)
+      return kSbMediaAudioConnectorHdmi;
+    else if (strncasecmp(name.c_str(), "spdif", 5) == 0)
+      return kSbMediaAudioConnectorSpdif;
+    else if (strncasecmp(name.c_str(), "bluetooth", 9) == 0)
+      return kSbMediaAudioConnectorBluetooth;
+#if SB_API_VERSION >= 15
+    else if (strncasecmp(name.c_str(), "speaker", 7) == 0)
+      return kSbMediaAudioConnectorBuiltIn;
+#endif
+    return kAudioConnectorUnknown;
+  };
+
+  memset(audio_configuration, 0, sizeof(SbMediaAudioConfiguration));
+
+  audio_configuration->connector = connectorType(port_name);
+  audio_configuration->coding_type = kSbMediaAudioCodingTypePcm;
+  audio_configuration->number_of_channels = SbAudioSinkGetMaxChannels();
+  return;
+}
+
+void DeviceInfoImpl::OnBluetoothStatusChanged(const StatusChangedData& data) {
+  const char kConnectionChange[] = "CONNECTION_CHANGE";
+
+  SB_LOG(INFO) << "Bluetooth status changed, new status: " << data.Newstatus.Value();
+
+  if (data.Newstatus.Value().compare(0, sizeof(kConnectionChange), kConnectionChange) != 0)
+    return;
+
+  if (!IsAudioOutputDeviceType(data.Devicetype.Value()))
+    return;
+
+  SB_LOG(INFO) << "Audio device change."
+               << " name: '" << data.Name.Value() << "',"
+               << " type: '" << data.Devicetype.Value() << "',"
+               << " connected: " << (data.Connected.Value() ? "yes" : "no");
+
+  const auto& hasBluetoothConnector = [&]() -> bool {
+    ::starboard::ScopedLock lock(mutex_);
+    return std::find_if(audio_configurations_.begin(), audio_configurations_.end(), [](const SbMediaAudioConfiguration& cfg) {
+      return cfg.connector == kSbMediaAudioConnectorBluetooth;
+    }) != audio_configurations_.end();
+  };
+
+  has_bluetooth_audio_connected_.store(data.Connected.Value());
+
+  ForceNeedsRefresh();
+
+  // Interrupt player only if new wireless device got connected
+  if (data.Connected.Value() && !hasBluetoothConnector()) {
+    SbEventSchedule([](void*) {
+      player::AudioConfigurationChanged();
+    }, nullptr, 0);
+  }
+}
+
+void DeviceInfoImpl::Refresh() {
+  if ( !needs_refresh_.load() || !needs_refresh_.exchange( false ) )
+    return;
+
+  std::vector<SbMediaAudioConfiguration> audio_configs;
+
+  uint32_t rc;
+  bool needs_refresh = false;
+  VariableTimeout timeout { kDefaultTimeoutMs, 1000 };
+
+  if (did_subscribe_.load() == false && did_subscribe_.exchange(true) == false) {
+    rc = bluetooth_.Subscribe<StatusChangedData>(timeout.value(), "onStatusChanged", &DeviceInfoImpl::OnBluetoothStatusChanged, this);
+    if (Core::ERROR_NONE != rc && Core::ERROR_DUPLICATE_KEY != rc) {
+      SB_LOG(ERROR) << "Failed to subscribe to '" << kBluetoothCallsign
+                    << ".onStatusChanged' event, rc=" << rc
+                    << " ( " << Core::ErrorToString(rc) << " )";
+    }
+  }
+
+  using namespace WPEFramework::JsonData::DeviceInfo;
+  SupportedaudioportsData audio_ports;
+  rc = device_info_.Get(timeout.value(), "supportedaudioports", audio_ports);
+  if (Core::ERROR_NONE != rc) {
+    SB_LOG(ERROR) << "'" << kDeviceInfoCallsign << ".supportedaudioports' failed, rc = " << rc
+                  << " ( " << Core::ErrorToString(rc) << " )";
+    needs_refresh |= (Core::ERROR_ASYNC_FAILED == rc || Core::ERROR_TIMEDOUT  == rc);
+  } else if (audio_ports.SupportedAudioPorts.Length() == 0) {
+    SB_LOG(INFO) << "No supported audio ports.";
+  } else {
+    auto index(audio_ports.SupportedAudioPorts.Elements());
+    while (index.Next()) {
+      const auto& port_name = index.Current().Value();
+      SB_LOG(INFO) << "Supported audio port name: " << port_name;
+      SbMediaAudioConfiguration configuration;
+      InitAudioConfigurationForAudioPort(port_name, &configuration);
+      if (configuration.connector != kAudioConnectorUnknown)
+        audio_configs.push_back(std::move(configuration));
+    }
+  }
+
+  if (has_bluetooth_audio_connected_.load()) {
+    SbMediaAudioConfiguration configuration;
+    InitAudioConfigurationForAudioPort("bluetooth", &configuration);
+    audio_configs.push_back(std::move(configuration));
+  } else {
+    ConnectedDevicesData connected_devices;
+    rc = bluetooth_.Get(timeout.value(), "getConnectedDevices", connected_devices);
+    if (Core::ERROR_NONE != rc) {
+      SB_LOG(ERROR) << "'" << kBluetoothCallsign << ".getConnectedDevices' failed, rc = " << rc
+                    << " ( " << Core::ErrorToString(rc) << " )";
+      needs_refresh |= (Core::ERROR_ASYNC_FAILED == rc || Core::ERROR_TIMEDOUT  == rc);
+    } else if (connected_devices.Connecteddevices.Length() == 0) {
+      SB_LOG(INFO) << "No bluetooth connected devices.";
+    } else {
+      auto index(connected_devices.Connecteddevices.Elements());
+      while (index.Next()) {
+        const auto& device_details = index.Current();
+        SB_LOG(INFO) << "Bluetooth device name: " << device_details.Name.Value() << ", type: " << device_details.Devicetype.Value();
+        if (IsAudioOutputDeviceType(device_details.Devicetype.Value())) {
+          SbMediaAudioConfiguration configuration;
+          InitAudioConfigurationForAudioPort("bluetooth", &configuration);
+          audio_configs.push_back(std::move(configuration));
+          break;
+        }
+      }
+    }
+  }
+
+  if (audio_configs.empty()) {
+    SbMediaAudioConfiguration configuration;
+    InitAudioConfigurationForAudioPort("", &configuration);
+    audio_configs.push_back(std::move(configuration));
+  }
+
+  if (needs_refresh) {
+    SbEventSchedule([](void* data) {
+      GetDeviceInfo()->ForceNeedsRefresh();
+    }, nullptr, kSbTimeSecond);
+  }
+
+  SB_LOG(INFO) << "Updated audio configuration:";
+  for (const auto& config : audio_configs) {
+    SB_LOG(INFO) << " connector: " << (uint32_t) config.connector << " (" << ::starboard::GetMediaAudioConnectorName(config.connector) << ")";
+  }
+
+  ::starboard::ScopedLock lock(mutex_);
+  std::swap(audio_configurations_, audio_configs);
+}
+
+bool DeviceInfoImpl::GetAudioConfiguration(int output_index, SbMediaAudioConfiguration* out_configuration) {
+  SB_DCHECK(output_index >= 0);
+  SB_DCHECK(out_configuration);
+
+  if (!out_configuration || output_index < 0)
+    return false;
+
+  Refresh();
+
+  ::starboard::ScopedLock lock(mutex_);
+  size_t index = output_index;
+  if (index < audio_configurations_.size()) {
+    *out_configuration = audio_configurations_[index];
+    return true;
+  }
+  else if (index == 0) {
+    InitAudioConfigurationForAudioPort("", out_configuration);
+    return true;
+  }
+
+  return false;
+}
+
 }  // namespace
 
 ResolutionInfo DisplayInfo::GetResolution() {
@@ -1238,10 +1558,15 @@
   return GetAuthService()->GetExperience(out);
 }
 
+bool DeviceInfo::GetAudioConfiguration(int index, SbMediaAudioConfiguration* out_audio_configuration) {
+  return GetDeviceInfo()->GetAudioConfiguration(index, out_audio_configuration);
+}
+
 void TeardownJSONRPCLink() {
   GetDisplayInfo()->Teardown();
   GetTextToSpeech()->Teardown();
   GetNetworkInfo()->Teardown();
+  GetDeviceInfo()->Teardown();
 }
 
 }  // namespace shared
diff --git a/src/third_party/starboard/rdk/shared/rdkservices.h b/src/third_party/starboard/rdk/shared/rdkservices.h
index d810bd0..e317ebe 100644
--- a/src/third_party/starboard/rdk/shared/rdkservices.h
+++ b/src/third_party/starboard/rdk/shared/rdkservices.h
@@ -25,6 +25,7 @@
 
 struct SbAccessibilityCaptionSettings;
 struct SbAccessibilityDisplaySettings;
+struct SbMediaAudioConfiguration;
 
 namespace third_party {
 namespace starboard {
@@ -33,10 +34,10 @@
 
 struct ResolutionInfo {
   ResolutionInfo() {}
-  ResolutionInfo(uint32_t w, uint32_t h)
+  ResolutionInfo(int32_t w, int32_t h)
     : Width(w), Height(h) {}
-  uint32_t Width { 1920 };
-  uint32_t Height { 1080 };
+  int32_t Width { 1920 };
+  int32_t Height { 1080 };
 };
 
 class DisplayInfo {
@@ -111,6 +112,10 @@
   static bool GetExperience(std::string &out);
 };
 
+class DeviceInfo {
+public:
+  static bool GetAudioConfiguration(int index, SbMediaAudioConfiguration* out_audio_configuration);
+};
 
 void TeardownJSONRPCLink();
 
diff --git a/src/third_party/starboard/rdk/shared/speech/speech_synthesis_cancel.cc b/src/third_party/starboard/rdk/shared/speech/speech_synthesis_cancel.cc
index 02ac70c..e757880 100644
--- a/src/third_party/starboard/rdk/shared/speech/speech_synthesis_cancel.cc
+++ b/src/third_party/starboard/rdk/shared/speech/speech_synthesis_cancel.cc
@@ -31,10 +31,6 @@
 #include "starboard/speech_synthesis.h"
 #include "third_party/starboard/rdk/shared/rdkservices.h"
 
-#if SB_API_VERSION >= 12 || SB_HAS(SPEECH_SYNTHESIS)
-
 void SbSpeechSynthesisCancel() {
   third_party::starboard::rdk::shared::TextToSpeech::Cancel();
 }
-
-#endif
diff --git a/src/third_party/starboard/rdk/shared/speech/speech_synthesis_is_supported.cc b/src/third_party/starboard/rdk/shared/speech/speech_synthesis_is_supported.cc
index d9e57c4..47f5c27 100644
--- a/src/third_party/starboard/rdk/shared/speech/speech_synthesis_is_supported.cc
+++ b/src/third_party/starboard/rdk/shared/speech/speech_synthesis_is_supported.cc
@@ -30,10 +30,6 @@
 
 #include "starboard/speech_synthesis.h"
 
-#if SB_API_VERSION >= 12
-
 bool SbSpeechSynthesisIsSupported() {
   return true;
 }
-
-#endif
diff --git a/src/third_party/starboard/rdk/shared/speech/speech_synthesis_speak.cc b/src/third_party/starboard/rdk/shared/speech/speech_synthesis_speak.cc
index 4772912..d231ef3 100644
--- a/src/third_party/starboard/rdk/shared/speech/speech_synthesis_speak.cc
+++ b/src/third_party/starboard/rdk/shared/speech/speech_synthesis_speak.cc
@@ -31,12 +31,8 @@
 #include "starboard/speech_synthesis.h"
 #include "third_party/starboard/rdk/shared/rdkservices.h"
 
-#if SB_API_VERSION >= 12 || SB_HAS(SPEECH_SYNTHESIS)
-
 void SbSpeechSynthesisSpeak(const char* text) {
   if (!text)
     return;
   third_party::starboard::rdk::shared::TextToSpeech::Speak(text);
 }
-
-#endif
diff --git a/src/third_party/starboard/rdk/shared/system/system_egl.cc b/src/third_party/starboard/rdk/shared/system/system_egl.cc
index 5149cd2..8f2ca67 100644
--- a/src/third_party/starboard/rdk/shared/system/system_egl.cc
+++ b/src/third_party/starboard/rdk/shared/system/system_egl.cc
@@ -118,7 +118,7 @@
 
 #ifdef EGL_PLATFORM_WAYLAND_EXT
   if (gEglCreatePlatformWindowSurfaceEXT) {
-    result = gEglCreatePlatformWindowSurfaceEXT(dpy, config, (EGLNativeWindowType)win,
+    result = gEglCreatePlatformWindowSurfaceEXT(dpy, config, (void*)win,
                                                 attrib_list);
     if (result == EGL_NO_SURFACE)
       SB_LOG(WARNING) << "eglCreatePlatformWindowSurfaceEXT failed, err: " << eglGetError();
diff --git a/src/third_party/starboard/rdk/shared/system/system_get_device_type.cc b/src/third_party/starboard/rdk/shared/system/system_get_device_type.cc
index a7bf7eb..b96b200 100644
--- a/src/third_party/starboard/rdk/shared/system/system_get_device_type.cc
+++ b/src/third_party/starboard/rdk/shared/system/system_get_device_type.cc
@@ -14,6 +14,8 @@
 #include "starboard/system.h"
 #include "starboard/string.h"
 
+#if SB_API_VERSION < 15
+
 #include <core/Enumerate.h>
 
 #include "third_party/starboard/rdk/shared/rdkservices.h"
@@ -59,3 +61,5 @@
   SB_LOG(INFO) << "DeviceType: 'SetTopBox'";
   return kSbSystemDeviceTypeSetTopBox;
 }
+
+#endif
diff --git a/src/third_party/starboard/rdk/shared/system/system_get_extensions.cc b/src/third_party/starboard/rdk/shared/system/system_get_extensions.cc
index 8dbffdd..8deea82 100644
--- a/src/third_party/starboard/rdk/shared/system/system_get_extensions.cc
+++ b/src/third_party/starboard/rdk/shared/system/system_get_extensions.cc
@@ -32,11 +32,12 @@
 
 #include <cstring>
 
-#include "cobalt/extension/platform_service.h"
-#include "cobalt/extension/configuration.h"
-#include "cobalt/extension/crash_handler.h"
+
 #include "starboard/common/string.h"
 #include "starboard/common/log.h"
+#include "starboard/extension/configuration.h"
+#include "starboard/extension/crash_handler.h"
+#include "starboard/extension/platform_service.h"
 #include "third_party/starboard/rdk/shared/configuration.h"
 #include "third_party/starboard/rdk/shared/platform_service.h"
 #if SB_IS(EVERGREEN_COMPATIBLE)
diff --git a/src/third_party/starboard/rdk/shared/system/system_get_path.cc b/src/third_party/starboard/rdk/shared/system/system_get_path.cc
index be5b04a..ec57651 100644
--- a/src/third_party/starboard/rdk/shared/system/system_get_path.cc
+++ b/src/third_party/starboard/rdk/shared/system/system_get_path.cc
@@ -210,26 +210,27 @@
     return false;
   }
 
-  char path[kSbFileMaxPath];
+  const int kPathSize = kSbFileMaxPath;
+  char path[kPathSize];
   path[0] = '\0';
 
   switch (path_id) {
     case kSbSystemPathContentDirectory:
-      if (!GetContentDirectory(path, kSbFileMaxPath)){
+      if (!GetContentDirectory(path, kPathSize)){
         return false;
       }
 #if SB_IS(EVERGREEN_COMPATIBLE)
-      if (!GetEvergreenContentPathOverride(path, kSbFileMaxPath)) {
+      if (!GetEvergreenContentPathOverride(path, kPathSize)) {
         return false;
       }
 #endif
       break;
 
     case kSbSystemPathCacheDirectory:
-      if (!GetCacheDirectory(path, kSbFileMaxPath)) {
+      if (!GetCacheDirectory(path, kPathSize)) {
         return false;
       }
-      if (starboard::strlcat<char>(path, "/cobalt", kSbFileMaxPath) >= kSbFileMaxPath) {
+      if (starboard::strlcat<char>(path, "/cobalt", kPathSize) >= kPathSize) {
         return false;
       }
       if (!SbDirectoryCreate(path)) {
@@ -238,38 +239,32 @@
       break;
 
     case kSbSystemPathDebugOutputDirectory:
-      if (!SbSystemGetPath(kSbSystemPathTempDirectory, path, kSbFileMaxPath)) {
+      if (!SbSystemGetPath(kSbSystemPathTempDirectory, path, kPathSize)) {
         return false;
       }
-      if (starboard::strlcat<char>(path, "/log", kSbFileMaxPath) >= kSbFileMaxPath) {
+      if (starboard::strlcat<char>(path, "/log", kPathSize) >= kPathSize) {
         return false;
       }
       SbDirectoryCreate(path);
       break;
 
     case kSbSystemPathTempDirectory:
-      if (!GetTemporaryDirectory(path, kSbFileMaxPath)) {
+      if (!GetTemporaryDirectory(path, kPathSize)) {
         return false;
       }
       SbDirectoryCreate(path);
       break;
 
-#if SB_API_VERSION < 14
-    case kSbSystemPathTestOutputDirectory:
-      return SbSystemGetPath(kSbSystemPathDebugOutputDirectory, out_path,
-                             path_size);
-#endif  // #if SB_API_VERSION < 14
-
     case kSbSystemPathExecutableFile:
       return GetExecutablePath(out_path, path_size);
 
     case kSbSystemPathFontConfigurationDirectory:
     case kSbSystemPathFontDirectory:
 #if SB_IS(EVERGREEN_COMPATIBLE)
-      if (!GetContentDirectory(path, kSbFileMaxPath)) {
+      if (!GetContentDirectory(path, kPathSize)) {
         return false;
       }
-      if (starboard::strlcat(path, "/fonts", kSbFileMaxPath) >= kSbFileMaxPath) {
+      if (starboard::strlcat(path, "/fonts", kPathSize) >= kPathSize) {
         return false;
       }
       break;
@@ -277,13 +272,11 @@
       return false;
 #endif
 
-#if SB_API_VERSION >= 12
     case kSbSystemPathStorageDirectory:
-      if (!GetStorageDirectory(path, kSbFileMaxPath)) {
+      if (!GetStorageDirectory(path, kPathSize)) {
           return false;
       }
       break;
-#endif
 
     default:
       SB_NOTIMPLEMENTED() << "SbSystemGetPath not implemented for " << path_id;
diff --git a/src/third_party/starboard/rdk/shared/system/system_get_property.cc b/src/third_party/starboard/rdk/shared/system/system_get_property.cc
index 2aec496..6207ec2 100644
--- a/src/third_party/starboard/rdk/shared/system/system_get_property.cc
+++ b/src/third_party/starboard/rdk/shared/system/system_get_property.cc
@@ -39,7 +39,6 @@
 #include "starboard/common/log.h"
 #include "starboard/common/string.h"
 #include "starboard/common/file.h"
-#include "starboard/character.h"
 #include "starboard/file.h"
 
 #include "third_party/starboard/rdk/shared/rdkservices.h"
@@ -52,7 +51,7 @@
 const char kPlatformName[] = "Linux";
 
 bool CopyStringAndTestIfSuccess(char* out_value,
-                                int value_length,
+                                size_t value_length,
                                 const char* from_value) {
   if (strlen(from_value) + 1 > value_length)
     return false;
@@ -60,7 +59,7 @@
   return true;
 }
 
-bool TryReadFromPropertiesFile(const char* prefix, size_t prefix_len, char* out_value, int value_length) {
+bool TryReadFromPropertiesFile(const char* prefix, size_t prefix_len, char* out_value, size_t value_length) {
   FILE* properties = fopen("/etc/device.properties", "r");
   if (!properties) {
     return false;
@@ -256,6 +255,19 @@
     return false;
 }
 
+#if SB_API_VERSION >= 15
+bool GetDeviceType(char* out_value, int value_length) {
+    std::string prop;
+    if (AuthService::GetExperience(prop) && prop == "Flex") {
+      prop = "OTT";
+    }
+    else if (!SystemProperties::GetDeviceType(prop)) {
+      prop = "STB";
+    }
+    return CopyStringAndTestIfSuccess(out_value, value_length, prop.c_str());
+}
+#endif
+
 }  // namespace
 
 bool SbSystemGetProperty(SbSystemPropertyId property_id,
@@ -295,18 +307,17 @@
 
     case kSbSystemPropertyCertificationScope:
       return GetCertificationScope(out_value, value_length);
-#if SB_API_VERSION < 13
-    case kSbSystemPropertyBase64EncodedCertificationSecret:
-      return false;
-#endif
 
-#if SB_API_VERSION >= 14
     case kSbSystemPropertyAdvertisingId:
       return GetAdvertisingId(out_value, value_length);
+
     case kSbSystemPropertyLimitAdTracking:
       return GetLimitAdTracking(out_value, value_length);
-#endif
 
+#if SB_API_VERSION >= 15
+    case kSbSystemPropertyDeviceType:
+      return GetDeviceType(out_value, value_length);
+#endif
     default:
       SB_DLOG(WARNING) << __FUNCTION__
                        << ": Unrecognized property: " << property_id;
diff --git a/src/third_party/starboard/rdk/shared/system/system_get_total_cpu_memory.cc b/src/third_party/starboard/rdk/shared/system/system_get_total_cpu_memory.cc
new file mode 100644
index 0000000..27e68c4
--- /dev/null
+++ b/src/third_party/starboard/rdk/shared/system/system_get_total_cpu_memory.cc
@@ -0,0 +1,69 @@
+//
+// Copyright 2020 Comcast Cable Communications Management, LLC
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+// Copyright 2016 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/system.h"
+
+#include <unistd.h>
+
+#include "starboard/common/file.h"
+#include "starboard/common/log.h"
+#include "starboard/common/string.h"
+
+int64_t SbSystemGetTotalCPUMemory() {
+
+  int64_t limit_in_bytes = INT64_MAX;
+
+  starboard::ScopedFile status_file(
+    "/sys/fs/cgroup/memory/memory.limit_in_bytes",
+    kSbFileOpenOnly | kSbFileRead);
+
+  if (status_file.IsValid()) {
+    const int kBufferSize = 512;
+    char buffer[kBufferSize];
+    int bytes_read = status_file.ReadAll(buffer, kBufferSize);
+    if (bytes_read == kBufferSize) {
+      bytes_read = kBufferSize - 1;
+    }
+    buffer[bytes_read] = '\0';
+    int64_t val = strtoll(buffer, nullptr, 10);
+    if (val > 0)
+      limit_in_bytes = val;
+  }
+
+  long pages = sysconf(_SC_PHYS_PAGES);     // NOLINT[runtime/int]
+  long page_size = sysconf(_SC_PAGE_SIZE);  // NOLINT[runtime/int]
+  if (pages == -1 || page_size == -1) {
+    SB_NOTREACHED();
+    return 0;
+  }
+
+  return std::min(limit_in_bytes, static_cast<int64_t>(pages) * page_size);
+}
diff --git a/src/third_party/starboard/rdk/shared/system/system_get_connection_type.cc b/src/third_party/starboard/rdk/shared/system/system_get_total_gpu_memory.cc
similarity index 66%
rename from src/third_party/starboard/rdk/shared/system/system_get_connection_type.cc
rename to src/third_party/starboard/rdk/shared/system/system_get_total_gpu_memory.cc
index 8db9bf4..21cee44 100644
--- a/src/third_party/starboard/rdk/shared/system/system_get_connection_type.cc
+++ b/src/third_party/starboard/rdk/shared/system/system_get_total_gpu_memory.cc
@@ -1,3 +1,4 @@
+//
 // Copyright 2020 Comcast Cable Communications Management, LLC
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,14 +31,27 @@
 
 #include "starboard/system.h"
 
-#include "third_party/starboard/rdk/shared/rdkservices.h"
+#include "starboard/common/file.h"
+#include "starboard/common/log.h"
+#include "starboard/common/string.h"
 
-#if SB_API_VERSION < 14
-SbSystemConnectionType SbSystemGetConnectionType() {
-  if (third_party::starboard::rdk::shared::NetworkInfo::IsConnectionTypeWireless()) {
-    return kSbSystemConnectionTypeWireless;
-  } else {
-    return kSbSystemConnectionTypeWired;
+int64_t SbSystemGetTotalGPUMemory() {
+  starboard::ScopedFile status_file(
+    "/sys/fs/cgroup/gpu/gpu.limit_in_bytes",
+    kSbFileOpenOnly | kSbFileRead);
+
+  if (status_file.IsValid()) {
+    const int kBufferSize = 512;
+    char buffer[kBufferSize];
+    int bytes_read = status_file.ReadAll(buffer, kBufferSize);
+    if (bytes_read == kBufferSize) {
+      bytes_read = kBufferSize - 1;
+    }
+    buffer[bytes_read] = '\0';
+    int64_t limit_in_bytes = strtoll(buffer, nullptr, 10);
+    if (limit_in_bytes > 0)
+      return limit_in_bytes;
   }
+
+  return 0;
 }
-#endif  // #if SB_API_VERSION < 14
diff --git a/src/third_party/starboard/rdk/shared/system/system_get_connection_type.cc b/src/third_party/starboard/rdk/shared/system/system_get_used_gpu_memory.cc
similarity index 65%
copy from src/third_party/starboard/rdk/shared/system/system_get_connection_type.cc
copy to src/third_party/starboard/rdk/shared/system/system_get_used_gpu_memory.cc
index 8db9bf4..d7c5b9e 100644
--- a/src/third_party/starboard/rdk/shared/system/system_get_connection_type.cc
+++ b/src/third_party/starboard/rdk/shared/system/system_get_used_gpu_memory.cc
@@ -1,3 +1,4 @@
+//
 // Copyright 2020 Comcast Cable Communications Management, LLC
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,14 +31,29 @@
 
 #include "starboard/system.h"
 
-#include "third_party/starboard/rdk/shared/rdkservices.h"
+#include "starboard/common/file.h"
+#include "starboard/common/log.h"
+#include "starboard/common/string.h"
 
-#if SB_API_VERSION < 14
-SbSystemConnectionType SbSystemGetConnectionType() {
-  if (third_party::starboard::rdk::shared::NetworkInfo::IsConnectionTypeWireless()) {
-    return kSbSystemConnectionTypeWireless;
-  } else {
-    return kSbSystemConnectionTypeWired;
+#include <cerrno>
+
+int64_t SbSystemGetUsedGPUMemory() {
+  starboard::ScopedFile status_file(
+    "/sys/fs/cgroup/gpu/gpu.usage_in_bytes",
+    kSbFileOpenOnly | kSbFileRead);
+
+  if (status_file.IsValid()) {
+    const int kBufferSize = 512;
+    char buffer[kBufferSize];
+    int bytes_read = status_file.ReadAll(buffer, kBufferSize);
+    if (bytes_read == kBufferSize) {
+      bytes_read = kBufferSize - 1;
+    }
+    buffer[bytes_read] = '\0';
+    int64_t usage_in_bytes = strtoll(buffer, nullptr, 10);
+    if (usage_in_bytes > 0 && errno != ERANGE)
+      return usage_in_bytes;
   }
+
+  return 0;
 }
-#endif  // #if SB_API_VERSION < 14
diff --git a/src/third_party/starboard/rdk/shared/system/system_has_capability.cc b/src/third_party/starboard/rdk/shared/system/system_has_capability.cc
index 60a9290..c514cb0 100644
--- a/src/third_party/starboard/rdk/shared/system/system_has_capability.cc
+++ b/src/third_party/starboard/rdk/shared/system/system_has_capability.cc
@@ -14,17 +14,15 @@
 #include "starboard/system.h"
 
 #include "starboard/common/log.h"
+#include "starboard/file.h"
 
 bool SbSystemHasCapability(SbSystemCapabilityId capability_id) {
   switch (capability_id) {
     case kSbSystemCapabilityReversedEnterAndBack:
       return false;
     case kSbSystemCapabilityCanQueryGPUMemoryStats:
-      return false;
-#if SB_API_VERSION < 13
-    case kSbSystemCapabilitySetsInputTimestamp:
-      return false;
-#endif
+      static bool gpu_stats_exists_cached = SbFileExists("/sys/fs/cgroup/gpu/gpu.usage_in_bytes");
+      return gpu_stats_exists_cached;
   }
 
   SB_DLOG(WARNING) << "Unrecognized capability: " << capability_id;
diff --git a/src/third_party/starboard/rdk/shared/system/system_request_conceal.cc b/src/third_party/starboard/rdk/shared/system/system_request_conceal.cc
index 32f5437..1cf8c42 100644
--- a/src/third_party/starboard/rdk/shared/system/system_request_conceal.cc
+++ b/src/third_party/starboard/rdk/shared/system/system_request_conceal.cc
@@ -32,8 +32,6 @@
 
 #include "third_party/starboard/rdk/shared/libcobalt.h"
 
-#if SB_API_VERSION >= 13
 void SbSystemRequestConceal() {
   SbRdkRequestConceal();
 }
-#endif  // SB_API_VERSION >= 13
diff --git a/src/third_party/starboard/rdk/shared/system/system_sign_with_certification_secret_key.cc b/src/third_party/starboard/rdk/shared/system/system_sign_with_certification_secret_key.cc
index aa929d4..8b55044 100644
--- a/src/third_party/starboard/rdk/shared/system/system_sign_with_certification_secret_key.cc
+++ b/src/third_party/starboard/rdk/shared/system/system_sign_with_certification_secret_key.cc
@@ -32,6 +32,7 @@
 #include <vector>
 #include <cstring>
 
+#include "starboard/file.h"
 #include "starboard/system.h"
 #include "starboard/string.h"
 #include "starboard/memory.h"
@@ -41,8 +42,10 @@
 
 #if defined(HAS_CRYPTOGRAPHY)
 #include <cryptography/cryptography.h>
+#if defined(HAS_RFC_API)
 #include <rfcapi.h>
 #endif
+#endif
 
 namespace {
 
@@ -71,9 +74,6 @@
   using CryptographyVault = cryptographyvault;
 #endif
 
-  const char kDefaultKeyName[] = "0381000003810001.key";
-  const char kRFCParamName[] = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Cobalt.AuthCertKeyName";
-
   third_party::starboard::rdk::shared::HangMonitor hang_monitor(__func__);
 
   std::string key_name;
@@ -82,6 +82,8 @@
     key_name = env;
     SB_LOG(INFO) << "Using ENV set key name: '" << key_name << "'";
   } else {
+#if defined(HAS_RFC_API)
+    const char kRFCParamName[] = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Cobalt.AuthCertKeyName";
     char *callerId = SbStringDuplicate("Cobalt");
     RFC_ParamData_t param;
     memset(&param, 0, sizeof (param));
@@ -91,19 +93,36 @@
       SB_LOG(INFO) << "Using RFC provided key name: '" << key_name << "'";
     }
     SbMemoryDeallocate(callerId);
+#endif
   }
 
   if ( key_name.empty() ) {
+    const char kDefaultKeyName[] = "0381000003810001.key";
     key_name = kDefaultKeyName;
     SB_LOG(INFO) << "Using default key name: '" << key_name << "'";
   }
 
+  const char *env_connection_point = std::getenv("COBALT_ICRYPTO_ACCESS_POINT");
+  std::string connection_point = env_connection_point ? env_connection_point : EMPTY_STRING;
+
+  if (env_connection_point != nullptr) {
+    if (SbFileExists(env_connection_point))
+      connection_point = env_connection_point;
+    else
+      SB_LOG(WARNING) << "ICrypto connection point ('" << env_connection_point << "') does not exist.";
+  }
+
+  if (connection_point.empty())
+    SB_LOG(INFO) << "Using ICrypto directly.";
+  else
+    SB_LOG(INFO) << "Using ICrypto connection point: '" << connection_point << "'.";
+
   ScopedRef<ICryptography> icrypto;
   ScopedRef<IVault> vault;
   ScopedRef<IPersistent> persistent;
   ScopedRef<IHash> hash;
 
-  icrypto.reset( ICryptography::Instance(EMPTY_STRING) );
+  icrypto.reset( ICryptography::Instance(connection_point) );
   if ( !icrypto ) {
     SB_LOG(ERROR) << "Failed to create ICryptography instance";
     return false;
diff --git a/src/third_party/starboard/rdk/shared/time_zone_get_name.cc b/src/third_party/starboard/rdk/shared/time_zone_get_name.cc
new file mode 100644
index 0000000..25a9a53
--- /dev/null
+++ b/src/third_party/starboard/rdk/shared/time_zone_get_name.cc
@@ -0,0 +1,108 @@
+//
+// Copyright 2020 Comcast Cable Communications Management, LLC
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2015 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Based on code from ICU which is:
+// Copyright 2016-2023 Unicode, Inc.
+// and
+// Copyright (c) 1995-2016 International Business Machines Corporation and others
+// All rights reserved.
+// Licensed under UNICODE LICENSE V3 and the ICU License from https://github.com/unicode-org/icu/blob/main/LICENSE
+
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "starboard/common/log.h"
+#include "starboard/time_zone.h"
+
+#define TZDEFAULT "/etc/localtime"
+#define TZZONEINFOTAIL "/zoneinfo/"
+#define isNonDigit(ch) (ch < '0' || '9' < ch)
+
+static char gTimeZoneBuffer[PATH_MAX];
+static char* gTimeZoneBufferPtr = NULL;
+
+static bool isValidOlsonID(const char* id) {
+  int32_t idx = 0;
+
+  /* Determine if this is something like Iceland (Olson ID)
+  or AST4ADT (non-Olson ID) */
+  while (id[idx] && isNonDigit(id[idx]) && id[idx] != ',') {
+    idx++;
+  }
+
+  /* If we went through the whole string, then it might be okay.
+  The timezone is sometimes set to "CST-7CDT", "CST6CDT5,J129,J131/19:30",
+  "GRNLNDST3GRNLNDDT" or similar, so we cannot use it.
+  The rest of the time it could be an Olson ID. George */
+  return static_cast<bool>(id[idx] == 0 || strcmp(id, "PST8PDT") == 0 ||
+                           strcmp(id, "MST7MDT") == 0 ||
+                           strcmp(id, "CST6CDT") == 0 ||
+                           strcmp(id, "EST5EDT") == 0);
+}
+
+// Similar to how ICU::putil.cpp gets IANA(Olsen) timezone ID.
+const char* SbTimeZoneGetName() {
+  /* Check TZ variable */
+  if (gTimeZoneBufferPtr == NULL) {
+    const char* tz = getenv("TZ");
+    if (tz && isValidOlsonID(tz)) {
+      strncpy(gTimeZoneBuffer, tz, sizeof(gTimeZoneBuffer));
+      gTimeZoneBuffer[sizeof(gTimeZoneBuffer) - 1] = 0;
+      gTimeZoneBufferPtr = &gTimeZoneBuffer[0];
+    }
+  }
+
+  /*
+  This is a trick to look at the name of the link to get the Olson ID
+  because the tzfile contents is underspecified.
+  This isn't guaranteed to work because it may not be a symlink.
+  But this is production-tested solution for most versions of Linux.
+  */
+
+  if (gTimeZoneBufferPtr == NULL) {
+    int32_t ret = (int32_t)readlink(TZDEFAULT, gTimeZoneBuffer,
+                                    sizeof(gTimeZoneBuffer) - 1);
+    if (0 < ret) {
+      int32_t tzZoneInfoTailLen = strlen(TZZONEINFOTAIL);
+      gTimeZoneBuffer[ret] = 0;
+      char* tzZoneInfoTailPtr = strstr(gTimeZoneBuffer, TZZONEINFOTAIL);
+
+      if (tzZoneInfoTailPtr != NULL &&
+          isValidOlsonID(tzZoneInfoTailPtr + tzZoneInfoTailLen)) {
+        return (gTimeZoneBufferPtr = tzZoneInfoTailPtr + tzZoneInfoTailLen);
+      }
+    }
+    SB_NOTREACHED();
+    return "";
+  } else {
+    return gTimeZoneBufferPtr;
+  }
+}