From af75c698345e1ff15ff238efc822894355c5961a Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Thu, 7 May 2026 16:04:05 -0400 Subject: [PATCH 01/37] RDKEMW-17483: Change Discovery.watched and Metrics methods return type bool to void --- include/firebolt/discovery.h | 2 +- include/firebolt/metrics.h | 36 ++++++------ src/discovery_impl.cpp | 9 +-- src/discovery_impl.h | 2 +- src/metrics_impl.cpp | 72 ++++++++++++------------ src/metrics_impl.h | 36 ++++++------ test/api_test_app/apis/discoveryDemo.cpp | 2 +- test/api_test_app/apis/metricsDemo.cpp | 36 ++++++------ test/component/discoveryTest.cpp | 7 +-- test/component/metricsTest.cpp | 51 ----------------- test/unit/discoveryTest.cpp | 11 +--- test/unit/metricsTest.cpp | 40 ++++++------- test/unit/mock_helper.h | 7 +++ 13 files changed, 126 insertions(+), 185 deletions(-) diff --git a/include/firebolt/discovery.h b/include/firebolt/discovery.h index 50cecb9..b73404c 100644 --- a/include/firebolt/discovery.h +++ b/include/firebolt/discovery.h @@ -41,7 +41,7 @@ class IDiscovery * * @retval The status. */ - virtual Result watched(const std::string& entityId, std::optional progress, + virtual Result watched(const std::string& entityId, std::optional progress, std::optional completed, std::optional watchedOn, std::optional agePolicy) const = 0; }; diff --git a/include/firebolt/metrics.h b/include/firebolt/metrics.h index d14c5bf..a13deb5 100644 --- a/include/firebolt/metrics.h +++ b/include/firebolt/metrics.h @@ -45,21 +45,21 @@ class IMetrics * * @retval The success state or error */ - virtual Result ready() const = 0; + virtual Result ready() const = 0; /** * @brief Logs a sign in event * * @retval The success state or error */ - virtual Result signIn() const = 0; + virtual Result signIn() const = 0; /** * @brief Logs a sign out event * * @retval The success state or error */ - virtual Result signOut() const = 0; + virtual Result signOut() const = 0; /** * @brief Informs the platform that your user has started content @@ -70,7 +70,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result startContent(const std::optional& entityId, + virtual Result startContent(const std::optional& entityId, const std::optional agePolicy) const = 0; /** @@ -82,7 +82,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result stopContent(const std::optional& entityId, + virtual Result stopContent(const std::optional& entityId, const std::optional agePolicy) const = 0; /** @@ -94,7 +94,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result page(const std::string& pageId, const std::optional& agePolicy) const = 0; + virtual Result page(const std::string& pageId, const std::optional& agePolicy) const = 0; /** * @brief Informs the platform of an error that has occurred in your app @@ -109,7 +109,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result error(const ErrorType type, const std::string& code, const std::string& description, + virtual Result error(const ErrorType type, const std::string& code, const std::string& description, const bool visible, const std::optional>& parameters, const std::optional& agePolicy) const = 0; @@ -122,7 +122,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result mediaLoadStart(const std::string& entityId, + virtual Result mediaLoadStart(const std::string& entityId, const std::optional& agePolicy) const = 0; /** @@ -135,7 +135,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result mediaPlaying(const std::string& entityId, + virtual Result mediaPlaying(const std::string& entityId, const std::optional& agePolicy) const = 0; /** @@ -147,7 +147,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result mediaPlay(const std::string& entityId, + virtual Result mediaPlay(const std::string& entityId, const std::optional& agePolicy) const = 0; /** @@ -159,7 +159,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result mediaPause(const std::string& entityId, + virtual Result mediaPause(const std::string& entityId, const std::optional& agePolicy) const = 0; /** @@ -171,7 +171,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result mediaWaiting(const std::string& entityId, + virtual Result mediaWaiting(const std::string& entityId, const std::optional& agePolicy) const = 0; /** @@ -185,7 +185,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result mediaSeeking(const std::string& entityId, const double target, + virtual Result mediaSeeking(const std::string& entityId, const double target, const std::optional& agePolicy) const = 0; /** @@ -200,7 +200,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result mediaSeeked(const std::string& entityId, const double position, + virtual Result mediaSeeked(const std::string& entityId, const double position, const std::optional& agePolicy) const = 0; /** @@ -213,7 +213,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result mediaRateChanged(const std::string& entityId, const double rate, + virtual Result mediaRateChanged(const std::string& entityId, const double rate, const std::optional& agePolicy) const = 0; /** @@ -229,7 +229,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result mediaRenditionChanged(const std::string& entityId, const unsigned bitrate, const unsigned width, + virtual Result mediaRenditionChanged(const std::string& entityId, const unsigned bitrate, const unsigned width, const unsigned height, const std::optional& profile, const std::optional& agePolicy) const = 0; @@ -242,7 +242,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result mediaEnded(const std::string& entityId, + virtual Result mediaEnded(const std::string& entityId, const std::optional& agePolicy) const = 0; /** @@ -255,7 +255,7 @@ class IMetrics * * @retval The success state or error */ - virtual Result event(const std::string& schema, const std::string& data, + virtual Result event(const std::string& schema, const std::string& data, const std::optional& agePolicy) const = 0; /** diff --git a/src/discovery_impl.cpp b/src/discovery_impl.cpp index cc209c0..e653777 100644 --- a/src/discovery_impl.cpp +++ b/src/discovery_impl.cpp @@ -27,7 +27,7 @@ DiscoveryImpl::DiscoveryImpl(Firebolt::Helpers::IHelper& helper) { } -Result DiscoveryImpl::watched(const std::string& entityId, std::optional progress, +Result DiscoveryImpl::watched(const std::string& entityId, std::optional progress, std::optional completed, std::optional watchedOn, std::optional agePolicy) const { @@ -50,11 +50,6 @@ Result DiscoveryImpl::watched(const std::string& entityId, std::optional result = helper_.get("Discovery.watched", parameters); - if (!result) - { - return Result{result.error()}; - } - return Result{result.value()}; + return helper_.invoke("Discovery.watched", parameters); } } // namespace Firebolt::Discovery diff --git a/src/discovery_impl.h b/src/discovery_impl.h index 30a78f8..34e12f1 100644 --- a/src/discovery_impl.h +++ b/src/discovery_impl.h @@ -33,7 +33,7 @@ class DiscoveryImpl : public IDiscovery ~DiscoveryImpl() override = default; - Result watched(const std::string& entityId, std::optional progress, std::optional completed, + Result watched(const std::string& entityId, std::optional progress, std::optional completed, std::optional watchedOn, std::optional agePolicy) const override; diff --git a/src/metrics_impl.cpp b/src/metrics_impl.cpp index 892be95..9f29027 100644 --- a/src/metrics_impl.cpp +++ b/src/metrics_impl.cpp @@ -28,22 +28,22 @@ MetricsImpl::MetricsImpl(Firebolt::Helpers::IHelper& helper) { } -Result MetricsImpl::ready() const +Result MetricsImpl::ready() const { - return helper_.get("Metrics.ready"); + return helper_.invoke("Metrics.ready", nlohmann::json({})); } -Result MetricsImpl::signIn() const +Result MetricsImpl::signIn() const { - return helper_.get("Metrics.signIn"); + return helper_.invoke("Metrics.signIn", nlohmann::json({})); } -Result MetricsImpl::signOut() const +Result MetricsImpl::signOut() const { - return helper_.get("Metrics.signOut"); + return helper_.invoke("Metrics.signOut", nlohmann::json({})); } -Result MetricsImpl::startContent(const std::optional& entityId, +Result MetricsImpl::startContent(const std::optional& entityId, const std::optional agePolicy) const { nlohmann::json parameters; @@ -55,10 +55,10 @@ Result MetricsImpl::startContent(const std::optional& entityI { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.startContent", parameters); + return helper_.invoke("Metrics.startContent", parameters); } -Result MetricsImpl::stopContent(const std::optional& entityId, +Result MetricsImpl::stopContent(const std::optional& entityId, const std::optional agePolicy) const { nlohmann::json parameters; @@ -70,10 +70,10 @@ Result MetricsImpl::stopContent(const std::optional& entityId { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.stopContent", parameters); + return helper_.invoke("Metrics.stopContent", parameters); } -Result MetricsImpl::page(const std::string& pageId, const std::optional& agePolicy) const +Result MetricsImpl::page(const std::string& pageId, const std::optional& agePolicy) const { nlohmann::json parameters; parameters["pageId"] = pageId; @@ -81,10 +81,10 @@ Result MetricsImpl::page(const std::string& pageId, const std::optional("Metrics.page", parameters); + return helper_.invoke("Metrics.page", parameters); } -Result MetricsImpl::error(const ErrorType type, const std::string& code, const std::string& description, +Result MetricsImpl::error(const ErrorType type, const std::string& code, const std::string& description, const bool visible, const std::optional>& parameters, const std::optional& agePolicy) const { @@ -106,10 +106,10 @@ Result MetricsImpl::error(const ErrorType type, const std::string& code, c { jsonParameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.error", jsonParameters); + return helper_.invoke("Metrics.error", jsonParameters); } -Result MetricsImpl::mediaLoadStart(const std::string& entityId, +Result MetricsImpl::mediaLoadStart(const std::string& entityId, const std::optional& agePolicy) const { nlohmann::json parameters; @@ -118,10 +118,10 @@ Result MetricsImpl::mediaLoadStart(const std::string& entityId, { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.mediaLoadStart", parameters); + return helper_.invoke("Metrics.mediaLoadStart", parameters); } -Result MetricsImpl::mediaPlay(const std::string& entityId, const std::optional& agePolicy) const +Result MetricsImpl::mediaPlay(const std::string& entityId, const std::optional& agePolicy) const { nlohmann::json parameters; parameters["entityId"] = entityId; @@ -129,10 +129,10 @@ Result MetricsImpl::mediaPlay(const std::string& entityId, const std::opti { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.mediaPlay", parameters); + return helper_.invoke("Metrics.mediaPlay", parameters); } -Result MetricsImpl::mediaPlaying(const std::string& entityId, +Result MetricsImpl::mediaPlaying(const std::string& entityId, const std::optional& agePolicy) const { nlohmann::json parameters; @@ -141,10 +141,10 @@ Result MetricsImpl::mediaPlaying(const std::string& entityId, { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.mediaPlaying", parameters); + return helper_.invoke("Metrics.mediaPlaying", parameters); } -Result MetricsImpl::mediaPause(const std::string& entityId, const std::optional& agePolicy) const +Result MetricsImpl::mediaPause(const std::string& entityId, const std::optional& agePolicy) const { nlohmann::json parameters; parameters["entityId"] = entityId; @@ -152,10 +152,10 @@ Result MetricsImpl::mediaPause(const std::string& entityId, const std::opt { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.mediaPause", parameters); + return helper_.invoke("Metrics.mediaPause", parameters); } -Result MetricsImpl::mediaWaiting(const std::string& entityId, +Result MetricsImpl::mediaWaiting(const std::string& entityId, const std::optional& agePolicy) const { nlohmann::json parameters; @@ -164,10 +164,10 @@ Result MetricsImpl::mediaWaiting(const std::string& entityId, { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.mediaWaiting", parameters); + return helper_.invoke("Metrics.mediaWaiting", parameters); } -Result MetricsImpl::mediaSeeking(const std::string& entityId, const double target, +Result MetricsImpl::mediaSeeking(const std::string& entityId, const double target, const std::optional& agePolicy) const { nlohmann::json parameters; @@ -177,10 +177,10 @@ Result MetricsImpl::mediaSeeking(const std::string& entityId, const double { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.mediaSeeking", parameters); + return helper_.invoke("Metrics.mediaSeeking", parameters); } -Result MetricsImpl::mediaSeeked(const std::string& entityId, const double position, +Result MetricsImpl::mediaSeeked(const std::string& entityId, const double position, const std::optional& agePolicy) const { nlohmann::json parameters; @@ -190,10 +190,10 @@ Result MetricsImpl::mediaSeeked(const std::string& entityId, const double { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.mediaSeeked", parameters); + return helper_.invoke("Metrics.mediaSeeked", parameters); } -Result MetricsImpl::mediaRateChanged(const std::string& entityId, const double rate, +Result MetricsImpl::mediaRateChanged(const std::string& entityId, const double rate, const std::optional& agePolicy) const { nlohmann::json parameters; @@ -203,10 +203,10 @@ Result MetricsImpl::mediaRateChanged(const std::string& entityId, const do { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.mediaRateChanged", parameters); + return helper_.invoke("Metrics.mediaRateChanged", parameters); } -Result MetricsImpl::mediaRenditionChanged(const std::string& entityId, const unsigned bitrate, const unsigned width, +Result MetricsImpl::mediaRenditionChanged(const std::string& entityId, const unsigned bitrate, const unsigned width, const unsigned height, const std::optional& profile, const std::optional& agePolicy) const { @@ -223,10 +223,10 @@ Result MetricsImpl::mediaRenditionChanged(const std::string& entityId, con { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.mediaRenditionChanged", parameters); + return helper_.invoke("Metrics.mediaRenditionChanged", parameters); } -Result MetricsImpl::mediaEnded(const std::string& entityId, const std::optional& agePolicy) const +Result MetricsImpl::mediaEnded(const std::string& entityId, const std::optional& agePolicy) const { nlohmann::json parameters; parameters["entityId"] = entityId; @@ -234,10 +234,10 @@ Result MetricsImpl::mediaEnded(const std::string& entityId, const std::opt { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.mediaEnded", parameters); + return helper_.invoke("Metrics.mediaEnded", parameters); } -Result MetricsImpl::event(const std::string& schema, const std::string& data, +Result MetricsImpl::event(const std::string& schema, const std::string& data, const std::optional& agePolicy) const { nlohmann::json parameters; @@ -247,7 +247,7 @@ Result MetricsImpl::event(const std::string& schema, const std::string& da { parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); } - return helper_.get("Metrics.event", parameters); + return helper_.invoke("Metrics.event", parameters); } Result MetricsImpl::appInfo(const std::string& build) const diff --git a/src/metrics_impl.h b/src/metrics_impl.h index 4eb0da6..ace303b 100644 --- a/src/metrics_impl.h +++ b/src/metrics_impl.h @@ -32,39 +32,39 @@ class MetricsImpl : public IMetrics ~MetricsImpl() override = default; - Result ready() const override; - Result signIn() const override; - Result signOut() const override; - Result startContent(const std::optional& entityId, + Result ready() const override; + Result signIn() const override; + Result signOut() const override; + Result startContent(const std::optional& entityId, const std::optional agePolicy) const override; - Result stopContent(const std::optional& entityId, + Result stopContent(const std::optional& entityId, const std::optional agePolicy) const override; - Result page(const std::string& pageId, const std::optional& agePolicy) const override; - Result error(const ErrorType type, const std::string& code, const std::string& description, + Result page(const std::string& pageId, const std::optional& agePolicy) const override; + Result error(const ErrorType type, const std::string& code, const std::string& description, const bool visible, const std::optional>& parameters, const std::optional& agePolicy) const override; - Result mediaLoadStart(const std::string& entityId, + Result mediaLoadStart(const std::string& entityId, const std::optional& agePolicy) const override; - Result mediaPlay(const std::string& entityId, + Result mediaPlay(const std::string& entityId, const std::optional& agePolicy) const override; - Result mediaPlaying(const std::string& entityId, + Result mediaPlaying(const std::string& entityId, const std::optional& agePolicy) const override; - Result mediaPause(const std::string& entityId, + Result mediaPause(const std::string& entityId, const std::optional& agePolicy) const override; - Result mediaWaiting(const std::string& entityId, + Result mediaWaiting(const std::string& entityId, const std::optional& agePolicy) const override; - Result mediaSeeking(const std::string& entityId, const double target, + Result mediaSeeking(const std::string& entityId, const double target, const std::optional& agePolicy) const override; - Result mediaSeeked(const std::string& entityId, const double position, + Result mediaSeeked(const std::string& entityId, const double position, const std::optional& agePolicy) const override; - Result mediaRateChanged(const std::string& entityId, const double rate, + Result mediaRateChanged(const std::string& entityId, const double rate, const std::optional& agePolicy) const override; - Result mediaRenditionChanged(const std::string& entityId, const unsigned bitrate, const unsigned width, + Result mediaRenditionChanged(const std::string& entityId, const unsigned bitrate, const unsigned width, const unsigned height, const std::optional& profile, const std::optional& agePolicy) const override; - Result mediaEnded(const std::string& entityId, + Result mediaEnded(const std::string& entityId, const std::optional& agePolicy) const override; - Result event(const std::string& schema, const std::string& data, + Result event(const std::string& schema, const std::string& data, const std::optional& agePolicy) const override; Result appInfo(const std::string& build) const override; diff --git a/test/api_test_app/apis/discoveryDemo.cpp b/test/api_test_app/apis/discoveryDemo.cpp index 0e3afba..5e0b9d6 100644 --- a/test/api_test_app/apis/discoveryDemo.cpp +++ b/test/api_test_app/apis/discoveryDemo.cpp @@ -61,7 +61,7 @@ void DiscoveryDemo::runOption(const std::string& method) watchedOn, agePolicyOpt); if (succeed(r)) { - std::cout << "Discovery.watched result: " << std::boolalpha << *r << std::endl; + std::cout << "Discovery.watched: Success" << std::endl; } } } diff --git a/test/api_test_app/apis/metricsDemo.cpp b/test/api_test_app/apis/metricsDemo.cpp index e494cd0..9ac520d 100644 --- a/test/api_test_app/apis/metricsDemo.cpp +++ b/test/api_test_app/apis/metricsDemo.cpp @@ -56,7 +56,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().ready(); if (succeed(r)) { - std::cout << "Metrics Ready: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Ready: Success" << std::endl; } } else if (method == "Metrics.signIn") @@ -64,7 +64,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().signIn(); if (succeed(r)) { - std::cout << "Metrics Sign In: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Sign In: Success" << std::endl; } } else if (method == "Metrics.signOut") @@ -72,7 +72,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().signOut(); if (succeed(r)) { - std::cout << "Metrics Sign Out: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Sign Out: Success" << std::endl; } } else if (method == "Metrics.startContent") @@ -80,7 +80,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().startContent("entity123", std::nullopt); if (succeed(r)) { - std::cout << "Metrics Start Content: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Start Content: Success" << std::endl; } } else if (method == "Metrics.stopContent") @@ -88,7 +88,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().stopContent("entity123", std::nullopt); if (succeed(r)) { - std::cout << "Metrics Stop Content: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Stop Content: Success" << std::endl; } } else if (method == "Metrics.page") @@ -96,7 +96,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().page("page123", std::nullopt); if (succeed(r)) { - std::cout << "Metrics Page: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Page: Success" << std::endl; } } else if (method == "Metrics.error") @@ -106,7 +106,7 @@ void MetricsDemo::runOption(const std::string& method) std::nullopt, std::nullopt); if (succeed(r)) { - std::cout << "Metrics Error: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Error: Success" << std::endl; } } else if (method == "Metrics.mediaLoadStart") @@ -114,7 +114,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaLoadStart("entity123", std::nullopt); if (succeed(r)) { - std::cout << "Metrics Media Load Start: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Media Load Start: Success" << std::endl; } } else if (method == "Metrics.mediaPlay") @@ -122,7 +122,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaPlay("entity123", std::nullopt); if (succeed(r)) { - std::cout << "Metrics Media Play: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Media Play: Success" << std::endl; } } else if (method == "Metrics.mediaPlaying") @@ -130,7 +130,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaPlaying("entity123", std::nullopt); if (succeed(r)) { - std::cout << "Metrics Media Playing: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Media Playing: Success" << std::endl; } } else if (method == "Metrics.mediaPause") @@ -138,7 +138,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaPause("entity123", std::nullopt); if (succeed(r)) { - std::cout << "Metrics Media Pause: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Media Pause: Success" << std::endl; } } else if (method == "Metrics.mediaWaiting") @@ -146,7 +146,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaWaiting("entity123", std::nullopt); if (succeed(r)) { - std::cout << "Metrics Media Waiting: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Media Waiting: Success" << std::endl; } } else if (method == "Metrics.mediaSeeking") @@ -154,7 +154,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaSeeking("entity123", 0.5, std::nullopt); if (succeed(r)) { - std::cout << "Metrics Media Seeking: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Media Seeking: Success" << std::endl; } } else if (method == "Metrics.mediaSeeked") @@ -162,7 +162,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaSeeked("entity123", 0.5, std::nullopt); if (succeed(r)) { - std::cout << "Metrics Media Seeked: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Media Seeked: Success" << std::endl; } } else if (method == "Metrics.mediaRateChanged") @@ -171,7 +171,7 @@ void MetricsDemo::runOption(const std::string& method) Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaRateChanged("entity123", 1.5, std::nullopt); if (succeed(r)) { - std::cout << "Metrics Media Rate Changed: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Media Rate Changed: Success" << std::endl; } } else if (method == "Metrics.mediaRenditionChanged") @@ -181,7 +181,7 @@ void MetricsDemo::runOption(const std::string& method) std::nullopt); if (succeed(r)) { - std::cout << "Metrics Media Rendition Changed: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Media Rendition Changed: Success" << std::endl; } } else if (method == "Metrics.mediaEnded") @@ -189,7 +189,7 @@ void MetricsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaEnded("entity123", std::nullopt); if (succeed(r)) { - std::cout << "Metrics Media Ended: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Media Ended: Success" << std::endl; } } else if (method == "Metrics.event") @@ -198,7 +198,7 @@ void MetricsDemo::runOption(const std::string& method) "{\"key\":\"value\"}", std::nullopt); if (succeed(r)) { - std::cout << "Metrics Event: " << std::boolalpha << *r << std::endl; + std::cout << "Metrics Event: Success" << std::endl; } } else if (method == "Metrics.appInfo") diff --git a/test/component/discoveryTest.cpp b/test/component/discoveryTest.cpp index bc118b6..c1cfcf1 100644 --- a/test/component/discoveryTest.cpp +++ b/test/component/discoveryTest.cpp @@ -18,12 +18,10 @@ #include "firebolt/discovery.h" #include "firebolt/firebolt.h" -#include "json_engine.h" +#include class DiscoveryCTest : public ::testing::Test { -protected: - JsonEngine jsonEngine; }; TEST_F(DiscoveryCTest, Watched) @@ -32,7 +30,4 @@ TEST_F(DiscoveryCTest, Watched) "2024-10-01T12:00:00Z", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "Failed to call watched"; - - auto expectedValue = jsonEngine.get_value("Discovery.watched"); - EXPECT_EQ(*result, expectedValue.get()); } diff --git a/test/component/metricsTest.cpp b/test/component/metricsTest.cpp index e626a6d..9e1d6fc 100644 --- a/test/component/metricsTest.cpp +++ b/test/component/metricsTest.cpp @@ -17,7 +17,6 @@ */ #include "firebolt/firebolt.h" -#include "json_engine.h" #include "utils.h" #include @@ -25,235 +24,185 @@ class MetricsCTest : public ::testing::Test { protected: void SetUp() override {} - - JsonEngine jsonEngine; }; TEST_F(MetricsCTest, Ready) { - auto expectedValue = jsonEngine.get_value("Metrics.ready"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().ready(); ASSERT_TRUE(result) << "MetricsImpl::ready() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, SignIn) { - auto expectedValue = jsonEngine.get_value("Metrics.signIn"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().signIn(); ASSERT_TRUE(result) << "MetricsImpl::signIn() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, SignOut) { - auto expectedValue = jsonEngine.get_value("Metrics.signOut"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().signOut(); ASSERT_TRUE(result) << "MetricsImpl::signOut() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, StartContent) { - auto expectedValue = jsonEngine.get_value("Metrics.startContent"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().startContent("entity123", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::startContent() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, StopContent) { - auto expectedValue = jsonEngine.get_value("Metrics.stopContent"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().stopContent("entity123", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::stopContent() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, Page) { - auto expectedValue = jsonEngine.get_value("Metrics.page"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().page("homePage", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::page() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, Error) { - auto expectedValue = jsonEngine.get_value("Metrics.error"); auto result = Firebolt::IFireboltAccessor::Instance() .MetricsInterface() .error(Firebolt::Metrics::ErrorType::Network, "ERR001", "Network error occurred", true, std::map{{"param1", "value1"}, {"param2", "value2"}}, Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::error() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, ErrorNoParameters) { - auto expectedValue = jsonEngine.get_value("Metrics.error"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().error(Firebolt::Metrics::ErrorType::Network, "ERR001", "Network error occurred", true, std::nullopt, Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::error() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, ErrorNoAgePolicy) { - auto expectedValue = jsonEngine.get_value("Metrics.error"); auto result = Firebolt::IFireboltAccessor::Instance() .MetricsInterface() .error(Firebolt::Metrics::ErrorType::Network, "ERR001", "Network error occurred", true, std::map{{"param1", "value1"}, {"param2", "value2"}}, std::nullopt); ASSERT_TRUE(result) << "MetricsImpl::error() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaLoadStart) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaLoadStart"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaLoadStart("mediaEntity123", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaLoadStart() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaPlay) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaPlay"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaPlay("mediaEntity123", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaPlay() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaPlaying) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaPlaying"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaPlaying("mediaEntity123", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaPlaying() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaPause) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaPause"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaPause("mediaEntity123", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaPause() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaWaiting) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaWaiting"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaWaiting("mediaEntity123", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaWaiting() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaSeeking) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaSeeking"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaSeeking("mediaEntity123", 0.5, Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaSeeking() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaSeekingInt) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaSeeking"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaSeeking("mediaEntity123", 500, Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaSeeking() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaSeeked) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaSeeked"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaSeeked("mediaEntity123", 0.5, Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaSeeked() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaSeekedInt) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaSeeked"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaSeeked("mediaEntity123", 500, Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaSeeked() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaRateChanged) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaRateChanged"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaRateChanged("mediaEntity123", 1.5, Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaRateChanged() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaRenditionChanged) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaRenditionChanged"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaRenditionChanged("mediaEntity123", 3000, 1920, 1080, "HDR", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaRenditionChanged() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaRenditionChangedNoProfile) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaRenditionChanged"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaRenditionChanged("mediaEntity123", 3000, 1920, 1080, std::nullopt, Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaRenditionChanged() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaRenditionChangedNoAgePolicy) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaRenditionChanged"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaRenditionChanged("mediaEntity123", 3000, 1920, 1080, std::nullopt, std::nullopt); ASSERT_TRUE(result) << "MetricsImpl::mediaRenditionChanged() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, MediaEnded) { - auto expectedValue = jsonEngine.get_value("Metrics.mediaEnded"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().mediaEnded("mediaEntity123", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::mediaEnded() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, Event) { - auto expectedValue = jsonEngine.get_value("Metrics.event"); auto result = Firebolt::IFireboltAccessor::Instance().MetricsInterface().event("https://com.example.event", "{\"key\":\"value\"}", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "MetricsImpl::event() returned an error"; - EXPECT_EQ(*result, expectedValue); } TEST_F(MetricsCTest, AppInfo) diff --git a/test/unit/discoveryTest.cpp b/test/unit/discoveryTest.cpp index 4e1c3ce..9b7b1b1 100644 --- a/test/unit/discoveryTest.cpp +++ b/test/unit/discoveryTest.cpp @@ -36,7 +36,7 @@ TEST_F(DiscoveryUTest, checkEnums) TEST_F(DiscoveryUTest, watched) { - mock("Discovery.watched"); + mockInvoke("Discovery.watched"); std::string entityId = "content123"; std::optional progress = 0.75f; std::optional completed = true; @@ -44,9 +44,6 @@ TEST_F(DiscoveryUTest, watched) std::optional agePolicy = Firebolt::AgePolicy::ADULT; auto result = discoveryImpl_.watched(entityId, progress, completed, watchedOn, agePolicy); ASSERT_TRUE(result) << "Error on watched"; - Firebolt::JSON::Boolean boolJson; - boolJson.fromJson(jsonEngine.get_value("Discovery.watched")); - EXPECT_EQ(boolJson.value(), *result); } TEST_F(DiscoveryUTest, watched_payload) @@ -57,14 +54,13 @@ TEST_F(DiscoveryUTest, watched_payload) expected["completed"] = true; expected["watchedOn"] = "2024-06-01T12:00:00Z"; expected["agePolicy"] = "app:adult"; - EXPECT_CALL(mockHelper, getJson("Discovery.watched", _)) + EXPECT_CALL(mockHelper, invoke("Discovery.watched", _)) .WillOnce(Invoke( [&](const std::string& /* methodName */, const nlohmann::json& parameters) { - bool res = parameters == expected; EXPECT_EQ(parameters, expected) << "Parameters do not match expected payload: " << expected.dump() << " but got: " << parameters.dump(); - return Firebolt::Result{res}; + return Firebolt::Result{Firebolt::Error::None}; })); std::string entityId = "content123"; std::optional progress = 0.75f; @@ -73,5 +69,4 @@ TEST_F(DiscoveryUTest, watched_payload) std::optional agePolicy = Firebolt::AgePolicy::ADULT; auto result = discoveryImpl_.watched(entityId, progress, completed, watchedOn, agePolicy); ASSERT_TRUE(result) << "Error on watched"; - EXPECT_EQ(true, *result); } diff --git a/test/unit/metricsTest.cpp b/test/unit/metricsTest.cpp index 321c6d1..a7dbcab 100644 --- a/test/unit/metricsTest.cpp +++ b/test/unit/metricsTest.cpp @@ -33,49 +33,49 @@ TEST_F(MetricsUTest, checkEnums) TEST_F(MetricsUTest, Ready) { - mock("Metrics.ready"); + mockInvoke("Metrics.ready"); auto result = metricsImpl_.ready(); EXPECT_TRUE(result); } TEST_F(MetricsUTest, SignIn) { - mock("Metrics.signIn"); + mockInvoke("Metrics.signIn"); auto result = metricsImpl_.signIn(); EXPECT_TRUE(result); } TEST_F(MetricsUTest, SignOut) { - mock("Metrics.signOut"); + mockInvoke("Metrics.signOut"); auto result = metricsImpl_.signOut(); EXPECT_TRUE(result); } TEST_F(MetricsUTest, StartContent) { - mock("Metrics.startContent"); + mockInvoke("Metrics.startContent"); auto result = metricsImpl_.startContent("entity123", Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } TEST_F(MetricsUTest, StopContent) { - mock("Metrics.stopContent"); + mockInvoke("Metrics.stopContent"); auto result = metricsImpl_.stopContent("entity123", Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } TEST_F(MetricsUTest, Page) { - mock("Metrics.page"); + mockInvoke("Metrics.page"); auto result = metricsImpl_.page("homePage", Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } TEST_F(MetricsUTest, Error) { - mock("Metrics.error"); + mockInvoke("Metrics.error"); auto result = metricsImpl_.error(Firebolt::Metrics::ErrorType::Network, "ERR001", "Network error occurred", true, std::map{{"param1", "value1"}, {"param2", "value2"}}, Firebolt::AgePolicy::ADULT); @@ -84,7 +84,7 @@ TEST_F(MetricsUTest, Error) TEST_F(MetricsUTest, ErrorNoParameters) { - mock("Metrics.error"); + mockInvoke("Metrics.error"); auto result = metricsImpl_.error(Firebolt::Metrics::ErrorType::Network, "ERR001", "Network error occurred", true, std::nullopt, Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); @@ -92,7 +92,7 @@ TEST_F(MetricsUTest, ErrorNoParameters) TEST_F(MetricsUTest, ErrorNoAgePolicy) { - mock("Metrics.error"); + mockInvoke("Metrics.error"); auto result = metricsImpl_.error(Firebolt::Metrics::ErrorType::Network, "ERR001", "Network error occurred", true, std::map{{"param1", "value1"}, {"param2", "value2"}}, std::nullopt); @@ -101,63 +101,63 @@ TEST_F(MetricsUTest, ErrorNoAgePolicy) TEST_F(MetricsUTest, MediaLoadStart) { - mock("Metrics.mediaLoadStart"); + mockInvoke("Metrics.mediaLoadStart"); auto result = metricsImpl_.mediaLoadStart("mediaEntity123", Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } TEST_F(MetricsUTest, MediaPlay) { - mock("Metrics.mediaPlay"); + mockInvoke("Metrics.mediaPlay"); auto result = metricsImpl_.mediaPlay("mediaEntity123", Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } TEST_F(MetricsUTest, MediaPlaying) { - mock("Metrics.mediaPlaying"); + mockInvoke("Metrics.mediaPlaying"); auto result = metricsImpl_.mediaPlaying("mediaEntity123", Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } TEST_F(MetricsUTest, MediaPause) { - mock("Metrics.mediaPause"); + mockInvoke("Metrics.mediaPause"); auto result = metricsImpl_.mediaPause("mediaEntity123", Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } TEST_F(MetricsUTest, MediaWaiting) { - mock("Metrics.mediaWaiting"); + mockInvoke("Metrics.mediaWaiting"); auto result = metricsImpl_.mediaWaiting("mediaEntity123", Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } TEST_F(MetricsUTest, MediaSeeking) { - mock("Metrics.mediaSeeking"); + mockInvoke("Metrics.mediaSeeking"); auto result = metricsImpl_.mediaSeeking("mediaEntity123", 0.5, Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } TEST_F(MetricsUTest, MediaSeeked) { - mock("Metrics.mediaSeeked"); + mockInvoke("Metrics.mediaSeeked"); auto result = metricsImpl_.mediaSeeked("mediaEntity123", 0.5, Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } TEST_F(MetricsUTest, MediaRateChanged) { - mock("Metrics.mediaRateChanged"); + mockInvoke("Metrics.mediaRateChanged"); auto result = metricsImpl_.mediaRateChanged("mediaEntity123", 1.5, Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } TEST_F(MetricsUTest, MediaRenditionChanged) { - mock("Metrics.mediaRenditionChanged"); + mockInvoke("Metrics.mediaRenditionChanged"); auto result = metricsImpl_.mediaRenditionChanged("mediaEntity123", 3000, 1920, 1080, "HDR", Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); @@ -165,14 +165,14 @@ TEST_F(MetricsUTest, MediaRenditionChanged) TEST_F(MetricsUTest, MediaEnded) { - mock("Metrics.mediaEnded"); + mockInvoke("Metrics.mediaEnded"); auto result = metricsImpl_.mediaEnded("mediaEntity123", Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } TEST_F(MetricsUTest, Event) { - mock("Metrics.event"); + mockInvoke("Metrics.event"); auto result = metricsImpl_.event("https://com.example.schema", "{\"key\":\"value\"}", Firebolt::AgePolicy::ADULT); EXPECT_TRUE(result); } diff --git a/test/unit/mock_helper.h b/test/unit/mock_helper.h index 9f9183e..f2a9ffb 100644 --- a/test/unit/mock_helper.h +++ b/test/unit/mock_helper.h @@ -104,6 +104,13 @@ class MockBase { return Firebolt::Result{response}; })); } + void mockInvoke(const std::string& methodName) + { + EXPECT_CALL(mockHelper, invoke(methodName, _)) + .WillOnce(Invoke([](const std::string& /*methodName*/, const nlohmann::json& /*parameters*/) + { return Firebolt::Result{Firebolt::Error::None}; })); + } + void mockSubscribe(const std::string& eventName) { EXPECT_CALL(mockHelper, subscribe(_, eventName, _, _)) From 3fc8635720c803eb87283989c1ed6743dd24a3ba Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Thu, 7 May 2026 16:04:06 -0400 Subject: [PATCH 02/37] RDKEMW-17483: Update comments and OpenRPC result schemas for void methods --- docs/openrpc/openrpc/discovery.json | 5 +- docs/openrpc/openrpc/metrics.json | 74 +- docs/openrpc/the-spec/firebolt-open-rpc.json | 7687 +++++++++--------- include/firebolt/discovery.h | 2 +- include/firebolt/metrics.h | 38 +- 5 files changed, 3902 insertions(+), 3904 deletions(-) diff --git a/docs/openrpc/openrpc/discovery.json b/docs/openrpc/openrpc/discovery.json index b6f22c0..41389e9 100644 --- a/docs/openrpc/openrpc/discovery.json +++ b/docs/openrpc/openrpc/discovery.json @@ -61,10 +61,9 @@ } ], "result": { - "name": "success", - "summary": "whether the call was successful or not", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ diff --git a/docs/openrpc/openrpc/metrics.json b/docs/openrpc/openrpc/metrics.json index fe89723..31cd571 100644 --- a/docs/openrpc/openrpc/metrics.json +++ b/docs/openrpc/openrpc/metrics.json @@ -19,9 +19,9 @@ "summary": "Inform the platform that your app is minimally usable. This method is called automatically by `Lifecycle.ready()`", "params": [], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -51,9 +51,9 @@ "summary": "Log a sign in event, called by Discovery.signIn().", "params": [], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -83,9 +83,9 @@ "summary": "Log a sign out event, called by Discovery.signOut().", "params": [], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -128,9 +128,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -203,9 +203,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -261,9 +261,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -356,9 +356,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -418,9 +418,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -468,9 +468,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -518,9 +518,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -568,9 +568,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -618,9 +618,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -676,9 +676,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -691,7 +691,7 @@ }, { "name": "target", - "value": 0.50 + "value": 0.5 } ], "result": { @@ -738,9 +738,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -800,9 +800,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -886,9 +886,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -952,9 +952,9 @@ } ], "result": { - "name": "success", + "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -1013,7 +1013,7 @@ "result": { "name": "result", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -1135,4 +1135,4 @@ } } } -} \ No newline at end of file +} diff --git a/docs/openrpc/the-spec/firebolt-open-rpc.json b/docs/openrpc/the-spec/firebolt-open-rpc.json index 05a1fc6..3a3b51a 100644 --- a/docs/openrpc/the-spec/firebolt-open-rpc.json +++ b/docs/openrpc/the-spec/firebolt-open-rpc.json @@ -1,3845 +1,3844 @@ { - "openrpc": "1.2.4", - "info": { - "title": "Firebolt JSON-RPC API", - "version": "", - "x-module-descriptions": { - "Accessibility": "The `Accessibility` module provides access to the user/device settings for closed captioning and voice guidance.\n\nApps **SHOULD** attempt o respect these settings, rather than manage and persist seprate settings, which would be different per-app.", - "Advertising": "A module for platform provided advertising settings and functionality.", - "Device": "A module for querying about the device and it's capabilities.", - "Discovery": "Your App likely wants to integrate with the Platform's discovery capabilities. For example to add a \"Watch Next\" tile that links to your app from the platform's home screen.\n\nGetting access to this information requires to connect to lower level APIs made available by the platform. Since implementations differ between operators and platforms, the Firebolt SDK offers a Discovery module, that exposes a generic, agnostic interface to the developer.\n\nUnder the hood, an underlaying transport layer will then take care of calling the right APIs for the actual platform implementation that your App is running on.\n\nThe Discovery plugin is used to _send_ information to the Platform.\n\n### Localization\nApps should provide all user-facing strings in the device's language, as specified by the Firebolt `Localization.language` property.\n\nApps should provide prices in the same currency presented in the app. If multiple currencies are supported in the app, the app should provide prices in the user's current default currency.", - "Display": "A module for querying about the display", - "Lifecycle2": "Methods and events for responding to Lifecycle changes in your app.", - "Localization": "Methods for accessing location and language preferences.", - "Metrics": "Methods for sending metrics", - "Network": "Methods for accessing network information.", - "Presentation": "Methods for accessing Presentation preferences.", - "Stats": "Provides methods to retrieve application-level system information.", - "TextToSpeech": "A module for controlling and accessing Text To Speech over Firebolt." - } - }, - "methods": [ - { - "name": "rpc.discover", - "summary": "The OpenRPC schema for this JSON-RPC API", - "params": [], - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:rpc:discover" - ] - } - ], - "result": { - "name": "OpenRPC Schema", - "schema": { - "type": "object" - } - }, - "examples": [ - { - "name": "Default", - "params": [], - "result": { - "name": "schema", - "value": {} - } - } - ] - }, - { - "name": "Accessibility.audioDescription", - "summary": "Returns the audio description setting of the device", - "params": [], - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:audio-descriptions" - ] - } - ], - "result": { - "name": "setting", - "summary": "the audio description setting", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Getting the audio description setting", - "params": [], - "result": { - "name": "Default Result", - "value": true - } - } - ] - }, - { - "name": "Accessibility.closedCaptionsSettings", - "summary": "Returns captions settings: enabled, and a list of zero or more languages in order of decreasing preference", - "params": [], - "tags": [ - { - "name": "property:readonly", - "x-notifier-params-flattening": "true" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:closed-captions" - ] - } - ], - "result": { - "name": "closedCaptionsSettings", - "summary": "the closed captions settings", - "schema": { - "$ref": "#/x-schemas/Accessibility/ClosedCaptionsSettings" - } - }, - "examples": [ - { - "name": "Getting the closed captions settings", - "params": [], - "result": { - "name": "settings", - "value": { - "enabled": true, - "preferredLanguages": [ - "eng", - "spa" - ] - } - } - } - ] - }, - { - "name": "Accessibility.highContrastUI", - "summary": "Returns the high contrast UI device setting", - "params": [], - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:high-contrast-ui" - ] - } - ], - "result": { - "name": "highContrastUI", - "summary": "Whether high-contrast UI mode is enabled", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "High-contrast UI mode is enabled", - "params": [], - "result": { - "name": "Default Result", - "value": true - } - } - ] - }, - { - "name": "Accessibility.voiceGuidanceSettings", - "summary": "Returns voice guidance settings: enabled, rate, and verbosity", - "params": [], - "tags": [ - { - "name": "property:readonly", - "x-notifier-params-flattening": "true" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:voice-guidance" - ] - } - ], - "result": { - "name": "settings", - "summary": "the voice guidance settings", - "schema": { - "$ref": "#/x-schemas/Accessibility/VoiceGuidanceSettings" - } - }, - "examples": [ - { - "name": "Getting the voice guidance settings", - "params": [], - "result": { - "name": "Default Result", - "value": { - "enabled": true, - "rate": 0.8, - "navigationHints": true - } - } - } - ] - }, - { - "name": "Advertising.advertisingId", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:advertising:identifier" - ] - } - ], - "summary": "Returns the IFA.", - "params": [], - "result": { - "name": "advertisingId", - "summary": "The advertising ID", - "schema": { - "$ref": "#/components/schemas/AdvertisingIdResult" - } - }, - "examples": [ - { - "name": "Getting the advertising ID", - "params": [], - "result": { - "name": "Default Result", - "value": { - "ifa": "bd87dd10-8d1d-4b93-b1a6-a8e5d410e400", - "ifa_type": "sspid", - "lmt": "0" - } - } - }, - { - "name": "Getting the advertising ID with scope browse", - "params": [], - "result": { - "name": "Default Result", - "value": { - "ifa": "bd87dd10-8d1d-4b93-b1a6-a8e5d410e400", - "ifa_type": "sspid", - "lmt": "1" - } - } - }, - { - "name": "Getting the advertising ID with scope content", - "params": [], - "result": { - "name": "Default Result", - "value": { - "ifa": "bd87dd10-8d1d-4b93-b1a6-a8e5d410e400", - "ifa_type": "idfa", - "lmt": "0" - } - } - } - ] - }, - { - "name": "Device.uid", - "summary": "Returns a persistent unique UUID for the current app and device. The UUID is reset when the app or device is reset", - "params": [], - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:uid" - ] - } - ], - "result": { - "name": "uniqueId", - "summary": "A unique UUID for this app-device pair.", - "schema": { - "type": "string" - } - }, - "examples": [ - { - "name": "Getting the unique UUID", - "params": [], - "result": { - "name": "Default Result", - "value": "ee6723b8-7ab3-462c-8d93-dbf61227998e" - } - } - ] - }, - { - "name": "Device.deviceClass", - "summary": "Returns the class of the device", - "params": [], - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:device-class" - ] - } - ], - "result": { - "name": "deviceClass", - "summary": "The device class", - "schema": { - "$ref": "#/components/schemas/DeviceClass" - } - }, - "examples": [ - { - "name": "Getting the device class", - "params": [], - "result": { - "name": "Default Result", - "value": "ott" - } - } - ] - }, - { - "name": "Device.uptime", - "summary": "Returns the number of seconds since most recent device boot, including any time spent during deep sleep", - "params": [], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "result": { - "name": "uptime", - "summary": "The device uptime", - "schema": { - "type": "number" - } - }, - "examples": [ - { - "name": "Getting the device uptime", - "params": [], - "result": { - "name": "Default Result", - "value": 123456 - } - } - ] - }, - { - "name": "Device.timeInActiveState", - "summary": "Returns the number of seconds since the device transitioned to the ON power state", - "params": [], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "result": { - "name": "timeInActiveState", - "summary": "The device time in active state", - "schema": { - "type": "number" - } - }, - "examples": [ - { - "name": "Getting the number of seconds since the device transitioned to the ON power state", - "params": [], - "result": { - "name": "Default Result", - "value": 654321 - } - } - ] - }, - { - "name": "Device.chipsetId", - "summary": "Returns chipset ID as a printable string, e.g. BCM72180", - "params": [], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "result": { - "name": "chipsetId", - "summary": "The device chipset ID", - "schema": { - "type": "string" - } - }, - "examples": [ - { - "name": "Getting the device chipset ID", - "params": [], - "result": { - "name": "Default Result", - "value": "BCM72180" - } - } - ] - }, - { - "name": "Device.hdr", - "summary": "Returns the HDR standards that are supported by the attached TV or the integral display", - "params": [], - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "result": { - "name": "negotiatedHdrFormats", - "summary": "the negotiated HDR formats", - "schema": { - "$ref": "#/components/schemas/HDRFormatMap" - } - }, - "examples": [ - { - "name": "Getting the negotiated HDR formats", - "params": [], - "result": { - "name": "Default Result", - "value": { - "hdr10": true, - "hdr10Plus": true, - "dolbyVision": true, - "hlg": true - } - } - } - ] - }, - { - "name": "Discovery.watched", - "summary": "Notify the platform that content was partially or completely watched", - "tags": [ - { - "name": "polymorphic-reducer" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:discovery:watched" - ] - } - ], - "params": [ - { - "name": "entityId", - "required": true, - "schema": { - "type": "string" - }, - "summary": "The entity Id of the watched content." - }, - { - "name": "progress", - "summary": "How much of the content has been watched (percentage as (0-0.999) for VOD, number of seconds for live)", - "schema": { - "type": "number", - "minimum": 0 - } - }, - { - "name": "completed", - "summary": "Whether or not this viewing is considered \"complete,\" per the app's definition thereof", - "schema": { - "type": "boolean" - } - }, - { - "name": "watchedOn", - "summary": "Date/Time the content was watched, ISO 8601 Date/Time", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "agePolicy", - "description": "The age policy associated with the watch event. The age policy describes the age groups to which content may be directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "summary": "whether the call was successful or not", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Notify the platform of watched content", - "params": [ - { - "name": "entityId", - "value": "partner.com/entity/123" - }, - { - "name": "progress", - "value": 0.95 - }, - { - "name": "completed", - "value": true - }, - { - "name": "watchedOn", - "value": "2021-04-23T18:25:43.511Z" - } - ], - "result": { - "name": "success", - "value": true - } - }, - { - "name": "Notify the platform that child-directed content was watched", - "params": [ - { - "name": "entityId", - "value": "partner.com/entity/123" - }, - { - "name": "progress", - "value": 0.95 - }, - { - "name": "completed", - "value": true - }, - { - "name": "watchedOn", - "value": "2021-04-23T18:25:43.511Z" - }, - { - "name": "agePolicy", - "value": "app:child" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Display.edid", - "summary": "Returns the EDID (and extensions) of the connected or integral display, as a Base64 encoded string", - "params": [], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:display:info" - ] - } - ], - "result": { - "name": "Base64 EDID", - "summary": "The EDID (and extensions) of the connected or integral display, as a Base64 encoded string", - "schema": { - "type": "string" - } - }, - "examples": [ - { - "name": "Getting the display EDID", - "params": [], - "result": { - "name": "Default Result", - "value": "ZWU2NzIzYjgtN2FiMy00NjJjLThkOTMtZGJmNjEyMjc5OThl" - } - } - ] - }, - { - "name": "Display.size", - "summary": "Returns the physical dimensions of the connected or integral display, in centimeters. Returns 0, 0 on a OTT/STB device when a display is not connected over HDMI", - "params": [], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:display:info" - ] - } - ], - "result": { - "name": "size", - "summary": "The display size in centimeters", - "schema": { - "type": "object", - "properties": { - "width": { - "type": "integer", - "description": "The width of the display in centimeters" - }, - "height": { - "type": "integer", - "description": "The height of the display in centimeters" - } - } - } - }, - "examples": [ - { - "name": "Getting the display size", - "params": [], - "result": { - "name": "Default Result", - "value": { - "width": 48, - "height": 27 - } - } - } - ] - }, - { - "name": "Display.maxResolution", - "summary": "Returns the physical/native resolution of the connected or integral display, in pixels. Returns 0, 0 on a OTT/STB device when a display is not connected over HDMI", - "params": [], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:display:info" - ] - } - ], - "result": { - "name": "maxResolution", - "summary": "The display resolution", - "schema": { - "type": "object", - "properties": { - "width": { - "type": "integer", - "description": "The width of the display in pixels" - }, - "height": { - "type": "integer", - "description": "The height of the display in pixels" - } - } - } - }, - "examples": [ - { - "name": "Getting the display size", - "params": [], - "result": { - "name": "Default Result", - "value": { - "width": 1920, - "height": 1080 - } - } - } - ] - }, - { - "name": "Lifecycle2.close", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:cpp-client-only" - ] - } - ], - "summary": "Request the platform to deactivate the app, and possibly take further action.", - "params": [ - { - "name": "type", - "summary": "The type of the close app is requesting", - "required": true, - "schema": { - "$ref": "#/components/schemas/CloseType" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Close the app when the user presses back on the app home screen", - "params": [ - { - "name": "type", - "value": "unload" - } - ], - "result": { - "name": "Default Result", - "value": null - } - }, - { - "name": "Close the app when the user selects an exit menu item", - "params": [ - { - "name": "type", - "value": "deactivate" - } - ], - "result": { - "name": "Default Result", - "value": null - } - } - ] - }, - { - "name": "Lifecycle2.state", - "summary": "Get the current lifecycle state of the app.", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:cpp-client-only" - ] - } - ], - "params": [], - "result": { - "name": "state", - "summary": "The current lifecycle state of the app.", - "schema": { - "$ref": "#/components/schemas/LifecycleState" - } - }, - "examples": [ - { - "name": "Default Example", - "params": [], - "result": { - "name": "Default Result", - "value": "active" - } - } - ] - }, - { - "name": "Localization.country", - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:country-code" - ] - } - ], - "summary": "Returns the ISO 3166-1 alpha-2 code for the country device is located in.", - "params": [], - "result": { - "name": "code", - "summary": "The device country code.", - "schema": { - "$ref": "#/x-schemas/Localization/CountryCode" - } - }, - "examples": [ - { - "name": "Default example", - "params": [], - "result": { - "name": "Default Result", - "value": "US" - } - }, - { - "name": "Another example", - "params": [], - "result": { - "name": "Default Result", - "value": "GB" - } - } - ] - }, - { - "name": "Localization.preferredAudioLanguages", - "summary": "Returns a list of ISO 639-2/B codes for the preferred audio languages on this device.", - "params": [], - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:preferred-audio-languages" - ] - } - ], - "result": { - "name": "languages", - "summary": "The preferred audio languages.", - "schema": { - "type": "array", - "items": { - "$ref": "#/x-schemas/Localization/ISO639_2Language" - } - } - }, - "examples": [ - { - "name": "Default example", - "params": [], - "result": { - "name": "Default Result", - "value": [ - "spa", - "eng" - ] - } - } - ] - }, - { - "name": "Localization.presentationLanguage", - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:locale" - ] - } - ], - "summary": "Get the *full* BCP 47 code, including script, region, variant, etc., for the preferred locale", - "params": [], - "result": { - "name": "locale", - "summary": "The device locale.", - "schema": { - "$ref": "#/x-schemas/Localization/Locale" - } - }, - "examples": [ - { - "name": "Default example", - "params": [], - "result": { - "name": "Default Result", - "value": "en-US" - } - } - ] - }, - { - "name": "Metrics.ready", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Inform the platform that your app is minimally usable. This method is called automatically by `Lifecycle.ready()`", - "params": [], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send ready metric", - "params": [], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.signIn", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Log a sign in event, called by Discovery.signIn().", - "params": [], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send signIn metric", - "params": [], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.signOut", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Log a sign out event, called by Discovery.signOut().", - "params": [], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send signOut metric", - "params": [], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.startContent", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Inform the platform that your user has started content.", - "params": [ - { - "name": "entityId", - "summary": "Optional entity ID of the content.", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send startContent metric", - "params": [], - "result": { - "name": "success", - "value": true - } - }, - { - "name": "Send startContent metric w/ entity", - "params": [ - { - "name": "entityId", - "value": "abc" - } - ], - "result": { - "name": "success", - "value": true - } - }, - { - "name": "Send startContent metric and notify the platform that the content is child-directed", - "params": [ - { - "name": "entityId", - "value": "abc" - }, - { - "name": "agePolicy", - "value": "app:child" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.stopContent", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Inform the platform that your user has stopped content.", - "params": [ - { - "name": "entityId", - "summary": "Optional entity ID of the content.", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send stopContent metric", - "params": [], - "result": { - "name": "success", - "value": true - } - }, - { - "name": "Send stopContent metric w/ entity", - "params": [ - { - "name": "entityId", - "value": "abc" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.page", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Inform the platform that your user has navigated to a page or view.", - "params": [ - { - "name": "pageId", - "summary": "Page ID of the content.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send page metric", - "params": [ - { - "name": "pageId", - "value": "xyz" - } - ], - "result": { - "name": "success", - "value": true - } - }, - { - "name": "Send page metric w/ pageId", - "params": [ - { - "name": "pageId", - "value": "home" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.error", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Inform the platform of an error that has occurred in your app.", - "params": [ - { - "name": "type", - "summary": "The type of error", - "schema": { - "$ref": "#/components/schemas/ErrorType" - }, - "required": true - }, - { - "name": "code", - "summary": "an app-specific error code", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "description", - "summary": "A short description of the error", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "visible", - "summary": "Whether or not this error was visible to the user.", - "schema": { - "type": "boolean" - }, - "required": true - }, - { - "name": "parameters", - "summary": "Optional additional parameters to be logged with the error", - "schema": { - "$ref": "#/x-schemas/Types/FlatMap" - }, - "required": false - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send error metric", - "params": [ - { - "name": "type", - "value": "media" - }, - { - "name": "code", - "value": "MEDIA-STALLED" - }, - { - "name": "description", - "value": "playback stalled" - }, - { - "name": "visible", - "value": true - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaLoadStart", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when setting the URL of a media asset to play, in order to infer load time.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send loadstart metric.", - "params": [ - { - "name": "entityId", - "value": "345" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaPlay", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when media playback should start due to autoplay, user-initiated play, or unpausing.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send play metric.", - "params": [ - { - "name": "entityId", - "value": "345" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaPlaying", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when media playback actually starts due to autoplay, user-initiated play, unpausing, or recovering from a buffering interruption.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send playing metric.", - "params": [ - { - "name": "entityId", - "value": "345" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaPause", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when media playback will pause due to an intentional pause operation.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send pause metric.", - "params": [ - { - "name": "entityId", - "value": "345" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaWaiting", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when media playback will halt due to a network, buffer, or other unintentional constraint.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send waiting metric.", - "params": [ - { - "name": "entityId", - "value": "345" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaSeeking", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when a seek is initiated during media playback.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "target", - "summary": "Target destination of the seek, as a decimal percentage (0-0.999) for content with a known duration, or an integer number of seconds (0-86400) for content with an unknown duration.", - "schema": { - "$ref": "#/components/schemas/MediaPosition" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send seeking metric.", - "params": [ - { - "name": "entityId", - "value": "345" - }, - { - "name": "target", - "value": 0.5 - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaSeeked", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when a seek is completed during media playback.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "position", - "summary": "Resulting position of the seek operation, as a decimal percentage (0-0.999) for content with a known duration, or an integer number of seconds (0-86400) for content with an unknown duration.", - "schema": { - "$ref": "#/components/schemas/MediaPosition" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send seeked metric.", - "params": [ - { - "name": "entityId", - "value": "345" - }, - { - "name": "position", - "value": 0.51 - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaRateChanged", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when the playback rate of media is changed.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "rate", - "summary": "The new playback rate.", - "schema": { - "type": "number" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send ratechange metric.", - "params": [ - { - "name": "entityId", - "value": "345" - }, - { - "name": "rate", - "value": 2 - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaRenditionChanged", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when the playback rendition (e.g. bitrate, dimensions, profile, etc) is changed.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "bitrate", - "summary": "The new bitrate in kbps.", - "schema": { - "type": "number" - }, - "required": true - }, - { - "name": "width", - "summary": "The new resolution width.", - "schema": { - "type": "number" - }, - "required": true - }, - { - "name": "height", - "summary": "The new resolution height.", - "schema": { - "type": "number" - }, - "required": true - }, - { - "name": "profile", - "summary": "A description of the new profile, e.g. 'HDR' etc.", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send renditionchange metric.", - "params": [ - { - "name": "entityId", - "value": "345" - }, - { - "name": "bitrate", - "value": 5000 - }, - { - "name": "width", - "value": 1920 - }, - { - "name": "height", - "value": 1080 - }, - { - "name": "profile", - "value": "HDR+" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaEnded", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when playback has stopped because the end of the media was reached.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "success", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send ended metric.", - "params": [ - { - "name": "entityId", - "value": "345" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.event", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:distributor" - ] - } - ], - "summary": "Inform the platform of 1st party distributor metrics. 'data' parameter is a JSON document", - "params": [ - { - "name": "schema", - "summary": "The schema URI of the metric type", - "schema": { - "type": "string", - "format": "uri" - }, - "required": true - }, - { - "name": "data", - "summary": "A JSON payload", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Send foo event", - "params": [ - { - "name": "schema", - "value": "http://meta.rdkcentral.com/some/schema" - }, - { - "name": "data", - "value": "foo" - } - ], - "result": { - "name": "result", - "value": true - } - } - ] - }, - { - "name": "Metrics.appInfo", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Inform the platform about an app's build info.", - "params": [ - { - "name": "build", - "summary": "The build / version of this app.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send appInfo metric", - "params": [ - { - "name": "build", - "value": "1.2.2" - } - ], - "result": { - "name": "result", - "value": null - } - } - ] - }, - { - "name": "Network.connected", - "summary": "Returns whether the device currently has a usable network connection.", - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:network:connected" - ] - } - ], - "params": [], - "result": { - "name": "success", - "summary": "Whether the device currently has a usable network connection.", - "schema": { - "$ref": "#/components/schemas/Connected" - } - }, - "examples": [ - { - "name": "Connected example", - "params": [], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Presentation.focused", - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:cpp-client-only" - ] - } - ], - "summary": "Whether the app is in focus, i.e. receiving key presses. Provided for those apps/runtimes that cannot use Wayland", - "params": [], - "result": { - "name": "focused", - "summary": "Whether the app is in focus.", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Default example", - "params": [], - "result": { - "name": "Default Result", - "value": true - } - } - ] - }, - { - "name": "Stats.memoryUsage", - "summary": "Returns information about container memory usage, in units of 1024 bytes.", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:cpp-client-only" - ] - } - ], - "params": [], - "result": { - "name": "result", - "schema": { - "$ref": "#/components/schemas/MemoryUsage" - } - }, - "examples": [ - { - "name": "Default example", - "params": [], - "result": { - "name": "value", - "description": "The memory usage information", - "value": { - "userMemoryUsedKiB": 123456, - "userMemoryLimitKiB": 789012, - "gpuMemoryUsedKiB": 345678, - "gpuMemoryLimitKiB": 901234 - } - } - } - ] - }, - { - "name": "TextToSpeech.speak", - "summary": "Speak the utterance immediately. Any ongoing speech is interrupted.", - "description": "Text argument is either plain text or a well-formed SSML document TTS_status, not success attribute, to be used by caller to indicate success of call 0 OK, 1 Fail, 2 not enabled, 3 invalid configuration Raises onSpeechinterrupted if speaking is interrupted", - "params": [ - { - "name": "text", - "summary": "String to be converted to Audio for speech", - "schema": { - "type": "string" - }, - "required": true - } - ], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "result": { - "name": "speakResult", - "summary": "Result for Speak", - "schema": { - "$ref": "#/components/schemas/SpeechResponse" - } - }, - "examples": [ - { - "name": "Getting the result of speak", - "params": [ - { - "name": "text", - "value": "I am a text waiting for speech." - } - ], - "result": { - "name": "result", - "value": { - "speechid": 1, - "TTS_Status": 0, - "success": true - } - } - } - ] - }, - { - "name": "TextToSpeech.pause", - "summary": "Pauses the speech for given speech id", - "description": "Pauses the utterance. Raises onSpeechpause if ongoing speech is paused. Does nothing if utterance is already paused", - "params": [ - { - "name": "speechid", - "summary": "Identifier for the speech call", - "schema": { - "$ref": "#/components/schemas/SpeechId" - }, - "required": true - } - ], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "result": { - "name": "pauseResult", - "summary": "Result for Pause", - "schema": { - "$ref": "#/components/schemas/TTSStatusResponse" - } - }, - "examples": [ - { - "name": "Pause a given speech id", - "params": [ - { - "name": "speechid", - "value": 1 - } - ], - "result": { - "name": "TTS_Status", - "value": { - "TTS_Status": 0, - "success": true - } - } - } - ] - }, - { - "name": "TextToSpeech.resume", - "summary": "Resumes the speech for given speech id", - "description": "Continue the paused utterance. Raises onSpeechresume if paused speech is resumed. Does nothing if the utterance is not paused", - "params": [ - { - "name": "speechid", - "summary": "Identifier for the speech call", - "schema": { - "$ref": "#/components/schemas/SpeechId" - }, - "required": true - } - ], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "result": { - "name": "resumeResult", - "summary": "Result for Resume", - "schema": { - "$ref": "#/components/schemas/TTSStatusResponse" - } - }, - "examples": [ - { - "name": "Resume a given speech id.", - "params": [ - { - "name": "speechid", - "value": 1 - } - ], - "result": { - "name": "TTS_Status", - "value": { - "TTS_Status": 0, - "success": true - } - } - } - ] - }, - { - "name": "TextToSpeech.cancel", - "summary": "Cancels the speech for given speech id", - "description": "Stop speaking if utterance is currently being spoken. Raises onSpeechinterrupted if speaking was interrupted.", - "params": [ - { - "name": "speechid", - "summary": "Identifier for the speech call", - "schema": { - "$ref": "#/components/schemas/SpeechId" - }, - "required": true - } - ], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "result": { - "name": "cancelResult", - "summary": "Result for cancel", - "schema": { - "$ref": "#/components/schemas/TTSStatusResponse" - } - }, - "examples": [ - { - "name": "Cancel a given speech id.", - "params": [ - { - "name": "speechid", - "value": 1 - } - ], - "result": { - "name": "TTS_Status", - "value": { - "TTS_Status": 0, - "success": true - } - } - } - ] - }, - { - "name": "TextToSpeech.getspeechstate", - "summary": "Returns the state of the utterance.", - "params": [ - { - "name": "speechid", - "summary": "Identifier for the speech call", - "schema": { - "$ref": "#/components/schemas/SpeechId" - }, - "required": true - } - ], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "result": { - "name": "speechStateResult", - "summary": "Result for speech state", - "schema": { - "$ref": "#/components/schemas/SpeechStateResponse" - } - }, - "examples": [ - { - "name": "State for a given speech id.", - "params": [ - { - "name": "speechid", - "value": 1 - } - ], - "result": { - "name": "speechstate", - "value": { - "speechstate": 1, - "TTS_Status": 0, - "success": true - } - } - } - ] - }, - { - "name": "TextToSpeech.listvoices", - "summary": "Returns the list of available voices as human-readable strings, e.g. 'ava', 'amelie', 'angelica'", - "params": [ - { - "name": "language", - "summary": "Language - string - BCP 47", - "schema": { - "$ref": "#/x-schemas/Localization/Locale" - }, - "required": true - } - ], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "result": { - "name": "listvoices", - "summary": "The list of voices supported for the language", - "schema": { - "$ref": "#/components/schemas/ListVoicesResponse" - } - }, - "examples": [ - { - "name": "Getting the list of voices", - "params": [ - { - "name": "language", - "value": "en-US" - } - ], - "result": { - "name": "voiceList", - "value": { - "TTS_Status": 0, - "voices": [ - "carol", - "tom" - ] - } - } - } - ] - }, - { - "name": "Lifecycle2.onStateChanged", - "tags": [ - { - "name": "event", - "x-contextual-parameters": 0, - "x-notifier": "Lifecycle2.onStateChanged" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:cpp-client-only" - ] - } - ], - "summary": "Notification of lifecycle state change, raised after the platform has transitioned the app/runtime to the new lifecycle state", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "App is active after being initialized", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - }, - { - "name": "Single transition to paused state", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onWillspeak", - "summary": "Text to speech conversion is about to start.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onWillspeak" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onSpeechstart", - "summary": "Utterance is about to be spoken.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onSpeechstart" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onSpeechpause", - "summary": "Ongoing speech was paused.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onSpeechpause" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onSpeechresume", - "summary": "Paused speech was resumed.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onSpeechresume" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onSpeechcomplete", - "summary": "Speech completed successfully.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onSpeechcomplete" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onSpeechinterrupted", - "summary": "Speech was stopped, due to another call to speak or cancel.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onSpeechinterrupted" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onNetworkerror", - "summary": "Utterance failed due to network error.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onNetworkerror" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onPlaybackerror", - "summary": "Utterance failed during playback.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onPlaybackerror" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Accessibility.onAudioDescriptionChanged", - "summary": "Returns the audio description setting of the device", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier": "Accessibility.onAudioDescriptionChanged", - "x-subscriber-for": "Accessibility.audioDescription" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:audio-descriptions" - ] - } - ], - "examples": [ - { - "name": "Getting the audio description setting", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Accessibility.onClosedCaptionsSettingsChanged", - "summary": "Returns captions settings: enabled, and a list of zero or more languages in order of decreasing preference", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier-params-flattening": "true", - "x-notifier": "Accessibility.onClosedCaptionsSettingsChanged", - "x-subscriber-for": "Accessibility.closedCaptionsSettings" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:closed-captions" - ] - } - ], - "examples": [ - { - "name": "Getting the closed captions settings", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Accessibility.onHighContrastUIChanged", - "summary": "Returns the high contrast UI device setting", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier": "Accessibility.onHighContrastUIChanged", - "x-subscriber-for": "Accessibility.highContrastUI" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:high-contrast-ui" - ] - } - ], - "examples": [ - { - "name": "High-contrast UI mode is enabled", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Accessibility.onVoiceGuidanceSettingsChanged", - "summary": "Returns voice guidance settings: enabled, rate, and verbosity", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier-params-flattening": "true", - "x-notifier": "Accessibility.onVoiceGuidanceSettingsChanged", - "x-subscriber-for": "Accessibility.voiceGuidanceSettings" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:voice-guidance" - ] - } - ], - "examples": [ - { - "name": "Getting the voice guidance settings", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Device.onHdrChanged", - "summary": "Returns the HDR standards that are supported by the attached TV or the integral display", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier": "Device.onHdrChanged", - "x-subscriber-for": "Device.hdr" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "examples": [ - { - "name": "Getting the negotiated HDR formats", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Localization.onCountryChanged", - "tags": [ - { - "name": "event", - "x-notifier": "Localization.onCountryChanged", - "x-subscriber-for": "Localization.country" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:country-code" - ] - } - ], - "summary": "Returns the ISO 3166-1 alpha-2 code for the country device is located in.", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - }, - { - "name": "Another example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Localization.onPreferredAudioLanguagesChanged", - "summary": "Returns a list of ISO 639-2/B codes for the preferred audio languages on this device.", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier": "Localization.onPreferredAudioLanguagesChanged", - "x-subscriber-for": "Localization.preferredAudioLanguages" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:preferred-audio-languages" - ] - } - ], - "examples": [ - { - "name": "Default example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Localization.onPresentationLanguageChanged", - "tags": [ - { - "name": "event", - "x-notifier": "Localization.onPresentationLanguageChanged", - "x-subscriber-for": "Localization.presentationLanguage" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:locale" - ] - } - ], - "summary": "Get the *full* BCP 47 code, including script, region, variant, etc., for the preferred locale", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Network.onConnectedChanged", - "summary": "Returns whether the device currently has a usable network connection.", - "tags": [ - { - "name": "event", - "x-notifier": "Network.onConnectedChanged", - "x-subscriber-for": "Network.connected" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:network:connected" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Connected example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Presentation.onFocusedChanged", - "tags": [ - { - "name": "event", - "x-notifier": "Presentation.onFocusedChanged", - "x-subscriber-for": "Presentation.focused" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:cpp-client-only" - ] - } - ], - "summary": "Whether the app is in focus, i.e. receiving key presses. Provided for those apps/runtimes that cannot use Wayland", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - } - ], - "components": { - "schemas": { - "AdvertisingIdResult": { - "title": "AdvertisingIdResult", - "type": "object", - "properties": { - "ifa": { - "type": "string", - "description": "UUID conforming to IAB standard" - }, - "ifa_type": { - "type": "string", - "description": "Source of the IFA as defined by IAB" - }, - "lmt": { - "type": "string", - "enum": [ - "0", - "1" - ], - "description": "Boolean that if set to 1, user has requested ad tracking and measurement is disabled" - } - }, - "required": [ - "ifa", - "ifa_type", - "lmt" - ] - }, - "HDRFormatMap": { - "title": "HDRFormatMap", - "type": "object", - "properties": { - "hdr10": { - "type": "boolean" - }, - "hdr10Plus": { - "type": "boolean" - }, - "dolbyVision": { - "type": "boolean" - }, - "hlg": { - "type": "boolean" - } - }, - "required": [ - "hdr10", - "hdr10Plus", - "dolbyVision", - "hlg" - ], - "description": "The type of HDR format" - }, - "DeviceClass": { - "title": "DeviceClass", - "type": "string", - "enum": [ - "ott", - "stb", - "tv" - ], - "description": "The type of device" - }, - "CloseType": { - "title": "CloseType", - "description": "The application close type", - "type": "string", - "enum": [ - "deactivate", - "unload", - "killReload", - "killReactivate" - ] - }, - "LifecycleState": { - "title": "LifecycleState", - "description": "The application Lifecycle state", - "type": "string", - "enum": [ - "initializing", - "active", - "paused", - "suspended", - "hibernated", - "terminating" - ] - }, - "StateChange": { - "title": "StateChange", - "type": "object", - "properties": { - "newState": { - "$ref": "#/components/schemas/LifecycleState" - }, - "oldState": { - "$ref": "#/components/schemas/LifecycleState" - } - } - }, - "MediaPosition": { - "title": "MediaPosition", - "description": "Represents a position inside playback content, as a decimal percentage (0-0.999) for content with a known duration, or an integer number of seconds (0-86400) for content with an unknown duration.", - "oneOf": [ - { - "const": 0 - }, - { - "type": "number", - "exclusiveMinimum": 0, - "exclusiveMaximum": 1 - }, - { - "type": "integer", - "minimum": 1, - "maximum": 86400 - } - ] - }, - "ErrorType": { - "title": "ErrorType", - "type": "string", - "enum": [ - "network", - "media", - "restriction", - "entitlement", - "other" - ] - }, - "EventObjectPrimitives": { - "title": "EventObjectPrimitives", - "anyOf": [ - { - "type": "string", - "maxLength": 256 - }, - { - "type": "number" - }, - { - "type": "integer" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "Connected": { - "type": "boolean", - "description": "Indicates whether the device currently has a usable network connection." - }, - "MemoryUsage": { - "title": "MemoryUsage", - "type": "object", - "description": "Describes current and maximum memory usage of the container.", - "properties": { - "userMemoryUsedKiB": { - "type": "integer", - "description": "User memory currently used in 1024 bytes." - }, - "userMemoryLimitKiB": { - "type": "integer", - "description": "Maximum user memory available in 1024 bytes." - }, - "gpuMemoryUsedKiB": { - "type": "integer", - "description": "GPU memory currently used in 1024 bytes." - }, - "gpuMemoryLimitKiB": { - "type": "integer", - "description": "Maximum GPU memory available in 1024 bytes." - } - }, - "required": [ - "userMemoryUsedKiB", - "userMemoryLimitKiB", - "gpuMemoryUsedKiB", - "gpuMemoryLimitKiB" - ] - }, - "TTSEnabled": { - "title": "TTSEnabled", - "type": "object", - "required": [ - "TTS_Status", - "isenabled" - ], - "properties": { - "TTS_Status": { - "$ref": "#/components/schemas/TTSStatus" - }, - "isenabled": { - "type": "boolean" - } - } - }, - "ListVoicesResponse": { - "title": "ListVoicesResponse", - "type": "object", - "required": [ - "TTS_Status", - "voices" - ], - "properties": { - "TTS_Status": { - "$ref": "#/components/schemas/TTSStatus" - }, - "voices": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "TTSConfiguration": { - "title": "TTSConfiguration", - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - }, - "ttsendpoint": { - "type": "string", - "description": "URL for Text to Speech API" - }, - "ttsendpointsecured": { - "type": "string", - "description": "Secure URL for Text to Speech API" - }, - "language": { - "type": "string", - "description": "Language used by Text to speech" - }, - "voice": { - "type": "string", - "description": "Voice used by Text to speech" - }, - "volume": { - "type": "integer", - "description": "Volume for Text to speech", - "minimum": 0, - "maximum": 100 - }, - "primvolduckpercent": { - "type": "integer", - "description": "Prime Volume duck percent for Text to speech", - "minimum": 0, - "maximum": 100 - }, - "rate": { - "type": "integer", - "description": "Speech rate for Text to speech", - "minimum": 0, - "maximum": 100 - }, - "speechrate": { - "description": "Rate for speech", - "$ref": "#/components/schemas/SpeechRate" - }, - "fallbacktext": { - "description": "Fallback text for TTS", - "$ref": "#/components/schemas/FallbackText" - } - }, - "examples": [ - {} - ] - }, - "SpeechRate": { - "title": "SpeechRate", - "type": "string", - "enum": [ - "slow", - "medium", - "fast", - "faster", - "fastest" - ] - }, - "FallbackText": { - "title": "FallbackText", - "type": "object", - "properties": { - "scenario": { - "type": "string", - "description": "Scenario for fallback Text" - }, - "value": { - "type": "string", - "description": "Value for fallback Text" - } - } - }, - "SpeechResponse": { - "title": "SpeechResponse", - "type": "object", - "properties": { - "speechid": { - "$ref": "#/components/schemas/SpeechId" - }, - "TTS_Status": { - "$ref": "#/components/schemas/TTSStatus" - }, - "success": { - "type": "boolean" - } - }, - "required": [ - "speechid", - "TTS_Status", - "success" - ] - }, - "SpeechId": { - "type": "integer" - }, - "SpeechIdEvent": { - "type": "object", - "properties": { - "speechid": { - "$ref": "#/components/schemas/SpeechId" - } - }, - "required": [ - "speechid" - ] - }, - "TTSStatus": { - "title": "TTSStatus", - "type": "integer", - "minimum": 0, - "maximum": 3 - }, - "SpeechState": { - "title": "SpeechState", - "type": "integer", - "enum": [ - 0, - 1, - 2, - 3 - ], - "description": "0 = SPEECH_PENDING, 1 = SPEECH_IN_PROGRESS, 2 = SPEECH_PAUSED, 3 = SPEECH_NOT_FOUND" - }, - "SpeechStateResponse": { - "title": "SpeechStateResponse", - "type": "object", - "properties": { - "speechstate": { - "$ref": "#/components/schemas/SpeechState" - }, - "TTS_Status": { - "$ref": "#/components/schemas/TTSStatus" - }, - "success": { - "type": "boolean" - } - }, - "required": [ - "speechstate", - "TTS_Status", - "success" - ] - }, - "TTSStatusResponse": { - "title": "TTSStatusResponse", - "type": "object", - "properties": { - "TTS_Status": { - "$ref": "#/components/schemas/TTSStatus" - }, - "success": { - "type": "boolean" - } - }, - "required": [ - "TTS_Status", - "success" - ] - }, - "TTSState": { - "title": "TTSState", - "type": "object", - "properties": { - "state": { - "type": "boolean" - } - }, - "required": [ - "state" - ] - }, - "TTSVoice": { - "title": "TTSVoice", - "type": "object", - "properties": { - "voice": { - "type": "string" - } - }, - "required": [ - "voice" - ] - } - } - }, - "x-schemas": { - "Accessibility": { - "uri": "https://meta.comcast.com/firebolt/accessibility", - "ClosedCaptionsSettings": { - "title": "ClosedCaptionsSettings", - "type": "object", - "required": [ - "enabled" - ], - "properties": { - "enabled": { - "type": "boolean", - "description": "Whether or not closed-captions should be enabled by default" - }, - "preferredLanguages": { - "type": "array", - "items": { - "$ref": "#/x-schemas/Localization/ISO639_2Language" - } - } - }, - "examples": [ - { - "enabled": true, - "styles": { - "fontFamily": "monospaced_serif", - "fontSize": 1, - "fontColor": "#ffffff", - "fontEdge": "none", - "fontEdgeColor": "#7F7F7F", - "fontOpacity": 100, - "backgroundColor": "#000000", - "backgroundOpacity": 100, - "textAlign": "center", - "textAlignVertical": "middle", - "windowColor": "white", - "windowOpacity": 50 - }, - "preferredLanguages": [ - "eng", - "spa" - ] - } - ] - }, - "VoiceGuidanceSettings": { - "title": "VoiceGuidanceSettings", - "type": "object", - "required": [ - "enabled", - "navigationHints", - "rate" - ], - "properties": { - "enabled": { - "type": "boolean", - "description": "Whether or not voice guidance should be enabled by default" - }, - "rate": { - "$ref": "#/x-schemas/Accessibility/SpeechRate", - "description": "The rate at which voice guidance speech will be read back to the user" - }, - "navigationHints": { - "type": "boolean", - "description": "Whether or not voice guidance should include additional navigation hints" - } - }, - "examples": [ - { - "enabled": true, - "navigationHints": true, - "rate": 0.8 - } - ] - }, - "SpeechRate": { - "title": "SpeechRate", - "type": "number", - "minimum": 0.1, - "maximum": 10 - } - }, - "Localization": { - "uri": "https://meta.comcast.com/firebolt/localization", - "ISO639_2Language": { - "type": "string", - "pattern": "^[a-z]{3}$" - }, - "CountryCode": { - "type": "string", - "pattern": "^[A-Z]{2}$" - }, - "Locale": { - "type": "string", - "pattern": "^[a-zA-Z]+([a-zA-Z0-9\\-]*)$" - } - }, - "Policies": { - "uri": "https://meta.comcast.com/firebolt/policies", - "AgePolicy": { - "title": "AgePolicy", - "description": "The policy that describes various age groups to which content is directed. See distributor documentation for further details.", - "anyOf": [ - { - "type": "string" - }, - { - "type": "string", - "enum": [ - "app:adult", - "app:child", - "app:teen" - ] - } - ] - } - }, - "Types": { - "uri": "https://meta.comcast.com/firebolt/types", - "FlatMap": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - } - ] - } - } - } - } -} \ No newline at end of file + "openrpc": "1.2.4", + "info": { + "title": "Firebolt JSON-RPC API", + "version": "", + "x-module-descriptions": { + "Accessibility": "The `Accessibility` module provides access to the user/device settings for closed captioning and voice guidance.\n\nApps **SHOULD** attempt o respect these settings, rather than manage and persist seprate settings, which would be different per-app.", + "Advertising": "A module for platform provided advertising settings and functionality.", + "Device": "A module for querying about the device and it's capabilities.", + "Discovery": "Your App likely wants to integrate with the Platform's discovery capabilities. For example to add a \"Watch Next\" tile that links to your app from the platform's home screen.\n\nGetting access to this information requires to connect to lower level APIs made available by the platform. Since implementations differ between operators and platforms, the Firebolt SDK offers a Discovery module, that exposes a generic, agnostic interface to the developer.\n\nUnder the hood, an underlaying transport layer will then take care of calling the right APIs for the actual platform implementation that your App is running on.\n\nThe Discovery plugin is used to _send_ information to the Platform.\n\n### Localization\nApps should provide all user-facing strings in the device's language, as specified by the Firebolt `Localization.language` property.\n\nApps should provide prices in the same currency presented in the app. If multiple currencies are supported in the app, the app should provide prices in the user's current default currency.", + "Display": "A module for querying about the display", + "Lifecycle2": "Methods and events for responding to Lifecycle changes in your app.", + "Localization": "Methods for accessing location and language preferences.", + "Metrics": "Methods for sending metrics", + "Network": "Methods for accessing network information.", + "Presentation": "Methods for accessing Presentation preferences.", + "Stats": "Provides methods to retrieve application-level system information.", + "TextToSpeech": "A module for controlling and accessing Text To Speech over Firebolt." + } + }, + "methods": [ + { + "name": "rpc.discover", + "summary": "The OpenRPC schema for this JSON-RPC API", + "params": [], + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:rpc:discover" + ] + } + ], + "result": { + "name": "OpenRPC Schema", + "schema": { + "type": "object" + } + }, + "examples": [ + { + "name": "Default", + "params": [], + "result": { + "name": "schema", + "value": {} + } + } + ] + }, + { + "name": "Accessibility.audioDescription", + "summary": "Returns the audio description setting of the device", + "params": [], + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:audio-descriptions" + ] + } + ], + "result": { + "name": "setting", + "summary": "the audio description setting", + "schema": { + "type": "boolean" + } + }, + "examples": [ + { + "name": "Getting the audio description setting", + "params": [], + "result": { + "name": "Default Result", + "value": true + } + } + ] + }, + { + "name": "Accessibility.closedCaptionsSettings", + "summary": "Returns captions settings: enabled, and a list of zero or more languages in order of decreasing preference", + "params": [], + "tags": [ + { + "name": "property:readonly", + "x-notifier-params-flattening": "true" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:closed-captions" + ] + } + ], + "result": { + "name": "closedCaptionsSettings", + "summary": "the closed captions settings", + "schema": { + "$ref": "#/x-schemas/Accessibility/ClosedCaptionsSettings" + } + }, + "examples": [ + { + "name": "Getting the closed captions settings", + "params": [], + "result": { + "name": "settings", + "value": { + "enabled": true, + "preferredLanguages": [ + "eng", + "spa" + ] + } + } + } + ] + }, + { + "name": "Accessibility.highContrastUI", + "summary": "Returns the high contrast UI device setting", + "params": [], + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:high-contrast-ui" + ] + } + ], + "result": { + "name": "highContrastUI", + "summary": "Whether high-contrast UI mode is enabled", + "schema": { + "type": "boolean" + } + }, + "examples": [ + { + "name": "High-contrast UI mode is enabled", + "params": [], + "result": { + "name": "Default Result", + "value": true + } + } + ] + }, + { + "name": "Accessibility.voiceGuidanceSettings", + "summary": "Returns voice guidance settings: enabled, rate, and verbosity", + "params": [], + "tags": [ + { + "name": "property:readonly", + "x-notifier-params-flattening": "true" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:voice-guidance" + ] + } + ], + "result": { + "name": "settings", + "summary": "the voice guidance settings", + "schema": { + "$ref": "#/x-schemas/Accessibility/VoiceGuidanceSettings" + } + }, + "examples": [ + { + "name": "Getting the voice guidance settings", + "params": [], + "result": { + "name": "Default Result", + "value": { + "enabled": true, + "rate": 0.8, + "navigationHints": true + } + } + } + ] + }, + { + "name": "Advertising.advertisingId", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:advertising:identifier" + ] + } + ], + "summary": "Returns the IFA.", + "params": [], + "result": { + "name": "advertisingId", + "summary": "The advertising ID", + "schema": { + "$ref": "#/components/schemas/AdvertisingIdResult" + } + }, + "examples": [ + { + "name": "Getting the advertising ID", + "params": [], + "result": { + "name": "Default Result", + "value": { + "ifa": "bd87dd10-8d1d-4b93-b1a6-a8e5d410e400", + "ifa_type": "sspid", + "lmt": "0" + } + } + }, + { + "name": "Getting the advertising ID with scope browse", + "params": [], + "result": { + "name": "Default Result", + "value": { + "ifa": "bd87dd10-8d1d-4b93-b1a6-a8e5d410e400", + "ifa_type": "sspid", + "lmt": "1" + } + } + }, + { + "name": "Getting the advertising ID with scope content", + "params": [], + "result": { + "name": "Default Result", + "value": { + "ifa": "bd87dd10-8d1d-4b93-b1a6-a8e5d410e400", + "ifa_type": "idfa", + "lmt": "0" + } + } + } + ] + }, + { + "name": "Device.uid", + "summary": "Returns a persistent unique UUID for the current app and device. The UUID is reset when the app or device is reset", + "params": [], + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:uid" + ] + } + ], + "result": { + "name": "uniqueId", + "summary": "A unique UUID for this app-device pair.", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Getting the unique UUID", + "params": [], + "result": { + "name": "Default Result", + "value": "ee6723b8-7ab3-462c-8d93-dbf61227998e" + } + } + ] + }, + { + "name": "Device.deviceClass", + "summary": "Returns the class of the device", + "params": [], + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:device-class" + ] + } + ], + "result": { + "name": "deviceClass", + "summary": "The device class", + "schema": { + "$ref": "#/components/schemas/DeviceClass" + } + }, + "examples": [ + { + "name": "Getting the device class", + "params": [], + "result": { + "name": "Default Result", + "value": "ott" + } + } + ] + }, + { + "name": "Device.uptime", + "summary": "Returns the number of seconds since most recent device boot, including any time spent during deep sleep", + "params": [], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "result": { + "name": "uptime", + "summary": "The device uptime", + "schema": { + "type": "number" + } + }, + "examples": [ + { + "name": "Getting the device uptime", + "params": [], + "result": { + "name": "Default Result", + "value": 123456 + } + } + ] + }, + { + "name": "Device.timeInActiveState", + "summary": "Returns the number of seconds since the device transitioned to the ON power state", + "params": [], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "result": { + "name": "timeInActiveState", + "summary": "The device time in active state", + "schema": { + "type": "number" + } + }, + "examples": [ + { + "name": "Getting the number of seconds since the device transitioned to the ON power state", + "params": [], + "result": { + "name": "Default Result", + "value": 654321 + } + } + ] + }, + { + "name": "Device.chipsetId", + "summary": "Returns chipset ID as a printable string, e.g. BCM72180", + "params": [], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "result": { + "name": "chipsetId", + "summary": "The device chipset ID", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Getting the device chipset ID", + "params": [], + "result": { + "name": "Default Result", + "value": "BCM72180" + } + } + ] + }, + { + "name": "Device.hdr", + "summary": "Returns the HDR standards that are supported by the attached TV or the integral display", + "params": [], + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "result": { + "name": "negotiatedHdrFormats", + "summary": "the negotiated HDR formats", + "schema": { + "$ref": "#/components/schemas/HDRFormatMap" + } + }, + "examples": [ + { + "name": "Getting the negotiated HDR formats", + "params": [], + "result": { + "name": "Default Result", + "value": { + "hdr10": true, + "hdr10Plus": true, + "dolbyVision": true, + "hlg": true + } + } + } + ] + }, + { + "name": "Discovery.watched", + "summary": "Notify the platform that content was partially or completely watched", + "tags": [ + { + "name": "polymorphic-reducer" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:discovery:watched" + ] + } + ], + "params": [ + { + "name": "entityId", + "required": true, + "schema": { + "type": "string" + }, + "summary": "The entity Id of the watched content." + }, + { + "name": "progress", + "summary": "How much of the content has been watched (percentage as (0-0.999) for VOD, number of seconds for live)", + "schema": { + "type": "number", + "minimum": 0 + } + }, + { + "name": "completed", + "summary": "Whether or not this viewing is considered \"complete,\" per the app's definition thereof", + "schema": { + "type": "boolean" + } + }, + { + "name": "watchedOn", + "summary": "Date/Time the content was watched, ISO 8601 Date/Time", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "agePolicy", + "description": "The age policy associated with the watch event. The age policy describes the age groups to which content may be directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Notify the platform of watched content", + "params": [ + { + "name": "entityId", + "value": "partner.com/entity/123" + }, + { + "name": "progress", + "value": 0.95 + }, + { + "name": "completed", + "value": true + }, + { + "name": "watchedOn", + "value": "2021-04-23T18:25:43.511Z" + } + ], + "result": { + "name": "success", + "value": true + } + }, + { + "name": "Notify the platform that child-directed content was watched", + "params": [ + { + "name": "entityId", + "value": "partner.com/entity/123" + }, + { + "name": "progress", + "value": 0.95 + }, + { + "name": "completed", + "value": true + }, + { + "name": "watchedOn", + "value": "2021-04-23T18:25:43.511Z" + }, + { + "name": "agePolicy", + "value": "app:child" + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Display.edid", + "summary": "Returns the EDID (and extensions) of the connected or integral display, as a Base64 encoded string", + "params": [], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:display:info" + ] + } + ], + "result": { + "name": "Base64 EDID", + "summary": "The EDID (and extensions) of the connected or integral display, as a Base64 encoded string", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Getting the display EDID", + "params": [], + "result": { + "name": "Default Result", + "value": "ZWU2NzIzYjgtN2FiMy00NjJjLThkOTMtZGJmNjEyMjc5OThl" + } + } + ] + }, + { + "name": "Display.size", + "summary": "Returns the physical dimensions of the connected or integral display, in centimeters. Returns 0, 0 on a OTT/STB device when a display is not connected over HDMI", + "params": [], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:display:info" + ] + } + ], + "result": { + "name": "size", + "summary": "The display size in centimeters", + "schema": { + "type": "object", + "properties": { + "width": { + "type": "integer", + "description": "The width of the display in centimeters" + }, + "height": { + "type": "integer", + "description": "The height of the display in centimeters" + } + } + } + }, + "examples": [ + { + "name": "Getting the display size", + "params": [], + "result": { + "name": "Default Result", + "value": { + "width": 48, + "height": 27 + } + } + } + ] + }, + { + "name": "Display.maxResolution", + "summary": "Returns the physical/native resolution of the connected or integral display, in pixels. Returns 0, 0 on a OTT/STB device when a display is not connected over HDMI", + "params": [], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:display:info" + ] + } + ], + "result": { + "name": "maxResolution", + "summary": "The display resolution", + "schema": { + "type": "object", + "properties": { + "width": { + "type": "integer", + "description": "The width of the display in pixels" + }, + "height": { + "type": "integer", + "description": "The height of the display in pixels" + } + } + } + }, + "examples": [ + { + "name": "Getting the display size", + "params": [], + "result": { + "name": "Default Result", + "value": { + "width": 1920, + "height": 1080 + } + } + } + ] + }, + { + "name": "Lifecycle2.close", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:cpp-client-only" + ] + } + ], + "summary": "Request the platform to deactivate the app, and possibly take further action.", + "params": [ + { + "name": "type", + "summary": "The type of the close app is requesting", + "required": true, + "schema": { + "$ref": "#/components/schemas/CloseType" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Close the app when the user presses back on the app home screen", + "params": [ + { + "name": "type", + "value": "unload" + } + ], + "result": { + "name": "Default Result", + "value": null + } + }, + { + "name": "Close the app when the user selects an exit menu item", + "params": [ + { + "name": "type", + "value": "deactivate" + } + ], + "result": { + "name": "Default Result", + "value": null + } + } + ] + }, + { + "name": "Lifecycle2.state", + "summary": "Get the current lifecycle state of the app.", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:cpp-client-only" + ] + } + ], + "params": [], + "result": { + "name": "state", + "summary": "The current lifecycle state of the app.", + "schema": { + "$ref": "#/components/schemas/LifecycleState" + } + }, + "examples": [ + { + "name": "Default Example", + "params": [], + "result": { + "name": "Default Result", + "value": "active" + } + } + ] + }, + { + "name": "Localization.country", + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:country-code" + ] + } + ], + "summary": "Returns the ISO 3166-1 alpha-2 code for the country device is located in.", + "params": [], + "result": { + "name": "code", + "summary": "The device country code.", + "schema": { + "$ref": "#/x-schemas/Localization/CountryCode" + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "Default Result", + "value": "US" + } + }, + { + "name": "Another example", + "params": [], + "result": { + "name": "Default Result", + "value": "GB" + } + } + ] + }, + { + "name": "Localization.preferredAudioLanguages", + "summary": "Returns a list of ISO 639-2/B codes for the preferred audio languages on this device.", + "params": [], + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:preferred-audio-languages" + ] + } + ], + "result": { + "name": "languages", + "summary": "The preferred audio languages.", + "schema": { + "type": "array", + "items": { + "$ref": "#/x-schemas/Localization/ISO639_2Language" + } + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "Default Result", + "value": [ + "spa", + "eng" + ] + } + } + ] + }, + { + "name": "Localization.presentationLanguage", + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:locale" + ] + } + ], + "summary": "Get the *full* BCP 47 code, including script, region, variant, etc., for the preferred locale", + "params": [], + "result": { + "name": "locale", + "summary": "The device locale.", + "schema": { + "$ref": "#/x-schemas/Localization/Locale" + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "Default Result", + "value": "en-US" + } + } + ] + }, + { + "name": "Metrics.ready", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Inform the platform that your app is minimally usable. This method is called automatically by `Lifecycle.ready()`", + "params": [], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send ready metric", + "params": [], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.signIn", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Log a sign in event, called by Discovery.signIn().", + "params": [], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send signIn metric", + "params": [], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.signOut", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Log a sign out event, called by Discovery.signOut().", + "params": [], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send signOut metric", + "params": [], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.startContent", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Inform the platform that your user has started content.", + "params": [ + { + "name": "entityId", + "summary": "Optional entity ID of the content.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send startContent metric", + "params": [], + "result": { + "name": "success", + "value": true + } + }, + { + "name": "Send startContent metric w/ entity", + "params": [ + { + "name": "entityId", + "value": "abc" + } + ], + "result": { + "name": "success", + "value": true + } + }, + { + "name": "Send startContent metric and notify the platform that the content is child-directed", + "params": [ + { + "name": "entityId", + "value": "abc" + }, + { + "name": "agePolicy", + "value": "app:child" + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.stopContent", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Inform the platform that your user has stopped content.", + "params": [ + { + "name": "entityId", + "summary": "Optional entity ID of the content.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send stopContent metric", + "params": [], + "result": { + "name": "success", + "value": true + } + }, + { + "name": "Send stopContent metric w/ entity", + "params": [ + { + "name": "entityId", + "value": "abc" + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.page", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Inform the platform that your user has navigated to a page or view.", + "params": [ + { + "name": "pageId", + "summary": "Page ID of the content.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send page metric", + "params": [ + { + "name": "pageId", + "value": "xyz" + } + ], + "result": { + "name": "success", + "value": true + } + }, + { + "name": "Send page metric w/ pageId", + "params": [ + { + "name": "pageId", + "value": "home" + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.error", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Inform the platform of an error that has occurred in your app.", + "params": [ + { + "name": "type", + "summary": "The type of error", + "schema": { + "$ref": "#/components/schemas/ErrorType" + }, + "required": true + }, + { + "name": "code", + "summary": "an app-specific error code", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "description", + "summary": "A short description of the error", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "visible", + "summary": "Whether or not this error was visible to the user.", + "schema": { + "type": "boolean" + }, + "required": true + }, + { + "name": "parameters", + "summary": "Optional additional parameters to be logged with the error", + "schema": { + "$ref": "#/x-schemas/Types/FlatMap" + }, + "required": false + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send error metric", + "params": [ + { + "name": "type", + "value": "media" + }, + { + "name": "code", + "value": "MEDIA-STALLED" + }, + { + "name": "description", + "value": "playback stalled" + }, + { + "name": "visible", + "value": true + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.mediaLoadStart", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when setting the URL of a media asset to play, in order to infer load time.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send loadstart metric.", + "params": [ + { + "name": "entityId", + "value": "345" + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.mediaPlay", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when media playback should start due to autoplay, user-initiated play, or unpausing.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send play metric.", + "params": [ + { + "name": "entityId", + "value": "345" + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.mediaPlaying", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when media playback actually starts due to autoplay, user-initiated play, unpausing, or recovering from a buffering interruption.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send playing metric.", + "params": [ + { + "name": "entityId", + "value": "345" + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.mediaPause", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when media playback will pause due to an intentional pause operation.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send pause metric.", + "params": [ + { + "name": "entityId", + "value": "345" + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.mediaWaiting", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when media playback will halt due to a network, buffer, or other unintentional constraint.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send waiting metric.", + "params": [ + { + "name": "entityId", + "value": "345" + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.mediaSeeking", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when a seek is initiated during media playback.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "target", + "summary": "Target destination of the seek, as a decimal percentage (0-0.999) for content with a known duration, or an integer number of seconds (0-86400) for content with an unknown duration.", + "schema": { + "$ref": "#/components/schemas/MediaPosition" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send seeking metric.", + "params": [ + { + "name": "entityId", + "value": "345" + }, + { + "name": "target", + "value": 0.5 + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.mediaSeeked", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when a seek is completed during media playback.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "position", + "summary": "Resulting position of the seek operation, as a decimal percentage (0-0.999) for content with a known duration, or an integer number of seconds (0-86400) for content with an unknown duration.", + "schema": { + "$ref": "#/components/schemas/MediaPosition" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send seeked metric.", + "params": [ + { + "name": "entityId", + "value": "345" + }, + { + "name": "position", + "value": 0.51 + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.mediaRateChanged", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when the playback rate of media is changed.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "rate", + "summary": "The new playback rate.", + "schema": { + "type": "number" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send ratechange metric.", + "params": [ + { + "name": "entityId", + "value": "345" + }, + { + "name": "rate", + "value": 2 + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.mediaRenditionChanged", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when the playback rendition (e.g. bitrate, dimensions, profile, etc) is changed.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "bitrate", + "summary": "The new bitrate in kbps.", + "schema": { + "type": "number" + }, + "required": true + }, + { + "name": "width", + "summary": "The new resolution width.", + "schema": { + "type": "number" + }, + "required": true + }, + { + "name": "height", + "summary": "The new resolution height.", + "schema": { + "type": "number" + }, + "required": true + }, + { + "name": "profile", + "summary": "A description of the new profile, e.g. 'HDR' etc.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send renditionchange metric.", + "params": [ + { + "name": "entityId", + "value": "345" + }, + { + "name": "bitrate", + "value": 5000 + }, + { + "name": "width", + "value": 1920 + }, + { + "name": "height", + "value": 1080 + }, + { + "name": "profile", + "value": "HDR+" + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.mediaEnded", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when playback has stopped because the end of the media was reached.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send ended metric.", + "params": [ + { + "name": "entityId", + "value": "345" + } + ], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Metrics.event", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:distributor" + ] + } + ], + "summary": "Inform the platform of 1st party distributor metrics. 'data' parameter is a JSON document", + "params": [ + { + "name": "schema", + "summary": "The schema URI of the metric type", + "schema": { + "type": "string", + "format": "uri" + }, + "required": true + }, + { + "name": "data", + "summary": "A JSON payload", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send foo event", + "params": [ + { + "name": "schema", + "value": "http://meta.rdkcentral.com/some/schema" + }, + { + "name": "data", + "value": "foo" + } + ], + "result": { + "name": "result", + "value": true + } + } + ] + }, + { + "name": "Metrics.appInfo", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Inform the platform about an app's build info.", + "params": [ + { + "name": "build", + "summary": "The build / version of this app.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send appInfo metric", + "params": [ + { + "name": "build", + "value": "1.2.2" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Network.connected", + "summary": "Returns whether the device currently has a usable network connection.", + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:network:connected" + ] + } + ], + "params": [], + "result": { + "name": "success", + "summary": "Whether the device currently has a usable network connection.", + "schema": { + "$ref": "#/components/schemas/Connected" + } + }, + "examples": [ + { + "name": "Connected example", + "params": [], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Presentation.focused", + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:cpp-client-only" + ] + } + ], + "summary": "Whether the app is in focus, i.e. receiving key presses. Provided for those apps/runtimes that cannot use Wayland", + "params": [], + "result": { + "name": "focused", + "summary": "Whether the app is in focus.", + "schema": { + "type": "boolean" + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "Default Result", + "value": true + } + } + ] + }, + { + "name": "Stats.memoryUsage", + "summary": "Returns information about container memory usage, in units of 1024 bytes.", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:cpp-client-only" + ] + } + ], + "params": [], + "result": { + "name": "result", + "schema": { + "$ref": "#/components/schemas/MemoryUsage" + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "value", + "description": "The memory usage information", + "value": { + "userMemoryUsedKiB": 123456, + "userMemoryLimitKiB": 789012, + "gpuMemoryUsedKiB": 345678, + "gpuMemoryLimitKiB": 901234 + } + } + } + ] + }, + { + "name": "TextToSpeech.speak", + "summary": "Speak the utterance immediately. Any ongoing speech is interrupted.", + "description": "Text argument is either plain text or a well-formed SSML document TTS_status, not success attribute, to be used by caller to indicate success of call 0 OK, 1 Fail, 2 not enabled, 3 invalid configuration Raises onSpeechinterrupted if speaking is interrupted", + "params": [ + { + "name": "text", + "summary": "String to be converted to Audio for speech", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "result": { + "name": "speakResult", + "summary": "Result for Speak", + "schema": { + "$ref": "#/components/schemas/SpeechResponse" + } + }, + "examples": [ + { + "name": "Getting the result of speak", + "params": [ + { + "name": "text", + "value": "I am a text waiting for speech." + } + ], + "result": { + "name": "result", + "value": { + "speechid": 1, + "TTS_Status": 0, + "success": true + } + } + } + ] + }, + { + "name": "TextToSpeech.pause", + "summary": "Pauses the speech for given speech id", + "description": "Pauses the utterance. Raises onSpeechpause if ongoing speech is paused. Does nothing if utterance is already paused", + "params": [ + { + "name": "speechid", + "summary": "Identifier for the speech call", + "schema": { + "$ref": "#/components/schemas/SpeechId" + }, + "required": true + } + ], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "result": { + "name": "pauseResult", + "summary": "Result for Pause", + "schema": { + "$ref": "#/components/schemas/TTSStatusResponse" + } + }, + "examples": [ + { + "name": "Pause a given speech id", + "params": [ + { + "name": "speechid", + "value": 1 + } + ], + "result": { + "name": "TTS_Status", + "value": { + "TTS_Status": 0, + "success": true + } + } + } + ] + }, + { + "name": "TextToSpeech.resume", + "summary": "Resumes the speech for given speech id", + "description": "Continue the paused utterance. Raises onSpeechresume if paused speech is resumed. Does nothing if the utterance is not paused", + "params": [ + { + "name": "speechid", + "summary": "Identifier for the speech call", + "schema": { + "$ref": "#/components/schemas/SpeechId" + }, + "required": true + } + ], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "result": { + "name": "resumeResult", + "summary": "Result for Resume", + "schema": { + "$ref": "#/components/schemas/TTSStatusResponse" + } + }, + "examples": [ + { + "name": "Resume a given speech id.", + "params": [ + { + "name": "speechid", + "value": 1 + } + ], + "result": { + "name": "TTS_Status", + "value": { + "TTS_Status": 0, + "success": true + } + } + } + ] + }, + { + "name": "TextToSpeech.cancel", + "summary": "Cancels the speech for given speech id", + "description": "Stop speaking if utterance is currently being spoken. Raises onSpeechinterrupted if speaking was interrupted.", + "params": [ + { + "name": "speechid", + "summary": "Identifier for the speech call", + "schema": { + "$ref": "#/components/schemas/SpeechId" + }, + "required": true + } + ], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "result": { + "name": "cancelResult", + "summary": "Result for cancel", + "schema": { + "$ref": "#/components/schemas/TTSStatusResponse" + } + }, + "examples": [ + { + "name": "Cancel a given speech id.", + "params": [ + { + "name": "speechid", + "value": 1 + } + ], + "result": { + "name": "TTS_Status", + "value": { + "TTS_Status": 0, + "success": true + } + } + } + ] + }, + { + "name": "TextToSpeech.getspeechstate", + "summary": "Returns the state of the utterance.", + "params": [ + { + "name": "speechid", + "summary": "Identifier for the speech call", + "schema": { + "$ref": "#/components/schemas/SpeechId" + }, + "required": true + } + ], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "result": { + "name": "speechStateResult", + "summary": "Result for speech state", + "schema": { + "$ref": "#/components/schemas/SpeechStateResponse" + } + }, + "examples": [ + { + "name": "State for a given speech id.", + "params": [ + { + "name": "speechid", + "value": 1 + } + ], + "result": { + "name": "speechstate", + "value": { + "speechstate": 1, + "TTS_Status": 0, + "success": true + } + } + } + ] + }, + { + "name": "TextToSpeech.listvoices", + "summary": "Returns the list of available voices as human-readable strings, e.g. 'ava', 'amelie', 'angelica'", + "params": [ + { + "name": "language", + "summary": "Language - string - BCP 47", + "schema": { + "$ref": "#/x-schemas/Localization/Locale" + }, + "required": true + } + ], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "result": { + "name": "listvoices", + "summary": "The list of voices supported for the language", + "schema": { + "$ref": "#/components/schemas/ListVoicesResponse" + } + }, + "examples": [ + { + "name": "Getting the list of voices", + "params": [ + { + "name": "language", + "value": "en-US" + } + ], + "result": { + "name": "voiceList", + "value": { + "TTS_Status": 0, + "voices": [ + "carol", + "tom" + ] + } + } + } + ] + }, + { + "name": "Lifecycle2.onStateChanged", + "tags": [ + { + "name": "event", + "x-contextual-parameters": 0, + "x-notifier": "Lifecycle2.onStateChanged" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:cpp-client-only" + ] + } + ], + "summary": "Notification of lifecycle state change, raised after the platform has transitioned the app/runtime to the new lifecycle state", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "App is active after being initialized", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + }, + { + "name": "Single transition to paused state", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onWillspeak", + "summary": "Text to speech conversion is about to start.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onWillspeak" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onSpeechstart", + "summary": "Utterance is about to be spoken.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onSpeechstart" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onSpeechpause", + "summary": "Ongoing speech was paused.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onSpeechpause" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onSpeechresume", + "summary": "Paused speech was resumed.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onSpeechresume" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onSpeechcomplete", + "summary": "Speech completed successfully.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onSpeechcomplete" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onSpeechinterrupted", + "summary": "Speech was stopped, due to another call to speak or cancel.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onSpeechinterrupted" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onNetworkerror", + "summary": "Utterance failed due to network error.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onNetworkerror" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onPlaybackerror", + "summary": "Utterance failed during playback.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onPlaybackerror" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Accessibility.onAudioDescriptionChanged", + "summary": "Returns the audio description setting of the device", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier": "Accessibility.onAudioDescriptionChanged", + "x-subscriber-for": "Accessibility.audioDescription" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:audio-descriptions" + ] + } + ], + "examples": [ + { + "name": "Getting the audio description setting", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Accessibility.onClosedCaptionsSettingsChanged", + "summary": "Returns captions settings: enabled, and a list of zero or more languages in order of decreasing preference", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier-params-flattening": "true", + "x-notifier": "Accessibility.onClosedCaptionsSettingsChanged", + "x-subscriber-for": "Accessibility.closedCaptionsSettings" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:closed-captions" + ] + } + ], + "examples": [ + { + "name": "Getting the closed captions settings", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Accessibility.onHighContrastUIChanged", + "summary": "Returns the high contrast UI device setting", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier": "Accessibility.onHighContrastUIChanged", + "x-subscriber-for": "Accessibility.highContrastUI" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:high-contrast-ui" + ] + } + ], + "examples": [ + { + "name": "High-contrast UI mode is enabled", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Accessibility.onVoiceGuidanceSettingsChanged", + "summary": "Returns voice guidance settings: enabled, rate, and verbosity", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier-params-flattening": "true", + "x-notifier": "Accessibility.onVoiceGuidanceSettingsChanged", + "x-subscriber-for": "Accessibility.voiceGuidanceSettings" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:voice-guidance" + ] + } + ], + "examples": [ + { + "name": "Getting the voice guidance settings", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Device.onHdrChanged", + "summary": "Returns the HDR standards that are supported by the attached TV or the integral display", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier": "Device.onHdrChanged", + "x-subscriber-for": "Device.hdr" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "examples": [ + { + "name": "Getting the negotiated HDR formats", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Localization.onCountryChanged", + "tags": [ + { + "name": "event", + "x-notifier": "Localization.onCountryChanged", + "x-subscriber-for": "Localization.country" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:country-code" + ] + } + ], + "summary": "Returns the ISO 3166-1 alpha-2 code for the country device is located in.", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + }, + { + "name": "Another example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Localization.onPreferredAudioLanguagesChanged", + "summary": "Returns a list of ISO 639-2/B codes for the preferred audio languages on this device.", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier": "Localization.onPreferredAudioLanguagesChanged", + "x-subscriber-for": "Localization.preferredAudioLanguages" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:preferred-audio-languages" + ] + } + ], + "examples": [ + { + "name": "Default example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Localization.onPresentationLanguageChanged", + "tags": [ + { + "name": "event", + "x-notifier": "Localization.onPresentationLanguageChanged", + "x-subscriber-for": "Localization.presentationLanguage" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:locale" + ] + } + ], + "summary": "Get the *full* BCP 47 code, including script, region, variant, etc., for the preferred locale", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Network.onConnectedChanged", + "summary": "Returns whether the device currently has a usable network connection.", + "tags": [ + { + "name": "event", + "x-notifier": "Network.onConnectedChanged", + "x-subscriber-for": "Network.connected" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:network:connected" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Connected example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Presentation.onFocusedChanged", + "tags": [ + { + "name": "event", + "x-notifier": "Presentation.onFocusedChanged", + "x-subscriber-for": "Presentation.focused" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:cpp-client-only" + ] + } + ], + "summary": "Whether the app is in focus, i.e. receiving key presses. Provided for those apps/runtimes that cannot use Wayland", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + } + ], + "components": { + "schemas": { + "AdvertisingIdResult": { + "title": "AdvertisingIdResult", + "type": "object", + "properties": { + "ifa": { + "type": "string", + "description": "UUID conforming to IAB standard" + }, + "ifa_type": { + "type": "string", + "description": "Source of the IFA as defined by IAB" + }, + "lmt": { + "type": "string", + "enum": [ + "0", + "1" + ], + "description": "Boolean that if set to 1, user has requested ad tracking and measurement is disabled" + } + }, + "required": [ + "ifa", + "ifa_type", + "lmt" + ] + }, + "HDRFormatMap": { + "title": "HDRFormatMap", + "type": "object", + "properties": { + "hdr10": { + "type": "boolean" + }, + "hdr10Plus": { + "type": "boolean" + }, + "dolbyVision": { + "type": "boolean" + }, + "hlg": { + "type": "boolean" + } + }, + "required": [ + "hdr10", + "hdr10Plus", + "dolbyVision", + "hlg" + ], + "description": "The type of HDR format" + }, + "DeviceClass": { + "title": "DeviceClass", + "type": "string", + "enum": [ + "ott", + "stb", + "tv" + ], + "description": "The type of device" + }, + "CloseType": { + "title": "CloseType", + "description": "The application close type", + "type": "string", + "enum": [ + "deactivate", + "unload", + "killReload", + "killReactivate" + ] + }, + "LifecycleState": { + "title": "LifecycleState", + "description": "The application Lifecycle state", + "type": "string", + "enum": [ + "initializing", + "active", + "paused", + "suspended", + "hibernated", + "terminating" + ] + }, + "StateChange": { + "title": "StateChange", + "type": "object", + "properties": { + "newState": { + "$ref": "#/components/schemas/LifecycleState" + }, + "oldState": { + "$ref": "#/components/schemas/LifecycleState" + } + } + }, + "MediaPosition": { + "title": "MediaPosition", + "description": "Represents a position inside playback content, as a decimal percentage (0-0.999) for content with a known duration, or an integer number of seconds (0-86400) for content with an unknown duration.", + "oneOf": [ + { + "const": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + { + "type": "integer", + "minimum": 1, + "maximum": 86400 + } + ] + }, + "ErrorType": { + "title": "ErrorType", + "type": "string", + "enum": [ + "network", + "media", + "restriction", + "entitlement", + "other" + ] + }, + "EventObjectPrimitives": { + "title": "EventObjectPrimitives", + "anyOf": [ + { + "type": "string", + "maxLength": 256 + }, + { + "type": "number" + }, + { + "type": "integer" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "Connected": { + "type": "boolean", + "description": "Indicates whether the device currently has a usable network connection." + }, + "MemoryUsage": { + "title": "MemoryUsage", + "type": "object", + "description": "Describes current and maximum memory usage of the container.", + "properties": { + "userMemoryUsedKiB": { + "type": "integer", + "description": "User memory currently used in 1024 bytes." + }, + "userMemoryLimitKiB": { + "type": "integer", + "description": "Maximum user memory available in 1024 bytes." + }, + "gpuMemoryUsedKiB": { + "type": "integer", + "description": "GPU memory currently used in 1024 bytes." + }, + "gpuMemoryLimitKiB": { + "type": "integer", + "description": "Maximum GPU memory available in 1024 bytes." + } + }, + "required": [ + "userMemoryUsedKiB", + "userMemoryLimitKiB", + "gpuMemoryUsedKiB", + "gpuMemoryLimitKiB" + ] + }, + "TTSEnabled": { + "title": "TTSEnabled", + "type": "object", + "required": [ + "TTS_Status", + "isenabled" + ], + "properties": { + "TTS_Status": { + "$ref": "#/components/schemas/TTSStatus" + }, + "isenabled": { + "type": "boolean" + } + } + }, + "ListVoicesResponse": { + "title": "ListVoicesResponse", + "type": "object", + "required": [ + "TTS_Status", + "voices" + ], + "properties": { + "TTS_Status": { + "$ref": "#/components/schemas/TTSStatus" + }, + "voices": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "TTSConfiguration": { + "title": "TTSConfiguration", + "type": "object", + "required": [ + "success" + ], + "properties": { + "success": { + "type": "boolean" + }, + "ttsendpoint": { + "type": "string", + "description": "URL for Text to Speech API" + }, + "ttsendpointsecured": { + "type": "string", + "description": "Secure URL for Text to Speech API" + }, + "language": { + "type": "string", + "description": "Language used by Text to speech" + }, + "voice": { + "type": "string", + "description": "Voice used by Text to speech" + }, + "volume": { + "type": "integer", + "description": "Volume for Text to speech", + "minimum": 0, + "maximum": 100 + }, + "primvolduckpercent": { + "type": "integer", + "description": "Prime Volume duck percent for Text to speech", + "minimum": 0, + "maximum": 100 + }, + "rate": { + "type": "integer", + "description": "Speech rate for Text to speech", + "minimum": 0, + "maximum": 100 + }, + "speechrate": { + "description": "Rate for speech", + "$ref": "#/components/schemas/SpeechRate" + }, + "fallbacktext": { + "description": "Fallback text for TTS", + "$ref": "#/components/schemas/FallbackText" + } + }, + "examples": [ + {} + ] + }, + "SpeechRate": { + "title": "SpeechRate", + "type": "string", + "enum": [ + "slow", + "medium", + "fast", + "faster", + "fastest" + ] + }, + "FallbackText": { + "title": "FallbackText", + "type": "object", + "properties": { + "scenario": { + "type": "string", + "description": "Scenario for fallback Text" + }, + "value": { + "type": "string", + "description": "Value for fallback Text" + } + } + }, + "SpeechResponse": { + "title": "SpeechResponse", + "type": "object", + "properties": { + "speechid": { + "$ref": "#/components/schemas/SpeechId" + }, + "TTS_Status": { + "$ref": "#/components/schemas/TTSStatus" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "speechid", + "TTS_Status", + "success" + ] + }, + "SpeechId": { + "type": "integer" + }, + "SpeechIdEvent": { + "type": "object", + "properties": { + "speechid": { + "$ref": "#/components/schemas/SpeechId" + } + }, + "required": [ + "speechid" + ] + }, + "TTSStatus": { + "title": "TTSStatus", + "type": "integer", + "minimum": 0, + "maximum": 3 + }, + "SpeechState": { + "title": "SpeechState", + "type": "integer", + "enum": [ + 0, + 1, + 2, + 3 + ], + "description": "0 = SPEECH_PENDING, 1 = SPEECH_IN_PROGRESS, 2 = SPEECH_PAUSED, 3 = SPEECH_NOT_FOUND" + }, + "SpeechStateResponse": { + "title": "SpeechStateResponse", + "type": "object", + "properties": { + "speechstate": { + "$ref": "#/components/schemas/SpeechState" + }, + "TTS_Status": { + "$ref": "#/components/schemas/TTSStatus" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "speechstate", + "TTS_Status", + "success" + ] + }, + "TTSStatusResponse": { + "title": "TTSStatusResponse", + "type": "object", + "properties": { + "TTS_Status": { + "$ref": "#/components/schemas/TTSStatus" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "TTS_Status", + "success" + ] + }, + "TTSState": { + "title": "TTSState", + "type": "object", + "properties": { + "state": { + "type": "boolean" + } + }, + "required": [ + "state" + ] + }, + "TTSVoice": { + "title": "TTSVoice", + "type": "object", + "properties": { + "voice": { + "type": "string" + } + }, + "required": [ + "voice" + ] + } + } + }, + "x-schemas": { + "Accessibility": { + "uri": "https://meta.comcast.com/firebolt/accessibility", + "ClosedCaptionsSettings": { + "title": "ClosedCaptionsSettings", + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether or not closed-captions should be enabled by default" + }, + "preferredLanguages": { + "type": "array", + "items": { + "$ref": "#/x-schemas/Localization/ISO639_2Language" + } + } + }, + "examples": [ + { + "enabled": true, + "styles": { + "fontFamily": "monospaced_serif", + "fontSize": 1, + "fontColor": "#ffffff", + "fontEdge": "none", + "fontEdgeColor": "#7F7F7F", + "fontOpacity": 100, + "backgroundColor": "#000000", + "backgroundOpacity": 100, + "textAlign": "center", + "textAlignVertical": "middle", + "windowColor": "white", + "windowOpacity": 50 + }, + "preferredLanguages": [ + "eng", + "spa" + ] + } + ] + }, + "VoiceGuidanceSettings": { + "title": "VoiceGuidanceSettings", + "type": "object", + "required": [ + "enabled", + "navigationHints", + "rate" + ], + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether or not voice guidance should be enabled by default" + }, + "rate": { + "$ref": "#/x-schemas/Accessibility/SpeechRate", + "description": "The rate at which voice guidance speech will be read back to the user" + }, + "navigationHints": { + "type": "boolean", + "description": "Whether or not voice guidance should include additional navigation hints" + } + }, + "examples": [ + { + "enabled": true, + "navigationHints": true, + "rate": 0.8 + } + ] + }, + "SpeechRate": { + "title": "SpeechRate", + "type": "number", + "minimum": 0.1, + "maximum": 10 + } + }, + "Localization": { + "uri": "https://meta.comcast.com/firebolt/localization", + "ISO639_2Language": { + "type": "string", + "pattern": "^[a-z]{3}$" + }, + "CountryCode": { + "type": "string", + "pattern": "^[A-Z]{2}$" + }, + "Locale": { + "type": "string", + "pattern": "^[a-zA-Z]+([a-zA-Z0-9\\-]*)$" + } + }, + "Policies": { + "uri": "https://meta.comcast.com/firebolt/policies", + "AgePolicy": { + "title": "AgePolicy", + "description": "The policy that describes various age groups to which content is directed. See distributor documentation for further details.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "string", + "enum": [ + "app:adult", + "app:child", + "app:teen" + ] + } + ] + } + }, + "Types": { + "uri": "https://meta.comcast.com/firebolt/types", + "FlatMap": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + } + } + } +} diff --git a/include/firebolt/discovery.h b/include/firebolt/discovery.h index b73404c..885380e 100644 --- a/include/firebolt/discovery.h +++ b/include/firebolt/discovery.h @@ -39,7 +39,7 @@ class IDiscovery * @param[in] agePolicy : The age policy associated with the watch event. The age policy describes the age groups * to which content may be directed * - * @retval The status. + * @retval An ok Result on success, or an error; no value is returned */ virtual Result watched(const std::string& entityId, std::optional progress, std::optional completed, std::optional watchedOn, diff --git a/include/firebolt/metrics.h b/include/firebolt/metrics.h index a13deb5..6927674 100644 --- a/include/firebolt/metrics.h +++ b/include/firebolt/metrics.h @@ -43,21 +43,21 @@ class IMetrics /** * @brief Informs the platform that the app is minimally usable * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result ready() const = 0; /** * @brief Logs a sign in event * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result signIn() const = 0; /** * @brief Logs a sign out event * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result signOut() const = 0; @@ -68,7 +68,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result startContent(const std::optional& entityId, const std::optional agePolicy) const = 0; @@ -80,7 +80,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result stopContent(const std::optional& entityId, const std::optional agePolicy) const = 0; @@ -92,7 +92,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result page(const std::string& pageId, const std::optional& agePolicy) const = 0; @@ -107,7 +107,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age * group to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result error(const ErrorType type, const std::string& code, const std::string& description, const bool visible, const std::optional>& parameters, @@ -120,7 +120,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result mediaLoadStart(const std::string& entityId, const std::optional& agePolicy) const = 0; @@ -133,7 +133,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result mediaPlaying(const std::string& entityId, const std::optional& agePolicy) const = 0; @@ -145,7 +145,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result mediaPlay(const std::string& entityId, const std::optional& agePolicy) const = 0; @@ -157,7 +157,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result mediaPause(const std::string& entityId, const std::optional& agePolicy) const = 0; @@ -169,7 +169,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result mediaWaiting(const std::string& entityId, const std::optional& agePolicy) const = 0; @@ -183,7 +183,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result mediaSeeking(const std::string& entityId, const double target, const std::optional& agePolicy) const = 0; @@ -198,7 +198,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result mediaSeeked(const std::string& entityId, const double position, const std::optional& agePolicy) const = 0; @@ -211,7 +211,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result mediaRateChanged(const std::string& entityId, const double rate, const std::optional& agePolicy) const = 0; @@ -227,7 +227,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result mediaRenditionChanged(const std::string& entityId, const unsigned bitrate, const unsigned width, const unsigned height, const std::optional& profile, @@ -240,7 +240,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result mediaEnded(const std::string& entityId, const std::optional& agePolicy) const = 0; @@ -253,7 +253,7 @@ class IMetrics * @param[in] agePolicy : The age policy to associate with the metrics event, the age policy describes the age group * to which content is directed * - * @retval The success state or error + * @retval An ok Result on success, or an error; no value is returned */ virtual Result event(const std::string& schema, const std::string& data, const std::optional& agePolicy) const = 0; @@ -263,7 +263,7 @@ class IMetrics * * @param[in] build : The build / version of this app * - * @retval The status + * @retval An ok Result on success, or an error; no value is returned */ virtual Result appInfo(const std::string& build) const = 0; }; From bd39f0da63769552b6fd3f077750688256b8a338 Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Thu, 7 May 2026 16:04:06 -0400 Subject: [PATCH 03/37] RDKEMW-17483: Align OpenRPC example results with null result schema --- docs/openrpc/openrpc/discovery.json | 8 +- docs/openrpc/openrpc/metrics.json | 86 +- docs/openrpc/the-spec/firebolt-open-rpc.json | 7686 +++++++++--------- 3 files changed, 3890 insertions(+), 3890 deletions(-) diff --git a/docs/openrpc/openrpc/discovery.json b/docs/openrpc/openrpc/discovery.json index 41389e9..8862606 100644 --- a/docs/openrpc/openrpc/discovery.json +++ b/docs/openrpc/openrpc/discovery.json @@ -88,8 +88,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } }, { @@ -117,8 +117,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] diff --git a/docs/openrpc/openrpc/metrics.json b/docs/openrpc/openrpc/metrics.json index 31cd571..b1d705b 100644 --- a/docs/openrpc/openrpc/metrics.json +++ b/docs/openrpc/openrpc/metrics.json @@ -29,8 +29,8 @@ "name": "Send ready metric", "params": [], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -61,8 +61,8 @@ "name": "Send signIn metric", "params": [], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -93,8 +93,8 @@ "name": "Send signOut metric", "params": [], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -138,8 +138,8 @@ "name": "Send startContent metric", "params": [], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } }, { @@ -151,8 +151,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } }, { @@ -168,8 +168,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -213,8 +213,8 @@ "name": "Send stopContent metric", "params": [], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } }, { @@ -226,8 +226,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -276,8 +276,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } }, { @@ -289,8 +289,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -383,8 +383,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -433,8 +433,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -483,8 +483,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -533,8 +533,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -583,8 +583,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -633,8 +633,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -695,8 +695,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -757,8 +757,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -819,8 +819,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -917,8 +917,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -967,8 +967,8 @@ } ], "result": { - "name": "success", - "value": true + "name": "result", + "value": null } } ] @@ -1031,7 +1031,7 @@ ], "result": { "name": "result", - "value": true + "value": null } } ] diff --git a/docs/openrpc/the-spec/firebolt-open-rpc.json b/docs/openrpc/the-spec/firebolt-open-rpc.json index 3a3b51a..82b8600 100644 --- a/docs/openrpc/the-spec/firebolt-open-rpc.json +++ b/docs/openrpc/the-spec/firebolt-open-rpc.json @@ -1,3844 +1,3844 @@ { - "openrpc": "1.2.4", - "info": { - "title": "Firebolt JSON-RPC API", - "version": "", - "x-module-descriptions": { - "Accessibility": "The `Accessibility` module provides access to the user/device settings for closed captioning and voice guidance.\n\nApps **SHOULD** attempt o respect these settings, rather than manage and persist seprate settings, which would be different per-app.", - "Advertising": "A module for platform provided advertising settings and functionality.", - "Device": "A module for querying about the device and it's capabilities.", - "Discovery": "Your App likely wants to integrate with the Platform's discovery capabilities. For example to add a \"Watch Next\" tile that links to your app from the platform's home screen.\n\nGetting access to this information requires to connect to lower level APIs made available by the platform. Since implementations differ between operators and platforms, the Firebolt SDK offers a Discovery module, that exposes a generic, agnostic interface to the developer.\n\nUnder the hood, an underlaying transport layer will then take care of calling the right APIs for the actual platform implementation that your App is running on.\n\nThe Discovery plugin is used to _send_ information to the Platform.\n\n### Localization\nApps should provide all user-facing strings in the device's language, as specified by the Firebolt `Localization.language` property.\n\nApps should provide prices in the same currency presented in the app. If multiple currencies are supported in the app, the app should provide prices in the user's current default currency.", - "Display": "A module for querying about the display", - "Lifecycle2": "Methods and events for responding to Lifecycle changes in your app.", - "Localization": "Methods for accessing location and language preferences.", - "Metrics": "Methods for sending metrics", - "Network": "Methods for accessing network information.", - "Presentation": "Methods for accessing Presentation preferences.", - "Stats": "Provides methods to retrieve application-level system information.", - "TextToSpeech": "A module for controlling and accessing Text To Speech over Firebolt." - } - }, - "methods": [ - { - "name": "rpc.discover", - "summary": "The OpenRPC schema for this JSON-RPC API", - "params": [], - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:rpc:discover" - ] - } - ], - "result": { - "name": "OpenRPC Schema", - "schema": { - "type": "object" - } - }, - "examples": [ - { - "name": "Default", - "params": [], - "result": { - "name": "schema", - "value": {} - } - } - ] - }, - { - "name": "Accessibility.audioDescription", - "summary": "Returns the audio description setting of the device", - "params": [], - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:audio-descriptions" - ] - } - ], - "result": { - "name": "setting", - "summary": "the audio description setting", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Getting the audio description setting", - "params": [], - "result": { - "name": "Default Result", - "value": true - } - } - ] - }, - { - "name": "Accessibility.closedCaptionsSettings", - "summary": "Returns captions settings: enabled, and a list of zero or more languages in order of decreasing preference", - "params": [], - "tags": [ - { - "name": "property:readonly", - "x-notifier-params-flattening": "true" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:closed-captions" - ] - } - ], - "result": { - "name": "closedCaptionsSettings", - "summary": "the closed captions settings", - "schema": { - "$ref": "#/x-schemas/Accessibility/ClosedCaptionsSettings" - } - }, - "examples": [ - { - "name": "Getting the closed captions settings", - "params": [], - "result": { - "name": "settings", - "value": { - "enabled": true, - "preferredLanguages": [ - "eng", - "spa" - ] - } - } - } - ] - }, - { - "name": "Accessibility.highContrastUI", - "summary": "Returns the high contrast UI device setting", - "params": [], - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:high-contrast-ui" - ] - } - ], - "result": { - "name": "highContrastUI", - "summary": "Whether high-contrast UI mode is enabled", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "High-contrast UI mode is enabled", - "params": [], - "result": { - "name": "Default Result", - "value": true - } - } - ] - }, - { - "name": "Accessibility.voiceGuidanceSettings", - "summary": "Returns voice guidance settings: enabled, rate, and verbosity", - "params": [], - "tags": [ - { - "name": "property:readonly", - "x-notifier-params-flattening": "true" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:voice-guidance" - ] - } - ], - "result": { - "name": "settings", - "summary": "the voice guidance settings", - "schema": { - "$ref": "#/x-schemas/Accessibility/VoiceGuidanceSettings" - } - }, - "examples": [ - { - "name": "Getting the voice guidance settings", - "params": [], - "result": { - "name": "Default Result", - "value": { - "enabled": true, - "rate": 0.8, - "navigationHints": true - } - } - } - ] - }, - { - "name": "Advertising.advertisingId", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:advertising:identifier" - ] - } - ], - "summary": "Returns the IFA.", - "params": [], - "result": { - "name": "advertisingId", - "summary": "The advertising ID", - "schema": { - "$ref": "#/components/schemas/AdvertisingIdResult" - } - }, - "examples": [ - { - "name": "Getting the advertising ID", - "params": [], - "result": { - "name": "Default Result", - "value": { - "ifa": "bd87dd10-8d1d-4b93-b1a6-a8e5d410e400", - "ifa_type": "sspid", - "lmt": "0" - } - } - }, - { - "name": "Getting the advertising ID with scope browse", - "params": [], - "result": { - "name": "Default Result", - "value": { - "ifa": "bd87dd10-8d1d-4b93-b1a6-a8e5d410e400", - "ifa_type": "sspid", - "lmt": "1" - } - } - }, - { - "name": "Getting the advertising ID with scope content", - "params": [], - "result": { - "name": "Default Result", - "value": { - "ifa": "bd87dd10-8d1d-4b93-b1a6-a8e5d410e400", - "ifa_type": "idfa", - "lmt": "0" - } - } - } - ] - }, - { - "name": "Device.uid", - "summary": "Returns a persistent unique UUID for the current app and device. The UUID is reset when the app or device is reset", - "params": [], - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:uid" - ] - } - ], - "result": { - "name": "uniqueId", - "summary": "A unique UUID for this app-device pair.", - "schema": { - "type": "string" - } - }, - "examples": [ - { - "name": "Getting the unique UUID", - "params": [], - "result": { - "name": "Default Result", - "value": "ee6723b8-7ab3-462c-8d93-dbf61227998e" - } - } - ] - }, - { - "name": "Device.deviceClass", - "summary": "Returns the class of the device", - "params": [], - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:device-class" - ] - } - ], - "result": { - "name": "deviceClass", - "summary": "The device class", - "schema": { - "$ref": "#/components/schemas/DeviceClass" - } - }, - "examples": [ - { - "name": "Getting the device class", - "params": [], - "result": { - "name": "Default Result", - "value": "ott" - } - } - ] - }, - { - "name": "Device.uptime", - "summary": "Returns the number of seconds since most recent device boot, including any time spent during deep sleep", - "params": [], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "result": { - "name": "uptime", - "summary": "The device uptime", - "schema": { - "type": "number" - } - }, - "examples": [ - { - "name": "Getting the device uptime", - "params": [], - "result": { - "name": "Default Result", - "value": 123456 - } - } - ] - }, - { - "name": "Device.timeInActiveState", - "summary": "Returns the number of seconds since the device transitioned to the ON power state", - "params": [], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "result": { - "name": "timeInActiveState", - "summary": "The device time in active state", - "schema": { - "type": "number" - } - }, - "examples": [ - { - "name": "Getting the number of seconds since the device transitioned to the ON power state", - "params": [], - "result": { - "name": "Default Result", - "value": 654321 - } - } - ] - }, - { - "name": "Device.chipsetId", - "summary": "Returns chipset ID as a printable string, e.g. BCM72180", - "params": [], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "result": { - "name": "chipsetId", - "summary": "The device chipset ID", - "schema": { - "type": "string" - } - }, - "examples": [ - { - "name": "Getting the device chipset ID", - "params": [], - "result": { - "name": "Default Result", - "value": "BCM72180" - } - } - ] - }, - { - "name": "Device.hdr", - "summary": "Returns the HDR standards that are supported by the attached TV or the integral display", - "params": [], - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "result": { - "name": "negotiatedHdrFormats", - "summary": "the negotiated HDR formats", - "schema": { - "$ref": "#/components/schemas/HDRFormatMap" - } - }, - "examples": [ - { - "name": "Getting the negotiated HDR formats", - "params": [], - "result": { - "name": "Default Result", - "value": { - "hdr10": true, - "hdr10Plus": true, - "dolbyVision": true, - "hlg": true - } - } - } - ] - }, - { - "name": "Discovery.watched", - "summary": "Notify the platform that content was partially or completely watched", - "tags": [ - { - "name": "polymorphic-reducer" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:discovery:watched" - ] - } - ], - "params": [ - { - "name": "entityId", - "required": true, - "schema": { - "type": "string" - }, - "summary": "The entity Id of the watched content." - }, - { - "name": "progress", - "summary": "How much of the content has been watched (percentage as (0-0.999) for VOD, number of seconds for live)", - "schema": { - "type": "number", - "minimum": 0 - } - }, - { - "name": "completed", - "summary": "Whether or not this viewing is considered \"complete,\" per the app's definition thereof", - "schema": { - "type": "boolean" - } - }, - { - "name": "watchedOn", - "summary": "Date/Time the content was watched, ISO 8601 Date/Time", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "agePolicy", - "description": "The age policy associated with the watch event. The age policy describes the age groups to which content may be directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Notify the platform of watched content", - "params": [ - { - "name": "entityId", - "value": "partner.com/entity/123" - }, - { - "name": "progress", - "value": 0.95 - }, - { - "name": "completed", - "value": true - }, - { - "name": "watchedOn", - "value": "2021-04-23T18:25:43.511Z" - } - ], - "result": { - "name": "success", - "value": true - } - }, - { - "name": "Notify the platform that child-directed content was watched", - "params": [ - { - "name": "entityId", - "value": "partner.com/entity/123" - }, - { - "name": "progress", - "value": 0.95 - }, - { - "name": "completed", - "value": true - }, - { - "name": "watchedOn", - "value": "2021-04-23T18:25:43.511Z" - }, - { - "name": "agePolicy", - "value": "app:child" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Display.edid", - "summary": "Returns the EDID (and extensions) of the connected or integral display, as a Base64 encoded string", - "params": [], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:display:info" - ] - } - ], - "result": { - "name": "Base64 EDID", - "summary": "The EDID (and extensions) of the connected or integral display, as a Base64 encoded string", - "schema": { - "type": "string" - } - }, - "examples": [ - { - "name": "Getting the display EDID", - "params": [], - "result": { - "name": "Default Result", - "value": "ZWU2NzIzYjgtN2FiMy00NjJjLThkOTMtZGJmNjEyMjc5OThl" - } - } - ] - }, - { - "name": "Display.size", - "summary": "Returns the physical dimensions of the connected or integral display, in centimeters. Returns 0, 0 on a OTT/STB device when a display is not connected over HDMI", - "params": [], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:display:info" - ] - } - ], - "result": { - "name": "size", - "summary": "The display size in centimeters", - "schema": { - "type": "object", - "properties": { - "width": { - "type": "integer", - "description": "The width of the display in centimeters" - }, - "height": { - "type": "integer", - "description": "The height of the display in centimeters" - } - } - } - }, - "examples": [ - { - "name": "Getting the display size", - "params": [], - "result": { - "name": "Default Result", - "value": { - "width": 48, - "height": 27 - } - } - } - ] - }, - { - "name": "Display.maxResolution", - "summary": "Returns the physical/native resolution of the connected or integral display, in pixels. Returns 0, 0 on a OTT/STB device when a display is not connected over HDMI", - "params": [], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:display:info" - ] - } - ], - "result": { - "name": "maxResolution", - "summary": "The display resolution", - "schema": { - "type": "object", - "properties": { - "width": { - "type": "integer", - "description": "The width of the display in pixels" - }, - "height": { - "type": "integer", - "description": "The height of the display in pixels" - } - } - } - }, - "examples": [ - { - "name": "Getting the display size", - "params": [], - "result": { - "name": "Default Result", - "value": { - "width": 1920, - "height": 1080 - } - } - } - ] - }, - { - "name": "Lifecycle2.close", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:cpp-client-only" - ] - } - ], - "summary": "Request the platform to deactivate the app, and possibly take further action.", - "params": [ - { - "name": "type", - "summary": "The type of the close app is requesting", - "required": true, - "schema": { - "$ref": "#/components/schemas/CloseType" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Close the app when the user presses back on the app home screen", - "params": [ - { - "name": "type", - "value": "unload" - } - ], - "result": { - "name": "Default Result", - "value": null - } - }, - { - "name": "Close the app when the user selects an exit menu item", - "params": [ - { - "name": "type", - "value": "deactivate" - } - ], - "result": { - "name": "Default Result", - "value": null - } - } - ] - }, - { - "name": "Lifecycle2.state", - "summary": "Get the current lifecycle state of the app.", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:cpp-client-only" - ] - } - ], - "params": [], - "result": { - "name": "state", - "summary": "The current lifecycle state of the app.", - "schema": { - "$ref": "#/components/schemas/LifecycleState" - } - }, - "examples": [ - { - "name": "Default Example", - "params": [], - "result": { - "name": "Default Result", - "value": "active" - } - } - ] - }, - { - "name": "Localization.country", - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:country-code" - ] - } - ], - "summary": "Returns the ISO 3166-1 alpha-2 code for the country device is located in.", - "params": [], - "result": { - "name": "code", - "summary": "The device country code.", - "schema": { - "$ref": "#/x-schemas/Localization/CountryCode" - } - }, - "examples": [ - { - "name": "Default example", - "params": [], - "result": { - "name": "Default Result", - "value": "US" - } - }, - { - "name": "Another example", - "params": [], - "result": { - "name": "Default Result", - "value": "GB" - } - } - ] - }, - { - "name": "Localization.preferredAudioLanguages", - "summary": "Returns a list of ISO 639-2/B codes for the preferred audio languages on this device.", - "params": [], - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:preferred-audio-languages" - ] - } - ], - "result": { - "name": "languages", - "summary": "The preferred audio languages.", - "schema": { - "type": "array", - "items": { - "$ref": "#/x-schemas/Localization/ISO639_2Language" - } - } - }, - "examples": [ - { - "name": "Default example", - "params": [], - "result": { - "name": "Default Result", - "value": [ - "spa", - "eng" - ] - } - } - ] - }, - { - "name": "Localization.presentationLanguage", - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:locale" - ] - } - ], - "summary": "Get the *full* BCP 47 code, including script, region, variant, etc., for the preferred locale", - "params": [], - "result": { - "name": "locale", - "summary": "The device locale.", - "schema": { - "$ref": "#/x-schemas/Localization/Locale" - } - }, - "examples": [ - { - "name": "Default example", - "params": [], - "result": { - "name": "Default Result", - "value": "en-US" - } - } - ] - }, - { - "name": "Metrics.ready", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Inform the platform that your app is minimally usable. This method is called automatically by `Lifecycle.ready()`", - "params": [], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send ready metric", - "params": [], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.signIn", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Log a sign in event, called by Discovery.signIn().", - "params": [], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send signIn metric", - "params": [], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.signOut", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Log a sign out event, called by Discovery.signOut().", - "params": [], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send signOut metric", - "params": [], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.startContent", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Inform the platform that your user has started content.", - "params": [ - { - "name": "entityId", - "summary": "Optional entity ID of the content.", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send startContent metric", - "params": [], - "result": { - "name": "success", - "value": true - } - }, - { - "name": "Send startContent metric w/ entity", - "params": [ - { - "name": "entityId", - "value": "abc" - } - ], - "result": { - "name": "success", - "value": true - } - }, - { - "name": "Send startContent metric and notify the platform that the content is child-directed", - "params": [ - { - "name": "entityId", - "value": "abc" - }, - { - "name": "agePolicy", - "value": "app:child" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.stopContent", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Inform the platform that your user has stopped content.", - "params": [ - { - "name": "entityId", - "summary": "Optional entity ID of the content.", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send stopContent metric", - "params": [], - "result": { - "name": "success", - "value": true - } - }, - { - "name": "Send stopContent metric w/ entity", - "params": [ - { - "name": "entityId", - "value": "abc" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.page", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Inform the platform that your user has navigated to a page or view.", - "params": [ - { - "name": "pageId", - "summary": "Page ID of the content.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send page metric", - "params": [ - { - "name": "pageId", - "value": "xyz" - } - ], - "result": { - "name": "success", - "value": true - } - }, - { - "name": "Send page metric w/ pageId", - "params": [ - { - "name": "pageId", - "value": "home" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.error", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Inform the platform of an error that has occurred in your app.", - "params": [ - { - "name": "type", - "summary": "The type of error", - "schema": { - "$ref": "#/components/schemas/ErrorType" - }, - "required": true - }, - { - "name": "code", - "summary": "an app-specific error code", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "description", - "summary": "A short description of the error", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "visible", - "summary": "Whether or not this error was visible to the user.", - "schema": { - "type": "boolean" - }, - "required": true - }, - { - "name": "parameters", - "summary": "Optional additional parameters to be logged with the error", - "schema": { - "$ref": "#/x-schemas/Types/FlatMap" - }, - "required": false - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send error metric", - "params": [ - { - "name": "type", - "value": "media" - }, - { - "name": "code", - "value": "MEDIA-STALLED" - }, - { - "name": "description", - "value": "playback stalled" - }, - { - "name": "visible", - "value": true - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaLoadStart", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when setting the URL of a media asset to play, in order to infer load time.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send loadstart metric.", - "params": [ - { - "name": "entityId", - "value": "345" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaPlay", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when media playback should start due to autoplay, user-initiated play, or unpausing.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send play metric.", - "params": [ - { - "name": "entityId", - "value": "345" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaPlaying", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when media playback actually starts due to autoplay, user-initiated play, unpausing, or recovering from a buffering interruption.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send playing metric.", - "params": [ - { - "name": "entityId", - "value": "345" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaPause", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when media playback will pause due to an intentional pause operation.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send pause metric.", - "params": [ - { - "name": "entityId", - "value": "345" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaWaiting", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when media playback will halt due to a network, buffer, or other unintentional constraint.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send waiting metric.", - "params": [ - { - "name": "entityId", - "value": "345" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaSeeking", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when a seek is initiated during media playback.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "target", - "summary": "Target destination of the seek, as a decimal percentage (0-0.999) for content with a known duration, or an integer number of seconds (0-86400) for content with an unknown duration.", - "schema": { - "$ref": "#/components/schemas/MediaPosition" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send seeking metric.", - "params": [ - { - "name": "entityId", - "value": "345" - }, - { - "name": "target", - "value": 0.5 - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaSeeked", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when a seek is completed during media playback.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "position", - "summary": "Resulting position of the seek operation, as a decimal percentage (0-0.999) for content with a known duration, or an integer number of seconds (0-86400) for content with an unknown duration.", - "schema": { - "$ref": "#/components/schemas/MediaPosition" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send seeked metric.", - "params": [ - { - "name": "entityId", - "value": "345" - }, - { - "name": "position", - "value": 0.51 - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaRateChanged", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when the playback rate of media is changed.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "rate", - "summary": "The new playback rate.", - "schema": { - "type": "number" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send ratechange metric.", - "params": [ - { - "name": "entityId", - "value": "345" - }, - { - "name": "rate", - "value": 2 - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaRenditionChanged", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when the playback rendition (e.g. bitrate, dimensions, profile, etc) is changed.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "bitrate", - "summary": "The new bitrate in kbps.", - "schema": { - "type": "number" - }, - "required": true - }, - { - "name": "width", - "summary": "The new resolution width.", - "schema": { - "type": "number" - }, - "required": true - }, - { - "name": "height", - "summary": "The new resolution height.", - "schema": { - "type": "number" - }, - "required": true - }, - { - "name": "profile", - "summary": "A description of the new profile, e.g. 'HDR' etc.", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send renditionchange metric.", - "params": [ - { - "name": "entityId", - "value": "345" - }, - { - "name": "bitrate", - "value": 5000 - }, - { - "name": "width", - "value": 1920 - }, - { - "name": "height", - "value": 1080 - }, - { - "name": "profile", - "value": "HDR+" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.mediaEnded", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:media" - ] - } - ], - "summary": "Called when playback has stopped because the end of the media was reached.", - "params": [ - { - "name": "entityId", - "summary": "The entityId of the media.", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send ended metric.", - "params": [ - { - "name": "entityId", - "value": "345" - } - ], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Metrics.event", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:distributor" - ] - } - ], - "summary": "Inform the platform of 1st party distributor metrics. 'data' parameter is a JSON document", - "params": [ - { - "name": "schema", - "summary": "The schema URI of the metric type", - "schema": { - "type": "string", - "format": "uri" - }, - "required": true - }, - { - "name": "data", - "summary": "A JSON payload", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "agePolicy", - "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", - "schema": { - "$ref": "#/x-schemas/Policies/AgePolicy" - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send foo event", - "params": [ - { - "name": "schema", - "value": "http://meta.rdkcentral.com/some/schema" - }, - { - "name": "data", - "value": "foo" - } - ], - "result": { - "name": "result", - "value": true - } - } - ] - }, - { - "name": "Metrics.appInfo", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:metrics:general" - ] - } - ], - "summary": "Inform the platform about an app's build info.", - "params": [ - { - "name": "build", - "summary": "The build / version of this app.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - }, - "examples": [ - { - "name": "Send appInfo metric", - "params": [ - { - "name": "build", - "value": "1.2.2" - } - ], - "result": { - "name": "result", - "value": null - } - } - ] - }, - { - "name": "Network.connected", - "summary": "Returns whether the device currently has a usable network connection.", - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:network:connected" - ] - } - ], - "params": [], - "result": { - "name": "success", - "summary": "Whether the device currently has a usable network connection.", - "schema": { - "$ref": "#/components/schemas/Connected" - } - }, - "examples": [ - { - "name": "Connected example", - "params": [], - "result": { - "name": "success", - "value": true - } - } - ] - }, - { - "name": "Presentation.focused", - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:cpp-client-only" - ] - } - ], - "summary": "Whether the app is in focus, i.e. receiving key presses. Provided for those apps/runtimes that cannot use Wayland", - "params": [], - "result": { - "name": "focused", - "summary": "Whether the app is in focus.", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Default example", - "params": [], - "result": { - "name": "Default Result", - "value": true - } - } - ] - }, - { - "name": "Stats.memoryUsage", - "summary": "Returns information about container memory usage, in units of 1024 bytes.", - "tags": [ - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:cpp-client-only" - ] - } - ], - "params": [], - "result": { - "name": "result", - "schema": { - "$ref": "#/components/schemas/MemoryUsage" - } - }, - "examples": [ - { - "name": "Default example", - "params": [], - "result": { - "name": "value", - "description": "The memory usage information", - "value": { - "userMemoryUsedKiB": 123456, - "userMemoryLimitKiB": 789012, - "gpuMemoryUsedKiB": 345678, - "gpuMemoryLimitKiB": 901234 - } - } - } - ] - }, - { - "name": "TextToSpeech.speak", - "summary": "Speak the utterance immediately. Any ongoing speech is interrupted.", - "description": "Text argument is either plain text or a well-formed SSML document TTS_status, not success attribute, to be used by caller to indicate success of call 0 OK, 1 Fail, 2 not enabled, 3 invalid configuration Raises onSpeechinterrupted if speaking is interrupted", - "params": [ - { - "name": "text", - "summary": "String to be converted to Audio for speech", - "schema": { - "type": "string" - }, - "required": true - } - ], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "result": { - "name": "speakResult", - "summary": "Result for Speak", - "schema": { - "$ref": "#/components/schemas/SpeechResponse" - } - }, - "examples": [ - { - "name": "Getting the result of speak", - "params": [ - { - "name": "text", - "value": "I am a text waiting for speech." - } - ], - "result": { - "name": "result", - "value": { - "speechid": 1, - "TTS_Status": 0, - "success": true - } - } - } - ] - }, - { - "name": "TextToSpeech.pause", - "summary": "Pauses the speech for given speech id", - "description": "Pauses the utterance. Raises onSpeechpause if ongoing speech is paused. Does nothing if utterance is already paused", - "params": [ - { - "name": "speechid", - "summary": "Identifier for the speech call", - "schema": { - "$ref": "#/components/schemas/SpeechId" - }, - "required": true - } - ], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "result": { - "name": "pauseResult", - "summary": "Result for Pause", - "schema": { - "$ref": "#/components/schemas/TTSStatusResponse" - } - }, - "examples": [ - { - "name": "Pause a given speech id", - "params": [ - { - "name": "speechid", - "value": 1 - } - ], - "result": { - "name": "TTS_Status", - "value": { - "TTS_Status": 0, - "success": true - } - } - } - ] - }, - { - "name": "TextToSpeech.resume", - "summary": "Resumes the speech for given speech id", - "description": "Continue the paused utterance. Raises onSpeechresume if paused speech is resumed. Does nothing if the utterance is not paused", - "params": [ - { - "name": "speechid", - "summary": "Identifier for the speech call", - "schema": { - "$ref": "#/components/schemas/SpeechId" - }, - "required": true - } - ], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "result": { - "name": "resumeResult", - "summary": "Result for Resume", - "schema": { - "$ref": "#/components/schemas/TTSStatusResponse" - } - }, - "examples": [ - { - "name": "Resume a given speech id.", - "params": [ - { - "name": "speechid", - "value": 1 - } - ], - "result": { - "name": "TTS_Status", - "value": { - "TTS_Status": 0, - "success": true - } - } - } - ] - }, - { - "name": "TextToSpeech.cancel", - "summary": "Cancels the speech for given speech id", - "description": "Stop speaking if utterance is currently being spoken. Raises onSpeechinterrupted if speaking was interrupted.", - "params": [ - { - "name": "speechid", - "summary": "Identifier for the speech call", - "schema": { - "$ref": "#/components/schemas/SpeechId" - }, - "required": true - } - ], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "result": { - "name": "cancelResult", - "summary": "Result for cancel", - "schema": { - "$ref": "#/components/schemas/TTSStatusResponse" - } - }, - "examples": [ - { - "name": "Cancel a given speech id.", - "params": [ - { - "name": "speechid", - "value": 1 - } - ], - "result": { - "name": "TTS_Status", - "value": { - "TTS_Status": 0, - "success": true - } - } - } - ] - }, - { - "name": "TextToSpeech.getspeechstate", - "summary": "Returns the state of the utterance.", - "params": [ - { - "name": "speechid", - "summary": "Identifier for the speech call", - "schema": { - "$ref": "#/components/schemas/SpeechId" - }, - "required": true - } - ], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "result": { - "name": "speechStateResult", - "summary": "Result for speech state", - "schema": { - "$ref": "#/components/schemas/SpeechStateResponse" - } - }, - "examples": [ - { - "name": "State for a given speech id.", - "params": [ - { - "name": "speechid", - "value": 1 - } - ], - "result": { - "name": "speechstate", - "value": { - "speechstate": 1, - "TTS_Status": 0, - "success": true - } - } - } - ] - }, - { - "name": "TextToSpeech.listvoices", - "summary": "Returns the list of available voices as human-readable strings, e.g. 'ava', 'amelie', 'angelica'", - "params": [ - { - "name": "language", - "summary": "Language - string - BCP 47", - "schema": { - "$ref": "#/x-schemas/Localization/Locale" - }, - "required": true - } - ], - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "result": { - "name": "listvoices", - "summary": "The list of voices supported for the language", - "schema": { - "$ref": "#/components/schemas/ListVoicesResponse" - } - }, - "examples": [ - { - "name": "Getting the list of voices", - "params": [ - { - "name": "language", - "value": "en-US" - } - ], - "result": { - "name": "voiceList", - "value": { - "TTS_Status": 0, - "voices": [ - "carol", - "tom" - ] - } - } - } - ] - }, - { - "name": "Lifecycle2.onStateChanged", - "tags": [ - { - "name": "event", - "x-contextual-parameters": 0, - "x-notifier": "Lifecycle2.onStateChanged" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:cpp-client-only" - ] - } - ], - "summary": "Notification of lifecycle state change, raised after the platform has transitioned the app/runtime to the new lifecycle state", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "App is active after being initialized", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - }, - { - "name": "Single transition to paused state", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onWillspeak", - "summary": "Text to speech conversion is about to start.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onWillspeak" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onSpeechstart", - "summary": "Utterance is about to be spoken.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onSpeechstart" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onSpeechpause", - "summary": "Ongoing speech was paused.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onSpeechpause" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onSpeechresume", - "summary": "Paused speech was resumed.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onSpeechresume" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onSpeechcomplete", - "summary": "Speech completed successfully.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onSpeechcomplete" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onSpeechinterrupted", - "summary": "Speech was stopped, due to another call to speak or cancel.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onSpeechinterrupted" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onNetworkerror", - "summary": "Utterance failed due to network error.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onNetworkerror" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "TextToSpeech.onPlaybackerror", - "summary": "Utterance failed during playback.", - "tags": [ - { - "name": "rpc-only" - }, - { - "name": "event", - "x-notifier": "TextToSpeech.onPlaybackerror" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:text-to-speech:general" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default Example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Accessibility.onAudioDescriptionChanged", - "summary": "Returns the audio description setting of the device", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier": "Accessibility.onAudioDescriptionChanged", - "x-subscriber-for": "Accessibility.audioDescription" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:audio-descriptions" - ] - } - ], - "examples": [ - { - "name": "Getting the audio description setting", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Accessibility.onClosedCaptionsSettingsChanged", - "summary": "Returns captions settings: enabled, and a list of zero or more languages in order of decreasing preference", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier-params-flattening": "true", - "x-notifier": "Accessibility.onClosedCaptionsSettingsChanged", - "x-subscriber-for": "Accessibility.closedCaptionsSettings" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:closed-captions" - ] - } - ], - "examples": [ - { - "name": "Getting the closed captions settings", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Accessibility.onHighContrastUIChanged", - "summary": "Returns the high contrast UI device setting", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier": "Accessibility.onHighContrastUIChanged", - "x-subscriber-for": "Accessibility.highContrastUI" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:high-contrast-ui" - ] - } - ], - "examples": [ - { - "name": "High-contrast UI mode is enabled", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Accessibility.onVoiceGuidanceSettingsChanged", - "summary": "Returns voice guidance settings: enabled, rate, and verbosity", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier-params-flattening": "true", - "x-notifier": "Accessibility.onVoiceGuidanceSettingsChanged", - "x-subscriber-for": "Accessibility.voiceGuidanceSettings" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:accessibility:voice-guidance" - ] - } - ], - "examples": [ - { - "name": "Getting the voice guidance settings", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Device.onHdrChanged", - "summary": "Returns the HDR standards that are supported by the attached TV or the integral display", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier": "Device.onHdrChanged", - "x-subscriber-for": "Device.hdr" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "examples": [ - { - "name": "Getting the negotiated HDR formats", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Localization.onCountryChanged", - "tags": [ - { - "name": "event", - "x-notifier": "Localization.onCountryChanged", - "x-subscriber-for": "Localization.country" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:country-code" - ] - } - ], - "summary": "Returns the ISO 3166-1 alpha-2 code for the country device is located in.", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - }, - { - "name": "Another example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Localization.onPreferredAudioLanguagesChanged", - "summary": "Returns a list of ISO 639-2/B codes for the preferred audio languages on this device.", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier": "Localization.onPreferredAudioLanguagesChanged", - "x-subscriber-for": "Localization.preferredAudioLanguages" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:preferred-audio-languages" - ] - } - ], - "examples": [ - { - "name": "Default example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Localization.onPresentationLanguageChanged", - "tags": [ - { - "name": "event", - "x-notifier": "Localization.onPresentationLanguageChanged", - "x-subscriber-for": "Localization.presentationLanguage" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:locale" - ] - } - ], - "summary": "Get the *full* BCP 47 code, including script, region, variant, etc., for the preferred locale", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Network.onConnectedChanged", - "summary": "Returns whether the device currently has a usable network connection.", - "tags": [ - { - "name": "event", - "x-notifier": "Network.onConnectedChanged", - "x-subscriber-for": "Network.connected" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:network:connected" - ] - } - ], - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Connected example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, - { - "name": "Presentation.onFocusedChanged", - "tags": [ - { - "name": "event", - "x-notifier": "Presentation.onFocusedChanged", - "x-subscriber-for": "Presentation.focused" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:cpp-client-only" - ] - } - ], - "summary": "Whether the app is in focus, i.e. receiving key presses. Provided for those apps/runtimes that cannot use Wayland", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - } - ], - "components": { - "schemas": { - "AdvertisingIdResult": { - "title": "AdvertisingIdResult", - "type": "object", - "properties": { - "ifa": { - "type": "string", - "description": "UUID conforming to IAB standard" - }, - "ifa_type": { - "type": "string", - "description": "Source of the IFA as defined by IAB" - }, - "lmt": { - "type": "string", - "enum": [ - "0", - "1" - ], - "description": "Boolean that if set to 1, user has requested ad tracking and measurement is disabled" - } - }, - "required": [ - "ifa", - "ifa_type", - "lmt" - ] - }, - "HDRFormatMap": { - "title": "HDRFormatMap", - "type": "object", - "properties": { - "hdr10": { - "type": "boolean" - }, - "hdr10Plus": { - "type": "boolean" - }, - "dolbyVision": { - "type": "boolean" - }, - "hlg": { - "type": "boolean" - } - }, - "required": [ - "hdr10", - "hdr10Plus", - "dolbyVision", - "hlg" - ], - "description": "The type of HDR format" - }, - "DeviceClass": { - "title": "DeviceClass", - "type": "string", - "enum": [ - "ott", - "stb", - "tv" - ], - "description": "The type of device" - }, - "CloseType": { - "title": "CloseType", - "description": "The application close type", - "type": "string", - "enum": [ - "deactivate", - "unload", - "killReload", - "killReactivate" - ] - }, - "LifecycleState": { - "title": "LifecycleState", - "description": "The application Lifecycle state", - "type": "string", - "enum": [ - "initializing", - "active", - "paused", - "suspended", - "hibernated", - "terminating" - ] - }, - "StateChange": { - "title": "StateChange", - "type": "object", - "properties": { - "newState": { - "$ref": "#/components/schemas/LifecycleState" - }, - "oldState": { - "$ref": "#/components/schemas/LifecycleState" - } - } - }, - "MediaPosition": { - "title": "MediaPosition", - "description": "Represents a position inside playback content, as a decimal percentage (0-0.999) for content with a known duration, or an integer number of seconds (0-86400) for content with an unknown duration.", - "oneOf": [ - { - "const": 0 - }, - { - "type": "number", - "exclusiveMinimum": 0, - "exclusiveMaximum": 1 - }, - { - "type": "integer", - "minimum": 1, - "maximum": 86400 - } - ] - }, - "ErrorType": { - "title": "ErrorType", - "type": "string", - "enum": [ - "network", - "media", - "restriction", - "entitlement", - "other" - ] - }, - "EventObjectPrimitives": { - "title": "EventObjectPrimitives", - "anyOf": [ - { - "type": "string", - "maxLength": 256 - }, - { - "type": "number" - }, - { - "type": "integer" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "Connected": { - "type": "boolean", - "description": "Indicates whether the device currently has a usable network connection." - }, - "MemoryUsage": { - "title": "MemoryUsage", - "type": "object", - "description": "Describes current and maximum memory usage of the container.", - "properties": { - "userMemoryUsedKiB": { - "type": "integer", - "description": "User memory currently used in 1024 bytes." - }, - "userMemoryLimitKiB": { - "type": "integer", - "description": "Maximum user memory available in 1024 bytes." - }, - "gpuMemoryUsedKiB": { - "type": "integer", - "description": "GPU memory currently used in 1024 bytes." - }, - "gpuMemoryLimitKiB": { - "type": "integer", - "description": "Maximum GPU memory available in 1024 bytes." - } - }, - "required": [ - "userMemoryUsedKiB", - "userMemoryLimitKiB", - "gpuMemoryUsedKiB", - "gpuMemoryLimitKiB" - ] - }, - "TTSEnabled": { - "title": "TTSEnabled", - "type": "object", - "required": [ - "TTS_Status", - "isenabled" - ], - "properties": { - "TTS_Status": { - "$ref": "#/components/schemas/TTSStatus" - }, - "isenabled": { - "type": "boolean" - } - } - }, - "ListVoicesResponse": { - "title": "ListVoicesResponse", - "type": "object", - "required": [ - "TTS_Status", - "voices" - ], - "properties": { - "TTS_Status": { - "$ref": "#/components/schemas/TTSStatus" - }, - "voices": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "TTSConfiguration": { - "title": "TTSConfiguration", - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - }, - "ttsendpoint": { - "type": "string", - "description": "URL for Text to Speech API" - }, - "ttsendpointsecured": { - "type": "string", - "description": "Secure URL for Text to Speech API" - }, - "language": { - "type": "string", - "description": "Language used by Text to speech" - }, - "voice": { - "type": "string", - "description": "Voice used by Text to speech" - }, - "volume": { - "type": "integer", - "description": "Volume for Text to speech", - "minimum": 0, - "maximum": 100 - }, - "primvolduckpercent": { - "type": "integer", - "description": "Prime Volume duck percent for Text to speech", - "minimum": 0, - "maximum": 100 - }, - "rate": { - "type": "integer", - "description": "Speech rate for Text to speech", - "minimum": 0, - "maximum": 100 - }, - "speechrate": { - "description": "Rate for speech", - "$ref": "#/components/schemas/SpeechRate" - }, - "fallbacktext": { - "description": "Fallback text for TTS", - "$ref": "#/components/schemas/FallbackText" - } - }, - "examples": [ - {} - ] - }, - "SpeechRate": { - "title": "SpeechRate", - "type": "string", - "enum": [ - "slow", - "medium", - "fast", - "faster", - "fastest" - ] - }, - "FallbackText": { - "title": "FallbackText", - "type": "object", - "properties": { - "scenario": { - "type": "string", - "description": "Scenario for fallback Text" - }, - "value": { - "type": "string", - "description": "Value for fallback Text" - } - } - }, - "SpeechResponse": { - "title": "SpeechResponse", - "type": "object", - "properties": { - "speechid": { - "$ref": "#/components/schemas/SpeechId" - }, - "TTS_Status": { - "$ref": "#/components/schemas/TTSStatus" - }, - "success": { - "type": "boolean" - } - }, - "required": [ - "speechid", - "TTS_Status", - "success" - ] - }, - "SpeechId": { - "type": "integer" - }, - "SpeechIdEvent": { - "type": "object", - "properties": { - "speechid": { - "$ref": "#/components/schemas/SpeechId" - } - }, - "required": [ - "speechid" - ] - }, - "TTSStatus": { - "title": "TTSStatus", - "type": "integer", - "minimum": 0, - "maximum": 3 - }, - "SpeechState": { - "title": "SpeechState", - "type": "integer", - "enum": [ - 0, - 1, - 2, - 3 - ], - "description": "0 = SPEECH_PENDING, 1 = SPEECH_IN_PROGRESS, 2 = SPEECH_PAUSED, 3 = SPEECH_NOT_FOUND" - }, - "SpeechStateResponse": { - "title": "SpeechStateResponse", - "type": "object", - "properties": { - "speechstate": { - "$ref": "#/components/schemas/SpeechState" - }, - "TTS_Status": { - "$ref": "#/components/schemas/TTSStatus" - }, - "success": { - "type": "boolean" - } - }, - "required": [ - "speechstate", - "TTS_Status", - "success" - ] - }, - "TTSStatusResponse": { - "title": "TTSStatusResponse", - "type": "object", - "properties": { - "TTS_Status": { - "$ref": "#/components/schemas/TTSStatus" - }, - "success": { - "type": "boolean" - } - }, - "required": [ - "TTS_Status", - "success" - ] - }, - "TTSState": { - "title": "TTSState", - "type": "object", - "properties": { - "state": { - "type": "boolean" - } - }, - "required": [ - "state" - ] - }, - "TTSVoice": { - "title": "TTSVoice", - "type": "object", - "properties": { - "voice": { - "type": "string" - } - }, - "required": [ - "voice" - ] - } - } - }, - "x-schemas": { - "Accessibility": { - "uri": "https://meta.comcast.com/firebolt/accessibility", - "ClosedCaptionsSettings": { - "title": "ClosedCaptionsSettings", - "type": "object", - "required": [ - "enabled" - ], - "properties": { - "enabled": { - "type": "boolean", - "description": "Whether or not closed-captions should be enabled by default" - }, - "preferredLanguages": { - "type": "array", - "items": { - "$ref": "#/x-schemas/Localization/ISO639_2Language" - } - } - }, - "examples": [ - { - "enabled": true, - "styles": { - "fontFamily": "monospaced_serif", - "fontSize": 1, - "fontColor": "#ffffff", - "fontEdge": "none", - "fontEdgeColor": "#7F7F7F", - "fontOpacity": 100, - "backgroundColor": "#000000", - "backgroundOpacity": 100, - "textAlign": "center", - "textAlignVertical": "middle", - "windowColor": "white", - "windowOpacity": 50 - }, - "preferredLanguages": [ - "eng", - "spa" - ] - } - ] - }, - "VoiceGuidanceSettings": { - "title": "VoiceGuidanceSettings", - "type": "object", - "required": [ - "enabled", - "navigationHints", - "rate" - ], - "properties": { - "enabled": { - "type": "boolean", - "description": "Whether or not voice guidance should be enabled by default" - }, - "rate": { - "$ref": "#/x-schemas/Accessibility/SpeechRate", - "description": "The rate at which voice guidance speech will be read back to the user" - }, - "navigationHints": { - "type": "boolean", - "description": "Whether or not voice guidance should include additional navigation hints" - } - }, - "examples": [ - { - "enabled": true, - "navigationHints": true, - "rate": 0.8 - } - ] - }, - "SpeechRate": { - "title": "SpeechRate", - "type": "number", - "minimum": 0.1, - "maximum": 10 - } - }, - "Localization": { - "uri": "https://meta.comcast.com/firebolt/localization", - "ISO639_2Language": { - "type": "string", - "pattern": "^[a-z]{3}$" - }, - "CountryCode": { - "type": "string", - "pattern": "^[A-Z]{2}$" - }, - "Locale": { - "type": "string", - "pattern": "^[a-zA-Z]+([a-zA-Z0-9\\-]*)$" - } - }, - "Policies": { - "uri": "https://meta.comcast.com/firebolt/policies", - "AgePolicy": { - "title": "AgePolicy", - "description": "The policy that describes various age groups to which content is directed. See distributor documentation for further details.", - "anyOf": [ - { - "type": "string" - }, - { - "type": "string", - "enum": [ - "app:adult", - "app:child", - "app:teen" - ] - } - ] - } - }, - "Types": { - "uri": "https://meta.comcast.com/firebolt/types", - "FlatMap": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - } - ] - } - } - } - } -} + "openrpc": "1.2.4", + "info": { + "title": "Firebolt JSON-RPC API", + "version": "", + "x-module-descriptions": { + "Accessibility": "The `Accessibility` module provides access to the user/device settings for closed captioning and voice guidance.\n\nApps **SHOULD** attempt o respect these settings, rather than manage and persist seprate settings, which would be different per-app.", + "Advertising": "A module for platform provided advertising settings and functionality.", + "Device": "A module for querying about the device and it's capabilities.", + "Discovery": "Your App likely wants to integrate with the Platform's discovery capabilities. For example to add a \"Watch Next\" tile that links to your app from the platform's home screen.\n\nGetting access to this information requires to connect to lower level APIs made available by the platform. Since implementations differ between operators and platforms, the Firebolt SDK offers a Discovery module, that exposes a generic, agnostic interface to the developer.\n\nUnder the hood, an underlaying transport layer will then take care of calling the right APIs for the actual platform implementation that your App is running on.\n\nThe Discovery plugin is used to _send_ information to the Platform.\n\n### Localization\nApps should provide all user-facing strings in the device's language, as specified by the Firebolt `Localization.language` property.\n\nApps should provide prices in the same currency presented in the app. If multiple currencies are supported in the app, the app should provide prices in the user's current default currency.", + "Display": "A module for querying about the display", + "Lifecycle2": "Methods and events for responding to Lifecycle changes in your app.", + "Localization": "Methods for accessing location and language preferences.", + "Metrics": "Methods for sending metrics", + "Network": "Methods for accessing network information.", + "Presentation": "Methods for accessing Presentation preferences.", + "Stats": "Provides methods to retrieve application-level system information.", + "TextToSpeech": "A module for controlling and accessing Text To Speech over Firebolt." + } + }, + "methods": [ + { + "name": "rpc.discover", + "summary": "The OpenRPC schema for this JSON-RPC API", + "params": [], + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:rpc:discover" + ] + } + ], + "result": { + "name": "OpenRPC Schema", + "schema": { + "type": "object" + } + }, + "examples": [ + { + "name": "Default", + "params": [], + "result": { + "name": "schema", + "value": {} + } + } + ] + }, + { + "name": "Accessibility.audioDescription", + "summary": "Returns the audio description setting of the device", + "params": [], + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:audio-descriptions" + ] + } + ], + "result": { + "name": "setting", + "summary": "the audio description setting", + "schema": { + "type": "boolean" + } + }, + "examples": [ + { + "name": "Getting the audio description setting", + "params": [], + "result": { + "name": "Default Result", + "value": true + } + } + ] + }, + { + "name": "Accessibility.closedCaptionsSettings", + "summary": "Returns captions settings: enabled, and a list of zero or more languages in order of decreasing preference", + "params": [], + "tags": [ + { + "name": "property:readonly", + "x-notifier-params-flattening": "true" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:closed-captions" + ] + } + ], + "result": { + "name": "closedCaptionsSettings", + "summary": "the closed captions settings", + "schema": { + "$ref": "#/x-schemas/Accessibility/ClosedCaptionsSettings" + } + }, + "examples": [ + { + "name": "Getting the closed captions settings", + "params": [], + "result": { + "name": "settings", + "value": { + "enabled": true, + "preferredLanguages": [ + "eng", + "spa" + ] + } + } + } + ] + }, + { + "name": "Accessibility.highContrastUI", + "summary": "Returns the high contrast UI device setting", + "params": [], + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:high-contrast-ui" + ] + } + ], + "result": { + "name": "highContrastUI", + "summary": "Whether high-contrast UI mode is enabled", + "schema": { + "type": "boolean" + } + }, + "examples": [ + { + "name": "High-contrast UI mode is enabled", + "params": [], + "result": { + "name": "Default Result", + "value": true + } + } + ] + }, + { + "name": "Accessibility.voiceGuidanceSettings", + "summary": "Returns voice guidance settings: enabled, rate, and verbosity", + "params": [], + "tags": [ + { + "name": "property:readonly", + "x-notifier-params-flattening": "true" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:voice-guidance" + ] + } + ], + "result": { + "name": "settings", + "summary": "the voice guidance settings", + "schema": { + "$ref": "#/x-schemas/Accessibility/VoiceGuidanceSettings" + } + }, + "examples": [ + { + "name": "Getting the voice guidance settings", + "params": [], + "result": { + "name": "Default Result", + "value": { + "enabled": true, + "rate": 0.8, + "navigationHints": true + } + } + } + ] + }, + { + "name": "Advertising.advertisingId", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:advertising:identifier" + ] + } + ], + "summary": "Returns the IFA.", + "params": [], + "result": { + "name": "advertisingId", + "summary": "The advertising ID", + "schema": { + "$ref": "#/components/schemas/AdvertisingIdResult" + } + }, + "examples": [ + { + "name": "Getting the advertising ID", + "params": [], + "result": { + "name": "Default Result", + "value": { + "ifa": "bd87dd10-8d1d-4b93-b1a6-a8e5d410e400", + "ifa_type": "sspid", + "lmt": "0" + } + } + }, + { + "name": "Getting the advertising ID with scope browse", + "params": [], + "result": { + "name": "Default Result", + "value": { + "ifa": "bd87dd10-8d1d-4b93-b1a6-a8e5d410e400", + "ifa_type": "sspid", + "lmt": "1" + } + } + }, + { + "name": "Getting the advertising ID with scope content", + "params": [], + "result": { + "name": "Default Result", + "value": { + "ifa": "bd87dd10-8d1d-4b93-b1a6-a8e5d410e400", + "ifa_type": "idfa", + "lmt": "0" + } + } + } + ] + }, + { + "name": "Device.uid", + "summary": "Returns a persistent unique UUID for the current app and device. The UUID is reset when the app or device is reset", + "params": [], + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:uid" + ] + } + ], + "result": { + "name": "uniqueId", + "summary": "A unique UUID for this app-device pair.", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Getting the unique UUID", + "params": [], + "result": { + "name": "Default Result", + "value": "ee6723b8-7ab3-462c-8d93-dbf61227998e" + } + } + ] + }, + { + "name": "Device.deviceClass", + "summary": "Returns the class of the device", + "params": [], + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:device-class" + ] + } + ], + "result": { + "name": "deviceClass", + "summary": "The device class", + "schema": { + "$ref": "#/components/schemas/DeviceClass" + } + }, + "examples": [ + { + "name": "Getting the device class", + "params": [], + "result": { + "name": "Default Result", + "value": "ott" + } + } + ] + }, + { + "name": "Device.uptime", + "summary": "Returns the number of seconds since most recent device boot, including any time spent during deep sleep", + "params": [], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "result": { + "name": "uptime", + "summary": "The device uptime", + "schema": { + "type": "number" + } + }, + "examples": [ + { + "name": "Getting the device uptime", + "params": [], + "result": { + "name": "Default Result", + "value": 123456 + } + } + ] + }, + { + "name": "Device.timeInActiveState", + "summary": "Returns the number of seconds since the device transitioned to the ON power state", + "params": [], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "result": { + "name": "timeInActiveState", + "summary": "The device time in active state", + "schema": { + "type": "number" + } + }, + "examples": [ + { + "name": "Getting the number of seconds since the device transitioned to the ON power state", + "params": [], + "result": { + "name": "Default Result", + "value": 654321 + } + } + ] + }, + { + "name": "Device.chipsetId", + "summary": "Returns chipset ID as a printable string, e.g. BCM72180", + "params": [], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "result": { + "name": "chipsetId", + "summary": "The device chipset ID", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Getting the device chipset ID", + "params": [], + "result": { + "name": "Default Result", + "value": "BCM72180" + } + } + ] + }, + { + "name": "Device.hdr", + "summary": "Returns the HDR standards that are supported by the attached TV or the integral display", + "params": [], + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "result": { + "name": "negotiatedHdrFormats", + "summary": "the negotiated HDR formats", + "schema": { + "$ref": "#/components/schemas/HDRFormatMap" + } + }, + "examples": [ + { + "name": "Getting the negotiated HDR formats", + "params": [], + "result": { + "name": "Default Result", + "value": { + "hdr10": true, + "hdr10Plus": true, + "dolbyVision": true, + "hlg": true + } + } + } + ] + }, + { + "name": "Discovery.watched", + "summary": "Notify the platform that content was partially or completely watched", + "tags": [ + { + "name": "polymorphic-reducer" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:discovery:watched" + ] + } + ], + "params": [ + { + "name": "entityId", + "required": true, + "schema": { + "type": "string" + }, + "summary": "The entity Id of the watched content." + }, + { + "name": "progress", + "summary": "How much of the content has been watched (percentage as (0-0.999) for VOD, number of seconds for live)", + "schema": { + "type": "number", + "minimum": 0 + } + }, + { + "name": "completed", + "summary": "Whether or not this viewing is considered \"complete,\" per the app's definition thereof", + "schema": { + "type": "boolean" + } + }, + { + "name": "watchedOn", + "summary": "Date/Time the content was watched, ISO 8601 Date/Time", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "agePolicy", + "description": "The age policy associated with the watch event. The age policy describes the age groups to which content may be directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Notify the platform of watched content", + "params": [ + { + "name": "entityId", + "value": "partner.com/entity/123" + }, + { + "name": "progress", + "value": 0.95 + }, + { + "name": "completed", + "value": true + }, + { + "name": "watchedOn", + "value": "2021-04-23T18:25:43.511Z" + } + ], + "result": { + "name": "result", + "value": null + } + }, + { + "name": "Notify the platform that child-directed content was watched", + "params": [ + { + "name": "entityId", + "value": "partner.com/entity/123" + }, + { + "name": "progress", + "value": 0.95 + }, + { + "name": "completed", + "value": true + }, + { + "name": "watchedOn", + "value": "2021-04-23T18:25:43.511Z" + }, + { + "name": "agePolicy", + "value": "app:child" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Display.edid", + "summary": "Returns the EDID (and extensions) of the connected or integral display, as a Base64 encoded string", + "params": [], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:display:info" + ] + } + ], + "result": { + "name": "Base64 EDID", + "summary": "The EDID (and extensions) of the connected or integral display, as a Base64 encoded string", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Getting the display EDID", + "params": [], + "result": { + "name": "Default Result", + "value": "ZWU2NzIzYjgtN2FiMy00NjJjLThkOTMtZGJmNjEyMjc5OThl" + } + } + ] + }, + { + "name": "Display.size", + "summary": "Returns the physical dimensions of the connected or integral display, in centimeters. Returns 0, 0 on a OTT/STB device when a display is not connected over HDMI", + "params": [], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:display:info" + ] + } + ], + "result": { + "name": "size", + "summary": "The display size in centimeters", + "schema": { + "type": "object", + "properties": { + "width": { + "type": "integer", + "description": "The width of the display in centimeters" + }, + "height": { + "type": "integer", + "description": "The height of the display in centimeters" + } + } + } + }, + "examples": [ + { + "name": "Getting the display size", + "params": [], + "result": { + "name": "Default Result", + "value": { + "width": 48, + "height": 27 + } + } + } + ] + }, + { + "name": "Display.maxResolution", + "summary": "Returns the physical/native resolution of the connected or integral display, in pixels. Returns 0, 0 on a OTT/STB device when a display is not connected over HDMI", + "params": [], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:display:info" + ] + } + ], + "result": { + "name": "maxResolution", + "summary": "The display resolution", + "schema": { + "type": "object", + "properties": { + "width": { + "type": "integer", + "description": "The width of the display in pixels" + }, + "height": { + "type": "integer", + "description": "The height of the display in pixels" + } + } + } + }, + "examples": [ + { + "name": "Getting the display size", + "params": [], + "result": { + "name": "Default Result", + "value": { + "width": 1920, + "height": 1080 + } + } + } + ] + }, + { + "name": "Lifecycle2.close", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:cpp-client-only" + ] + } + ], + "summary": "Request the platform to deactivate the app, and possibly take further action.", + "params": [ + { + "name": "type", + "summary": "The type of the close app is requesting", + "required": true, + "schema": { + "$ref": "#/components/schemas/CloseType" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Close the app when the user presses back on the app home screen", + "params": [ + { + "name": "type", + "value": "unload" + } + ], + "result": { + "name": "Default Result", + "value": null + } + }, + { + "name": "Close the app when the user selects an exit menu item", + "params": [ + { + "name": "type", + "value": "deactivate" + } + ], + "result": { + "name": "Default Result", + "value": null + } + } + ] + }, + { + "name": "Lifecycle2.state", + "summary": "Get the current lifecycle state of the app.", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:cpp-client-only" + ] + } + ], + "params": [], + "result": { + "name": "state", + "summary": "The current lifecycle state of the app.", + "schema": { + "$ref": "#/components/schemas/LifecycleState" + } + }, + "examples": [ + { + "name": "Default Example", + "params": [], + "result": { + "name": "Default Result", + "value": "active" + } + } + ] + }, + { + "name": "Localization.country", + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:country-code" + ] + } + ], + "summary": "Returns the ISO 3166-1 alpha-2 code for the country device is located in.", + "params": [], + "result": { + "name": "code", + "summary": "The device country code.", + "schema": { + "$ref": "#/x-schemas/Localization/CountryCode" + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "Default Result", + "value": "US" + } + }, + { + "name": "Another example", + "params": [], + "result": { + "name": "Default Result", + "value": "GB" + } + } + ] + }, + { + "name": "Localization.preferredAudioLanguages", + "summary": "Returns a list of ISO 639-2/B codes for the preferred audio languages on this device.", + "params": [], + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:preferred-audio-languages" + ] + } + ], + "result": { + "name": "languages", + "summary": "The preferred audio languages.", + "schema": { + "type": "array", + "items": { + "$ref": "#/x-schemas/Localization/ISO639_2Language" + } + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "Default Result", + "value": [ + "spa", + "eng" + ] + } + } + ] + }, + { + "name": "Localization.presentationLanguage", + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:locale" + ] + } + ], + "summary": "Get the *full* BCP 47 code, including script, region, variant, etc., for the preferred locale", + "params": [], + "result": { + "name": "locale", + "summary": "The device locale.", + "schema": { + "$ref": "#/x-schemas/Localization/Locale" + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "Default Result", + "value": "en-US" + } + } + ] + }, + { + "name": "Metrics.ready", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Inform the platform that your app is minimally usable. This method is called automatically by `Lifecycle.ready()`", + "params": [], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send ready metric", + "params": [], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.signIn", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Log a sign in event, called by Discovery.signIn().", + "params": [], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send signIn metric", + "params": [], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.signOut", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Log a sign out event, called by Discovery.signOut().", + "params": [], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send signOut metric", + "params": [], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.startContent", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Inform the platform that your user has started content.", + "params": [ + { + "name": "entityId", + "summary": "Optional entity ID of the content.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send startContent metric", + "params": [], + "result": { + "name": "result", + "value": null + } + }, + { + "name": "Send startContent metric w/ entity", + "params": [ + { + "name": "entityId", + "value": "abc" + } + ], + "result": { + "name": "result", + "value": null + } + }, + { + "name": "Send startContent metric and notify the platform that the content is child-directed", + "params": [ + { + "name": "entityId", + "value": "abc" + }, + { + "name": "agePolicy", + "value": "app:child" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.stopContent", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Inform the platform that your user has stopped content.", + "params": [ + { + "name": "entityId", + "summary": "Optional entity ID of the content.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send stopContent metric", + "params": [], + "result": { + "name": "result", + "value": null + } + }, + { + "name": "Send stopContent metric w/ entity", + "params": [ + { + "name": "entityId", + "value": "abc" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.page", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Inform the platform that your user has navigated to a page or view.", + "params": [ + { + "name": "pageId", + "summary": "Page ID of the content.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send page metric", + "params": [ + { + "name": "pageId", + "value": "xyz" + } + ], + "result": { + "name": "result", + "value": null + } + }, + { + "name": "Send page metric w/ pageId", + "params": [ + { + "name": "pageId", + "value": "home" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.error", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Inform the platform of an error that has occurred in your app.", + "params": [ + { + "name": "type", + "summary": "The type of error", + "schema": { + "$ref": "#/components/schemas/ErrorType" + }, + "required": true + }, + { + "name": "code", + "summary": "an app-specific error code", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "description", + "summary": "A short description of the error", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "visible", + "summary": "Whether or not this error was visible to the user.", + "schema": { + "type": "boolean" + }, + "required": true + }, + { + "name": "parameters", + "summary": "Optional additional parameters to be logged with the error", + "schema": { + "$ref": "#/x-schemas/Types/FlatMap" + }, + "required": false + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send error metric", + "params": [ + { + "name": "type", + "value": "media" + }, + { + "name": "code", + "value": "MEDIA-STALLED" + }, + { + "name": "description", + "value": "playback stalled" + }, + { + "name": "visible", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.mediaLoadStart", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when setting the URL of a media asset to play, in order to infer load time.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send loadstart metric.", + "params": [ + { + "name": "entityId", + "value": "345" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.mediaPlay", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when media playback should start due to autoplay, user-initiated play, or unpausing.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send play metric.", + "params": [ + { + "name": "entityId", + "value": "345" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.mediaPlaying", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when media playback actually starts due to autoplay, user-initiated play, unpausing, or recovering from a buffering interruption.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send playing metric.", + "params": [ + { + "name": "entityId", + "value": "345" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.mediaPause", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when media playback will pause due to an intentional pause operation.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send pause metric.", + "params": [ + { + "name": "entityId", + "value": "345" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.mediaWaiting", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when media playback will halt due to a network, buffer, or other unintentional constraint.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send waiting metric.", + "params": [ + { + "name": "entityId", + "value": "345" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.mediaSeeking", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when a seek is initiated during media playback.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "target", + "summary": "Target destination of the seek, as a decimal percentage (0-0.999) for content with a known duration, or an integer number of seconds (0-86400) for content with an unknown duration.", + "schema": { + "$ref": "#/components/schemas/MediaPosition" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send seeking metric.", + "params": [ + { + "name": "entityId", + "value": "345" + }, + { + "name": "target", + "value": 0.5 + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.mediaSeeked", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when a seek is completed during media playback.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "position", + "summary": "Resulting position of the seek operation, as a decimal percentage (0-0.999) for content with a known duration, or an integer number of seconds (0-86400) for content with an unknown duration.", + "schema": { + "$ref": "#/components/schemas/MediaPosition" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send seeked metric.", + "params": [ + { + "name": "entityId", + "value": "345" + }, + { + "name": "position", + "value": 0.51 + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.mediaRateChanged", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when the playback rate of media is changed.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "rate", + "summary": "The new playback rate.", + "schema": { + "type": "number" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send ratechange metric.", + "params": [ + { + "name": "entityId", + "value": "345" + }, + { + "name": "rate", + "value": 2 + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.mediaRenditionChanged", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when the playback rendition (e.g. bitrate, dimensions, profile, etc) is changed.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "bitrate", + "summary": "The new bitrate in kbps.", + "schema": { + "type": "number" + }, + "required": true + }, + { + "name": "width", + "summary": "The new resolution width.", + "schema": { + "type": "number" + }, + "required": true + }, + { + "name": "height", + "summary": "The new resolution height.", + "schema": { + "type": "number" + }, + "required": true + }, + { + "name": "profile", + "summary": "A description of the new profile, e.g. 'HDR' etc.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send renditionchange metric.", + "params": [ + { + "name": "entityId", + "value": "345" + }, + { + "name": "bitrate", + "value": 5000 + }, + { + "name": "width", + "value": 1920 + }, + { + "name": "height", + "value": 1080 + }, + { + "name": "profile", + "value": "HDR+" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.mediaEnded", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:media" + ] + } + ], + "summary": "Called when playback has stopped because the end of the media was reached.", + "params": [ + { + "name": "entityId", + "summary": "The entityId of the media.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send ended metric.", + "params": [ + { + "name": "entityId", + "value": "345" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.event", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:distributor" + ] + } + ], + "summary": "Inform the platform of 1st party distributor metrics. 'data' parameter is a JSON document", + "params": [ + { + "name": "schema", + "summary": "The schema URI of the metric type", + "schema": { + "type": "string", + "format": "uri" + }, + "required": true + }, + { + "name": "data", + "summary": "A JSON payload", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "agePolicy", + "summary": "The age policy to associate with the metrics event. The age policy describes the age group to which content is directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send foo event", + "params": [ + { + "name": "schema", + "value": "http://meta.rdkcentral.com/some/schema" + }, + { + "name": "data", + "value": "foo" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Metrics.appInfo", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:metrics:general" + ] + } + ], + "summary": "Inform the platform about an app's build info.", + "params": [ + { + "name": "build", + "summary": "The build / version of this app.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Send appInfo metric", + "params": [ + { + "name": "build", + "value": "1.2.2" + } + ], + "result": { + "name": "result", + "value": null + } + } + ] + }, + { + "name": "Network.connected", + "summary": "Returns whether the device currently has a usable network connection.", + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:network:connected" + ] + } + ], + "params": [], + "result": { + "name": "success", + "summary": "Whether the device currently has a usable network connection.", + "schema": { + "$ref": "#/components/schemas/Connected" + } + }, + "examples": [ + { + "name": "Connected example", + "params": [], + "result": { + "name": "success", + "value": true + } + } + ] + }, + { + "name": "Presentation.focused", + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:cpp-client-only" + ] + } + ], + "summary": "Whether the app is in focus, i.e. receiving key presses. Provided for those apps/runtimes that cannot use Wayland", + "params": [], + "result": { + "name": "focused", + "summary": "Whether the app is in focus.", + "schema": { + "type": "boolean" + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "Default Result", + "value": true + } + } + ] + }, + { + "name": "Stats.memoryUsage", + "summary": "Returns information about container memory usage, in units of 1024 bytes.", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:cpp-client-only" + ] + } + ], + "params": [], + "result": { + "name": "result", + "schema": { + "$ref": "#/components/schemas/MemoryUsage" + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "value", + "description": "The memory usage information", + "value": { + "userMemoryUsedKiB": 123456, + "userMemoryLimitKiB": 789012, + "gpuMemoryUsedKiB": 345678, + "gpuMemoryLimitKiB": 901234 + } + } + } + ] + }, + { + "name": "TextToSpeech.speak", + "summary": "Speak the utterance immediately. Any ongoing speech is interrupted.", + "description": "Text argument is either plain text or a well-formed SSML document TTS_status, not success attribute, to be used by caller to indicate success of call 0 OK, 1 Fail, 2 not enabled, 3 invalid configuration Raises onSpeechinterrupted if speaking is interrupted", + "params": [ + { + "name": "text", + "summary": "String to be converted to Audio for speech", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "result": { + "name": "speakResult", + "summary": "Result for Speak", + "schema": { + "$ref": "#/components/schemas/SpeechResponse" + } + }, + "examples": [ + { + "name": "Getting the result of speak", + "params": [ + { + "name": "text", + "value": "I am a text waiting for speech." + } + ], + "result": { + "name": "result", + "value": { + "speechid": 1, + "TTS_Status": 0, + "success": true + } + } + } + ] + }, + { + "name": "TextToSpeech.pause", + "summary": "Pauses the speech for given speech id", + "description": "Pauses the utterance. Raises onSpeechpause if ongoing speech is paused. Does nothing if utterance is already paused", + "params": [ + { + "name": "speechid", + "summary": "Identifier for the speech call", + "schema": { + "$ref": "#/components/schemas/SpeechId" + }, + "required": true + } + ], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "result": { + "name": "pauseResult", + "summary": "Result for Pause", + "schema": { + "$ref": "#/components/schemas/TTSStatusResponse" + } + }, + "examples": [ + { + "name": "Pause a given speech id", + "params": [ + { + "name": "speechid", + "value": 1 + } + ], + "result": { + "name": "TTS_Status", + "value": { + "TTS_Status": 0, + "success": true + } + } + } + ] + }, + { + "name": "TextToSpeech.resume", + "summary": "Resumes the speech for given speech id", + "description": "Continue the paused utterance. Raises onSpeechresume if paused speech is resumed. Does nothing if the utterance is not paused", + "params": [ + { + "name": "speechid", + "summary": "Identifier for the speech call", + "schema": { + "$ref": "#/components/schemas/SpeechId" + }, + "required": true + } + ], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "result": { + "name": "resumeResult", + "summary": "Result for Resume", + "schema": { + "$ref": "#/components/schemas/TTSStatusResponse" + } + }, + "examples": [ + { + "name": "Resume a given speech id.", + "params": [ + { + "name": "speechid", + "value": 1 + } + ], + "result": { + "name": "TTS_Status", + "value": { + "TTS_Status": 0, + "success": true + } + } + } + ] + }, + { + "name": "TextToSpeech.cancel", + "summary": "Cancels the speech for given speech id", + "description": "Stop speaking if utterance is currently being spoken. Raises onSpeechinterrupted if speaking was interrupted.", + "params": [ + { + "name": "speechid", + "summary": "Identifier for the speech call", + "schema": { + "$ref": "#/components/schemas/SpeechId" + }, + "required": true + } + ], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "result": { + "name": "cancelResult", + "summary": "Result for cancel", + "schema": { + "$ref": "#/components/schemas/TTSStatusResponse" + } + }, + "examples": [ + { + "name": "Cancel a given speech id.", + "params": [ + { + "name": "speechid", + "value": 1 + } + ], + "result": { + "name": "TTS_Status", + "value": { + "TTS_Status": 0, + "success": true + } + } + } + ] + }, + { + "name": "TextToSpeech.getspeechstate", + "summary": "Returns the state of the utterance.", + "params": [ + { + "name": "speechid", + "summary": "Identifier for the speech call", + "schema": { + "$ref": "#/components/schemas/SpeechId" + }, + "required": true + } + ], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "result": { + "name": "speechStateResult", + "summary": "Result for speech state", + "schema": { + "$ref": "#/components/schemas/SpeechStateResponse" + } + }, + "examples": [ + { + "name": "State for a given speech id.", + "params": [ + { + "name": "speechid", + "value": 1 + } + ], + "result": { + "name": "speechstate", + "value": { + "speechstate": 1, + "TTS_Status": 0, + "success": true + } + } + } + ] + }, + { + "name": "TextToSpeech.listvoices", + "summary": "Returns the list of available voices as human-readable strings, e.g. 'ava', 'amelie', 'angelica'", + "params": [ + { + "name": "language", + "summary": "Language - string - BCP 47", + "schema": { + "$ref": "#/x-schemas/Localization/Locale" + }, + "required": true + } + ], + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "result": { + "name": "listvoices", + "summary": "The list of voices supported for the language", + "schema": { + "$ref": "#/components/schemas/ListVoicesResponse" + } + }, + "examples": [ + { + "name": "Getting the list of voices", + "params": [ + { + "name": "language", + "value": "en-US" + } + ], + "result": { + "name": "voiceList", + "value": { + "TTS_Status": 0, + "voices": [ + "carol", + "tom" + ] + } + } + } + ] + }, + { + "name": "Lifecycle2.onStateChanged", + "tags": [ + { + "name": "event", + "x-contextual-parameters": 0, + "x-notifier": "Lifecycle2.onStateChanged" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:cpp-client-only" + ] + } + ], + "summary": "Notification of lifecycle state change, raised after the platform has transitioned the app/runtime to the new lifecycle state", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "App is active after being initialized", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + }, + { + "name": "Single transition to paused state", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onWillspeak", + "summary": "Text to speech conversion is about to start.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onWillspeak" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onSpeechstart", + "summary": "Utterance is about to be spoken.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onSpeechstart" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onSpeechpause", + "summary": "Ongoing speech was paused.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onSpeechpause" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onSpeechresume", + "summary": "Paused speech was resumed.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onSpeechresume" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onSpeechcomplete", + "summary": "Speech completed successfully.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onSpeechcomplete" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onSpeechinterrupted", + "summary": "Speech was stopped, due to another call to speak or cancel.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onSpeechinterrupted" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onNetworkerror", + "summary": "Utterance failed due to network error.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onNetworkerror" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "TextToSpeech.onPlaybackerror", + "summary": "Utterance failed during playback.", + "tags": [ + { + "name": "rpc-only" + }, + { + "name": "event", + "x-notifier": "TextToSpeech.onPlaybackerror" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:text-to-speech:general" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default Example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Accessibility.onAudioDescriptionChanged", + "summary": "Returns the audio description setting of the device", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier": "Accessibility.onAudioDescriptionChanged", + "x-subscriber-for": "Accessibility.audioDescription" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:audio-descriptions" + ] + } + ], + "examples": [ + { + "name": "Getting the audio description setting", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Accessibility.onClosedCaptionsSettingsChanged", + "summary": "Returns captions settings: enabled, and a list of zero or more languages in order of decreasing preference", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier-params-flattening": "true", + "x-notifier": "Accessibility.onClosedCaptionsSettingsChanged", + "x-subscriber-for": "Accessibility.closedCaptionsSettings" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:closed-captions" + ] + } + ], + "examples": [ + { + "name": "Getting the closed captions settings", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Accessibility.onHighContrastUIChanged", + "summary": "Returns the high contrast UI device setting", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier": "Accessibility.onHighContrastUIChanged", + "x-subscriber-for": "Accessibility.highContrastUI" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:high-contrast-ui" + ] + } + ], + "examples": [ + { + "name": "High-contrast UI mode is enabled", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Accessibility.onVoiceGuidanceSettingsChanged", + "summary": "Returns voice guidance settings: enabled, rate, and verbosity", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier-params-flattening": "true", + "x-notifier": "Accessibility.onVoiceGuidanceSettingsChanged", + "x-subscriber-for": "Accessibility.voiceGuidanceSettings" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:accessibility:voice-guidance" + ] + } + ], + "examples": [ + { + "name": "Getting the voice guidance settings", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Device.onHdrChanged", + "summary": "Returns the HDR standards that are supported by the attached TV or the integral display", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier": "Device.onHdrChanged", + "x-subscriber-for": "Device.hdr" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "examples": [ + { + "name": "Getting the negotiated HDR formats", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Localization.onCountryChanged", + "tags": [ + { + "name": "event", + "x-notifier": "Localization.onCountryChanged", + "x-subscriber-for": "Localization.country" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:country-code" + ] + } + ], + "summary": "Returns the ISO 3166-1 alpha-2 code for the country device is located in.", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + }, + { + "name": "Another example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Localization.onPreferredAudioLanguagesChanged", + "summary": "Returns a list of ISO 639-2/B codes for the preferred audio languages on this device.", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier": "Localization.onPreferredAudioLanguagesChanged", + "x-subscriber-for": "Localization.preferredAudioLanguages" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:preferred-audio-languages" + ] + } + ], + "examples": [ + { + "name": "Default example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Localization.onPresentationLanguageChanged", + "tags": [ + { + "name": "event", + "x-notifier": "Localization.onPresentationLanguageChanged", + "x-subscriber-for": "Localization.presentationLanguage" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:locale" + ] + } + ], + "summary": "Get the *full* BCP 47 code, including script, region, variant, etc., for the preferred locale", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Network.onConnectedChanged", + "summary": "Returns whether the device currently has a usable network connection.", + "tags": [ + { + "name": "event", + "x-notifier": "Network.onConnectedChanged", + "x-subscriber-for": "Network.connected" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:network:connected" + ] + } + ], + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Connected example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, + { + "name": "Presentation.onFocusedChanged", + "tags": [ + { + "name": "event", + "x-notifier": "Presentation.onFocusedChanged", + "x-subscriber-for": "Presentation.focused" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:cpp-client-only" + ] + } + ], + "summary": "Whether the app is in focus, i.e. receiving key presses. Provided for those apps/runtimes that cannot use Wayland", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + } + ], + "components": { + "schemas": { + "AdvertisingIdResult": { + "title": "AdvertisingIdResult", + "type": "object", + "properties": { + "ifa": { + "type": "string", + "description": "UUID conforming to IAB standard" + }, + "ifa_type": { + "type": "string", + "description": "Source of the IFA as defined by IAB" + }, + "lmt": { + "type": "string", + "enum": [ + "0", + "1" + ], + "description": "Boolean that if set to 1, user has requested ad tracking and measurement is disabled" + } + }, + "required": [ + "ifa", + "ifa_type", + "lmt" + ] + }, + "HDRFormatMap": { + "title": "HDRFormatMap", + "type": "object", + "properties": { + "hdr10": { + "type": "boolean" + }, + "hdr10Plus": { + "type": "boolean" + }, + "dolbyVision": { + "type": "boolean" + }, + "hlg": { + "type": "boolean" + } + }, + "required": [ + "hdr10", + "hdr10Plus", + "dolbyVision", + "hlg" + ], + "description": "The type of HDR format" + }, + "DeviceClass": { + "title": "DeviceClass", + "type": "string", + "enum": [ + "ott", + "stb", + "tv" + ], + "description": "The type of device" + }, + "CloseType": { + "title": "CloseType", + "description": "The application close type", + "type": "string", + "enum": [ + "deactivate", + "unload", + "killReload", + "killReactivate" + ] + }, + "LifecycleState": { + "title": "LifecycleState", + "description": "The application Lifecycle state", + "type": "string", + "enum": [ + "initializing", + "active", + "paused", + "suspended", + "hibernated", + "terminating" + ] + }, + "StateChange": { + "title": "StateChange", + "type": "object", + "properties": { + "newState": { + "$ref": "#/components/schemas/LifecycleState" + }, + "oldState": { + "$ref": "#/components/schemas/LifecycleState" + } + } + }, + "MediaPosition": { + "title": "MediaPosition", + "description": "Represents a position inside playback content, as a decimal percentage (0-0.999) for content with a known duration, or an integer number of seconds (0-86400) for content with an unknown duration.", + "oneOf": [ + { + "const": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + { + "type": "integer", + "minimum": 1, + "maximum": 86400 + } + ] + }, + "ErrorType": { + "title": "ErrorType", + "type": "string", + "enum": [ + "network", + "media", + "restriction", + "entitlement", + "other" + ] + }, + "EventObjectPrimitives": { + "title": "EventObjectPrimitives", + "anyOf": [ + { + "type": "string", + "maxLength": 256 + }, + { + "type": "number" + }, + { + "type": "integer" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "Connected": { + "type": "boolean", + "description": "Indicates whether the device currently has a usable network connection." + }, + "MemoryUsage": { + "title": "MemoryUsage", + "type": "object", + "description": "Describes current and maximum memory usage of the container.", + "properties": { + "userMemoryUsedKiB": { + "type": "integer", + "description": "User memory currently used in 1024 bytes." + }, + "userMemoryLimitKiB": { + "type": "integer", + "description": "Maximum user memory available in 1024 bytes." + }, + "gpuMemoryUsedKiB": { + "type": "integer", + "description": "GPU memory currently used in 1024 bytes." + }, + "gpuMemoryLimitKiB": { + "type": "integer", + "description": "Maximum GPU memory available in 1024 bytes." + } + }, + "required": [ + "userMemoryUsedKiB", + "userMemoryLimitKiB", + "gpuMemoryUsedKiB", + "gpuMemoryLimitKiB" + ] + }, + "TTSEnabled": { + "title": "TTSEnabled", + "type": "object", + "required": [ + "TTS_Status", + "isenabled" + ], + "properties": { + "TTS_Status": { + "$ref": "#/components/schemas/TTSStatus" + }, + "isenabled": { + "type": "boolean" + } + } + }, + "ListVoicesResponse": { + "title": "ListVoicesResponse", + "type": "object", + "required": [ + "TTS_Status", + "voices" + ], + "properties": { + "TTS_Status": { + "$ref": "#/components/schemas/TTSStatus" + }, + "voices": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "TTSConfiguration": { + "title": "TTSConfiguration", + "type": "object", + "required": [ + "success" + ], + "properties": { + "success": { + "type": "boolean" + }, + "ttsendpoint": { + "type": "string", + "description": "URL for Text to Speech API" + }, + "ttsendpointsecured": { + "type": "string", + "description": "Secure URL for Text to Speech API" + }, + "language": { + "type": "string", + "description": "Language used by Text to speech" + }, + "voice": { + "type": "string", + "description": "Voice used by Text to speech" + }, + "volume": { + "type": "integer", + "description": "Volume for Text to speech", + "minimum": 0, + "maximum": 100 + }, + "primvolduckpercent": { + "type": "integer", + "description": "Prime Volume duck percent for Text to speech", + "minimum": 0, + "maximum": 100 + }, + "rate": { + "type": "integer", + "description": "Speech rate for Text to speech", + "minimum": 0, + "maximum": 100 + }, + "speechrate": { + "description": "Rate for speech", + "$ref": "#/components/schemas/SpeechRate" + }, + "fallbacktext": { + "description": "Fallback text for TTS", + "$ref": "#/components/schemas/FallbackText" + } + }, + "examples": [ + {} + ] + }, + "SpeechRate": { + "title": "SpeechRate", + "type": "string", + "enum": [ + "slow", + "medium", + "fast", + "faster", + "fastest" + ] + }, + "FallbackText": { + "title": "FallbackText", + "type": "object", + "properties": { + "scenario": { + "type": "string", + "description": "Scenario for fallback Text" + }, + "value": { + "type": "string", + "description": "Value for fallback Text" + } + } + }, + "SpeechResponse": { + "title": "SpeechResponse", + "type": "object", + "properties": { + "speechid": { + "$ref": "#/components/schemas/SpeechId" + }, + "TTS_Status": { + "$ref": "#/components/schemas/TTSStatus" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "speechid", + "TTS_Status", + "success" + ] + }, + "SpeechId": { + "type": "integer" + }, + "SpeechIdEvent": { + "type": "object", + "properties": { + "speechid": { + "$ref": "#/components/schemas/SpeechId" + } + }, + "required": [ + "speechid" + ] + }, + "TTSStatus": { + "title": "TTSStatus", + "type": "integer", + "minimum": 0, + "maximum": 3 + }, + "SpeechState": { + "title": "SpeechState", + "type": "integer", + "enum": [ + 0, + 1, + 2, + 3 + ], + "description": "0 = SPEECH_PENDING, 1 = SPEECH_IN_PROGRESS, 2 = SPEECH_PAUSED, 3 = SPEECH_NOT_FOUND" + }, + "SpeechStateResponse": { + "title": "SpeechStateResponse", + "type": "object", + "properties": { + "speechstate": { + "$ref": "#/components/schemas/SpeechState" + }, + "TTS_Status": { + "$ref": "#/components/schemas/TTSStatus" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "speechstate", + "TTS_Status", + "success" + ] + }, + "TTSStatusResponse": { + "title": "TTSStatusResponse", + "type": "object", + "properties": { + "TTS_Status": { + "$ref": "#/components/schemas/TTSStatus" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "TTS_Status", + "success" + ] + }, + "TTSState": { + "title": "TTSState", + "type": "object", + "properties": { + "state": { + "type": "boolean" + } + }, + "required": [ + "state" + ] + }, + "TTSVoice": { + "title": "TTSVoice", + "type": "object", + "properties": { + "voice": { + "type": "string" + } + }, + "required": [ + "voice" + ] + } + } + }, + "x-schemas": { + "Accessibility": { + "uri": "https://meta.comcast.com/firebolt/accessibility", + "ClosedCaptionsSettings": { + "title": "ClosedCaptionsSettings", + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether or not closed-captions should be enabled by default" + }, + "preferredLanguages": { + "type": "array", + "items": { + "$ref": "#/x-schemas/Localization/ISO639_2Language" + } + } + }, + "examples": [ + { + "enabled": true, + "styles": { + "fontFamily": "monospaced_serif", + "fontSize": 1, + "fontColor": "#ffffff", + "fontEdge": "none", + "fontEdgeColor": "#7F7F7F", + "fontOpacity": 100, + "backgroundColor": "#000000", + "backgroundOpacity": 100, + "textAlign": "center", + "textAlignVertical": "middle", + "windowColor": "white", + "windowOpacity": 50 + }, + "preferredLanguages": [ + "eng", + "spa" + ] + } + ] + }, + "VoiceGuidanceSettings": { + "title": "VoiceGuidanceSettings", + "type": "object", + "required": [ + "enabled", + "navigationHints", + "rate" + ], + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether or not voice guidance should be enabled by default" + }, + "rate": { + "$ref": "#/x-schemas/Accessibility/SpeechRate", + "description": "The rate at which voice guidance speech will be read back to the user" + }, + "navigationHints": { + "type": "boolean", + "description": "Whether or not voice guidance should include additional navigation hints" + } + }, + "examples": [ + { + "enabled": true, + "navigationHints": true, + "rate": 0.8 + } + ] + }, + "SpeechRate": { + "title": "SpeechRate", + "type": "number", + "minimum": 0.1, + "maximum": 10 + } + }, + "Localization": { + "uri": "https://meta.comcast.com/firebolt/localization", + "ISO639_2Language": { + "type": "string", + "pattern": "^[a-z]{3}$" + }, + "CountryCode": { + "type": "string", + "pattern": "^[A-Z]{2}$" + }, + "Locale": { + "type": "string", + "pattern": "^[a-zA-Z]+([a-zA-Z0-9\\-]*)$" + } + }, + "Policies": { + "uri": "https://meta.comcast.com/firebolt/policies", + "AgePolicy": { + "title": "AgePolicy", + "description": "The policy that describes various age groups to which content is directed. See distributor documentation for further details.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "string", + "enum": [ + "app:adult", + "app:child", + "app:teen" + ] + } + ] + } + }, + "Types": { + "uri": "https://meta.comcast.com/firebolt/types", + "FlatMap": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + } + } + } +} \ No newline at end of file From 63604b09f2af9489d8d08277d53fd4c70e9e4afb Mon Sep 17 00:00:00 2001 From: bobra200 Date: Tue, 26 May 2026 14:55:21 -0700 Subject: [PATCH 04/37] feat: actions.intent() and related eventing --- README.md | 24 +++++ build.sh | 9 +- include/firebolt/actions.h | 34 +++++++ include/firebolt/firebolt.h | 8 ++ lint.sh | 195 ++++++++++++++++++++++++++++++++++++ run-all-test.sh | 151 ++++++++++++++++++++++++++++ run-component-tests.sh | 98 ++++++++++++++++++ run-unit-tests.sh | 98 ++++++++++++++++++ setup-device-tunnel.sh | 119 ++++++++++++++++++++++ src/actions_impl.cpp | 39 ++++++++ src/actions_impl.h | 33 ++++++ src/firebolt.cpp | 5 + src/json_types/actions.h | 17 ++++ test/CMakeLists.txt | 2 +- test/ComponentTestsMain.cpp | 5 +- test/unit/actionsTest.cpp | 60 +++++++++++ 16 files changed, 892 insertions(+), 5 deletions(-) create mode 100644 include/firebolt/actions.h create mode 100755 lint.sh create mode 100755 run-all-test.sh create mode 100755 run-component-tests.sh create mode 100755 run-unit-tests.sh create mode 100755 setup-device-tunnel.sh create mode 100644 src/actions_impl.cpp create mode 100644 src/actions_impl.h create mode 100644 src/json_types/actions.h create mode 100644 test/unit/actionsTest.cpp diff --git a/README.md b/README.md index 5af09fa..b6289a6 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,27 @@ Implementation of Firebolt C++ Client. For usage instructions of the API test application, see: - [test/api_test_app/README.md](test/api_test_app/README.md) + +## Test Runner + +Use `run-all-test.sh` to build and run unit/component tests locally. + +Examples: + +- `./run-all-test.sh` +- `./run-unit-tests.sh --unit-filter "ActionsUTest.*"` +- `./run-component-tests.sh --component-filter "*Localization*"` + +For the device websocket tunnel, use `setup-device-tunnel.sh`. +Before running it, export `DEVICE_SSH_USER`, `DEVICE_SSH_HOST`, and `DEVICE_SSH_PORT`. + +## Lint + +Use `lint.sh` to run local static analysis for C/C++ sources. + +Examples: + +- `./lint.sh` +- `./lint.sh --tidy-only` +- `./lint.sh --tidy-only --fix` +- `./lint.sh --cppcheck-only` diff --git a/build.sh b/build.sh index 3b1f1c7..3482ffd 100755 --- a/build.sh +++ b/build.sh @@ -51,8 +51,12 @@ while [[ ! -z $1 ]]; do esac; shift done -[[ ! -z $SYSROOT_PATH ]] || { echo "SYSROOT_PATH not set" >/dev/stderr; exit 1; } -[[ -e $SYSROOT_PATH ]] || { echo "SYSROOT_PATH not exist ($SYSROOT_PATH)" >/dev/stderr; exit 1; } +if [[ -n "$SYSROOT_PATH" ]]; then + [[ -e "$SYSROOT_PATH" ]] || { echo "SYSROOT_PATH not exist ($SYSROOT_PATH)" >/dev/stderr; exit 1; } + params+=" -DSYSROOT_PATH=$SYSROOT_PATH" +else + echo "SYSROOT_PATH not set; building without SYSROOT_PATH override" +fi $cleanFirst && rm -rf $bdir @@ -61,7 +65,6 @@ if [[ ! -e "$bdir" || -n "$@" ]]; then command -v ccache >/dev/null 2>&1 && params+=" -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache" cmake -B $bdir \ -DCMAKE_BUILD_TYPE=$buildType \ - -DSYSROOT_PATH=$SYSROOT_PATH \ $params \ "$@" || exit $? fi diff --git a/include/firebolt/actions.h b/include/firebolt/actions.h new file mode 100644 index 0000000..6d047b5 --- /dev/null +++ b/include/firebolt/actions.h @@ -0,0 +1,34 @@ +// ============================================================================ +// AUTO-GENERATED by fb-gen — DO NOT EDIT +// ============================================================================ +#ifndef FIREBOLT_ACTIONS_H +#define FIREBOLT_ACTIONS_H + +#include +#include +#include +#include +#include +#include + +namespace Firebolt::Actions { + +class IActions { +public: + virtual ~IActions() = default; + + virtual Result intent() const = 0; + + virtual Result subscribeOnIntent(std::function&& notification) = 0; + + virtual Result unsubscribe(SubscriptionId id) = 0; + virtual void unsubscribeAll() = 0; + + // Factory + static IActions* create(); + +}; // class IActions + +} // namespace Firebolt::Actions + +#endif // FIREBOLT_ACTIONS_H diff --git a/include/firebolt/firebolt.h b/include/firebolt/firebolt.h index f51a7fd..003414e 100644 --- a/include/firebolt/firebolt.h +++ b/include/firebolt/firebolt.h @@ -20,6 +20,7 @@ #include "firebolt/accessibility.h" #include "firebolt/advertising.h" +#include "firebolt/actions.h" #include "firebolt/client_export.h" #include "firebolt/device.h" #include "firebolt/discovery.h" @@ -92,6 +93,13 @@ class FIREBOLTCLIENT_EXPORT IFireboltAccessor */ virtual Advertising::IAdvertising& AdvertisingInterface() = 0; + /** + * @brief Returns instance of Actions interface + * + * @return Reference to Actions interface + */ + virtual Actions::IActions& ActionsInterface() = 0; + /** * @brief Returns instance of Device interface * diff --git a/lint.sh b/lint.sh new file mode 100755 index 0000000..f0b4768 --- /dev/null +++ b/lint.sh @@ -0,0 +1,195 @@ +#!/usr/bin/env bash + +# Copyright 2026 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 + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BUILD_DIR="build-dev" +NO_BUILD=false +CLEAN=false +RUN_CLANG_TIDY=true +RUN_CPPCHECK=true +APPLY_FIXES=false +CLANG_TIDY_PATHS=(src include test/unit test/component) + +usage() { + cat < Build directory containing compile_commands.json (default: build-dev) + --tidy-path

Add path for clang-tidy scan (repeatable) + --fix Apply clang-tidy fix-its (clang-tidy only) + --tidy-only Run clang-tidy only + --cppcheck-only Run cppcheck only + --help Show this help + +Examples: + ./lint.sh + ./lint.sh --tidy-only + ./lint.sh --tidy-only --fix + ./lint.sh --tidy-path test/api_test_app + ./lint.sh --no-build --build-dir build-dev +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --clean) + CLEAN=true + ;; + --no-build) + NO_BUILD=true + ;; + --build-dir) + BUILD_DIR="${2:-}" + shift + ;; + --tidy-path) + CLANG_TIDY_PATHS+=("${2:-}") + shift + ;; + --fix) + APPLY_FIXES=true + ;; + --tidy-only) + RUN_CLANG_TIDY=true + RUN_CPPCHECK=false + ;; + --cppcheck-only) + RUN_CLANG_TIDY=false + RUN_CPPCHECK=true + ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + usage + exit 1 + ;; + esac + shift +done + +cd "$ROOT_DIR" + +if [[ "$RUN_CLANG_TIDY" == false && "$RUN_CPPCHECK" == false ]]; then + echo "Nothing to run: both clang-tidy and cppcheck are disabled." >&2 + exit 1 +fi + +if [[ "$APPLY_FIXES" == true && "$RUN_CLANG_TIDY" == false ]]; then + echo "--fix requires clang-tidy to be enabled (remove --cppcheck-only)." >&2 + exit 1 +fi + +if [[ "$RUN_CLANG_TIDY" == true ]] && ! command -v clang-tidy >/dev/null 2>&1; then + echo "clang-tidy not found. Install it (e.g. apt install clang-tidy)." >&2 + exit 1 +fi + +if [[ "$RUN_CPPCHECK" == true ]] && ! command -v cppcheck >/dev/null 2>&1; then + echo "cppcheck not found. Install it (e.g. apt install cppcheck)." >&2 + exit 1 +fi + +if [[ "$CLEAN" == true ]]; then + rm -rf "$BUILD_DIR" +fi + +if [[ "$NO_BUILD" == false ]]; then + ./build.sh +tests +fi + +if [[ ! -f "$BUILD_DIR/compile_commands.json" ]]; then + echo "Missing $BUILD_DIR/compile_commands.json. Run ./build.sh +tests first." >&2 + exit 1 +fi + +if [[ "$RUN_CLANG_TIDY" == true ]]; then + if [[ "$APPLY_FIXES" == true ]]; then + echo "[lint] Running clang-tidy with fixes enabled" + else + echo "[lint] Running clang-tidy" + fi + + existing_paths=() + for p in "${CLANG_TIDY_PATHS[@]}"; do + if [[ -e "$p" ]]; then + existing_paths+=("$p") + fi + done + + if [[ ${#existing_paths[@]} -eq 0 ]]; then + echo "No valid clang-tidy paths found." >&2 + exit 1 + fi + + mapfile -t source_files < <( + find "${existing_paths[@]}" -type f \( -name "*.c" -o -name "*.cc" -o -name "*.cpp" -o -name "*.cxx" \) | sort + ) + + if [[ ${#source_files[@]} -eq 0 ]]; then + echo "No C/C++ source files found for clang-tidy." >&2 + exit 1 + fi + + clang_tidy_failed=0 + total_files=${#source_files[@]} + index=0 + for f in "${source_files[@]}"; do + index=$((index + 1)) + echo "[lint][clang-tidy] ${index}/${total_files}: $f" + clang_tidy_cmd=(clang-tidy -p "$BUILD_DIR") + if [[ "$APPLY_FIXES" == true ]]; then + clang_tidy_cmd+=("-fix") + fi + clang_tidy_cmd+=("$f") + if ! "${clang_tidy_cmd[@]}"; then + clang_tidy_failed=1 + fi + done + + if [[ $clang_tidy_failed -ne 0 ]]; then + echo "clang-tidy reported issues." >&2 + exit 1 + fi +fi + +if [[ "$RUN_CPPCHECK" == true ]]; then + echo "[lint] Running cppcheck" + cppcheck \ + --enable=warning,style,performance,portability \ + --std=c++17 \ + --language=c++ \ + --inline-suppr \ + --error-exitcode=1 \ + -I include \ + -I src \ + src include test +fi + +echo "[lint] Completed successfully" diff --git a/run-all-test.sh b/run-all-test.sh new file mode 100755 index 0000000..028d7f9 --- /dev/null +++ b/run-all-test.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash + +# Copyright 2026 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 + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +RUN_UNIT=true +RUN_COMPONENT=true +BUILD_ONLY=false +CLEAN=false +UNIT_FILTER="" +COMPONENT_FILTER="" + +usage() { + cat < GTest filter passed to utApp + --component-filter GTest filter passed to ctApp + --help Show this help + +Examples: + ./run-all-test.sh + ./run-all-test.sh --unit-only --unit-filter "ActionsUTest.*" + ./run-all-test.sh --component-only --component-filter "*Localization*" +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --clean) + CLEAN=true + ;; + --build-only) + BUILD_ONLY=true + ;; + --unit-only) + RUN_COMPONENT=false + ;; + --component-only) + RUN_UNIT=false + ;; + --unit-filter) + UNIT_FILTER="${2:-}" + shift + ;; + --component-filter) + COMPONENT_FILTER="${2:-}" + shift + ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + usage + exit 1 + ;; + esac + shift +done + +if [[ "$RUN_UNIT" == false && "$RUN_COMPONENT" == false ]]; then + echo "Nothing to run: both unit and component test execution are disabled." >&2 + exit 1 +fi + +run_unit_script="$ROOT_DIR/run-unit-tests.sh" +run_component_script="$ROOT_DIR/run-component-tests.sh" + +bootstrap_args=() +if [[ "$CLEAN" == true ]]; then + bootstrap_args+=(--clean) +fi + +if [[ "$RUN_UNIT" == true && "$RUN_COMPONENT" == true ]]; then + echo "[run-all-test] Bootstrapping build once via run-unit-tests.sh --build-only" + "$run_unit_script" "${bootstrap_args[@]}" --build-only + + if [[ "$BUILD_ONLY" == true ]]; then + echo "Build complete. Skipping test execution (--build-only)." + exit 0 + fi + + unit_args=(--no-build) + if [[ -n "$UNIT_FILTER" ]]; then + unit_args+=(--unit-filter "$UNIT_FILTER") + fi + echo "[run-all-test] Running unit tests via run-unit-tests.sh" + "$run_unit_script" "${unit_args[@]}" + + component_args=(--no-build) + if [[ -n "$COMPONENT_FILTER" ]]; then + component_args+=(--component-filter "$COMPONENT_FILTER") + fi + echo "[run-all-test] Running component tests via run-component-tests.sh" + "$run_component_script" "${component_args[@]}" + exit 0 +fi + +if [[ "$RUN_UNIT" == true ]]; then + unit_args=() + if [[ "$CLEAN" == true ]]; then + unit_args+=(--clean) + fi + if [[ "$BUILD_ONLY" == true ]]; then + unit_args+=(--build-only) + fi + if [[ -n "$UNIT_FILTER" ]]; then + unit_args+=(--unit-filter "$UNIT_FILTER") + fi + echo "[run-all-test] Delegating to run-unit-tests.sh" + "$run_unit_script" "${unit_args[@]}" + exit 0 +fi + +component_args=() +if [[ "$CLEAN" == true ]]; then + component_args+=(--clean) +fi +if [[ "$BUILD_ONLY" == true ]]; then + component_args+=(--build-only) +fi +if [[ -n "$COMPONENT_FILTER" ]]; then + component_args+=(--component-filter "$COMPONENT_FILTER") +fi +echo "[run-all-test] Delegating to run-component-tests.sh" +"$run_component_script" "${component_args[@]}" diff --git a/run-component-tests.sh b/run-component-tests.sh new file mode 100755 index 0000000..e3162be --- /dev/null +++ b/run-component-tests.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash + +# Copyright 2026 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 + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BUILD_DIR="build-dev" +BUILD_ONLY=false +NO_BUILD=false +CLEAN=false +COMPONENT_FILTER="" + +usage() { + cat < GTest filter passed to ctApp + --help Show this help + +Examples: + ./run-component-tests.sh + FIREBOLT_ENDPOINT=ws://127.0.0.1:3474/ ./run-component-tests.sh --component-filter "*Localization*" +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --clean) + CLEAN=true + ;; + --build-only) + BUILD_ONLY=true + ;; + --no-build) + NO_BUILD=true + ;; + --component-filter) + COMPONENT_FILTER="${2:-}" + shift + ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + usage + exit 1 + ;; + esac + shift +done + +cd "$ROOT_DIR" + +if [[ "$CLEAN" == true ]]; then + rm -rf "$BUILD_DIR" +fi + +if [[ "$NO_BUILD" == false ]]; then + ./build.sh +tests +fi + +if [[ "$BUILD_ONLY" == true ]]; then + echo "Build complete. Skipping test execution (--build-only)." + exit 0 +fi + +cd "$BUILD_DIR/test" +export LD_LIBRARY_PATH="../src:${LD_LIBRARY_PATH:-}" + +component_cmd=(./ctApp) +if [[ -n "$COMPONENT_FILTER" ]]; then + component_cmd+=("--gtest_filter=$COMPONENT_FILTER") +fi +echo "[run-component-tests] Running component tests: ${component_cmd[*]}" +"${component_cmd[@]}" \ No newline at end of file diff --git a/run-unit-tests.sh b/run-unit-tests.sh new file mode 100755 index 0000000..c2f2706 --- /dev/null +++ b/run-unit-tests.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash + +# Copyright 2026 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 + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BUILD_DIR="build-dev" +BUILD_ONLY=false +NO_BUILD=false +CLEAN=false +UNIT_FILTER="" + +usage() { + cat < GTest filter passed to utApp + --help Show this help + +Examples: + ./run-unit-tests.sh + ./run-unit-tests.sh --unit-filter "ActionsUTest.*" +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --clean) + CLEAN=true + ;; + --build-only) + BUILD_ONLY=true + ;; + --no-build) + NO_BUILD=true + ;; + --unit-filter) + UNIT_FILTER="${2:-}" + shift + ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + usage + exit 1 + ;; + esac + shift +done + +cd "$ROOT_DIR" + +if [[ "$CLEAN" == true ]]; then + rm -rf "$BUILD_DIR" +fi + +if [[ "$NO_BUILD" == false ]]; then + ./build.sh +tests +fi + +if [[ "$BUILD_ONLY" == true ]]; then + echo "Build complete. Skipping test execution (--build-only)." + exit 0 +fi + +cd "$BUILD_DIR/test" +export LD_LIBRARY_PATH="../src:${LD_LIBRARY_PATH:-}" + +unit_cmd=(./utApp) +if [[ -n "$UNIT_FILTER" ]]; then + unit_cmd+=("--gtest_filter=$UNIT_FILTER") +fi +echo "[run-unit-tests] Running unit tests: ${unit_cmd[*]}" +"${unit_cmd[@]}" \ No newline at end of file diff --git a/setup-device-tunnel.sh b/setup-device-tunnel.sh new file mode 100755 index 0000000..49927a7 --- /dev/null +++ b/setup-device-tunnel.sh @@ -0,0 +1,119 @@ +#!/usr/bin/env bash + +# Copyright 2026 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 + +set -euo pipefail + +LOCAL_PORT="3474" +REMOTE_PORT="3474" +REMOTE_BIND_ADDR="127.0.0.1" +BACKGROUND=false + +require_env() { + local name="$1" + local value="${!name:-}" + if [[ -z "$value" ]]; then + echo "Error: required environment variable $name is not set" >&2 + exit 1 + fi +} + +usage() { + cat < -> : on + +Required environment variables: + DEVICE_SSH_USER SSH username + DEVICE_SSH_HOST Remote SSH host + DEVICE_SSH_PORT SSH port + +Defaults: + local-port ${LOCAL_PORT} + remote-port ${REMOTE_PORT} + remote-bind-addr ${REMOTE_BIND_ADDR} + +Options: + --local-port Local forwarded port (default: ${LOCAL_PORT}) + --remote-port Remote websocket port (default: ${REMOTE_PORT}) + --remote-bind Remote bind address (default: ${REMOTE_BIND_ADDR}) + --background Run ssh tunnel in background + --help Show this help + +Examples: + export DEVICE_SSH_USER=root + export DEVICE_SSH_HOST=192.168.201.170 + export DEVICE_SSH_PORT=10022 + ./setup-device-tunnel.sh + +After tunnel is up, run component tests with: + FIREBOLT_ENDPOINT=ws://127.0.0.1:${LOCAL_PORT}/ ./run-component-tests.sh +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --local-port) + LOCAL_PORT="${2:-}" + shift + ;; + --remote-port) + REMOTE_PORT="${2:-}" + shift + ;; + --remote-bind) + REMOTE_BIND_ADDR="${2:-}" + shift + ;; + --background) + BACKGROUND=true + ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + usage + exit 1 + ;; + esac + shift +done + +require_env DEVICE_SSH_USER +require_env DEVICE_SSH_HOST +require_env DEVICE_SSH_PORT + +TARGET="${DEVICE_SSH_USER}@${DEVICE_SSH_HOST}" +FORWARD_SPEC="${LOCAL_PORT}:${REMOTE_BIND_ADDR}:${REMOTE_PORT}" +SSH_ARGS=(-N -o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ExitOnForwardFailure=yes -p "$DEVICE_SSH_PORT" -L "$FORWARD_SPEC" "$TARGET") + +echo "Opening SSH tunnel: localhost:${LOCAL_PORT} -> ${REMOTE_BIND_ADDR}:${REMOTE_PORT} on ${TARGET}" + +if [[ "$BACKGROUND" == true ]]; then + LOG_FILE="${TMPDIR:-/tmp}/firebolt-tunnel-${LOCAL_PORT}.log" + nohup ssh "${SSH_ARGS[@]}" >"$LOG_FILE" 2>&1 & + SSH_PID=$! + echo "Tunnel PID: ${SSH_PID}" + echo "Tunnel log: ${LOG_FILE}" + exit 0 +fi + +exec ssh "${SSH_ARGS[@]}" diff --git a/src/actions_impl.cpp b/src/actions_impl.cpp new file mode 100644 index 0000000..33d09e4 --- /dev/null +++ b/src/actions_impl.cpp @@ -0,0 +1,39 @@ +// ============================================================================ +// AUTO-GENERATED by fb-gen — DO NOT EDIT +// ============================================================================ +#include "actions_impl.h" +#include "json_types/actions.h" +#include +#include + +namespace Firebolt::Actions { + +ActionsImpl::ActionsImpl(Firebolt::Helpers::IHelper& helper) + : helper_(helper), + subscriptionManager_(helper, this) +{} + +Result ActionsImpl::intent() const { + return helper_.get("actions.intent"); +} + +Result ActionsImpl::subscribeOnIntent(std::function&& notification) +{ + return subscriptionManager_.subscribe("Actions.onIntent", std::move(notification)); +} + +Result ActionsImpl::unsubscribe(SubscriptionId id) +{ + return subscriptionManager_.unsubscribe(id); +} + +void ActionsImpl::unsubscribeAll() +{ + subscriptionManager_.unsubscribeAll(); +} + +IActions* IActions::create() { + return new ActionsImpl(Firebolt::Helpers::GetHelperInstance()); +} + +} // namespace Firebolt::Actions diff --git a/src/actions_impl.h b/src/actions_impl.h new file mode 100644 index 0000000..c561970 --- /dev/null +++ b/src/actions_impl.h @@ -0,0 +1,33 @@ +// ============================================================================ +// AUTO-GENERATED by fb-gen — DO NOT EDIT +// ============================================================================ +#ifndef FIREBOLT_ACTIONS_IMPL_H +#define FIREBOLT_ACTIONS_IMPL_H + +#include "firebolt/actions.h" +#include + +namespace Firebolt::Actions { + +class ActionsImpl : public IActions { +public: + explicit ActionsImpl(Firebolt::Helpers::IHelper& helper); + ActionsImpl(const ActionsImpl&) = delete; + ActionsImpl& operator=(const ActionsImpl&) = delete; + ~ActionsImpl() override = default; + + Result intent() const override; + + Result subscribeOnIntent(std::function&& notification) override; + + Result unsubscribe(SubscriptionId id) override; + void unsubscribeAll() override; + +private: + Firebolt::Helpers::IHelper& helper_; + Firebolt::Helpers::SubscriptionManager subscriptionManager_; +}; + +} // namespace Firebolt::Actions + +#endif // FIREBOLT_ACTIONS_IMPL_H diff --git a/src/firebolt.cpp b/src/firebolt.cpp index ba0470c..48ec277 100644 --- a/src/firebolt.cpp +++ b/src/firebolt.cpp @@ -19,6 +19,7 @@ #include "firebolt/firebolt.h" #include "accessibility_impl.h" #include "advertising_impl.h" +#include "actions_impl.h" #include "device_impl.h" #include "discovery_impl.h" #include "display_impl.h" @@ -40,6 +41,7 @@ class FireboltAccessorImpl : public IFireboltAccessor FireboltAccessorImpl() : accessibility_(Firebolt::Helpers::GetHelperInstance()), advertising_(Firebolt::Helpers::GetHelperInstance()), + actions_(Firebolt::Helpers::GetHelperInstance()), device_(Firebolt::Helpers::GetHelperInstance()), discovery_(Firebolt::Helpers::GetHelperInstance()), display_(Firebolt::Helpers::GetHelperInstance()), @@ -73,6 +75,7 @@ class FireboltAccessorImpl : public IFireboltAccessor Accessibility::IAccessibility& AccessibilityInterface() override { return accessibility_; } Advertising::IAdvertising& AdvertisingInterface() override { return advertising_; } + Actions::IActions& ActionsInterface() override { return actions_; } Device::IDevice& DeviceInterface() override { return device_; } Discovery::IDiscovery& DiscoveryInterface() override { return discovery_; } Display::IDisplay& DisplayInterface() override { return display_; } @@ -88,6 +91,7 @@ class FireboltAccessorImpl : public IFireboltAccessor void unsubscribeAll() { accessibility_.unsubscribeAll(); + actions_.unsubscribeAll(); lifecycle_.unsubscribeAll(); localization_.unsubscribeAll(); network_.unsubscribeAll(); @@ -98,6 +102,7 @@ class FireboltAccessorImpl : public IFireboltAccessor private: Accessibility::AccessibilityImpl accessibility_; Advertising::AdvertisingImpl advertising_; + Actions::ActionsImpl actions_; Device::DeviceImpl device_; Discovery::DiscoveryImpl discovery_; Display::DisplayImpl display_; diff --git a/src/json_types/actions.h b/src/json_types/actions.h new file mode 100644 index 0000000..e8d71b1 --- /dev/null +++ b/src/json_types/actions.h @@ -0,0 +1,17 @@ +// ============================================================================ +// AUTO-GENERATED by fb-gen — DO NOT EDIT +// ============================================================================ +#ifndef FIREBOLT_ACTIONS_JSON_H +#define FIREBOLT_ACTIONS_JSON_H + +#pragma once +#include +#include +#include +#include "firebolt/actions.h" + +namespace Firebolt::Actions { + +} // namespace Firebolt::Actions + +#endif // FIREBOLT_ACTIONS_JSON_H diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9b60ab9..a27713b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -22,7 +22,7 @@ include(GoogleTest) enable_testing() -add_compile_definitions(UT_OPEN_RPC_FILE="firebolt-open-rpc.json") +add_compile_definitions(UT_OPEN_RPC_FILE="${CMAKE_SOURCE_DIR}/docs/openrpc/the-spec/firebolt-open-rpc.json") set(UNIT_TESTS_APP utApp) diff --git a/test/ComponentTestsMain.cpp b/test/ComponentTestsMain.cpp index 0346a2b..dd58c01 100644 --- a/test/ComponentTestsMain.cpp +++ b/test/ComponentTestsMain.cpp @@ -18,6 +18,7 @@ #include "firebolt/firebolt.h" #include "gtest/gtest.h" +#include #include #include #include @@ -68,7 +69,9 @@ bool waitOnConnectionReady() int main(int argc, char** argv) { - string url = "ws://127.0.0.1:9998/"; + const char* endpoint = std::getenv("FIREBOLT_ENDPOINT"); + string url = (endpoint && endpoint[0] != '\0') ? endpoint : "ws://127.0.0.1:3474/"; + cout << "Using Firebolt endpoint: " << url << endl; createFireboltInstance(url); std::this_thread::sleep_for(std::chrono::seconds(1)); diff --git a/test/unit/actionsTest.cpp b/test/unit/actionsTest.cpp new file mode 100644 index 0000000..1eafe27 --- /dev/null +++ b/test/unit/actionsTest.cpp @@ -0,0 +1,60 @@ +/** + * Copyright 2025 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 + */ + +#include "json_engine.h" +#include "mock_helper.h" +#include "actions_impl.h" + +class ActionsUTest : public ::testing::Test, protected MockBase +{ +protected: + Firebolt::Actions::ActionsImpl actionsImpl_{mockHelper}; +}; + +TEST_F(ActionsUTest, Intent) +{ + const std::string expectedValue = "{\"intent\":\"launch\"}"; + mock_with_response("actions.intent", expectedValue); + + auto result = actionsImpl_.intent(); + + ASSERT_TRUE(result) << "ActionsImpl::intent() returned an error"; + EXPECT_EQ(*result, expectedValue); +} + +TEST_F(ActionsUTest, IntentBadResponse) +{ + mock_with_response("actions.intent", true); + + auto result = actionsImpl_.intent(); + + ASSERT_FALSE(result) << "ActionsImpl::intent() did not return an error"; +} + +TEST_F(ActionsUTest, SubscribeOnIntent) +{ + nlohmann::json expectedValue = 1; + mockSubscribe("Actions.onIntent"); + + auto result = actionsImpl_.subscribeOnIntent([&](const std::string& /*value*/) {}); + + ASSERT_TRUE(result) << "ActionsImpl::subscribeOnIntent() returned an error"; + EXPECT_EQ(*result, expectedValue); + + actionsImpl_.unsubscribe(*result); +} From d1c7f4c44e95618a1c501a5f3c5d7f7608675a55 Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 27 May 2026 09:07:56 -0700 Subject: [PATCH 05/37] fix: copilot feedback on bad accessor --- include/firebolt/actions.h | 8 ++-- src/actions_impl.cpp | 23 ++++------ src/actions_impl.h | 4 +- test/component/actionsGeneratedTest.cpp | 29 +++++++++++++ test/unit/actionsGeneratedTest.cpp | 57 +++++++++++++++++++++++++ test/unit/actionsTest.cpp | 30 ++++++------- 6 files changed, 112 insertions(+), 39 deletions(-) create mode 100644 test/component/actionsGeneratedTest.cpp create mode 100644 test/unit/actionsGeneratedTest.cpp diff --git a/include/firebolt/actions.h b/include/firebolt/actions.h index 6d047b5..613d840 100644 --- a/include/firebolt/actions.h +++ b/include/firebolt/actions.h @@ -17,16 +17,16 @@ class IActions { public: virtual ~IActions() = default; - virtual Result intent() const = 0; + virtual Result start(const std::string& intent) const = 0; virtual Result subscribeOnIntent(std::function&& notification) = 0; + virtual Result subscribeOnIntentChanged(std::function&& notification) { + return subscribeOnIntent(std::move(notification)); + } virtual Result unsubscribe(SubscriptionId id) = 0; virtual void unsubscribeAll() = 0; - // Factory - static IActions* create(); - }; // class IActions } // namespace Firebolt::Actions diff --git a/src/actions_impl.cpp b/src/actions_impl.cpp index 33d09e4..7d04bc4 100644 --- a/src/actions_impl.cpp +++ b/src/actions_impl.cpp @@ -9,31 +9,26 @@ namespace Firebolt::Actions { ActionsImpl::ActionsImpl(Firebolt::Helpers::IHelper& helper) - : helper_(helper), - subscriptionManager_(helper, this) + : helper_(helper) + , subscriptionManager_(helper, this) {} -Result ActionsImpl::intent() const { - return helper_.get("actions.intent"); +Result ActionsImpl::start(const std::string& intent) const { + nlohmann::json params; + params["intent"] = intent; + return helper_.invoke("Actions.start", params); } -Result ActionsImpl::subscribeOnIntent(std::function&& notification) -{ +Result ActionsImpl::subscribeOnIntent(std::function&& notification) { return subscriptionManager_.subscribe("Actions.onIntent", std::move(notification)); } -Result ActionsImpl::unsubscribe(SubscriptionId id) -{ +Result ActionsImpl::unsubscribe(SubscriptionId id) { return subscriptionManager_.unsubscribe(id); } -void ActionsImpl::unsubscribeAll() -{ +void ActionsImpl::unsubscribeAll() { subscriptionManager_.unsubscribeAll(); } -IActions* IActions::create() { - return new ActionsImpl(Firebolt::Helpers::GetHelperInstance()); -} - } // namespace Firebolt::Actions diff --git a/src/actions_impl.h b/src/actions_impl.h index c561970..e259cfb 100644 --- a/src/actions_impl.h +++ b/src/actions_impl.h @@ -12,11 +12,9 @@ namespace Firebolt::Actions { class ActionsImpl : public IActions { public: explicit ActionsImpl(Firebolt::Helpers::IHelper& helper); - ActionsImpl(const ActionsImpl&) = delete; - ActionsImpl& operator=(const ActionsImpl&) = delete; ~ActionsImpl() override = default; - Result intent() const override; + Result start(const std::string& intent) const override; Result subscribeOnIntent(std::function&& notification) override; diff --git a/test/component/actionsGeneratedTest.cpp b/test/component/actionsGeneratedTest.cpp new file mode 100644 index 0000000..39f86ea --- /dev/null +++ b/test/component/actionsGeneratedTest.cpp @@ -0,0 +1,29 @@ +/** + * Copyright 2026 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 + */ + +#include "firebolt/actions.h" +#include + +TEST(ActionsGeneratedCTest, InterfaceSurfaceHasstart) +{ + using Interface = Firebolt::Actions::IActions; + auto ptr = &Interface::start; + (void)ptr; + SUCCEED(); +} + diff --git a/test/unit/actionsGeneratedTest.cpp b/test/unit/actionsGeneratedTest.cpp new file mode 100644 index 0000000..634c663 --- /dev/null +++ b/test/unit/actionsGeneratedTest.cpp @@ -0,0 +1,57 @@ +/** + * Copyright 2026 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 + */ + +#include "mock_helper.h" +#include "actions_impl.h" +#include + +class ActionsGeneratedUTest : public ::testing::Test +{ +protected: + ::testing::NiceMock mockHelper; + Firebolt::Actions::ActionsImpl impl{mockHelper}; +}; + +TEST_F(ActionsGeneratedUTest, Constructs) +{ + SUCCEED(); +} + +TEST_F(ActionsGeneratedUTest, UnsubscribeForwardsToHelper) +{ + EXPECT_CALL(mockHelper, unsubscribe(7)) + .WillOnce(::testing::Return(Firebolt::Result{Firebolt::Error::None})); + + auto result = impl.unsubscribe(7); + ASSERT_TRUE(result) << "unsubscribe should return success when helper succeeds"; +} + + +TEST_F(ActionsGeneratedUTest, ForwardsstartTransportErrors) +{ + EXPECT_CALL(mockHelper, invoke("Actions.start", ::testing::_)) + .WillOnce(::testing::Invoke([](const std::string& /*method*/, const nlohmann::json& params) { + EXPECT_TRUE(params.is_object()) << "Expected params object for method call"; + EXPECT_TRUE(params.contains("intent")) << "Missing expected param key: intent"; + return Firebolt::Result{Firebolt::Error::General}; + })); + + auto result = impl.start({}); + EXPECT_FALSE(result) << "Expected error propagation when helper invoke fails"; +} + diff --git a/test/unit/actionsTest.cpp b/test/unit/actionsTest.cpp index 1eafe27..b457e23 100644 --- a/test/unit/actionsTest.cpp +++ b/test/unit/actionsTest.cpp @@ -26,24 +26,16 @@ class ActionsUTest : public ::testing::Test, protected MockBase Firebolt::Actions::ActionsImpl actionsImpl_{mockHelper}; }; -TEST_F(ActionsUTest, Intent) +TEST_F(ActionsUTest, Start) { - const std::string expectedValue = "{\"intent\":\"launch\"}"; - mock_with_response("actions.intent", expectedValue); - - auto result = actionsImpl_.intent(); - - ASSERT_TRUE(result) << "ActionsImpl::intent() returned an error"; - EXPECT_EQ(*result, expectedValue); -} - -TEST_F(ActionsUTest, IntentBadResponse) -{ - mock_with_response("actions.intent", true); - - auto result = actionsImpl_.intent(); - - ASSERT_FALSE(result) << "ActionsImpl::intent() did not return an error"; + nlohmann::json expectedParams; + expectedParams["intent"] = "launch"; + EXPECT_CALL(mockHelper, invoke("Actions.start", expectedParams)) + .WillOnce(Invoke([&](const std::string& /*methodName*/, const nlohmann::json& /*parameters*/) + { return Firebolt::Result{Firebolt::Error::None}; })); + + auto result = actionsImpl_.start("launch"); + EXPECT_TRUE(result); } TEST_F(ActionsUTest, SubscribeOnIntent) @@ -56,5 +48,7 @@ TEST_F(ActionsUTest, SubscribeOnIntent) ASSERT_TRUE(result) << "ActionsImpl::subscribeOnIntent() returned an error"; EXPECT_EQ(*result, expectedValue); - actionsImpl_.unsubscribe(*result); + auto unsubResult = actionsImpl_.unsubscribe(*result); + ASSERT_TRUE(unsubResult) << "ActionsImpl::unsubscribe() returned an error"; } + From 87dc59c186720bbe53c1b06c6920ef4009fa6445 Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 27 May 2026 13:35:10 -0700 Subject: [PATCH 06/37] chore(actions): regenerate json_types with JsonData namespace --- src/json_types/actions.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/json_types/actions.h b/src/json_types/actions.h index e8d71b1..066e915 100644 --- a/src/json_types/actions.h +++ b/src/json_types/actions.h @@ -12,6 +12,10 @@ namespace Firebolt::Actions { +namespace JsonData { + +} // namespace JsonData + } // namespace Firebolt::Actions #endif // FIREBOLT_ACTIONS_JSON_H From a201befba2664ee8d34b7061f5c326aee82d83ee Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 27 May 2026 13:47:44 -0700 Subject: [PATCH 07/37] fix(scripts): validate option args and guard install without sysroot --- build.sh | 5 +++++ lint.sh | 10 ++++++++++ run-all-test.sh | 10 ++++++++++ run-component-tests.sh | 5 +++++ run-unit-tests.sh | 5 +++++ setup-device-tunnel.sh | 15 +++++++++++++++ 6 files changed, 50 insertions(+) diff --git a/build.sh b/build.sh index 3482ffd..c155223 100755 --- a/build.sh +++ b/build.sh @@ -58,6 +58,11 @@ else echo "SYSROOT_PATH not set; building without SYSROOT_PATH override" fi +if [[ "$do_install" == true && "$bdir" == "build" && -z "${SYSROOT_PATH:-}" ]]; then + echo "Refusing --install without --sysroot to avoid host install into /usr" >&2 + exit 1 +fi + $cleanFirst && rm -rf $bdir if [[ ! -e "$bdir" || -n "$@" ]]; then diff --git a/lint.sh b/lint.sh index f0b4768..999560a 100755 --- a/lint.sh +++ b/lint.sh @@ -63,10 +63,20 @@ while [[ $# -gt 0 ]]; do NO_BUILD=true ;; --build-dir) + if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + echo "Missing value for --build-dir" >&2 + usage + exit 1 + fi BUILD_DIR="${2:-}" shift ;; --tidy-path) + if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + echo "Missing value for --tidy-path" >&2 + usage + exit 1 + fi CLANG_TIDY_PATHS+=("${2:-}") shift ;; diff --git a/run-all-test.sh b/run-all-test.sh index 028d7f9..d8e9cdc 100755 --- a/run-all-test.sh +++ b/run-all-test.sh @@ -63,10 +63,20 @@ while [[ $# -gt 0 ]]; do RUN_UNIT=false ;; --unit-filter) + if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + echo "Missing value for --unit-filter" >&2 + usage + exit 1 + fi UNIT_FILTER="${2:-}" shift ;; --component-filter) + if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + echo "Missing value for --component-filter" >&2 + usage + exit 1 + fi COMPONENT_FILTER="${2:-}" shift ;; diff --git a/run-component-tests.sh b/run-component-tests.sh index e3162be..e1615bb 100755 --- a/run-component-tests.sh +++ b/run-component-tests.sh @@ -56,6 +56,11 @@ while [[ $# -gt 0 ]]; do NO_BUILD=true ;; --component-filter) + if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + echo "Missing value for --component-filter" >&2 + usage + exit 1 + fi COMPONENT_FILTER="${2:-}" shift ;; diff --git a/run-unit-tests.sh b/run-unit-tests.sh index c2f2706..c7ba317 100755 --- a/run-unit-tests.sh +++ b/run-unit-tests.sh @@ -56,6 +56,11 @@ while [[ $# -gt 0 ]]; do NO_BUILD=true ;; --unit-filter) + if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + echo "Missing value for --unit-filter" >&2 + usage + exit 1 + fi UNIT_FILTER="${2:-}" shift ;; diff --git a/setup-device-tunnel.sh b/setup-device-tunnel.sh index 49927a7..73a3e43 100755 --- a/setup-device-tunnel.sh +++ b/setup-device-tunnel.sh @@ -70,14 +70,29 @@ EOF while [[ $# -gt 0 ]]; do case "$1" in --local-port) + if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + echo "Missing value for --local-port" >&2 + usage + exit 1 + fi LOCAL_PORT="${2:-}" shift ;; --remote-port) + if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + echo "Missing value for --remote-port" >&2 + usage + exit 1 + fi REMOTE_PORT="${2:-}" shift ;; --remote-bind) + if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + echo "Missing value for --remote-bind" >&2 + usage + exit 1 + fi REMOTE_BIND_ADDR="${2:-}" shift ;; From 2a7e03cbffae841050bfce9343e4885c5c116b57 Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 27 May 2026 14:15:54 -0700 Subject: [PATCH 08/37] feat(actions): rename start API to intent --- include/firebolt/actions.h | 2 +- src/actions_impl.cpp | 4 ++-- src/actions_impl.h | 2 +- test/component/actionsGeneratedTest.cpp | 4 ++-- test/unit/actionsGeneratedTest.cpp | 6 +++--- test/unit/actionsTest.cpp | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/firebolt/actions.h b/include/firebolt/actions.h index 613d840..4c5a8ec 100644 --- a/include/firebolt/actions.h +++ b/include/firebolt/actions.h @@ -17,7 +17,7 @@ class IActions { public: virtual ~IActions() = default; - virtual Result start(const std::string& intent) const = 0; + virtual Result intent(const std::string& intent) const = 0; virtual Result subscribeOnIntent(std::function&& notification) = 0; virtual Result subscribeOnIntentChanged(std::function&& notification) { diff --git a/src/actions_impl.cpp b/src/actions_impl.cpp index 7d04bc4..1c95da8 100644 --- a/src/actions_impl.cpp +++ b/src/actions_impl.cpp @@ -13,10 +13,10 @@ ActionsImpl::ActionsImpl(Firebolt::Helpers::IHelper& helper) , subscriptionManager_(helper, this) {} -Result ActionsImpl::start(const std::string& intent) const { +Result ActionsImpl::intent(const std::string& intent) const { nlohmann::json params; params["intent"] = intent; - return helper_.invoke("Actions.start", params); + return helper_.invoke("Actions.intent", params); } Result ActionsImpl::subscribeOnIntent(std::function&& notification) { diff --git a/src/actions_impl.h b/src/actions_impl.h index e259cfb..989c3a9 100644 --- a/src/actions_impl.h +++ b/src/actions_impl.h @@ -14,7 +14,7 @@ class ActionsImpl : public IActions { explicit ActionsImpl(Firebolt::Helpers::IHelper& helper); ~ActionsImpl() override = default; - Result start(const std::string& intent) const override; + Result intent(const std::string& intent) const override; Result subscribeOnIntent(std::function&& notification) override; diff --git a/test/component/actionsGeneratedTest.cpp b/test/component/actionsGeneratedTest.cpp index 39f86ea..a08372b 100644 --- a/test/component/actionsGeneratedTest.cpp +++ b/test/component/actionsGeneratedTest.cpp @@ -19,10 +19,10 @@ #include "firebolt/actions.h" #include -TEST(ActionsGeneratedCTest, InterfaceSurfaceHasstart) +TEST(ActionsGeneratedCTest, InterfaceSurfaceHasintent) { using Interface = Firebolt::Actions::IActions; - auto ptr = &Interface::start; + auto ptr = &Interface::intent; (void)ptr; SUCCEED(); } diff --git a/test/unit/actionsGeneratedTest.cpp b/test/unit/actionsGeneratedTest.cpp index 634c663..4c0b71e 100644 --- a/test/unit/actionsGeneratedTest.cpp +++ b/test/unit/actionsGeneratedTest.cpp @@ -42,16 +42,16 @@ TEST_F(ActionsGeneratedUTest, UnsubscribeForwardsToHelper) } -TEST_F(ActionsGeneratedUTest, ForwardsstartTransportErrors) +TEST_F(ActionsGeneratedUTest, ForwardsintentTransportErrors) { - EXPECT_CALL(mockHelper, invoke("Actions.start", ::testing::_)) + EXPECT_CALL(mockHelper, invoke("Actions.intent", ::testing::_)) .WillOnce(::testing::Invoke([](const std::string& /*method*/, const nlohmann::json& params) { EXPECT_TRUE(params.is_object()) << "Expected params object for method call"; EXPECT_TRUE(params.contains("intent")) << "Missing expected param key: intent"; return Firebolt::Result{Firebolt::Error::General}; })); - auto result = impl.start({}); + auto result = impl.intent({}); EXPECT_FALSE(result) << "Expected error propagation when helper invoke fails"; } diff --git a/test/unit/actionsTest.cpp b/test/unit/actionsTest.cpp index b457e23..7444bd1 100644 --- a/test/unit/actionsTest.cpp +++ b/test/unit/actionsTest.cpp @@ -30,11 +30,11 @@ TEST_F(ActionsUTest, Start) { nlohmann::json expectedParams; expectedParams["intent"] = "launch"; - EXPECT_CALL(mockHelper, invoke("Actions.start", expectedParams)) + EXPECT_CALL(mockHelper, invoke("Actions.intent", expectedParams)) .WillOnce(Invoke([&](const std::string& /*methodName*/, const nlohmann::json& /*parameters*/) { return Firebolt::Result{Firebolt::Error::None}; })); - auto result = actionsImpl_.start("launch"); + auto result = actionsImpl_.intent("launch"); EXPECT_TRUE(result); } From e6c37d3c38266af1ac95b13753de04c4041235ac Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 27 May 2026 14:38:40 -0700 Subject: [PATCH 09/37] fix(actions): address review feedback on headers and scripts --- include/firebolt/actions.h | 18 ++++++++++++++++++ lint.sh | 9 +++++++-- run-all-test.sh | 4 ++-- run-component-tests.sh | 2 +- run-unit-tests.sh | 2 +- setup-device-tunnel.sh | 8 +++----- src/actions_impl.cpp | 18 ++++++++++++++++++ src/actions_impl.h | 18 ++++++++++++++++++ src/json_types/actions.h | 18 ++++++++++++++++++ 9 files changed, 86 insertions(+), 11 deletions(-) diff --git a/include/firebolt/actions.h b/include/firebolt/actions.h index 4c5a8ec..6ee6625 100644 --- a/include/firebolt/actions.h +++ b/include/firebolt/actions.h @@ -1,3 +1,21 @@ +/** + * Copyright 2026 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 + */ +// // ============================================================================ // AUTO-GENERATED by fb-gen — DO NOT EDIT // ============================================================================ diff --git a/lint.sh b/lint.sh index 999560a..e574b3e 100755 --- a/lint.sh +++ b/lint.sh @@ -63,7 +63,7 @@ while [[ $# -gt 0 ]]; do NO_BUILD=true ;; --build-dir) - if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + if [[ $# -lt 2 || -z "${2:-}" || "$2" == --* ]]; then echo "Missing value for --build-dir" >&2 usage exit 1 @@ -72,7 +72,7 @@ while [[ $# -gt 0 ]]; do shift ;; --tidy-path) - if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + if [[ $# -lt 2 || -z "${2:-}" || "$2" == --* ]]; then echo "Missing value for --tidy-path" >&2 usage exit 1 @@ -106,6 +106,11 @@ done cd "$ROOT_DIR" +if [[ "$NO_BUILD" == false && "$BUILD_DIR" != "build-dev" ]]; then + echo "--build-dir is only supported with --no-build (build step always uses build-dev)." >&2 + exit 1 +fi + if [[ "$RUN_CLANG_TIDY" == false && "$RUN_CPPCHECK" == false ]]; then echo "Nothing to run: both clang-tidy and cppcheck are disabled." >&2 exit 1 diff --git a/run-all-test.sh b/run-all-test.sh index d8e9cdc..bc0b324 100755 --- a/run-all-test.sh +++ b/run-all-test.sh @@ -63,7 +63,7 @@ while [[ $# -gt 0 ]]; do RUN_UNIT=false ;; --unit-filter) - if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + if [[ $# -lt 2 || -z "${2:-}" || "$2" == --* ]]; then echo "Missing value for --unit-filter" >&2 usage exit 1 @@ -72,7 +72,7 @@ while [[ $# -gt 0 ]]; do shift ;; --component-filter) - if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + if [[ $# -lt 2 || -z "${2:-}" || "$2" == --* ]]; then echo "Missing value for --component-filter" >&2 usage exit 1 diff --git a/run-component-tests.sh b/run-component-tests.sh index e1615bb..859d91a 100755 --- a/run-component-tests.sh +++ b/run-component-tests.sh @@ -56,7 +56,7 @@ while [[ $# -gt 0 ]]; do NO_BUILD=true ;; --component-filter) - if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + if [[ $# -lt 2 || -z "${2:-}" || "$2" == --* ]]; then echo "Missing value for --component-filter" >&2 usage exit 1 diff --git a/run-unit-tests.sh b/run-unit-tests.sh index c7ba317..0c36a6e 100755 --- a/run-unit-tests.sh +++ b/run-unit-tests.sh @@ -56,7 +56,7 @@ while [[ $# -gt 0 ]]; do NO_BUILD=true ;; --unit-filter) - if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + if [[ $# -lt 2 || -z "${2:-}" || "$2" == --* ]]; then echo "Missing value for --unit-filter" >&2 usage exit 1 diff --git a/setup-device-tunnel.sh b/setup-device-tunnel.sh index 73a3e43..e3f7843 100755 --- a/setup-device-tunnel.sh +++ b/setup-device-tunnel.sh @@ -123,11 +123,9 @@ SSH_ARGS=(-N -o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ExitOnForwa echo "Opening SSH tunnel: localhost:${LOCAL_PORT} -> ${REMOTE_BIND_ADDR}:${REMOTE_PORT} on ${TARGET}" if [[ "$BACKGROUND" == true ]]; then - LOG_FILE="${TMPDIR:-/tmp}/firebolt-tunnel-${LOCAL_PORT}.log" - nohup ssh "${SSH_ARGS[@]}" >"$LOG_FILE" 2>&1 & - SSH_PID=$! - echo "Tunnel PID: ${SSH_PID}" - echo "Tunnel log: ${LOG_FILE}" + # -f backgrounds only after authentication and forwarding are set up. + ssh -f "${SSH_ARGS[@]}" + echo "Tunnel established in background mode." exit 0 fi diff --git a/src/actions_impl.cpp b/src/actions_impl.cpp index 1c95da8..edb3d35 100644 --- a/src/actions_impl.cpp +++ b/src/actions_impl.cpp @@ -1,3 +1,21 @@ +/** + * Copyright 2026 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 + */ +// // ============================================================================ // AUTO-GENERATED by fb-gen — DO NOT EDIT // ============================================================================ diff --git a/src/actions_impl.h b/src/actions_impl.h index 989c3a9..eb964e0 100644 --- a/src/actions_impl.h +++ b/src/actions_impl.h @@ -1,3 +1,21 @@ +/** + * Copyright 2026 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 + */ +// // ============================================================================ // AUTO-GENERATED by fb-gen — DO NOT EDIT // ============================================================================ diff --git a/src/json_types/actions.h b/src/json_types/actions.h index 066e915..6025350 100644 --- a/src/json_types/actions.h +++ b/src/json_types/actions.h @@ -1,3 +1,21 @@ +/** + * Copyright 2026 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 + */ +// // ============================================================================ // AUTO-GENERATED by fb-gen — DO NOT EDIT // ============================================================================ From da592f38da9dd453a9a98965374dce81ab785181 Mon Sep 17 00:00:00 2001 From: Brendan O'Bra Date: Wed, 27 May 2026 14:48:24 -0700 Subject: [PATCH 10/37] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- build.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.sh b/build.sh index c155223..6dac83d 100755 --- a/build.sh +++ b/build.sh @@ -55,6 +55,10 @@ if [[ -n "$SYSROOT_PATH" ]]; then [[ -e "$SYSROOT_PATH" ]] || { echo "SYSROOT_PATH not exist ($SYSROOT_PATH)" >/dev/stderr; exit 1; } params+=" -DSYSROOT_PATH=$SYSROOT_PATH" else + if $do_install; then + echo "--install requires --sysroot to be set; refusing to install without SYSROOT_PATH" >/dev/stderr + exit 1 + fi echo "SYSROOT_PATH not set; building without SYSROOT_PATH override" fi From d744c05a1bc559fa5d108e75f8f24055fdd93bdf Mon Sep 17 00:00:00 2001 From: Brendan O'Bra Date: Wed, 27 May 2026 14:51:34 -0700 Subject: [PATCH 11/37] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/firebolt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/firebolt.cpp b/src/firebolt.cpp index 48ec277..bb44f45 100644 --- a/src/firebolt.cpp +++ b/src/firebolt.cpp @@ -41,7 +41,7 @@ class FireboltAccessorImpl : public IFireboltAccessor FireboltAccessorImpl() : accessibility_(Firebolt::Helpers::GetHelperInstance()), advertising_(Firebolt::Helpers::GetHelperInstance()), - actions_(Firebolt::Helpers::GetHelperInstance()), + actions_(Firebolt::Helpers::GetHelperInstance()), device_(Firebolt::Helpers::GetHelperInstance()), discovery_(Firebolt::Helpers::GetHelperInstance()), display_(Firebolt::Helpers::GetHelperInstance()), From 118d76a69aacdf0c2a118f3cfa40f2197365d78f Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 27 May 2026 14:55:01 -0700 Subject: [PATCH 12/37] fix(review): harden thread resolver and make ActionsImpl non-copyable --- resolve-review-threads.sh | 251 ++++++++++++++++++++++++++++++++++++++ src/actions_impl.h | 2 + 2 files changed, 253 insertions(+) create mode 100755 resolve-review-threads.sh diff --git a/resolve-review-threads.sh b/resolve-review-threads.sh new file mode 100755 index 0000000..c31d106 --- /dev/null +++ b/resolve-review-threads.sh @@ -0,0 +1,251 @@ +#!/usr/bin/env bash + +set -euo pipefail + +die() { + echo "Error: $*" >&2 + exit 1 +} + +require_cmd() { + local cmd="$1" + local install_hint="$2" + if ! command -v "$cmd" >/dev/null 2>&1; then + die "Missing required dependency '$cmd'. ${install_hint}" + fi +} + +preflight_checks() { + if [[ -z "${BASH_VERSION:-}" ]]; then + die "This script must be run with bash. Example: bash ./resolve-review-threads.sh " + fi + + if (( BASH_VERSINFO[0] < 4 )); then + die "Bash 4+ is required (mapfile is used). Current bash version: ${BASH_VERSION}" + fi + + require_cmd "gh" "Install GitHub CLI: https://cli.github.com/" + require_cmd "jq" "Install jq (for example: sudo apt-get install jq)" + + if ! gh auth status >/dev/null 2>&1; then + die "GitHub CLI is not authenticated. Run: gh auth login" + fi + + if ! gh api graphql -f query='query { viewer { login } }' >/dev/null 2>&1; then + die "GitHub GraphQL API call failed. Check network connectivity and token permissions for gh auth." + fi +} + +usage() { + cat <<'EOF' +Usage: ./resolve-review-threads.sh [options] + +Resolves unresolved PR review threads that you are allowed to resolve. + +Options: + --repo Repository to target. Default: current gh repo + --all-unresolved Resolve all unresolved resolvable threads + --dry-run Print what would be resolved without mutating anything + --help Show this help + +Examples: + ./resolve-review-threads.sh 63 + ./resolve-review-threads.sh 63 --all-unresolved + ./resolve-review-threads.sh 63 --repo rdkcentral/firebolt-cpp-client +EOF +} + +preflight_checks + +if [[ $# -lt 1 ]]; then + usage + exit 1 +fi + +PR_NUMBER="" +REPO="" +OUTDATED_ONLY=false +RESOLVE_ALL=false +DRY_RUN=false + +if [[ "$1" =~ ^[0-9]+$ ]]; then + PR_NUMBER="$1" + shift +else + echo "Error: first argument must be a PR number." >&2 + usage + exit 1 +fi + +while [[ $# -gt 0 ]]; do + case "$1" in + --repo) + if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then + echo "Error: --repo requires owner/repo." >&2 + exit 1 + fi + REPO="$2" + shift 2 + ;; + --all-unresolved) + RESOLVE_ALL=true + shift + ;; + --dry-run) + DRY_RUN=true + shift + ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "Error: unknown option: $1" >&2 + usage + exit 1 + ;; + esac +done + +# Default mode is outdated-only unless explicitly overridden. +if [[ "$RESOLVE_ALL" == "true" ]]; then + OUTDATED_ONLY=false +else + OUTDATED_ONLY=true +fi + +if [[ -z "$REPO" ]]; then + REPO="$(gh repo view --json nameWithOwner -q .nameWithOwner)" +fi + +if [[ "$REPO" != */* ]]; then + die "Invalid repository value '$REPO'. Expected format: owner/repo" +fi + +OWNER="${REPO%%/*}" +NAME="${REPO##*/}" + +QUERY_FIRST='query($owner:String!, $name:String!, $number:Int!) { + repository(owner:$owner, name:$name) { + pullRequest(number:$number) { + reviewThreads(first:100) { + pageInfo { hasNextPage endCursor } + nodes { + id + isResolved + isOutdated + viewerCanResolve + } + } + } + } +}' + +QUERY_NEXT='query($owner:String!, $name:String!, $number:Int!, $cursor:String!) { + repository(owner:$owner, name:$name) { + pullRequest(number:$number) { + reviewThreads(first:100, after:$cursor) { + pageInfo { hasNextPage endCursor } + nodes { + id + isResolved + isOutdated + viewerCanResolve + } + } + } + } +}' + +MUTATION_RESOLVE='mutation($id:ID!) { + resolveReviewThread(input:{threadId:$id}) { + thread { id isResolved } + } +}' + +cursor="" +has_next=true + +declare -a THREAD_IDS=() +total_threads=0 +unresolved_threads=0 +unresolved_outdated_threads=0 +unresolved_resolvable_threads=0 +unresolved_unresolvable_threads=0 + +while [[ "$has_next" == "true" ]]; do + if [[ -z "$cursor" ]]; then + resp="$(gh api graphql -f query="$QUERY_FIRST" -F owner="$OWNER" -F name="$NAME" -F number="$PR_NUMBER")" + else + resp="$(gh api graphql -f query="$QUERY_NEXT" -F owner="$OWNER" -F name="$NAME" -F number="$PR_NUMBER" -F cursor="$cursor")" + fi + + if [[ "$(echo "$resp" | jq -r '.data.repository.pullRequest == null')" == "true" ]]; then + echo "Error: PR #$PR_NUMBER not found in $REPO" >&2 + exit 1 + fi + + page_total="$(echo "$resp" | jq -r '.data.repository.pullRequest.reviewThreads.nodes | length')" + page_unresolved="$(echo "$resp" | jq -r '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved | not)] | length')" + page_unresolved_outdated="$(echo "$resp" | jq -r '[.data.repository.pullRequest.reviewThreads.nodes[] | select((.isResolved | not) and (.isOutdated == true))] | length')" + page_unresolved_resolvable="$(echo "$resp" | jq -r '[.data.repository.pullRequest.reviewThreads.nodes[] | select((.isResolved | not) and (.viewerCanResolve == true))] | length')" + page_unresolved_unresolvable="$(echo "$resp" | jq -r '[.data.repository.pullRequest.reviewThreads.nodes[] | select((.isResolved | not) and (.viewerCanResolve == false))] | length')" + + total_threads=$((total_threads + page_total)) + unresolved_threads=$((unresolved_threads + page_unresolved)) + unresolved_outdated_threads=$((unresolved_outdated_threads + page_unresolved_outdated)) + unresolved_resolvable_threads=$((unresolved_resolvable_threads + page_unresolved_resolvable)) + unresolved_unresolvable_threads=$((unresolved_unresolvable_threads + page_unresolved_unresolvable)) + + if [[ "$OUTDATED_ONLY" == "true" ]]; then + mapfile -t page_ids < <(echo "$resp" | jq -r '.data.repository.pullRequest.reviewThreads.nodes[] | select((.isResolved | not) and (.viewerCanResolve == true) and (.isOutdated == true)) | .id') + else + mapfile -t page_ids < <(echo "$resp" | jq -r '.data.repository.pullRequest.reviewThreads.nodes[] | select((.isResolved | not) and (.viewerCanResolve == true)) | .id') + fi + + if [[ ${#page_ids[@]} -gt 0 ]]; then + THREAD_IDS+=("${page_ids[@]}") + fi + + has_next="$(echo "$resp" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.hasNextPage')" + cursor="$(echo "$resp" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.endCursor // ""')" +done + +if [[ ${#THREAD_IDS[@]} -eq 0 ]]; then + echo "Target repo: $REPO" + echo "PR: #$PR_NUMBER" + echo "Threads total: $total_threads" + echo "Unresolved: $unresolved_threads" + echo "Unresolved outdated: $unresolved_outdated_threads" + echo "Unresolved resolvable by current user: $unresolved_resolvable_threads" + echo "Unresolved NOT resolvable by current user: $unresolved_unresolvable_threads" + + if [[ "$unresolved_threads" -gt 0 && "$unresolved_resolvable_threads" -eq 0 ]]; then + echo "Note: unresolved threads exist, but your account cannot resolve them (viewerCanResolve=false)." + fi + + if [[ "$OUTDATED_ONLY" == "true" ]]; then + echo "No unresolved outdated threads to resolve in $REPO PR #$PR_NUMBER." + else + echo "No unresolved resolvable threads to resolve in $REPO PR #$PR_NUMBER." + fi + exit 0 +fi + +echo "Target repo: $REPO" +echo "PR: #$PR_NUMBER" +echo "Threads to resolve: ${#THREAD_IDS[@]}" + +if [[ "$DRY_RUN" == "true" ]]; then + echo "Dry run enabled. Thread IDs:" + printf '%s\n' "${THREAD_IDS[@]}" + exit 0 +fi + +resolved=0 +for thread_id in "${THREAD_IDS[@]}"; do + gh api graphql -f query="$MUTATION_RESOLVE" -F id="$thread_id" >/dev/null + resolved=$((resolved + 1)) +done + +echo "Resolved $resolved thread(s)." diff --git a/src/actions_impl.h b/src/actions_impl.h index eb964e0..157c88f 100644 --- a/src/actions_impl.h +++ b/src/actions_impl.h @@ -30,6 +30,8 @@ namespace Firebolt::Actions { class ActionsImpl : public IActions { public: explicit ActionsImpl(Firebolt::Helpers::IHelper& helper); + ActionsImpl(const ActionsImpl&) = delete; + ActionsImpl& operator=(const ActionsImpl&) = delete; ~ActionsImpl() override = default; Result intent(const std::string& intent) const override; From 8a5f934d39b7b07f834812f7f263727bbf778d33 Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 27 May 2026 14:56:32 -0700 Subject: [PATCH 13/37] fix(review): address remaining ABI and include comments --- include/firebolt/actions.h | 1 + include/firebolt/firebolt.h | 14 +++++++------- src/firebolt.cpp | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/firebolt/actions.h b/include/firebolt/actions.h index 6ee6625..762171b 100644 --- a/include/firebolt/actions.h +++ b/include/firebolt/actions.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/include/firebolt/firebolt.h b/include/firebolt/firebolt.h index 003414e..4003c32 100644 --- a/include/firebolt/firebolt.h +++ b/include/firebolt/firebolt.h @@ -93,13 +93,6 @@ class FIREBOLTCLIENT_EXPORT IFireboltAccessor */ virtual Advertising::IAdvertising& AdvertisingInterface() = 0; - /** - * @brief Returns instance of Actions interface - * - * @return Reference to Actions interface - */ - virtual Actions::IActions& ActionsInterface() = 0; - /** * @brief Returns instance of Device interface * @@ -169,5 +162,12 @@ class FIREBOLTCLIENT_EXPORT IFireboltAccessor * @return Reference to TextToSpeech interface */ virtual TextToSpeech::ITextToSpeech& TextToSpeechInterface() = 0; + + /** + * @brief Returns instance of Actions interface + * + * @return Reference to Actions interface + */ + virtual Actions::IActions& ActionsInterface() = 0; }; } // namespace Firebolt diff --git a/src/firebolt.cpp b/src/firebolt.cpp index bb44f45..88f945f 100644 --- a/src/firebolt.cpp +++ b/src/firebolt.cpp @@ -75,7 +75,6 @@ class FireboltAccessorImpl : public IFireboltAccessor Accessibility::IAccessibility& AccessibilityInterface() override { return accessibility_; } Advertising::IAdvertising& AdvertisingInterface() override { return advertising_; } - Actions::IActions& ActionsInterface() override { return actions_; } Device::IDevice& DeviceInterface() override { return device_; } Discovery::IDiscovery& DiscoveryInterface() override { return discovery_; } Display::IDisplay& DisplayInterface() override { return display_; } @@ -86,6 +85,7 @@ class FireboltAccessorImpl : public IFireboltAccessor Presentation::IPresentation& PresentationInterface() override { return presentation_; } Stats::IStats& StatsInterface() override { return stats_; } TextToSpeech::ITextToSpeech& TextToSpeechInterface() override { return textToSpeech_; } + Actions::IActions& ActionsInterface() override { return actions_; } private: void unsubscribeAll() From 9d86e6c17bee1678fb21ea785c814d92a5fb4fe0 Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 27 May 2026 14:57:18 -0700 Subject: [PATCH 14/37] test(actions): add component coverage for intent and onIntent --- test/component/actionsGeneratedTest.cpp | 43 +++++++++++++++++++++---- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/test/component/actionsGeneratedTest.cpp b/test/component/actionsGeneratedTest.cpp index a08372b..aff810c 100644 --- a/test/component/actionsGeneratedTest.cpp +++ b/test/component/actionsGeneratedTest.cpp @@ -16,14 +16,45 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "firebolt/actions.h" +#include "firebolt/firebolt.h" +#include "utils.h" #include -TEST(ActionsGeneratedCTest, InterfaceSurfaceHasintent) +class ActionsGeneratedCTest : public ::testing::Test { - using Interface = Firebolt::Actions::IActions; - auto ptr = &Interface::intent; - (void)ptr; - SUCCEED(); +protected: + void SetUp() override { eventReceived = false; } + + std::condition_variable cv; + std::mutex mtx; + bool eventReceived; +}; + +TEST_F(ActionsGeneratedCTest, Intent) +{ + auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().intent("launch"); + EXPECT_TRUE(result) << toError(result); +} + +TEST_F(ActionsGeneratedCTest, SubscribeOnIntent) +{ + auto id = Firebolt::IFireboltAccessor::Instance().ActionsInterface().subscribeOnIntent( + [&](const std::string& intent) + { + EXPECT_EQ(intent, "launch"); + { + std::lock_guard lock(mtx); + eventReceived = true; + } + cv.notify_one(); + }); + + verifyEventSubscription(id); + + triggerEvent("Actions.onIntent", R"({"value":"launch"})"); + verifyEventReceived(mtx, cv, eventReceived); + + auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().unsubscribe(id.value()); + verifyUnsubscribeResult(result); } From e3506a8d47e2a83d57e8a6d0e966686be947a962 Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 27 May 2026 15:02:15 -0700 Subject: [PATCH 15/37] fix(review): address latest CI and script feedback --- resolve-review-threads.sh | 24 ++++++++++++++++++++++++ test/ComponentTestsMain.cpp | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/resolve-review-threads.sh b/resolve-review-threads.sh index c31d106..6cd4c34 100755 --- a/resolve-review-threads.sh +++ b/resolve-review-threads.sh @@ -1,5 +1,21 @@ #!/usr/bin/env bash +# Copyright 2026 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 + set -euo pipefail die() { @@ -55,6 +71,14 @@ Examples: EOF } +# Allow usage output in unconfigured environments. +for arg in "$@"; do + if [[ "$arg" == "--help" || "$arg" == "-h" ]]; then + usage + exit 0 + fi +done + preflight_checks if [[ $# -lt 1 ]]; then diff --git a/test/ComponentTestsMain.cpp b/test/ComponentTestsMain.cpp index dd58c01..578ae28 100644 --- a/test/ComponentTestsMain.cpp +++ b/test/ComponentTestsMain.cpp @@ -70,7 +70,7 @@ bool waitOnConnectionReady() int main(int argc, char** argv) { const char* endpoint = std::getenv("FIREBOLT_ENDPOINT"); - string url = (endpoint && endpoint[0] != '\0') ? endpoint : "ws://127.0.0.1:3474/"; + string url = (endpoint && endpoint[0] != '\0') ? endpoint : "ws://127.0.0.1:9998/"; cout << "Using Firebolt endpoint: " << url << endl; createFireboltInstance(url); From d416d8afd86736198209d96b72aa9e8bf3a5e57f Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 27 May 2026 15:26:19 -0700 Subject: [PATCH 16/37] chore: remove review-thread helper script from PR --- resolve-review-threads.sh | 275 -------------------------------------- 1 file changed, 275 deletions(-) delete mode 100755 resolve-review-threads.sh diff --git a/resolve-review-threads.sh b/resolve-review-threads.sh deleted file mode 100755 index 6cd4c34..0000000 --- a/resolve-review-threads.sh +++ /dev/null @@ -1,275 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2026 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 - -set -euo pipefail - -die() { - echo "Error: $*" >&2 - exit 1 -} - -require_cmd() { - local cmd="$1" - local install_hint="$2" - if ! command -v "$cmd" >/dev/null 2>&1; then - die "Missing required dependency '$cmd'. ${install_hint}" - fi -} - -preflight_checks() { - if [[ -z "${BASH_VERSION:-}" ]]; then - die "This script must be run with bash. Example: bash ./resolve-review-threads.sh " - fi - - if (( BASH_VERSINFO[0] < 4 )); then - die "Bash 4+ is required (mapfile is used). Current bash version: ${BASH_VERSION}" - fi - - require_cmd "gh" "Install GitHub CLI: https://cli.github.com/" - require_cmd "jq" "Install jq (for example: sudo apt-get install jq)" - - if ! gh auth status >/dev/null 2>&1; then - die "GitHub CLI is not authenticated. Run: gh auth login" - fi - - if ! gh api graphql -f query='query { viewer { login } }' >/dev/null 2>&1; then - die "GitHub GraphQL API call failed. Check network connectivity and token permissions for gh auth." - fi -} - -usage() { - cat <<'EOF' -Usage: ./resolve-review-threads.sh [options] - -Resolves unresolved PR review threads that you are allowed to resolve. - -Options: - --repo Repository to target. Default: current gh repo - --all-unresolved Resolve all unresolved resolvable threads - --dry-run Print what would be resolved without mutating anything - --help Show this help - -Examples: - ./resolve-review-threads.sh 63 - ./resolve-review-threads.sh 63 --all-unresolved - ./resolve-review-threads.sh 63 --repo rdkcentral/firebolt-cpp-client -EOF -} - -# Allow usage output in unconfigured environments. -for arg in "$@"; do - if [[ "$arg" == "--help" || "$arg" == "-h" ]]; then - usage - exit 0 - fi -done - -preflight_checks - -if [[ $# -lt 1 ]]; then - usage - exit 1 -fi - -PR_NUMBER="" -REPO="" -OUTDATED_ONLY=false -RESOLVE_ALL=false -DRY_RUN=false - -if [[ "$1" =~ ^[0-9]+$ ]]; then - PR_NUMBER="$1" - shift -else - echo "Error: first argument must be a PR number." >&2 - usage - exit 1 -fi - -while [[ $# -gt 0 ]]; do - case "$1" in - --repo) - if [[ $# -lt 2 || -z "${2:-}" || "${2:0:1}" == "-" ]]; then - echo "Error: --repo requires owner/repo." >&2 - exit 1 - fi - REPO="$2" - shift 2 - ;; - --all-unresolved) - RESOLVE_ALL=true - shift - ;; - --dry-run) - DRY_RUN=true - shift - ;; - --help|-h) - usage - exit 0 - ;; - *) - echo "Error: unknown option: $1" >&2 - usage - exit 1 - ;; - esac -done - -# Default mode is outdated-only unless explicitly overridden. -if [[ "$RESOLVE_ALL" == "true" ]]; then - OUTDATED_ONLY=false -else - OUTDATED_ONLY=true -fi - -if [[ -z "$REPO" ]]; then - REPO="$(gh repo view --json nameWithOwner -q .nameWithOwner)" -fi - -if [[ "$REPO" != */* ]]; then - die "Invalid repository value '$REPO'. Expected format: owner/repo" -fi - -OWNER="${REPO%%/*}" -NAME="${REPO##*/}" - -QUERY_FIRST='query($owner:String!, $name:String!, $number:Int!) { - repository(owner:$owner, name:$name) { - pullRequest(number:$number) { - reviewThreads(first:100) { - pageInfo { hasNextPage endCursor } - nodes { - id - isResolved - isOutdated - viewerCanResolve - } - } - } - } -}' - -QUERY_NEXT='query($owner:String!, $name:String!, $number:Int!, $cursor:String!) { - repository(owner:$owner, name:$name) { - pullRequest(number:$number) { - reviewThreads(first:100, after:$cursor) { - pageInfo { hasNextPage endCursor } - nodes { - id - isResolved - isOutdated - viewerCanResolve - } - } - } - } -}' - -MUTATION_RESOLVE='mutation($id:ID!) { - resolveReviewThread(input:{threadId:$id}) { - thread { id isResolved } - } -}' - -cursor="" -has_next=true - -declare -a THREAD_IDS=() -total_threads=0 -unresolved_threads=0 -unresolved_outdated_threads=0 -unresolved_resolvable_threads=0 -unresolved_unresolvable_threads=0 - -while [[ "$has_next" == "true" ]]; do - if [[ -z "$cursor" ]]; then - resp="$(gh api graphql -f query="$QUERY_FIRST" -F owner="$OWNER" -F name="$NAME" -F number="$PR_NUMBER")" - else - resp="$(gh api graphql -f query="$QUERY_NEXT" -F owner="$OWNER" -F name="$NAME" -F number="$PR_NUMBER" -F cursor="$cursor")" - fi - - if [[ "$(echo "$resp" | jq -r '.data.repository.pullRequest == null')" == "true" ]]; then - echo "Error: PR #$PR_NUMBER not found in $REPO" >&2 - exit 1 - fi - - page_total="$(echo "$resp" | jq -r '.data.repository.pullRequest.reviewThreads.nodes | length')" - page_unresolved="$(echo "$resp" | jq -r '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved | not)] | length')" - page_unresolved_outdated="$(echo "$resp" | jq -r '[.data.repository.pullRequest.reviewThreads.nodes[] | select((.isResolved | not) and (.isOutdated == true))] | length')" - page_unresolved_resolvable="$(echo "$resp" | jq -r '[.data.repository.pullRequest.reviewThreads.nodes[] | select((.isResolved | not) and (.viewerCanResolve == true))] | length')" - page_unresolved_unresolvable="$(echo "$resp" | jq -r '[.data.repository.pullRequest.reviewThreads.nodes[] | select((.isResolved | not) and (.viewerCanResolve == false))] | length')" - - total_threads=$((total_threads + page_total)) - unresolved_threads=$((unresolved_threads + page_unresolved)) - unresolved_outdated_threads=$((unresolved_outdated_threads + page_unresolved_outdated)) - unresolved_resolvable_threads=$((unresolved_resolvable_threads + page_unresolved_resolvable)) - unresolved_unresolvable_threads=$((unresolved_unresolvable_threads + page_unresolved_unresolvable)) - - if [[ "$OUTDATED_ONLY" == "true" ]]; then - mapfile -t page_ids < <(echo "$resp" | jq -r '.data.repository.pullRequest.reviewThreads.nodes[] | select((.isResolved | not) and (.viewerCanResolve == true) and (.isOutdated == true)) | .id') - else - mapfile -t page_ids < <(echo "$resp" | jq -r '.data.repository.pullRequest.reviewThreads.nodes[] | select((.isResolved | not) and (.viewerCanResolve == true)) | .id') - fi - - if [[ ${#page_ids[@]} -gt 0 ]]; then - THREAD_IDS+=("${page_ids[@]}") - fi - - has_next="$(echo "$resp" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.hasNextPage')" - cursor="$(echo "$resp" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.endCursor // ""')" -done - -if [[ ${#THREAD_IDS[@]} -eq 0 ]]; then - echo "Target repo: $REPO" - echo "PR: #$PR_NUMBER" - echo "Threads total: $total_threads" - echo "Unresolved: $unresolved_threads" - echo "Unresolved outdated: $unresolved_outdated_threads" - echo "Unresolved resolvable by current user: $unresolved_resolvable_threads" - echo "Unresolved NOT resolvable by current user: $unresolved_unresolvable_threads" - - if [[ "$unresolved_threads" -gt 0 && "$unresolved_resolvable_threads" -eq 0 ]]; then - echo "Note: unresolved threads exist, but your account cannot resolve them (viewerCanResolve=false)." - fi - - if [[ "$OUTDATED_ONLY" == "true" ]]; then - echo "No unresolved outdated threads to resolve in $REPO PR #$PR_NUMBER." - else - echo "No unresolved resolvable threads to resolve in $REPO PR #$PR_NUMBER." - fi - exit 0 -fi - -echo "Target repo: $REPO" -echo "PR: #$PR_NUMBER" -echo "Threads to resolve: ${#THREAD_IDS[@]}" - -if [[ "$DRY_RUN" == "true" ]]; then - echo "Dry run enabled. Thread IDs:" - printf '%s\n' "${THREAD_IDS[@]}" - exit 0 -fi - -resolved=0 -for thread_id in "${THREAD_IDS[@]}"; do - gh api graphql -f query="$MUTATION_RESOLVE" -F id="$thread_id" >/dev/null - resolved=$((resolved + 1)) -done - -echo "Resolved $resolved thread(s)." From 542310003cd0177c35230debdd4fa71f36ef07fb Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 27 May 2026 15:41:39 -0700 Subject: [PATCH 17/37] fix(lint): add clang-format check/fix and apply formatting --- include/firebolt/actions.h | 15 ++-- include/firebolt/firebolt.h | 2 +- lint.sh | 105 ++++++++++++++++++++++-- src/actions_impl.cpp | 22 +++-- src/actions_impl.h | 6 +- src/firebolt.cpp | 2 +- src/json_types/actions.h | 12 +-- test/component/actionsGeneratedTest.cpp | 1 - test/unit/actionsGeneratedTest.cpp | 19 ++--- test/unit/actionsTest.cpp | 3 +- test/utils.cpp | 4 +- test/utils.h | 4 +- 12 files changed, 148 insertions(+), 47 deletions(-) diff --git a/include/firebolt/actions.h b/include/firebolt/actions.h index 762171b..9c39198 100644 --- a/include/firebolt/actions.h +++ b/include/firebolt/actions.h @@ -22,31 +22,34 @@ #ifndef FIREBOLT_ACTIONS_H #define FIREBOLT_ACTIONS_H +#include #include #include #include -#include #include +#include #include -#include -namespace Firebolt::Actions { +namespace Firebolt::Actions +{ -class IActions { +class IActions +{ public: virtual ~IActions() = default; virtual Result intent(const std::string& intent) const = 0; virtual Result subscribeOnIntent(std::function&& notification) = 0; - virtual Result subscribeOnIntentChanged(std::function&& notification) { + virtual Result subscribeOnIntentChanged(std::function&& notification) + { return subscribeOnIntent(std::move(notification)); } virtual Result unsubscribe(SubscriptionId id) = 0; virtual void unsubscribeAll() = 0; -}; // class IActions +}; // class IActions } // namespace Firebolt::Actions diff --git a/include/firebolt/firebolt.h b/include/firebolt/firebolt.h index 4003c32..d889ec0 100644 --- a/include/firebolt/firebolt.h +++ b/include/firebolt/firebolt.h @@ -19,8 +19,8 @@ #pragma once #include "firebolt/accessibility.h" -#include "firebolt/advertising.h" #include "firebolt/actions.h" +#include "firebolt/advertising.h" #include "firebolt/client_export.h" #include "firebolt/device.h" #include "firebolt/discovery.h" diff --git a/lint.sh b/lint.sh index e574b3e..9487bd0 100755 --- a/lint.sh +++ b/lint.sh @@ -24,23 +24,30 @@ NO_BUILD=false CLEAN=false RUN_CLANG_TIDY=true RUN_CPPCHECK=true +RUN_CLANG_FORMAT=true APPLY_FIXES=false +FORMAT_FIX=false CLANG_TIDY_PATHS=(src include test/unit test/component) +CLANG_FORMAT_PATHS=(src include test) usage() { cat < Build directory containing compile_commands.json (default: build-dev) --tidy-path

Add path for clang-tidy scan (repeatable) + --format-path

Add path for clang-format scan (repeatable) --fix Apply clang-tidy fix-its (clang-tidy only) + --format-fix Apply clang-format fixes in-place + --format-only Run clang-format only + --no-format Skip clang-format checks --tidy-only Run clang-tidy only --cppcheck-only Run cppcheck only --help Show this help @@ -49,7 +56,10 @@ Examples: ./lint.sh ./lint.sh --tidy-only ./lint.sh --tidy-only --fix + ./lint.sh --format-only + ./lint.sh --format-fix ./lint.sh --tidy-path test/api_test_app + ./lint.sh --format-path include/firebolt ./lint.sh --no-build --build-dir build-dev EOF } @@ -80,9 +90,30 @@ while [[ $# -gt 0 ]]; do CLANG_TIDY_PATHS+=("${2:-}") shift ;; + --format-path) + if [[ $# -lt 2 || -z "${2:-}" || "$2" == --* ]]; then + echo "Missing value for --format-path" >&2 + usage + exit 1 + fi + CLANG_FORMAT_PATHS+=("${2:-}") + shift + ;; --fix) APPLY_FIXES=true ;; + --format-fix) + FORMAT_FIX=true + RUN_CLANG_FORMAT=true + ;; + --format-only) + RUN_CLANG_FORMAT=true + RUN_CLANG_TIDY=false + RUN_CPPCHECK=false + ;; + --no-format) + RUN_CLANG_FORMAT=false + ;; --tidy-only) RUN_CLANG_TIDY=true RUN_CPPCHECK=false @@ -106,13 +137,13 @@ done cd "$ROOT_DIR" -if [[ "$NO_BUILD" == false && "$BUILD_DIR" != "build-dev" ]]; then +if [[ "$RUN_CLANG_TIDY" == true && "$NO_BUILD" == false && "$BUILD_DIR" != "build-dev" ]]; then echo "--build-dir is only supported with --no-build (build step always uses build-dev)." >&2 exit 1 fi -if [[ "$RUN_CLANG_TIDY" == false && "$RUN_CPPCHECK" == false ]]; then - echo "Nothing to run: both clang-tidy and cppcheck are disabled." >&2 +if [[ "$RUN_CLANG_FORMAT" == false && "$RUN_CLANG_TIDY" == false && "$RUN_CPPCHECK" == false ]]; then + echo "Nothing to run: clang-format, clang-tidy, and cppcheck are all disabled." >&2 exit 1 fi @@ -121,6 +152,11 @@ if [[ "$APPLY_FIXES" == true && "$RUN_CLANG_TIDY" == false ]]; then exit 1 fi +if [[ "$FORMAT_FIX" == true && "$RUN_CLANG_FORMAT" == false ]]; then + echo "--format-fix requires clang-format to be enabled (remove --no-format)." >&2 + exit 1 +fi + if [[ "$RUN_CLANG_TIDY" == true ]] && ! command -v clang-tidy >/dev/null 2>&1; then echo "clang-tidy not found. Install it (e.g. apt install clang-tidy)." >&2 exit 1 @@ -131,19 +167,74 @@ if [[ "$RUN_CPPCHECK" == true ]] && ! command -v cppcheck >/dev/null 2>&1; then exit 1 fi +if [[ "$RUN_CLANG_FORMAT" == true ]] && ! command -v clang-format >/dev/null 2>&1; then + echo "clang-format not found. Install it (e.g. apt install clang-format)." >&2 + exit 1 +fi + if [[ "$CLEAN" == true ]]; then rm -rf "$BUILD_DIR" fi -if [[ "$NO_BUILD" == false ]]; then +if [[ "$NO_BUILD" == false && "$RUN_CLANG_TIDY" == true ]]; then ./build.sh +tests fi -if [[ ! -f "$BUILD_DIR/compile_commands.json" ]]; then +if [[ "$RUN_CLANG_TIDY" == true && ! -f "$BUILD_DIR/compile_commands.json" ]]; then echo "Missing $BUILD_DIR/compile_commands.json. Run ./build.sh +tests first." >&2 exit 1 fi +if [[ "$RUN_CLANG_FORMAT" == true ]]; then + if [[ "$FORMAT_FIX" == true ]]; then + echo "[lint] Running clang-format with fixes enabled" + else + echo "[lint] Running clang-format check" + fi + + format_paths=() + for p in "${CLANG_FORMAT_PATHS[@]}"; do + if [[ -e "$p" ]]; then + format_paths+=("$p") + fi + done + + if [[ ${#format_paths[@]} -eq 0 ]]; then + echo "No valid clang-format paths found." >&2 + exit 1 + fi + + mapfile -t format_files < <( + find "${format_paths[@]}" -type f \( -name "*.h" -o -name "*.hh" -o -name "*.hpp" -o -name "*.hxx" -o -name "*.c" -o -name "*.cc" -o -name "*.cpp" -o -name "*.cxx" \) | sort + ) + + if [[ ${#format_files[@]} -eq 0 ]]; then + echo "No C/C++ files found for clang-format." >&2 + exit 1 + fi + + clang_format_failed=0 + total_format_files=${#format_files[@]} + format_index=0 + for f in "${format_files[@]}"; do + format_index=$((format_index + 1)) + echo "[lint][clang-format] ${format_index}/${total_format_files}: $f" + if [[ "$FORMAT_FIX" == true ]]; then + clang-format -i "$f" + else + if ! clang-format --dry-run --Werror "$f"; then + clang_format_failed=1 + fi + fi + done + + if [[ "$FORMAT_FIX" == false && $clang_format_failed -ne 0 ]]; then + echo "clang-format reported issues." >&2 + echo "Run ./lint.sh --format-fix to apply formatting automatically." >&2 + exit 1 + fi +fi + if [[ "$RUN_CLANG_TIDY" == true ]]; then if [[ "$APPLY_FIXES" == true ]]; then echo "[lint] Running clang-tidy with fixes enabled" diff --git a/src/actions_impl.cpp b/src/actions_impl.cpp index edb3d35..431496f 100644 --- a/src/actions_impl.cpp +++ b/src/actions_impl.cpp @@ -24,28 +24,34 @@ #include #include -namespace Firebolt::Actions { +namespace Firebolt::Actions +{ ActionsImpl::ActionsImpl(Firebolt::Helpers::IHelper& helper) - : helper_(helper) - , subscriptionManager_(helper, this) -{} + : helper_(helper), + subscriptionManager_(helper, this) +{ +} -Result ActionsImpl::intent(const std::string& intent) const { +Result ActionsImpl::intent(const std::string& intent) const +{ nlohmann::json params; params["intent"] = intent; return helper_.invoke("Actions.intent", params); } -Result ActionsImpl::subscribeOnIntent(std::function&& notification) { +Result ActionsImpl::subscribeOnIntent(std::function&& notification) +{ return subscriptionManager_.subscribe("Actions.onIntent", std::move(notification)); } -Result ActionsImpl::unsubscribe(SubscriptionId id) { +Result ActionsImpl::unsubscribe(SubscriptionId id) +{ return subscriptionManager_.unsubscribe(id); } -void ActionsImpl::unsubscribeAll() { +void ActionsImpl::unsubscribeAll() +{ subscriptionManager_.unsubscribeAll(); } diff --git a/src/actions_impl.h b/src/actions_impl.h index 157c88f..e7eaf61 100644 --- a/src/actions_impl.h +++ b/src/actions_impl.h @@ -25,9 +25,11 @@ #include "firebolt/actions.h" #include -namespace Firebolt::Actions { +namespace Firebolt::Actions +{ -class ActionsImpl : public IActions { +class ActionsImpl : public IActions +{ public: explicit ActionsImpl(Firebolt::Helpers::IHelper& helper); ActionsImpl(const ActionsImpl&) = delete; diff --git a/src/firebolt.cpp b/src/firebolt.cpp index 88f945f..0afad53 100644 --- a/src/firebolt.cpp +++ b/src/firebolt.cpp @@ -18,8 +18,8 @@ #include "firebolt/firebolt.h" #include "accessibility_impl.h" -#include "advertising_impl.h" #include "actions_impl.h" +#include "advertising_impl.h" #include "device_impl.h" #include "discovery_impl.h" #include "display_impl.h" diff --git a/src/json_types/actions.h b/src/json_types/actions.h index 6025350..60c76ce 100644 --- a/src/json_types/actions.h +++ b/src/json_types/actions.h @@ -23,14 +23,16 @@ #define FIREBOLT_ACTIONS_JSON_H #pragma once -#include -#include -#include #include "firebolt/actions.h" +#include +#include +#include -namespace Firebolt::Actions { +namespace Firebolt::Actions +{ -namespace JsonData { +namespace JsonData +{ } // namespace JsonData diff --git a/test/component/actionsGeneratedTest.cpp b/test/component/actionsGeneratedTest.cpp index aff810c..c157be9 100644 --- a/test/component/actionsGeneratedTest.cpp +++ b/test/component/actionsGeneratedTest.cpp @@ -57,4 +57,3 @@ TEST_F(ActionsGeneratedCTest, SubscribeOnIntent) auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().unsubscribe(id.value()); verifyUnsubscribeResult(result); } - diff --git a/test/unit/actionsGeneratedTest.cpp b/test/unit/actionsGeneratedTest.cpp index 4c0b71e..86006f3 100644 --- a/test/unit/actionsGeneratedTest.cpp +++ b/test/unit/actionsGeneratedTest.cpp @@ -16,8 +16,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "mock_helper.h" #include "actions_impl.h" +#include "mock_helper.h" #include class ActionsGeneratedUTest : public ::testing::Test @@ -34,24 +34,23 @@ TEST_F(ActionsGeneratedUTest, Constructs) TEST_F(ActionsGeneratedUTest, UnsubscribeForwardsToHelper) { - EXPECT_CALL(mockHelper, unsubscribe(7)) - .WillOnce(::testing::Return(Firebolt::Result{Firebolt::Error::None})); + EXPECT_CALL(mockHelper, unsubscribe(7)).WillOnce(::testing::Return(Firebolt::Result{Firebolt::Error::None})); auto result = impl.unsubscribe(7); ASSERT_TRUE(result) << "unsubscribe should return success when helper succeeds"; } - TEST_F(ActionsGeneratedUTest, ForwardsintentTransportErrors) { EXPECT_CALL(mockHelper, invoke("Actions.intent", ::testing::_)) - .WillOnce(::testing::Invoke([](const std::string& /*method*/, const nlohmann::json& params) { - EXPECT_TRUE(params.is_object()) << "Expected params object for method call"; - EXPECT_TRUE(params.contains("intent")) << "Missing expected param key: intent"; - return Firebolt::Result{Firebolt::Error::General}; - })); + .WillOnce(::testing::Invoke( + [](const std::string& /*method*/, const nlohmann::json& params) + { + EXPECT_TRUE(params.is_object()) << "Expected params object for method call"; + EXPECT_TRUE(params.contains("intent")) << "Missing expected param key: intent"; + return Firebolt::Result{Firebolt::Error::General}; + })); auto result = impl.intent({}); EXPECT_FALSE(result) << "Expected error propagation when helper invoke fails"; } - diff --git a/test/unit/actionsTest.cpp b/test/unit/actionsTest.cpp index 7444bd1..7295886 100644 --- a/test/unit/actionsTest.cpp +++ b/test/unit/actionsTest.cpp @@ -16,9 +16,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "actions_impl.h" #include "json_engine.h" #include "mock_helper.h" -#include "actions_impl.h" class ActionsUTest : public ::testing::Test, protected MockBase { @@ -51,4 +51,3 @@ TEST_F(ActionsUTest, SubscribeOnIntent) auto unsubResult = actionsImpl_.unsubscribe(*result); ASSERT_TRUE(unsubResult) << "ActionsImpl::unsubscribe() returned an error"; } - diff --git a/test/utils.cpp b/test/utils.cpp index 792bf4f..60de1be 100644 --- a/test/utils.cpp +++ b/test/utils.cpp @@ -125,7 +125,7 @@ void verifyUnsubscribeResult(const Firebolt::Result& result) FAIL() << "Unsubscribe failed." + toError(result); } } -void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, bool& eventReceived) +void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, const bool& eventReceived) { std::unique_lock lock(mtx); if (!cv.wait_for(lock, EventWaitTime, [&] { return eventReceived; })) @@ -134,7 +134,7 @@ void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, bool& eve } } -void verifyEventNotReceived(std::mutex& mtx, std::condition_variable& cv, bool& eventReceived) +void verifyEventNotReceived(std::mutex& mtx, std::condition_variable& cv, const bool& eventReceived) { // Wait for the event to be received or timeout after 5 seconds std::unique_lock lock(mtx); diff --git a/test/utils.h b/test/utils.h index bd1e2e3..b5d0693 100644 --- a/test/utils.h +++ b/test/utils.h @@ -32,8 +32,8 @@ void triggerRaw(const std::string& payload); void verifyEventSubscription(const Firebolt::Result& id); void verifyUnsubscribeResult(const Firebolt::Result& result); -void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, bool& eventReceived); -void verifyEventNotReceived(std::mutex& mtx, std::condition_variable& cv, bool& eventReceived); +void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, const bool& eventReceived); +void verifyEventNotReceived(std::mutex& mtx, std::condition_variable& cv, const bool& eventReceived); template inline std::string toError(const Firebolt::Result& result) { From 2a0b0b96a8fd8bc0af6fbccaf3670140fa87063e Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 27 May 2026 15:48:53 -0700 Subject: [PATCH 18/37] fix(review): tighten test safety and lint mode semantics --- lint.sh | 2 ++ test/component/actionsGeneratedTest.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/lint.sh b/lint.sh index 9487bd0..552384d 100755 --- a/lint.sh +++ b/lint.sh @@ -115,10 +115,12 @@ while [[ $# -gt 0 ]]; do RUN_CLANG_FORMAT=false ;; --tidy-only) + RUN_CLANG_FORMAT=false RUN_CLANG_TIDY=true RUN_CPPCHECK=false ;; --cppcheck-only) + RUN_CLANG_FORMAT=false RUN_CLANG_TIDY=false RUN_CPPCHECK=true ;; diff --git a/test/component/actionsGeneratedTest.cpp b/test/component/actionsGeneratedTest.cpp index c157be9..6ce5e5d 100644 --- a/test/component/actionsGeneratedTest.cpp +++ b/test/component/actionsGeneratedTest.cpp @@ -49,6 +49,7 @@ TEST_F(ActionsGeneratedCTest, SubscribeOnIntent) cv.notify_one(); }); + ASSERT_TRUE(id) << toError(id); verifyEventSubscription(id); triggerEvent("Actions.onIntent", R"({"value":"launch"})"); From f14e3b4894e2c9fd33f3ea20046e8c411f50fb49 Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Mon, 1 Jun 2026 15:29:13 -0400 Subject: [PATCH 19/37] Update changelog for v0.6.0 --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8863674..27e3477 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## [0.6.0](https://github.com/rdkcentral/firebolt-cpp-client/compare/v0.5.5...v0.6.0) + +### Added +- New APIs + - Actions.intent() + - Actions.onIntent event + +### Changed +- **Breaking**: `Discovery.watched` and `Metrics` methods return type changed from `bool` to `void` + ## [0.5.5](https://github.com/rdkcentral/firebolt-cpp-client/compare/v0.5.4...v0.5.5) ### Changed From 477a2778e63133b90d40b19b91d6ad0a643aab1c Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Mon, 1 Jun 2026 15:55:50 -0400 Subject: [PATCH 20/37] Update changelog for v0.6.0 --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27e3477..2c650a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,11 @@ ### Added - New APIs - - Actions.intent() - - Actions.onIntent event + - `Actions.intent()` + - `Actions.onIntent` event ### Changed -- **Breaking**: `Discovery.watched` and `Metrics` methods return type changed from `bool` to `void` +- **Breaking**: `Discovery.watched` and `Metrics` methods return type changed from `Result` to `Result` ## [0.5.5](https://github.com/rdkcentral/firebolt-cpp-client/compare/v0.5.4...v0.5.5) From 4a8c72a4c23b97c4bfbae5b8cd7040295c687306 Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Mon, 1 Jun 2026 16:04:01 -0400 Subject: [PATCH 21/37] Address changelog review comments --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c650a6..799eb4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,11 @@ ### Added - New APIs - - `Actions.intent()` + - `Actions.intent` - `Actions.onIntent` event ### Changed -- **Breaking**: `Discovery.watched` and `Metrics` methods return type changed from `Result` to `Result` +- **Breaking**: `Discovery.watched` and all `Metrics.*` methods now return `Result` (previously `Result`) ## [0.5.5](https://github.com/rdkcentral/firebolt-cpp-client/compare/v0.5.4...v0.5.5) From abc0e58bcdb397e4cbedbebe4a5667ccb3a56097 Mon Sep 17 00:00:00 2001 From: bobra200 Date: Tue, 2 Jun 2026 08:44:01 -0700 Subject: [PATCH 22/37] fix: actions.intent no args/correct return type --- CHANGELOG.md | 2 +- docs/openrpc/the-spec/firebolt-open-rpc.json | 78 ++++++++++ include/firebolt/actions.h | 2 +- run-component-tests-docker.sh | 151 +++++++++++++++++++ src/actions_impl.cpp | 6 +- src/actions_impl.h | 2 +- test/component/actionsGeneratedTest.cpp | 7 +- test/unit/actionsGeneratedTest.cpp | 9 +- test/unit/actionsTest.cpp | 13 +- 9 files changed, 247 insertions(+), 23 deletions(-) create mode 100755 run-component-tests-docker.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 799eb4e..58e532d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Added - New APIs - - `Actions.intent` + - `Actions.intent` (no parameters, returns string) - `Actions.onIntent` event ### Changed diff --git a/docs/openrpc/the-spec/firebolt-open-rpc.json b/docs/openrpc/the-spec/firebolt-open-rpc.json index 82b8600..89ae940 100644 --- a/docs/openrpc/the-spec/firebolt-open-rpc.json +++ b/docs/openrpc/the-spec/firebolt-open-rpc.json @@ -5,6 +5,7 @@ "version": "", "x-module-descriptions": { "Accessibility": "The `Accessibility` module provides access to the user/device settings for closed captioning and voice guidance.\n\nApps **SHOULD** attempt o respect these settings, rather than manage and persist seprate settings, which would be different per-app.", + "Actions": "Methods for setting and observing app intents.", "Advertising": "A module for platform provided advertising settings and functionality.", "Device": "A module for querying about the device and it's capabilities.", "Discovery": "Your App likely wants to integrate with the Platform's discovery capabilities. For example to add a \"Watch Next\" tile that links to your app from the platform's home screen.\n\nGetting access to this information requires to connect to lower level APIs made available by the platform. Since implementations differ between operators and platforms, the Firebolt SDK offers a Discovery module, that exposes a generic, agnostic interface to the developer.\n\nUnder the hood, an underlaying transport layer will then take care of calling the right APIs for the actual platform implementation that your App is running on.\n\nThe Discovery plugin is used to _send_ information to the Platform.\n\n### Localization\nApps should provide all user-facing strings in the device's language, as specified by the Firebolt `Localization.language` property.\n\nApps should provide prices in the same currency presented in the app. If multiple currencies are supported in the app, the app should provide prices in the user's current default currency.", @@ -48,6 +49,83 @@ } ] }, + { + "name": "Actions.intent", + "summary": "Returns the current intent.", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:actions:intent" + ] + } + ], + "params": [ + ], + "result": { + "name": "intent", + "summary": "The current intent.", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Get the current intent", + "result": { + "name": "Default Result", + "value": "launch" + } + } + ] + }, + { + "name": "Actions.onIntent", + "tags": [ + { + "name": "event", + "x-notifier": "Actions.onIntent", + "x-subscriber-for": "Actions.intent" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:actions:intent" + ] + } + ], + "summary": "Notifies when the current intent changes.", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "result": { + "name": "intent", + "summary": "The current intent.", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Listen for intent changes", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "Default Result", + "value": "launch" + } + } + ] + }, { "name": "Accessibility.audioDescription", "summary": "Returns the audio description setting of the device", diff --git a/include/firebolt/actions.h b/include/firebolt/actions.h index 9c39198..660abd6 100644 --- a/include/firebolt/actions.h +++ b/include/firebolt/actions.h @@ -38,7 +38,7 @@ class IActions public: virtual ~IActions() = default; - virtual Result intent(const std::string& intent) const = 0; + virtual Result intent() const = 0; virtual Result subscribeOnIntent(std::function&& notification) = 0; virtual Result subscribeOnIntentChanged(std::function&& notification) diff --git a/run-component-tests-docker.sh b/run-component-tests-docker.sh new file mode 100755 index 0000000..aaa13e7 --- /dev/null +++ b/run-component-tests-docker.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +PROTOCOL="rpc_v2" +MOCK_DIR="/tmp/mock-firebolt-firebolt-cpp-client" +IMAGE_TAG="firebolt-client-ci:local" +SKIP_IMAGE_BUILD="false" + +usage() { + cat < RPC protocol (default: rpc_v2) + --mock-dir Host directory for mock-firebolt cache + (default: /tmp/mock-firebolt-firebolt-cpp-client) + --image-tag Docker image tag to use/build + (default: firebolt-client-ci:local) + --skip-image-build Reuse existing image tag; do not run docker build + --help Show this help + +Examples: + ./run-component-tests-docker.sh + ./run-component-tests-docker.sh --protocol legacy + ./run-component-tests-docker.sh --skip-image-build --image-tag firebolt-client-ci:local +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --protocol) + [[ $# -ge 2 ]] || { echo "Missing value for --protocol" >&2; exit 1; } + PROTOCOL="$2" + shift + ;; + --mock-dir) + [[ $# -ge 2 ]] || { echo "Missing value for --mock-dir" >&2; exit 1; } + MOCK_DIR="$2" + shift + ;; + --image-tag) + [[ $# -ge 2 ]] || { echo "Missing value for --image-tag" >&2; exit 1; } + IMAGE_TAG="$2" + shift + ;; + --skip-image-build) + SKIP_IMAGE_BUILD="true" + ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + usage + exit 1 + ;; + esac + shift +done + +if [[ "$PROTOCOL" != "rpc_v2" && "$PROTOCOL" != "legacy" ]]; then + echo "Invalid --protocol '$PROTOCOL'. Expected 'rpc_v2' or 'legacy'." >&2 + exit 1 +fi + +cd "$ROOT_DIR" + +if [[ ! -f .transport.version ]]; then + echo "Missing .transport.version in $ROOT_DIR" >&2 + exit 1 +fi + +TRANSPORT_VERSION="$(cat .transport.version)" +MOCK_SHA1SUM="1fec7b75190e75ac8ea8ebf9f3e00c0a070b2566" +MOCK_BRANCH="topic/changes-for-bidirectional" +NODE_VERSION="24.11.0" + +mkdir -p "$MOCK_DIR" + +echo "[1/4] Docker image: $IMAGE_TAG" +if [[ "$SKIP_IMAGE_BUILD" == "false" ]]; then + docker build \ + -f "$ROOT_DIR/.github/Dockerfile" \ + -t "$IMAGE_TAG" \ + --build-arg "DEPS_TRANSPORT_V=$TRANSPORT_VERSION" \ + --build-arg "DEPS_TRANSPORT_PROTOCOL=$PROTOCOL" \ + "$ROOT_DIR" +else + echo "Skipping image build (--skip-image-build)" +fi + +echo "[2/4] Preparing mock-firebolt in $MOCK_DIR" +docker run --rm --user "$(id -u):$(id -g)" \ + -v "$ROOT_DIR:/workspace" \ + -v "$MOCK_DIR:/mock-host" \ + "$IMAGE_TAG" \ + bash -c ' + set -e + if [ ! -d /mock-host/.git ]; then + git clone --depth 1 --branch '"$MOCK_BRANCH"' \ + https://github.com/rdkcentral/mock-firebolt.git /mock-host + fi + cd /mock-host + git fetch --shallow-since=2026-01-01 + git -c advice.detachedHead=false checkout '"$MOCK_SHA1SUM"' + source /usr/local/nvm/nvm.sh + nvm use --delete-prefix '"$NODE_VERSION"' >/dev/null + cd server + npm ci + ' + +BUILD_SUBDIR="build-docker" + +echo "[3/4] Building ctApp (build dir: $BUILD_SUBDIR)" +docker run --rm --user "$(id -u):$(id -g)" \ + -v "$ROOT_DIR:/workspace" \ + "$IMAGE_TAG" \ + bash -c ' + set -e + cd /workspace + rm -rf '"$BUILD_SUBDIR"' + cmake -B '"$BUILD_SUBDIR"' -S . -DCMAKE_BUILD_TYPE=Debug -DENABLE_TESTS=ON + cp docs/openrpc/the-spec/firebolt-open-rpc.json '"$BUILD_SUBDIR"'/test/ + cmake --build '"$BUILD_SUBDIR"' --parallel + chmod +x '"$BUILD_SUBDIR"'/test/ctApp + ' + +echo "[4/4] Running component tests" +docker run --rm --user "$(id -u):$(id -g)" \ + -v "$ROOT_DIR:/workspace" \ + -v "$MOCK_DIR:/mock" \ + "$IMAGE_TAG" \ + /workspace/.github/scripts/run-component-tests.sh \ + --mock /mock \ + --protocol "$PROTOCOL" \ + --config /workspace/.github/mock-firebolt/config.json \ + --openrpc /workspace/docs/openrpc/the-spec/firebolt-open-rpc.json \ + --app-openrpc /workspace/docs/openrpc/the-spec/firebolt-app-open-rpc.json \ + --test-exe /workspace/"$BUILD_SUBDIR"/test/ctApp + +echo "Done." diff --git a/src/actions_impl.cpp b/src/actions_impl.cpp index 431496f..61597de 100644 --- a/src/actions_impl.cpp +++ b/src/actions_impl.cpp @@ -33,11 +33,9 @@ ActionsImpl::ActionsImpl(Firebolt::Helpers::IHelper& helper) { } -Result ActionsImpl::intent(const std::string& intent) const +Result ActionsImpl::intent() const { - nlohmann::json params; - params["intent"] = intent; - return helper_.invoke("Actions.intent", params); + return helper_.get("Actions.intent"); } Result ActionsImpl::subscribeOnIntent(std::function&& notification) diff --git a/src/actions_impl.h b/src/actions_impl.h index e7eaf61..4c8d6ba 100644 --- a/src/actions_impl.h +++ b/src/actions_impl.h @@ -36,7 +36,7 @@ class ActionsImpl : public IActions ActionsImpl& operator=(const ActionsImpl&) = delete; ~ActionsImpl() override = default; - Result intent(const std::string& intent) const override; + Result intent() const override; Result subscribeOnIntent(std::function&& notification) override; diff --git a/test/component/actionsGeneratedTest.cpp b/test/component/actionsGeneratedTest.cpp index 6ce5e5d..ff1d53e 100644 --- a/test/component/actionsGeneratedTest.cpp +++ b/test/component/actionsGeneratedTest.cpp @@ -32,8 +32,9 @@ class ActionsGeneratedCTest : public ::testing::Test TEST_F(ActionsGeneratedCTest, Intent) { - auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().intent("launch"); - EXPECT_TRUE(result) << toError(result); + auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().intent(); + ASSERT_TRUE(result) << toError(result); + EXPECT_EQ(*result, "launch"); } TEST_F(ActionsGeneratedCTest, SubscribeOnIntent) @@ -52,7 +53,7 @@ TEST_F(ActionsGeneratedCTest, SubscribeOnIntent) ASSERT_TRUE(id) << toError(id); verifyEventSubscription(id); - triggerEvent("Actions.onIntent", R"({"value":"launch"})"); + triggerEvent("Actions.onIntent", R"("launch")"); verifyEventReceived(mtx, cv, eventReceived); auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().unsubscribe(id.value()); diff --git a/test/unit/actionsGeneratedTest.cpp b/test/unit/actionsGeneratedTest.cpp index 86006f3..cd024d6 100644 --- a/test/unit/actionsGeneratedTest.cpp +++ b/test/unit/actionsGeneratedTest.cpp @@ -42,15 +42,14 @@ TEST_F(ActionsGeneratedUTest, UnsubscribeForwardsToHelper) TEST_F(ActionsGeneratedUTest, ForwardsintentTransportErrors) { - EXPECT_CALL(mockHelper, invoke("Actions.intent", ::testing::_)) + EXPECT_CALL(mockHelper, getJson("Actions.intent", ::testing::_)) .WillOnce(::testing::Invoke( [](const std::string& /*method*/, const nlohmann::json& params) { - EXPECT_TRUE(params.is_object()) << "Expected params object for method call"; - EXPECT_TRUE(params.contains("intent")) << "Missing expected param key: intent"; - return Firebolt::Result{Firebolt::Error::General}; + EXPECT_TRUE(params.is_null() || params.empty()) << "Expected no params for method call"; + return Firebolt::Result{Firebolt::Error::General}; })); - auto result = impl.intent({}); + auto result = impl.intent(); EXPECT_FALSE(result) << "Expected error propagation when helper invoke fails"; } diff --git a/test/unit/actionsTest.cpp b/test/unit/actionsTest.cpp index 7295886..1b87480 100644 --- a/test/unit/actionsTest.cpp +++ b/test/unit/actionsTest.cpp @@ -28,14 +28,11 @@ class ActionsUTest : public ::testing::Test, protected MockBase TEST_F(ActionsUTest, Start) { - nlohmann::json expectedParams; - expectedParams["intent"] = "launch"; - EXPECT_CALL(mockHelper, invoke("Actions.intent", expectedParams)) - .WillOnce(Invoke([&](const std::string& /*methodName*/, const nlohmann::json& /*parameters*/) - { return Firebolt::Result{Firebolt::Error::None}; })); - - auto result = actionsImpl_.intent("launch"); - EXPECT_TRUE(result); + mock_with_response("Actions.intent", "launch"); + + auto result = actionsImpl_.intent(); + ASSERT_TRUE(result) << "ActionsImpl::intent() returned an error"; + EXPECT_EQ(*result, "launch"); } TEST_F(ActionsUTest, SubscribeOnIntent) From e80002249d20be761fbbd95d71b00c48cc018990 Mon Sep 17 00:00:00 2001 From: bobra200 Date: Tue, 2 Jun 2026 09:17:06 -0700 Subject: [PATCH 23/37] feat: use sdk gen to gen fix --- include/firebolt/actions.h | 14 +++--- ...-docker.sh => run-component-tests-local.sh | 0 src/actions_impl.cpp | 23 ++++------ src/actions_impl.h | 8 +--- src/json_types/actions.h | 12 +++-- test/component/actionsGeneratedTest.cpp | 44 +++---------------- test/unit/actionsGeneratedTest.cpp | 18 ++++---- 7 files changed, 36 insertions(+), 83 deletions(-) rename run-component-tests-docker.sh => run-component-tests-local.sh (100%) diff --git a/include/firebolt/actions.h b/include/firebolt/actions.h index 660abd6..23bb270 100644 --- a/include/firebolt/actions.h +++ b/include/firebolt/actions.h @@ -22,34 +22,30 @@ #ifndef FIREBOLT_ACTIONS_H #define FIREBOLT_ACTIONS_H -#include #include #include #include #include -#include #include +#include -namespace Firebolt::Actions -{ +namespace Firebolt::Actions { -class IActions -{ +class IActions { public: virtual ~IActions() = default; virtual Result intent() const = 0; virtual Result subscribeOnIntent(std::function&& notification) = 0; - virtual Result subscribeOnIntentChanged(std::function&& notification) - { + virtual Result subscribeOnIntentChanged(std::function&& notification) { return subscribeOnIntent(std::move(notification)); } virtual Result unsubscribe(SubscriptionId id) = 0; virtual void unsubscribeAll() = 0; -}; // class IActions +}; // class IActions } // namespace Firebolt::Actions diff --git a/run-component-tests-docker.sh b/run-component-tests-local.sh similarity index 100% rename from run-component-tests-docker.sh rename to run-component-tests-local.sh diff --git a/src/actions_impl.cpp b/src/actions_impl.cpp index 61597de..01dca17 100644 --- a/src/actions_impl.cpp +++ b/src/actions_impl.cpp @@ -23,33 +23,28 @@ #include "json_types/actions.h" #include #include +#include -namespace Firebolt::Actions -{ +namespace Firebolt::Actions { ActionsImpl::ActionsImpl(Firebolt::Helpers::IHelper& helper) - : helper_(helper), - subscriptionManager_(helper, this) -{ -} + : helper_(helper) + , subscriptionManager_(helper, this) +{} -Result ActionsImpl::intent() const -{ +Result ActionsImpl::intent() const { return helper_.get("Actions.intent"); } -Result ActionsImpl::subscribeOnIntent(std::function&& notification) -{ +Result ActionsImpl::subscribeOnIntent(std::function&& notification) { return subscriptionManager_.subscribe("Actions.onIntent", std::move(notification)); } -Result ActionsImpl::unsubscribe(SubscriptionId id) -{ +Result ActionsImpl::unsubscribe(SubscriptionId id) { return subscriptionManager_.unsubscribe(id); } -void ActionsImpl::unsubscribeAll() -{ +void ActionsImpl::unsubscribeAll() { subscriptionManager_.unsubscribeAll(); } diff --git a/src/actions_impl.h b/src/actions_impl.h index 4c8d6ba..8653882 100644 --- a/src/actions_impl.h +++ b/src/actions_impl.h @@ -25,15 +25,11 @@ #include "firebolt/actions.h" #include -namespace Firebolt::Actions -{ +namespace Firebolt::Actions { -class ActionsImpl : public IActions -{ +class ActionsImpl : public IActions { public: explicit ActionsImpl(Firebolt::Helpers::IHelper& helper); - ActionsImpl(const ActionsImpl&) = delete; - ActionsImpl& operator=(const ActionsImpl&) = delete; ~ActionsImpl() override = default; Result intent() const override; diff --git a/src/json_types/actions.h b/src/json_types/actions.h index 60c76ce..6025350 100644 --- a/src/json_types/actions.h +++ b/src/json_types/actions.h @@ -23,16 +23,14 @@ #define FIREBOLT_ACTIONS_JSON_H #pragma once -#include "firebolt/actions.h" -#include -#include #include +#include +#include +#include "firebolt/actions.h" -namespace Firebolt::Actions -{ +namespace Firebolt::Actions { -namespace JsonData -{ +namespace JsonData { } // namespace JsonData diff --git a/test/component/actionsGeneratedTest.cpp b/test/component/actionsGeneratedTest.cpp index ff1d53e..a08372b 100644 --- a/test/component/actionsGeneratedTest.cpp +++ b/test/component/actionsGeneratedTest.cpp @@ -16,46 +16,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "firebolt/firebolt.h" -#include "utils.h" +#include "firebolt/actions.h" #include -class ActionsGeneratedCTest : public ::testing::Test +TEST(ActionsGeneratedCTest, InterfaceSurfaceHasintent) { -protected: - void SetUp() override { eventReceived = false; } - - std::condition_variable cv; - std::mutex mtx; - bool eventReceived; -}; - -TEST_F(ActionsGeneratedCTest, Intent) -{ - auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().intent(); - ASSERT_TRUE(result) << toError(result); - EXPECT_EQ(*result, "launch"); + using Interface = Firebolt::Actions::IActions; + auto ptr = &Interface::intent; + (void)ptr; + SUCCEED(); } -TEST_F(ActionsGeneratedCTest, SubscribeOnIntent) -{ - auto id = Firebolt::IFireboltAccessor::Instance().ActionsInterface().subscribeOnIntent( - [&](const std::string& intent) - { - EXPECT_EQ(intent, "launch"); - { - std::lock_guard lock(mtx); - eventReceived = true; - } - cv.notify_one(); - }); - - ASSERT_TRUE(id) << toError(id); - verifyEventSubscription(id); - - triggerEvent("Actions.onIntent", R"("launch")"); - verifyEventReceived(mtx, cv, eventReceived); - - auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().unsubscribe(id.value()); - verifyUnsubscribeResult(result); -} diff --git a/test/unit/actionsGeneratedTest.cpp b/test/unit/actionsGeneratedTest.cpp index cd024d6..f1e0129 100644 --- a/test/unit/actionsGeneratedTest.cpp +++ b/test/unit/actionsGeneratedTest.cpp @@ -16,8 +16,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "actions_impl.h" #include "mock_helper.h" +#include "actions_impl.h" #include class ActionsGeneratedUTest : public ::testing::Test @@ -34,22 +34,22 @@ TEST_F(ActionsGeneratedUTest, Constructs) TEST_F(ActionsGeneratedUTest, UnsubscribeForwardsToHelper) { - EXPECT_CALL(mockHelper, unsubscribe(7)).WillOnce(::testing::Return(Firebolt::Result{Firebolt::Error::None})); + EXPECT_CALL(mockHelper, unsubscribe(7)) + .WillOnce(::testing::Return(Firebolt::Result{Firebolt::Error::None})); auto result = impl.unsubscribe(7); ASSERT_TRUE(result) << "unsubscribe should return success when helper succeeds"; } + TEST_F(ActionsGeneratedUTest, ForwardsintentTransportErrors) { EXPECT_CALL(mockHelper, getJson("Actions.intent", ::testing::_)) - .WillOnce(::testing::Invoke( - [](const std::string& /*method*/, const nlohmann::json& params) - { - EXPECT_TRUE(params.is_null() || params.empty()) << "Expected no params for method call"; - return Firebolt::Result{Firebolt::Error::General}; - })); + .WillOnce(::testing::Invoke([](const std::string& /*method*/, const nlohmann::json& /*params*/) { + return Firebolt::Result{Firebolt::Error::General}; + })); auto result = impl.intent(); - EXPECT_FALSE(result) << "Expected error propagation when helper invoke fails"; + EXPECT_FALSE(result) << "Expected error propagation when helper getJson fails"; } + From 08384df5a39a113b1930b0eb23a8b556b6c8cf4b Mon Sep 17 00:00:00 2001 From: Brendan O'Bra Date: Tue, 2 Jun 2026 10:00:10 -0700 Subject: [PATCH 24/37] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- run-component-tests-local.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/run-component-tests-local.sh b/run-component-tests-local.sh index aaa13e7..9a0d6d1 100755 --- a/run-component-tests-local.sh +++ b/run-component-tests-local.sh @@ -11,7 +11,7 @@ SKIP_IMAGE_BUILD="false" usage() { cat < Date: Tue, 2 Jun 2026 10:06:43 -0700 Subject: [PATCH 25/37] fix: delete copy constructor added --- src/actions_impl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/actions_impl.h b/src/actions_impl.h index 8653882..229b60d 100644 --- a/src/actions_impl.h +++ b/src/actions_impl.h @@ -30,6 +30,8 @@ namespace Firebolt::Actions { class ActionsImpl : public IActions { public: explicit ActionsImpl(Firebolt::Helpers::IHelper& helper); + ActionsImpl(const ActionsImpl&) = delete; + ActionsImpl& operator=(const ActionsImpl&) = delete; ~ActionsImpl() override = default; Result intent() const override; From 684a7043b3b56c85afed31d046a0488c6ad22848 Mon Sep 17 00:00:00 2001 From: bobra200 Date: Tue, 2 Jun 2026 10:14:12 -0700 Subject: [PATCH 26/37] fix(actions): address include review comments --- include/firebolt/actions.h | 1 + src/actions_impl.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/firebolt/actions.h b/include/firebolt/actions.h index 23bb270..f76efbd 100644 --- a/include/firebolt/actions.h +++ b/include/firebolt/actions.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff --git a/src/actions_impl.cpp b/src/actions_impl.cpp index 01dca17..ced5bef 100644 --- a/src/actions_impl.cpp +++ b/src/actions_impl.cpp @@ -23,7 +23,6 @@ #include "json_types/actions.h" #include #include -#include namespace Firebolt::Actions { From 53bf62b4d7c20420f7f7d09feaef0175eca0d9cd Mon Sep 17 00:00:00 2001 From: bobra200 Date: Tue, 2 Jun 2026 10:16:46 -0700 Subject: [PATCH 27/37] fix(actions): address remaining review feedback --- docs/openrpc/the-spec/firebolt-open-rpc.json | 5 ++- test/component/actionsGeneratedTest.cpp | 47 +++++++++++++++++--- test/unit/actionsGeneratedTest.cpp | 2 +- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/docs/openrpc/the-spec/firebolt-open-rpc.json b/docs/openrpc/the-spec/firebolt-open-rpc.json index 89ae940..b66c62f 100644 --- a/docs/openrpc/the-spec/firebolt-open-rpc.json +++ b/docs/openrpc/the-spec/firebolt-open-rpc.json @@ -5,7 +5,7 @@ "version": "", "x-module-descriptions": { "Accessibility": "The `Accessibility` module provides access to the user/device settings for closed captioning and voice guidance.\n\nApps **SHOULD** attempt o respect these settings, rather than manage and persist seprate settings, which would be different per-app.", - "Actions": "Methods for setting and observing app intents.", + "Actions": "Methods for getting and observing app intents.", "Advertising": "A module for platform provided advertising settings and functionality.", "Device": "A module for querying about the device and it's capabilities.", "Discovery": "Your App likely wants to integrate with the Platform's discovery capabilities. For example to add a \"Watch Next\" tile that links to your app from the platform's home screen.\n\nGetting access to this information requires to connect to lower level APIs made available by the platform. Since implementations differ between operators and platforms, the Firebolt SDK offers a Discovery module, that exposes a generic, agnostic interface to the developer.\n\nUnder the hood, an underlaying transport layer will then take care of calling the right APIs for the actual platform implementation that your App is running on.\n\nThe Discovery plugin is used to _send_ information to the Platform.\n\n### Localization\nApps should provide all user-facing strings in the device's language, as specified by the Firebolt `Localization.language` property.\n\nApps should provide prices in the same currency presented in the app. If multiple currencies are supported in the app, the app should provide prices in the user's current default currency.", @@ -25,6 +25,9 @@ "summary": "The OpenRPC schema for this JSON-RPC API", "params": [], "tags": [ + { + "name": "property:readonly" + }, { "name": "capabilities", "x-uses": [ diff --git a/test/component/actionsGeneratedTest.cpp b/test/component/actionsGeneratedTest.cpp index a08372b..e14323e 100644 --- a/test/component/actionsGeneratedTest.cpp +++ b/test/component/actionsGeneratedTest.cpp @@ -16,14 +16,49 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "firebolt/actions.h" +#include "firebolt/firebolt.h" +#include "utils.h" +#include #include +#include -TEST(ActionsGeneratedCTest, InterfaceSurfaceHasintent) +class ActionsGeneratedCTest : public ::testing::Test { - using Interface = Firebolt::Actions::IActions; - auto ptr = &Interface::intent; - (void)ptr; - SUCCEED(); +protected: + void SetUp() override { eventReceived = false; } + + std::condition_variable cv; + std::mutex mtx; + bool eventReceived; +}; + +TEST_F(ActionsGeneratedCTest, Intent) +{ + auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().intent(); + ASSERT_TRUE(result) << toError(result); + EXPECT_EQ(*result, "launch"); +} + +TEST_F(ActionsGeneratedCTest, SubscribeOnIntent) +{ + auto id = Firebolt::IFireboltAccessor::Instance().ActionsInterface().subscribeOnIntent( + [&](const std::string& intent) + { + EXPECT_EQ(intent, "launch"); + { + std::lock_guard lock(mtx); + eventReceived = true; + } + cv.notify_one(); + }); + + ASSERT_TRUE(id) << toError(id); + verifyEventSubscription(id); + + triggerEvent("Actions.onIntent", R"("launch")"); + verifyEventReceived(mtx, cv, eventReceived); + + auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().unsubscribe(id.value()); + verifyUnsubscribeResult(result); } diff --git a/test/unit/actionsGeneratedTest.cpp b/test/unit/actionsGeneratedTest.cpp index f1e0129..0a19b4f 100644 --- a/test/unit/actionsGeneratedTest.cpp +++ b/test/unit/actionsGeneratedTest.cpp @@ -42,7 +42,7 @@ TEST_F(ActionsGeneratedUTest, UnsubscribeForwardsToHelper) } -TEST_F(ActionsGeneratedUTest, ForwardsintentTransportErrors) +TEST_F(ActionsGeneratedUTest, ForwardsIntentTransportErrors) { EXPECT_CALL(mockHelper, getJson("Actions.intent", ::testing::_)) .WillOnce(::testing::Invoke([](const std::string& /*method*/, const nlohmann::json& /*params*/) { From 020afc90e5851b870c8a28d2fd2b1c353ed2a30d Mon Sep 17 00:00:00 2001 From: bobra200 Date: Tue, 2 Jun 2026 10:19:44 -0700 Subject: [PATCH 28/37] docs: add copilot instructions for cpp client conventions --- .github/copilot-instructions.md | 84 +++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..e80616f --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,84 @@ +# firebolt-cpp-client Copilot Instructions + +Scope: This file applies to the firebolt-cpp-client repository. + +## Primary goals + +- Preserve API contract correctness across interface, implementation, tests, and OpenRPC fixtures. +- Keep generated surfaces and bespoke conventions aligned. +- Prefer minimal, targeted changes. + +## High-signal workflow + +1. For API-facing changes, update all of the following in one pass: + - `include/firebolt/*.h` + - `src/*_impl.h` and `src/*_impl.cpp` + - `test/unit/*Test.cpp` and `test/component/*Test.cpp` + - `docs/openrpc/the-spec/firebolt-open-rpc.json` when component tests depend on fixture shape. +2. Run component tests after edits. +3. If behavior is generator-owned, patch generator code in sibling repo and regenerate module artifacts. + +## Test commands + +- Local one-shot (current preferred): + - `./run-component-tests-local.sh` + - `./run-component-tests-local.sh --skip-image-build` +- Legacy wrappers may still exist in conversation history; prefer the local script in this repo. +- Unit-only: + - `./run-unit-tests.sh` + +## Actions module rules (important) + +- `Actions.intent` is getter-only: + - takes no parameters + - returns `Result` +- `Actions.onIntent` callback payload is a string value. +- Component event trigger for `Actions.onIntent` should use a string JSON payload (for example `"launch"`), not an object. + +## Generated-code conventions that must be preserved + +- `*Impl` classes should delete copy constructor and copy assignment: + - `ClassName(const ClassName&) = delete;` + - `ClassName& operator=(const ClassName&) = delete;` +- Unless explicitly justified as safe, `*Impl` classes should also delete move operations: + - `ClassName(ClassName&&) = delete;` + - `ClassName& operator=(ClassName&&) = delete;` +- Keep include hygiene strict: + - include `` when using `std::move` + - remove unused includes such as `` when not used +- Keep test names in consistent CamelCase for filtering. + +## Component test expectations + +- Red schema validation lines in logs can be expected for negative-path tests. +- Negative tests must still verify runtime behavior (callbacks not delivered for invalid payloads), not just compile-time surface checks. + +## OpenRPC fixture expectations + +- Module descriptions must match actual API behavior. +- Getter-style methods should carry property tags consistent with the rest of the file (for example `property:readonly` where applicable). +- Keep notifier/subscriber metadata aligned (`x-notifier`, `x-subscriber-for`). + +## Regeneration notes (sibling repo) + +When a change is generator-owned, use `firebolt-sdk-gen` and apply module-scoped output back into this repo. + +Typical flow: + +- From `../firebolt-sdk-gen`: + - `./sync-plan-checklist.sh --profile core --module actions --apply --no-accessor-touchpoints --target-root ../firebolt-cpp-client` + +This keeps migration incremental and avoids unrelated accessor touchpoint churn. + +## CI parity reminders + +- CI uses Dockerized build/test flow and mock-firebolt integration. +- Keep changes compatible with: + - `.github/workflows/ci.yml` + - `.github/scripts/run-component-tests.sh` + +## PR hygiene + +- If a review asks for include-file fixes, prefer precise header/source edits and re-run component tests. +- Do not relax negative tests just to suppress red validation logs. +- Keep commit messages scoped and explicit (example: `fix(actions): address include review comments`). From 74c8f2b104c2d4e85be30ae4741627f36d4e008b Mon Sep 17 00:00:00 2001 From: Brendan O'Bra Date: Tue, 2 Jun 2026 10:34:07 -0700 Subject: [PATCH 29/37] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- docs/openrpc/the-spec/firebolt-open-rpc.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/openrpc/the-spec/firebolt-open-rpc.json b/docs/openrpc/the-spec/firebolt-open-rpc.json index b66c62f..4600d5d 100644 --- a/docs/openrpc/the-spec/firebolt-open-rpc.json +++ b/docs/openrpc/the-spec/firebolt-open-rpc.json @@ -56,6 +56,9 @@ "name": "Actions.intent", "summary": "Returns the current intent.", "tags": [ + { + "name": "property:readonly" + }, { "name": "capabilities", "x-uses": [ @@ -63,8 +66,7 @@ ] } ], - "params": [ - ], + "params": [], "result": { "name": "intent", "summary": "The current intent.", From 45d1ffce78f2c8dbe1342ea2a6dc933d81bc7278 Mon Sep 17 00:00:00 2001 From: bobra200 Date: Tue, 2 Jun 2026 10:37:31 -0700 Subject: [PATCH 30/37] fix(actions): finalize PR review follow-ups --- docs/openrpc/the-spec/firebolt-open-rpc.json | 3 --- test/unit/actionsGeneratedTest.cpp | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/openrpc/the-spec/firebolt-open-rpc.json b/docs/openrpc/the-spec/firebolt-open-rpc.json index 4600d5d..9ad9084 100644 --- a/docs/openrpc/the-spec/firebolt-open-rpc.json +++ b/docs/openrpc/the-spec/firebolt-open-rpc.json @@ -25,9 +25,6 @@ "summary": "The OpenRPC schema for this JSON-RPC API", "params": [], "tags": [ - { - "name": "property:readonly" - }, { "name": "capabilities", "x-uses": [ diff --git a/test/unit/actionsGeneratedTest.cpp b/test/unit/actionsGeneratedTest.cpp index 0a19b4f..51b3ee3 100644 --- a/test/unit/actionsGeneratedTest.cpp +++ b/test/unit/actionsGeneratedTest.cpp @@ -45,7 +45,9 @@ TEST_F(ActionsGeneratedUTest, UnsubscribeForwardsToHelper) TEST_F(ActionsGeneratedUTest, ForwardsIntentTransportErrors) { EXPECT_CALL(mockHelper, getJson("Actions.intent", ::testing::_)) - .WillOnce(::testing::Invoke([](const std::string& /*method*/, const nlohmann::json& /*params*/) { + .WillOnce(::testing::Invoke([](const std::string& /*method*/, const nlohmann::json& params) { + EXPECT_TRUE(params.is_null() || (params.is_object() && params.empty())) + << "Actions.intent getter should not send request params"; return Firebolt::Result{Firebolt::Error::General}; })); From e98cce604f57c3c4ec6cf1905ab40e0ed0c1286f Mon Sep 17 00:00:00 2001 From: bobra200 Date: Tue, 2 Jun 2026 10:42:08 -0700 Subject: [PATCH 31/37] fix(actions): drop unused nlohmann include --- src/actions_impl.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/actions_impl.cpp b/src/actions_impl.cpp index ced5bef..aba7b5b 100644 --- a/src/actions_impl.cpp +++ b/src/actions_impl.cpp @@ -22,7 +22,6 @@ #include "actions_impl.h" #include "json_types/actions.h" #include -#include namespace Firebolt::Actions { From f2fc7a3903ddc3d88b909af515f9f71aac008bb0 Mon Sep 17 00:00:00 2001 From: Brendan O'Bra Date: Tue, 2 Jun 2026 10:59:50 -0700 Subject: [PATCH 32/37] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- run-component-tests-local.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run-component-tests-local.sh b/run-component-tests-local.sh index 9a0d6d1..1752276 100755 --- a/run-component-tests-local.sh +++ b/run-component-tests-local.sh @@ -111,7 +111,7 @@ docker run --rm --user "$(id -u):$(id -g)" \ https://github.com/rdkcentral/mock-firebolt.git /mock-host fi cd /mock-host - git fetch --shallow-since=2026-01-01 + git fetch --depth 1 origin '"$MOCK_SHA1SUM"' git -c advice.detachedHead=false checkout '"$MOCK_SHA1SUM"' source /usr/local/nvm/nvm.sh nvm use --delete-prefix '"$NODE_VERSION"' >/dev/null From 46fc48d3d547e02d87513d830b6afed5cf291263 Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Tue, 2 Jun 2026 15:14:06 -0400 Subject: [PATCH 33/37] fix(actions): apply clang-format to resolve CI formatting violations --- include/firebolt/actions.h | 13 ++++++++----- src/actions_impl.cpp | 22 ++++++++++++++-------- src/actions_impl.h | 6 ++++-- src/json_types/actions.h | 12 +++++++----- test/component/actionsGeneratedTest.cpp | 1 - test/unit/actionsGeneratedTest.cpp | 12 ++++-------- 6 files changed, 37 insertions(+), 29 deletions(-) diff --git a/include/firebolt/actions.h b/include/firebolt/actions.h index f76efbd..660abd6 100644 --- a/include/firebolt/actions.h +++ b/include/firebolt/actions.h @@ -22,31 +22,34 @@ #ifndef FIREBOLT_ACTIONS_H #define FIREBOLT_ACTIONS_H +#include #include #include #include #include #include #include -#include -namespace Firebolt::Actions { +namespace Firebolt::Actions +{ -class IActions { +class IActions +{ public: virtual ~IActions() = default; virtual Result intent() const = 0; virtual Result subscribeOnIntent(std::function&& notification) = 0; - virtual Result subscribeOnIntentChanged(std::function&& notification) { + virtual Result subscribeOnIntentChanged(std::function&& notification) + { return subscribeOnIntent(std::move(notification)); } virtual Result unsubscribe(SubscriptionId id) = 0; virtual void unsubscribeAll() = 0; -}; // class IActions +}; // class IActions } // namespace Firebolt::Actions diff --git a/src/actions_impl.cpp b/src/actions_impl.cpp index ced5bef..61597de 100644 --- a/src/actions_impl.cpp +++ b/src/actions_impl.cpp @@ -24,26 +24,32 @@ #include #include -namespace Firebolt::Actions { +namespace Firebolt::Actions +{ ActionsImpl::ActionsImpl(Firebolt::Helpers::IHelper& helper) - : helper_(helper) - , subscriptionManager_(helper, this) -{} + : helper_(helper), + subscriptionManager_(helper, this) +{ +} -Result ActionsImpl::intent() const { +Result ActionsImpl::intent() const +{ return helper_.get("Actions.intent"); } -Result ActionsImpl::subscribeOnIntent(std::function&& notification) { +Result ActionsImpl::subscribeOnIntent(std::function&& notification) +{ return subscriptionManager_.subscribe("Actions.onIntent", std::move(notification)); } -Result ActionsImpl::unsubscribe(SubscriptionId id) { +Result ActionsImpl::unsubscribe(SubscriptionId id) +{ return subscriptionManager_.unsubscribe(id); } -void ActionsImpl::unsubscribeAll() { +void ActionsImpl::unsubscribeAll() +{ subscriptionManager_.unsubscribeAll(); } diff --git a/src/actions_impl.h b/src/actions_impl.h index 229b60d..4c8d6ba 100644 --- a/src/actions_impl.h +++ b/src/actions_impl.h @@ -25,9 +25,11 @@ #include "firebolt/actions.h" #include -namespace Firebolt::Actions { +namespace Firebolt::Actions +{ -class ActionsImpl : public IActions { +class ActionsImpl : public IActions +{ public: explicit ActionsImpl(Firebolt::Helpers::IHelper& helper); ActionsImpl(const ActionsImpl&) = delete; diff --git a/src/json_types/actions.h b/src/json_types/actions.h index 6025350..60c76ce 100644 --- a/src/json_types/actions.h +++ b/src/json_types/actions.h @@ -23,14 +23,16 @@ #define FIREBOLT_ACTIONS_JSON_H #pragma once -#include -#include -#include #include "firebolt/actions.h" +#include +#include +#include -namespace Firebolt::Actions { +namespace Firebolt::Actions +{ -namespace JsonData { +namespace JsonData +{ } // namespace JsonData diff --git a/test/component/actionsGeneratedTest.cpp b/test/component/actionsGeneratedTest.cpp index e14323e..38a5356 100644 --- a/test/component/actionsGeneratedTest.cpp +++ b/test/component/actionsGeneratedTest.cpp @@ -61,4 +61,3 @@ TEST_F(ActionsGeneratedCTest, SubscribeOnIntent) auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().unsubscribe(id.value()); verifyUnsubscribeResult(result); } - diff --git a/test/unit/actionsGeneratedTest.cpp b/test/unit/actionsGeneratedTest.cpp index 0a19b4f..9fba572 100644 --- a/test/unit/actionsGeneratedTest.cpp +++ b/test/unit/actionsGeneratedTest.cpp @@ -16,8 +16,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "mock_helper.h" #include "actions_impl.h" +#include "mock_helper.h" #include class ActionsGeneratedUTest : public ::testing::Test @@ -34,22 +34,18 @@ TEST_F(ActionsGeneratedUTest, Constructs) TEST_F(ActionsGeneratedUTest, UnsubscribeForwardsToHelper) { - EXPECT_CALL(mockHelper, unsubscribe(7)) - .WillOnce(::testing::Return(Firebolt::Result{Firebolt::Error::None})); + EXPECT_CALL(mockHelper, unsubscribe(7)).WillOnce(::testing::Return(Firebolt::Result{Firebolt::Error::None})); auto result = impl.unsubscribe(7); ASSERT_TRUE(result) << "unsubscribe should return success when helper succeeds"; } - TEST_F(ActionsGeneratedUTest, ForwardsIntentTransportErrors) { EXPECT_CALL(mockHelper, getJson("Actions.intent", ::testing::_)) - .WillOnce(::testing::Invoke([](const std::string& /*method*/, const nlohmann::json& /*params*/) { - return Firebolt::Result{Firebolt::Error::General}; - })); + .WillOnce(::testing::Invoke([](const std::string& /*method*/, const nlohmann::json& /*params*/) + { return Firebolt::Result{Firebolt::Error::General}; })); auto result = impl.intent(); EXPECT_FALSE(result) << "Expected error propagation when helper getJson fails"; } - From 959ef6239866ed1e68dd1f5ce7e22c0ec8a4b096 Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Tue, 2 Jun 2026 15:39:36 -0400 Subject: [PATCH 34/37] Update workflow to trigger checks for develop branch push/pull_request --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 01baa9a..0c7d124 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,9 +12,9 @@ on: - rpc_v2 - legacy push: - branches: [ main, next ] + branches: [ main, develop, next ] pull_request: - branches: [ main, next ] + branches: [ main, develop, next ] defaults: run: From 49f255a9fc3dc0e05f88f7b2eb4b634fbbd817d6 Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 3 Jun 2026 06:21:11 -0700 Subject: [PATCH 35/37] Address PR #66 review comments on params and test robustness --- src/metrics_impl.cpp | 6 +++--- test/unit/mock_helper.h | 18 ++++++++++++++++-- test/utils.cpp | 4 ++-- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/metrics_impl.cpp b/src/metrics_impl.cpp index 9f29027..0e04139 100644 --- a/src/metrics_impl.cpp +++ b/src/metrics_impl.cpp @@ -30,17 +30,17 @@ MetricsImpl::MetricsImpl(Firebolt::Helpers::IHelper& helper) Result MetricsImpl::ready() const { - return helper_.invoke("Metrics.ready", nlohmann::json({})); + return helper_.invoke("Metrics.ready", nlohmann::json()); } Result MetricsImpl::signIn() const { - return helper_.invoke("Metrics.signIn", nlohmann::json({})); + return helper_.invoke("Metrics.signIn", nlohmann::json()); } Result MetricsImpl::signOut() const { - return helper_.invoke("Metrics.signOut", nlohmann::json({})); + return helper_.invoke("Metrics.signOut", nlohmann::json()); } Result MetricsImpl::startContent(const std::optional& entityId, diff --git a/test/unit/mock_helper.h b/test/unit/mock_helper.h index f2a9ffb..e29342c 100644 --- a/test/unit/mock_helper.h +++ b/test/unit/mock_helper.h @@ -107,8 +107,22 @@ class MockBase void mockInvoke(const std::string& methodName) { EXPECT_CALL(mockHelper, invoke(methodName, _)) - .WillOnce(Invoke([](const std::string& /*methodName*/, const nlohmann::json& /*parameters*/) - { return Firebolt::Result{Firebolt::Error::None}; })); + .WillOnce(Invoke([&](const std::string& methodName, const nlohmann::json& parameters) + { + nlohmann::json message = { + {"jsonrpc", "2.0"}, + {"id", "0"}, + {"method", methodName}, + }; + + if (!parameters.is_null()) + { + message["params"] = parameters; + } + + Firebolt::Error err = jsonEngine.MockResponse(message); + return Firebolt::Result{err}; + })); } void mockSubscribe(const std::string& eventName) diff --git a/test/utils.cpp b/test/utils.cpp index 60de1be..cc75f38 100644 --- a/test/utils.cpp +++ b/test/utils.cpp @@ -136,9 +136,9 @@ void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, const boo void verifyEventNotReceived(std::mutex& mtx, std::condition_variable& cv, const bool& eventReceived) { - // Wait for the event to be received or timeout after 5 seconds + // Wait for the event to be received or timeout after EventWaitTime. std::unique_lock lock(mtx); - if (cv.wait_for(lock, std::chrono::seconds(EventWaitTime), [&] { return eventReceived; })) + if (cv.wait_for(lock, EventWaitTime, [&] { return eventReceived; })) { FAIL() << "Unexpectedly received event"; } From ed57b7ccf20de0eb5769634f0b5a69e83e34010f Mon Sep 17 00:00:00 2001 From: bobra200 Date: Wed, 3 Jun 2026 06:39:14 -0700 Subject: [PATCH 36/37] Apply clang-format to mock_helper after review fixes --- test/unit/mock_helper.h | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/test/unit/mock_helper.h b/test/unit/mock_helper.h index e29342c..d5d5580 100644 --- a/test/unit/mock_helper.h +++ b/test/unit/mock_helper.h @@ -107,22 +107,23 @@ class MockBase void mockInvoke(const std::string& methodName) { EXPECT_CALL(mockHelper, invoke(methodName, _)) - .WillOnce(Invoke([&](const std::string& methodName, const nlohmann::json& parameters) - { - nlohmann::json message = { - {"jsonrpc", "2.0"}, - {"id", "0"}, - {"method", methodName}, - }; - - if (!parameters.is_null()) - { - message["params"] = parameters; - } - - Firebolt::Error err = jsonEngine.MockResponse(message); - return Firebolt::Result{err}; - })); + .WillOnce(Invoke( + [&](const std::string& methodName, const nlohmann::json& parameters) + { + nlohmann::json message = { + {"jsonrpc", "2.0"}, + {"id", "0"}, + {"method", methodName}, + }; + + if (!parameters.is_null()) + { + message["params"] = parameters; + } + + Firebolt::Error err = jsonEngine.MockResponse(message); + return Firebolt::Result{err}; + })); } void mockSubscribe(const std::string& eventName) From 51e0df3f7a6c53847bf77d12b5092f0927e59933 Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Wed, 3 Jun 2026 11:21:09 -0400 Subject: [PATCH 37/37] Address copilot comments --- test/unit/mock_helper.h | 4 ++-- test/utils.cpp | 4 ++-- test/utils.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/unit/mock_helper.h b/test/unit/mock_helper.h index d5d5580..00598e5 100644 --- a/test/unit/mock_helper.h +++ b/test/unit/mock_helper.h @@ -108,12 +108,12 @@ class MockBase { EXPECT_CALL(mockHelper, invoke(methodName, _)) .WillOnce(Invoke( - [&](const std::string& methodName, const nlohmann::json& parameters) + [&](const std::string& invokedMethodName, const nlohmann::json& parameters) { nlohmann::json message = { {"jsonrpc", "2.0"}, {"id", "0"}, - {"method", methodName}, + {"method", invokedMethodName}, }; if (!parameters.is_null()) diff --git a/test/utils.cpp b/test/utils.cpp index cc75f38..c24a4e1 100644 --- a/test/utils.cpp +++ b/test/utils.cpp @@ -125,7 +125,7 @@ void verifyUnsubscribeResult(const Firebolt::Result& result) FAIL() << "Unsubscribe failed." + toError(result); } } -void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, const bool& eventReceived) +void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, bool& eventReceived) { std::unique_lock lock(mtx); if (!cv.wait_for(lock, EventWaitTime, [&] { return eventReceived; })) @@ -134,7 +134,7 @@ void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, const boo } } -void verifyEventNotReceived(std::mutex& mtx, std::condition_variable& cv, const bool& eventReceived) +void verifyEventNotReceived(std::mutex& mtx, std::condition_variable& cv, bool& eventReceived) { // Wait for the event to be received or timeout after EventWaitTime. std::unique_lock lock(mtx); diff --git a/test/utils.h b/test/utils.h index b5d0693..bd1e2e3 100644 --- a/test/utils.h +++ b/test/utils.h @@ -32,8 +32,8 @@ void triggerRaw(const std::string& payload); void verifyEventSubscription(const Firebolt::Result& id); void verifyUnsubscribeResult(const Firebolt::Result& result); -void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, const bool& eventReceived); -void verifyEventNotReceived(std::mutex& mtx, std::condition_variable& cv, const bool& eventReceived); +void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, bool& eventReceived); +void verifyEventNotReceived(std::mutex& mtx, std::condition_variable& cv, bool& eventReceived); template inline std::string toError(const Firebolt::Result& result) {