diff --git a/docs/openrpc/the-spec/firebolt-open-rpc.json b/docs/openrpc/the-spec/firebolt-open-rpc.json index 3f85e59..3b2f7b9 100644 --- a/docs/openrpc/the-spec/firebolt-open-rpc.json +++ b/docs/openrpc/the-spec/firebolt-open-rpc.json @@ -883,6 +883,39 @@ } ] }, + { + "name": "Device.name", + "summary": "Returns the device friendly name", + "params": [], + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "result": { + "name": "name", + "summary": "The device friendly name", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Getting the device friendly name", + "params": [], + "result": { + "name": "Default Result", + "value": "Living Room TV" + } + } + ] + }, { "name": "Discovery.watched", "summary": "Notify the platform that content was partially or completely watched", @@ -4118,6 +4151,52 @@ } } }, + { + "name": "Device.onNameChanged", + "summary": "Returns the device friendly name", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "tags": [ + { + "name": "event", + "x-notifier": "Device.onNameChanged", + "x-subscriber-for": "Device.name" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "examples": [ + { + "name": "Getting the device friendly name", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "string" + } + } + }, { "name": "VideoOutput.resolution", "summary": "Returns the resolution for the active video output", diff --git a/include/firebolt/device.h b/include/firebolt/device.h index a5d9481..cec464b 100644 --- a/include/firebolt/device.h +++ b/include/firebolt/device.h @@ -166,6 +166,20 @@ class IDevice */ virtual Result subscribeOnDolbyAtmosExperienceAvailableChanged(std::function&& notification) = 0; + + /** + * @brief Returns the device friendly name + * + * @retval The device name string or error + */ + [[nodiscard]] virtual Result name() const = 0; + + /** + * @brief Subscribe to device friendly name changes + * + * @retval SubscriptionId or error + */ + virtual Result subscribeOnNameChanged(std::function&& notification) = 0; }; } // namespace Firebolt::Device diff --git a/src/device_impl.cpp b/src/device_impl.cpp index adee10b..4a1082f 100644 --- a/src/device_impl.cpp +++ b/src/device_impl.cpp @@ -111,4 +111,14 @@ Result DeviceImpl::subscribeOnDolbyAtmosExperienceAvailableChang return subscriptionManager_.subscribe("Device.onDolbyAtmosExperienceAvailableChanged", std::move(notification)); } + +Result DeviceImpl::name() const +{ + return helper_.get("Device.name"); +} + +Result DeviceImpl::subscribeOnNameChanged(std::function&& notification) +{ + return subscriptionManager_.subscribe("Device.onNameChanged", std::move(notification)); +} } // namespace Firebolt::Device diff --git a/src/device_impl.h b/src/device_impl.h index 297eede..7f67007 100644 --- a/src/device_impl.h +++ b/src/device_impl.h @@ -53,6 +53,9 @@ class DeviceImpl : public IDevice Result subscribeOnDolbyAtmosExperienceAvailableChanged(std::function&& notification) override; + [[nodiscard]] Result name() const override; + Result subscribeOnNameChanged(std::function&& notification) override; + private: Firebolt::Helpers::IHelper& helper_; Firebolt::Helpers::SubscriptionManager subscriptionManager_; diff --git a/src/firebolt.cpp b/src/firebolt.cpp index 09b7296..6842a9f 100644 --- a/src/firebolt.cpp +++ b/src/firebolt.cpp @@ -98,6 +98,7 @@ class FireboltAccessorImpl : public IFireboltAccessor { accessibility_.unsubscribeAll(); actions_.unsubscribeAll(); + device_.unsubscribeAll(); lifecycle_.unsubscribeAll(); localization_.unsubscribeAll(); network_.unsubscribeAll(); diff --git a/test/api_test_app/apis/deviceDemo.cpp b/test/api_test_app/apis/deviceDemo.cpp index ef1a99f..cdfb428 100644 --- a/test/api_test_app/apis/deviceDemo.cpp +++ b/test/api_test_app/apis/deviceDemo.cpp @@ -35,6 +35,7 @@ DeviceDemo::DeviceDemo() methods_.push_back("Device.deviceClass"); methods_.push_back("Device.dolbyAtmosExperienceAvailable"); methods_.push_back("Device.hdr"); + methods_.push_back("Device.name"); methods_.push_back("Device.timeInActiveState"); methods_.push_back("Device.uid"); methods_.push_back("Device.uptime"); @@ -142,4 +143,12 @@ void DeviceDemo::runOption(const std::string& method) std::cout << std::boolalpha << "Dolby Atmos Experience Available: " << *r << std::endl; } } + else if (method == "Device.name") + { + auto r = Firebolt::IFireboltAccessor::Instance().DeviceInterface().name(); + if (succeed(r)) + { + std::cout << "Device Name: " << *r << std::endl; + } + } } diff --git a/test/component/deviceTest.cpp b/test/component/deviceTest.cpp index 00163ac..f8a05ff 100644 --- a/test/component/deviceTest.cpp +++ b/test/component/deviceTest.cpp @@ -187,3 +187,34 @@ TEST_F(DeviceCTest, SubscribeOnDolbyAtmosExperienceAvailableChanged) auto result = Firebolt::IFireboltAccessor::Instance().DeviceInterface().unsubscribe(id.value()); verifyUnsubscribeResult(result); } + +TEST_F(DeviceCTest, Name) +{ + auto expectedValue = jsonEngine.get_value("Device.name"); + auto result = Firebolt::IFireboltAccessor::Instance().DeviceInterface().name(); + ASSERT_TRUE(result) << "DeviceImpl::name() returned an error"; + EXPECT_EQ(*result, expectedValue); +} + +TEST_F(DeviceCTest, SubscribeOnNameChanged) +{ + auto id = Firebolt::IFireboltAccessor::Instance().DeviceInterface().subscribeOnNameChanged( + [&](const std::string& value) + { + std::cout << "[Subscription] Device name changed" << '\n'; + EXPECT_EQ(value, "Living Room TV"); + { + std::lock_guard lock(mtx); + eventReceived = true; + } + cv.notify_one(); + }); + + verifyEventSubscription(id); + + triggerEvent("Device.onNameChanged", R"("Living Room TV")"); + verifyEventReceived(mtx, cv, eventReceived); + + auto result = Firebolt::IFireboltAccessor::Instance().DeviceInterface().unsubscribe(id.value()); + verifyUnsubscribeResult(result); +} diff --git a/test/unit/deviceTest.cpp b/test/unit/deviceTest.cpp index c5f34cf..dc39c4b 100644 --- a/test/unit/deviceTest.cpp +++ b/test/unit/deviceTest.cpp @@ -224,3 +224,33 @@ TEST_F(DeviceUTest, SubscribeOnDolbyAtmosExperienceAvailableChanged) deviceImpl_.unsubscribe(*result); } + +TEST_F(DeviceUTest, Name) +{ + mock("Device.name"); + auto expectedValue = jsonEngine.get_value("Device.name"); + + auto result = deviceImpl_.name(); + ASSERT_TRUE(result) << "DeviceImpl::name() returned an error"; + + EXPECT_EQ(*result, expectedValue); +} + +TEST_F(DeviceUTest, NameBadResponse) +{ + mock_with_response("Device.name", 12345); + ASSERT_FALSE(deviceImpl_.name()) << "DeviceImpl::name() did not return an error"; +} + +TEST_F(DeviceUTest, SubscribeOnNameChanged) +{ + nlohmann::json expectedValue = 1; + mockSubscribe("Device.onNameChanged"); + + auto result = deviceImpl_.subscribeOnNameChanged([&](const std::string& /*value*/) {}); + + ASSERT_TRUE(result) << "DeviceImpl::subscribeOnNameChanged() returned an error"; + EXPECT_EQ(*result, expectedValue); + + deviceImpl_.unsubscribe(*result); +}