diff --git a/HdcpProfile/CMakeLists.txt b/HdcpProfile/CMakeLists.txt index 9d04c99c..3a65466f 100644 --- a/HdcpProfile/CMakeLists.txt +++ b/HdcpProfile/CMakeLists.txt @@ -17,6 +17,7 @@ set(PLUGIN_NAME HdcpProfile) set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) +set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) set(PLUGIN_HDCPPROFILE_AUTOSTART "false" CACHE STRING "Automatically start HdcpProfile plugin") set(PLUGIN_HDCPPROFILE_STARTUPORDER "" CACHE STRING "To configure startup order of HdcpProfile plugin") @@ -32,20 +33,42 @@ add_library(${MODULE_NAME} SHARED HdcpProfile.cpp Module.cpp) + set_target_properties(${MODULE_NAME} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED YES) target_compile_definitions(${MODULE_NAME} PRIVATE MODULE_NAME=Plugin_${PLUGIN_NAME}) + +include_directories( + ../helpers) + +target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins) + +install(TARGETS ${MODULE_NAME} + DESTINATION lib/${STORAGE_DIRECTORY}/plugins) + +add_library(${PLUGIN_IMPLEMENTATION} SHARED + HdcpProfileImplementation.cpp + Module.cpp) +target_link_libraries(${PLUGIN_IMPLEMENTATION} + PRIVATE + ${NAMESPACE}Plugins::${NAMESPACE}Plugins) +set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED YES) + + if (USE_THUNDER_R4) -target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}COM::${NAMESPACE}COM) +target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${NAMESPACE}COM::${NAMESPACE}COM) else () -target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}Protocols::${NAMESPACE}Protocols) +target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${NAMESPACE}Protocols::${NAMESPACE}Protocols) endif (USE_THUNDER_R4) find_package(DS) find_package(IARMBus) +find_package(CEC) if (RDK_SERVICE_L2_TEST) message ("L2 test Enabled") @@ -58,16 +81,17 @@ if (RDK_SERVICE_L2_TEST) endif (TESTMOCKLIB_LIBRARIES) endif() -target_include_directories(${MODULE_NAME} PRIVATE ${IARMBUS_INCLUDE_DIRS}) -target_include_directories(${MODULE_NAME} PRIVATE ${DS_INCLUDE_DIRS}) -target_include_directories(${MODULE_NAME} PRIVATE ../helpers) + +target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${IARMBUS_INCLUDE_DIRS}) +target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${DS_INCLUDE_DIRS}) +target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ../helpers) set_source_files_properties(HdcpProfile.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") -target_link_libraries(${MODULE_NAME} PUBLIC ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${IARMBUS_LIBRARIES} ${DS_LIBRARIES} ) +target_link_libraries(${PLUGIN_IMPLEMENTATION} PUBLIC ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${IARMBUS_LIBRARIES} ${DS_LIBRARIES}) -install(TARGETS ${MODULE_NAME} +install(TARGETS ${PLUGIN_IMPLEMENTATION} DESTINATION lib/${STORAGE_DIRECTORY}/plugins) write_config(${PLUGIN_NAME}) diff --git a/HdcpProfile/HdcpProfile.conf.in b/HdcpProfile/HdcpProfile.conf.in index 9f2255e9..cddff2db 100644 --- a/HdcpProfile/HdcpProfile.conf.in +++ b/HdcpProfile/HdcpProfile.conf.in @@ -2,3 +2,11 @@ precondition = ["Platform"] callsign = "org.rdk.HdcpProfile" autostart = "@PLUGIN_HDCPPROFILE_AUTOSTART@" startuporder = "@PLUGIN_HDCPPROFILE_STARTUPORDER@" + +configuration = JSON() +rootobject = JSON() + +rootobject.add("mode", "@PLUGIN_HDCPPROFILE_MODE@") +rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") + +configuration.add("root", rootobject) diff --git a/HdcpProfile/HdcpProfile.config b/HdcpProfile/HdcpProfile.config index 139315c6..16c374cb 100644 --- a/HdcpProfile/HdcpProfile.config +++ b/HdcpProfile/HdcpProfile.config @@ -5,3 +5,12 @@ set (callsign "org.rdk.HdcpProfile") if(PLUGIN_HDCPPROFILE_STARTUPORDER) set (startuporder ${PLUGIN_HDCPPROFILE_STARTUPORDER}) endif() + +map() + key(root) + map() + kv(mode ${PLUGIN_HDCPPROFILE_MODE}) + kv(locator lib${PLUGIN_IMPLEMENTATION}.so) + end() +end() +ans(configuration) diff --git a/HdcpProfile/HdcpProfile.cpp b/HdcpProfile/HdcpProfile.cpp index 1d7edabe..4b24b151 100644 --- a/HdcpProfile/HdcpProfile.cpp +++ b/HdcpProfile/HdcpProfile.cpp @@ -17,41 +17,15 @@ * limitations under the License. **/ -#include - #include "HdcpProfile.h" -#include "videoOutputPort.hpp" -#include "videoOutputPortConfig.hpp" -#include "dsMgr.h" -#include "manager.hpp" -#include "host.hpp" - -#include "UtilsJsonRpc.h" -#include "UtilsIarm.h" - -#include "UtilsSynchroIarm.hpp" - -#define HDMI_HOT_PLUG_EVENT_CONNECTED 0 -#define HDMI_HOT_PLUG_EVENT_DISCONNECTED 1 - -#define HDCP_PROFILE_METHOD_GET_HDCP_STATUS "getHDCPStatus" -#define HDCP_PROFILE_METHOD_GET_SETTOP_HDCP_SUPPORT "getSettopHDCPSupport" -#define HDCP_PROFILE_METHOD_SET_HDCPPROFILE "setHDCPProfile" -#define HDCP_PROFILE_METHOD_GET_HDCPPROFILE "getHDCPProfile" - -#define HDCP_PROFILE_EVT_ON_DISPLAY_CONNECTION_CHANGED "onDisplayConnectionChanged" - #define API_VERSION_NUMBER_MAJOR 1 #define API_VERSION_NUMBER_MINOR 0 #define API_VERSION_NUMBER_PATCH 9 -using PowerState = WPEFramework::Exchange::IPowerManager::PowerState; - - - namespace WPEFramework { + namespace { static Plugin::Metadata metadata( @@ -68,278 +42,134 @@ namespace WPEFramework namespace Plugin { - PowerManagerInterfaceRef HdcpProfile::_powerManagerPlugin; SERVICE_REGISTRATION(HdcpProfile, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - HdcpProfile* HdcpProfile::_instance = nullptr; - - HdcpProfile::HdcpProfile() - : PluginHost::JSONRPC() + HdcpProfile::HdcpProfile() + : _service(nullptr) + , _connectionId(0) + , _hdcpProfile(nullptr) + , _hdcpProfileNotification(this) { - RegisterAll(); + SYSLOG(Logging::Startup, (_T("HdcpProfile Constructor"))); } HdcpProfile::~HdcpProfile() { - UnregisterAll(); - } - - const string HdcpProfile::Initialize(PluginHost::IShell *service) - { - HdcpProfile::_instance = this; - InitializeIARM(); - InitializePowerManager(service); - try - { - device::Manager::Initialize(); - LOGINFO("HdcpProfile device::Manager::Initialize success"); - } - catch(...) - { - LOGINFO("HdcpProfile device::Manager::Initialize failed"); - } - return (string()); - } - - void HdcpProfile::Deinitialize(PluginHost::IShell* /* service */) - { - if (_powerManagerPlugin) { - _powerManagerPlugin.Reset(); - } - - HdcpProfile::_instance = nullptr; - // No need to run device::Manager::DeInitialize for individual plugin. As it is a singleton instance - // and shared among all wpeframework plugins - DeinitializeIARM(); - } - - void HdcpProfile::InitializePowerManager(PluginHost::IShell *service) - { - _powerManagerPlugin = PowerManagerInterfaceBuilder(_T("org.rdk.PowerManager")) - .withIShell(service) - .withRetryIntervalMS(200) - .withRetryCount(25) - .createInterface(); + SYSLOG(Logging::Shutdown, (string(_T("HdcpProfile Destructor")))); } - - void HdcpProfile::InitializeIARM() + + const string HdcpProfile::Initialize(PluginHost::IShell *service) { - Utils::IARM::init(); + string message = ""; - IARM_Result_t res; - IARM_CHECK( Utils::Synchro::RegisterLockedIarmEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG, dsHdmiEventHandler) ); - IARM_CHECK( Utils::Synchro::RegisterLockedIarmEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDCP_STATUS, dsHdmiEventHandler) ); - } + ASSERT(nullptr != service); + ASSERT(nullptr == _service); + ASSERT(nullptr == _hdcpProfile); + ASSERT(0 == _connectionId); - void HdcpProfile::DeinitializeIARM() - { - if (Utils::IARM::isConnected()) - { - IARM_Result_t res; - IARM_CHECK( Utils::Synchro::RemoveLockedEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG, dsHdmiEventHandler) ); - IARM_CHECK( Utils::Synchro::RemoveLockedEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDCP_STATUS, dsHdmiEventHandler) ); - } - } + SYSLOG(Logging::Startup, (_T("HdcpProfile::Initialize: PID=%u"), getpid())); - void HdcpProfile::RegisterAll() - { - Utils::Synchro::RegisterLockedApi(_T(HDCP_PROFILE_METHOD_GET_HDCP_STATUS), &HdcpProfile::getHDCPStatusWrapper, this); - Utils::Synchro::RegisterLockedApi(_T(HDCP_PROFILE_METHOD_GET_SETTOP_HDCP_SUPPORT), &HdcpProfile::getSettopHDCPSupportWrapper, this); - } + _service = service; + _service->AddRef(); + _service->Register(&_hdcpProfileNotification); + _hdcpProfile = _service->Root(_connectionId, 5000, _T("HdcpProfileImplementation")); - void HdcpProfile::UnregisterAll() - { - Unregister(_T(HDCP_PROFILE_METHOD_GET_HDCP_STATUS)); - Unregister(_T(HDCP_PROFILE_METHOD_GET_SETTOP_HDCP_SUPPORT)); - } - uint32_t HdcpProfile::getHDCPStatusWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - - response["HDCPStatus"] = getHDCPStatus(); - returnResponse(true); - } - - uint32_t HdcpProfile::getSettopHDCPSupportWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - - dsHdcpProtocolVersion_t hdcpProtocol = dsHDCP_VERSION_MAX; - - try + if (nullptr != _hdcpProfile) { - std::string strVideoPort = device::Host::getInstance().getDefaultVideoPortName(); - device::VideoOutputPort vPort = device::VideoOutputPortConfig::getInstance().getPort(strVideoPort.c_str()); - hdcpProtocol = (dsHdcpProtocolVersion_t)vPort.getHDCPProtocol(); + configure = _hdcpProfile->QueryInterface(); + if (configure != nullptr) + { + uint32_t result = configure->Configure(_service); + if(result != Core::ERROR_NONE) + { + message = _T("HdcpProfile could not be configured"); + } + } + else + { + message = _T("HdcpProfile implementation did not provide a configuration interface"); + } + // Register for notifications + _hdcpProfile->Register(&_hdcpProfileNotification); + + // Invoking Plugin API register to wpeframework + Exchange::JHdcpProfile::Register(*this, _hdcpProfile); } - catch (const std::exception& e) + else { - LOGWARN("DS exception caught from %s\r\n", __FUNCTION__); + SYSLOG(Logging::Startup, (_T("HdcpProfile::Initialize: Failed to initialise HdcpProfile plugin"))); + message = _T("HdcpProfile plugin could not be initialised"); } - if(hdcpProtocol == dsHDCP_VERSION_2X) + if (0 != message.length()) { - response["supportedHDCPVersion"] = "2.2"; - LOGWARN("supportedHDCPVersion :2.2"); + printf("HdcpProfile::Initialize: Failed to initialise HdcpProfile plugin"); + Deinitialize(service); } - else - { - response["supportedHDCPVersion"] = "1.4"; - LOGWARN("supportedHDCPVersion :1.4"); - } - - response["isHDCPSupported"] = true; - returnResponse(true); + return message; } - JsonObject HdcpProfile::getHDCPStatus() + void HdcpProfile::Deinitialize(PluginHost::IShell *service) { - JsonObject hdcpStatus; - - bool isConnected = false; - bool isHDCPCompliant = false; - bool isHDCPEnabled = true; - int eHDCPEnabledStatus = dsHDCP_STATUS_UNPOWERED; - dsHdcpProtocolVersion_t hdcpProtocol = dsHDCP_VERSION_MAX; - dsHdcpProtocolVersion_t hdcpReceiverProtocol = dsHDCP_VERSION_MAX; - dsHdcpProtocolVersion_t hdcpCurrentProtocol = dsHDCP_VERSION_MAX; + ASSERT(_service == service); + printf("HdcpProfile::Deinitialize: service = %p", service); + SYSLOG(Logging::Shutdown, (string(_T("HdcpProfile::Deinitialize")))); - try + // Make sure the Activated and Deactivated are no longer called before we start cleaning up.. + if (_service != nullptr) { - std::string strVideoPort = device::Host::getInstance().getDefaultVideoPortName(); - device::VideoOutputPort vPort = device::VideoOutputPortConfig::getInstance().getPort(strVideoPort.c_str()); - isConnected = vPort.isDisplayConnected(); - hdcpProtocol = (dsHdcpProtocolVersion_t)vPort.getHDCPProtocol(); - eHDCPEnabledStatus = vPort.getHDCPStatus(); - if(isConnected) - { - isHDCPCompliant = (eHDCPEnabledStatus == dsHDCP_STATUS_AUTHENTICATED); - isHDCPEnabled = vPort.isContentProtected(); - hdcpReceiverProtocol = (dsHdcpProtocolVersion_t)vPort.getHDCPReceiverProtocol(); - hdcpCurrentProtocol = (dsHdcpProtocolVersion_t)vPort.getHDCPCurrentProtocol(); - } - else - { - isHDCPCompliant = false; - isHDCPEnabled = false; - } + _service->Unregister(&_hdcpProfileNotification); } - catch (const std::exception& e) + if (nullptr != _hdcpProfile) { - LOGWARN("DS exception caught from %s\r\n", __FUNCTION__); - } + + _hdcpProfile->Unregister(&_hdcpProfileNotification); + Exchange::JHdcpProfile::Unregister(*this); - hdcpStatus["isConnected"] = isConnected; - hdcpStatus["isHDCPCompliant"] = isHDCPCompliant; - hdcpStatus["isHDCPEnabled"] = isHDCPEnabled; - hdcpStatus["hdcpReason"] = eHDCPEnabledStatus; + // Stop processing: + RPC::IRemoteConnection *connection = service->RemoteConnection(_connectionId); + VARIABLE_IS_NOT_USED uint32_t result = _hdcpProfile->Release(); - if(hdcpProtocol == dsHDCP_VERSION_2X) - { - hdcpStatus["supportedHDCPVersion"] = "2.2"; - } - else - { - hdcpStatus["supportedHDCPVersion"] = "1.4"; - } + _hdcpProfile = nullptr; - if(hdcpReceiverProtocol == dsHDCP_VERSION_2X) - { - hdcpStatus["receiverHDCPVersion"] = "2.2"; - } - else - { - hdcpStatus["receiverHDCPVersion"] = "1.4"; - } + // It should have been the last reference we are releasing, + // so it should endup in a DESTRUCTION_SUCCEEDED, if not we + // are leaking... + ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - if(hdcpCurrentProtocol == dsHDCP_VERSION_2X) - { - hdcpStatus["currentHDCPVersion"] = "2.2"; + // If this was running in a (container) process... + if (nullptr != connection) + { + // Lets trigger the cleanup sequence for + // out-of-process code. Which will guard + // that unwilling processes, get shot if + // not stopped friendly :-) + connection->Terminate(); + connection->Release(); + } } - else + _connectionId = 0; + + if (_service != nullptr) { - hdcpStatus["currentHDCPVersion"] = "1.4"; + _service->Release(); + _service = nullptr; } - - logHdcpStatus("Request", hdcpStatus); - return hdcpStatus; - } - - void HdcpProfile::onHdmiOutputHotPlug(int connectStatus) - { - if (HDMI_HOT_PLUG_EVENT_CONNECTED == connectStatus) - LOGWARN(" %s Status : %d \n",__FUNCTION__, connectStatus); - - JsonObject status = getHDCPStatus(); - JsonObject params; - params["HDCPStatus"] = status; - sendNotify(HDCP_PROFILE_EVT_ON_DISPLAY_CONNECTION_CHANGED, params); - - logHdcpStatus("Hotplug", status); - return; + SYSLOG(Logging::Shutdown, (string(_T("HdcpProfile de-initialised")))); } - - void HdcpProfile::logHdcpStatus (const char *trigger, const JsonObject& status) - { - LOGWARN("[%s]-HDCPStatus::isConnected : %s", trigger, status["isConnected"].Boolean() ? "true" : "false"); - LOGWARN("[%s]-HDCPStatus::isHDCPEnabled: %s", trigger, status["isHDCPEnabled"].Boolean() ? "true" : "false"); - LOGWARN("[%s]-HDCPStatus::isHDCPCompliant: %s", trigger, status["isHDCPCompliant"].Boolean() ? "true" : "false"); - LOGWARN("[%s]-HDCPStatus::supportedHDCPVersion: %s", trigger, status["supportedHDCPVersion"].String().c_str()); - LOGWARN("[%s]-HDCPStatus::receiverHDCPVersion: %s", trigger, status["receiverHDCPVersion"].String().c_str()); - LOGWARN("[%s]-HDCPStatus::currentHDCPVersion %s", trigger, status["currentHDCPVersion"].String().c_str()); - LOGWARN("[%s]-HDCPStatus::hdcpReason %s", trigger, status["hdcpReason"].String().c_str()); - LOGWARN("[%s]-HDCPStatus Response: %s,%s,%s,%s,%s,%s,%s", trigger, status["isConnected"].Boolean() ? "true" : "false",status["isHDCPEnabled"].Boolean() ? "true" : "false",status["isHDCPCompliant"].Boolean() ? "true" : "false", - status["supportedHDCPVersion"].String().c_str(), status["receiverHDCPVersion"].String().c_str(), status["currentHDCPVersion"].String().c_str(), status["hdcpReason"].String().c_str()); - } - - void HdcpProfile::onHdmiOutputHDCPStatusEvent(int hdcpStatus) + string HdcpProfile::Information() const { - JsonObject status = getHDCPStatus(); - JsonObject params; - params["HDCPStatus"] = status; - sendNotify(HDCP_PROFILE_EVT_ON_DISPLAY_CONNECTION_CHANGED, params); - - logHdcpStatus("AuthRslt", status); - return; + return ("This HdcpProfile Plugin facilitates to persist event data for monitoring applications"); } - void HdcpProfile::dsHdmiEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len) + void HdcpProfile::Deactivated(RPC::IRemoteConnection *connection) { - Core::hresult res = Core::ERROR_GENERAL; - PowerState pwrStateCur = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; - PowerState pwrStatePrev = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; - - if(!HdcpProfile::_instance) - return; - - if (IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG == eventId) - { - IARM_Bus_DSMgr_EventData_t *eventData = (IARM_Bus_DSMgr_EventData_t *)data; - int hdmi_hotplug_event = eventData->data.hdmi_hpd.event; - LOGINFO("Received IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG event data:%d \r\n", hdmi_hotplug_event); - - HdcpProfile::_instance->onHdmiOutputHotPlug(hdmi_hotplug_event); - } - else if (IARM_BUS_DSMGR_EVENT_HDCP_STATUS == eventId) + if (connection->Id() == _connectionId) { - ASSERT (_powerManagerPlugin); - if (_powerManagerPlugin){ - res = _powerManagerPlugin->GetPowerState(pwrStateCur, pwrStatePrev); - if (Core::ERROR_NONE != res) - { - LOGWARN("Failed to Invoke RPC method: GetPowerState"); - } - else - { - IARM_Bus_DSMgr_EventData_t *eventData = (IARM_Bus_DSMgr_EventData_t *)data; - int hdcpStatus = eventData->data.hdmi_hdcp.hdcpStatus; - LOGINFO("Received IARM_BUS_DSMGR_EVENT_HDCP_STATUS event data:%d param.curState: %d \r\n", hdcpStatus,pwrStateCur); - HdcpProfile::_instance->onHdmiOutputHDCPStatusEvent(hdcpStatus); - } - } + ASSERT(nullptr != _service); + Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); } } } // namespace Plugin } // namespace WPEFramework - diff --git a/HdcpProfile/HdcpProfile.h b/HdcpProfile/HdcpProfile.h index 52340dd9..ddf5fd91 100644 --- a/HdcpProfile/HdcpProfile.h +++ b/HdcpProfile/HdcpProfile.h @@ -19,70 +19,95 @@ #pragma once -#include "libIBus.h" - #include "Module.h" -#include -#include "PowerManagerInterface.h" +#include +#include +#include +#include +#include "UtilsLogging.h" +#include "tracing/Logging.h" + namespace WPEFramework { namespace Plugin { - // This is a server for a JSONRPC communication channel. - // For a plugin to be capable to handle JSONRPC, inherit from PluginHost::JSONRPC. - // By inheriting from this class, the plugin realizes the interface PluginHost::IDispatcher. - // This realization of this interface implements, by default, the following methods on this plugin - // - exists - // - register - // - unregister - // Any other methood to be handled by this plugin can be added can be added by using the - // templated methods Register on the PluginHost::JSONRPC class. - // As the registration/unregistration of notifications is realized by the class PluginHost::JSONRPC, - // this class exposes a public method called, Notify(), using this methods, all subscribed clients - // will receive a JSONRPC message as a notification, in case this method is called. - class HdcpProfile : public PluginHost::IPlugin, public PluginHost::JSONRPC { - private: - - // We do not allow this plugin to be copied !! - HdcpProfile(const HdcpProfile&) = delete; - HdcpProfile& operator=(const HdcpProfile&) = delete; - static PowerManagerInterfaceRef _powerManagerPlugin; - - void InitializeIARM(); - void DeinitializeIARM(); - - void RegisterAll(); - void UnregisterAll(); - void InitializePowerManager(PluginHost::IShell * service); - - //Begin methods - uint32_t getHDCPStatusWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getSettopHDCPSupportWrapper(const JsonObject& parameters, JsonObject& response); - - //End methods - - JsonObject getHDCPStatus(); - void onHdmiOutputHotPlug(int connectStatus); - void onHdmiOutputHDCPStatusEvent(int); - void logHdcpStatus (const char *trigger, const JsonObject& status); - static void dsHdmiEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len); - - public: - HdcpProfile(); - virtual ~HdcpProfile(); - virtual const string Initialize(PluginHost::IShell* shell) override; - virtual void Deinitialize(PluginHost::IShell* service) override; - virtual string Information() const override { return {}; } - - void terminate(); - - BEGIN_INTERFACE_MAP(HdcpProfile) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - END_INTERFACE_MAP - - static HdcpProfile* _instance; + + class HdcpProfile : public PluginHost::IPlugin, public PluginHost::JSONRPC + { + private: + class Notification : public RPC::IRemoteConnection::INotification, public Exchange::IHdcpProfile::INotification + { + private: + Notification() = delete; + Notification(const Notification&) = delete; + Notification& operator=(const Notification&) = delete; + + public: + explicit Notification(HdcpProfile *parent) + : _parent(*parent) + { + ASSERT(parent != nullptr); + } + + virtual ~Notification() + { + } + + BEGIN_INTERFACE_MAP(Notification) + INTERFACE_ENTRY(Exchange::IHdcpProfile::INotification) + INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) + END_INTERFACE_MAP + + void Activated(RPC::IRemoteConnection *) override + { + LOGINFO("HdcpProfile Notification Activated"); + } + + void Deactivated(RPC::IRemoteConnection *connection) override + { + LOGINFO("HdcpProfile Notification Deactivated"); + _parent.Deactivated(connection); + } + + void OnDisplayConnectionChanged(const Exchange::IHdcpProfile::HDCPStatus hdcpstatus) override + { + LOGINFO("OnDisplayConnectionChanged: isConnected: %d isHDCPCompliant: %d isHDCPEnabled: %d hdcpReason: %d supportedHDCPVersion: %s receiverHDCPVersion: %s currentHDCPVersion: %s", hdcpstatus.isConnected, hdcpstatus.isHDCPCompliant, hdcpstatus.isHDCPEnabled, hdcpstatus.hdcpReason, hdcpstatus.supportedHDCPVersion.c_str(), hdcpstatus.receiverHDCPVersion.c_str(), hdcpstatus.currentHDCPVersion.c_str()); + Exchange::JHdcpProfile::Event::OnDisplayConnectionChanged(_parent, hdcpstatus); + } + + private: + HdcpProfile &_parent; + }; + + public: + HdcpProfile(const HdcpProfile &) = delete; + HdcpProfile &operator=(const HdcpProfile &) = delete; + + HdcpProfile(); + virtual ~HdcpProfile(); + + BEGIN_INTERFACE_MAP(HdcpProfile) + INTERFACE_ENTRY(PluginHost::IPlugin) + INTERFACE_ENTRY(PluginHost::IDispatcher) + INTERFACE_AGGREGATE(Exchange::IHdcpProfile, _hdcpProfile) + END_INTERFACE_MAP + + // IPlugin methods + // ------------------------------------------------------------------------------------------------------- + const string Initialize(PluginHost::IShell* service) override; + void Deinitialize(PluginHost::IShell* service) override; + string Information() const override; + + private: + void Deactivated(RPC::IRemoteConnection* connection); + + private: + PluginHost::IShell *_service{}; + uint32_t _connectionId{}; + Exchange::IHdcpProfile *_hdcpProfile{}; + Core::Sink _hdcpProfileNotification; + Exchange::IConfiguration* configure; }; - } // namespace Plugin -} // namespace WPEFramework + } // namespace Plugin +} // namespace WPEFramework diff --git a/HdcpProfile/HdcpProfileImplementation.cpp b/HdcpProfile/HdcpProfileImplementation.cpp new file mode 100644 index 00000000..83456c9e --- /dev/null +++ b/HdcpProfile/HdcpProfileImplementation.cpp @@ -0,0 +1,382 @@ +/** + * If not stated otherwise in this file or this component's LICENSE + * file the following copyright and licenses apply: + * + * Copyright 2025 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + + #include + + #include "HdcpProfileImplementation.h" + + #include "videoOutputPort.hpp" + #include "videoOutputPortConfig.hpp" + #include "dsMgr.h" + #include "manager.hpp" + #include "host.hpp" + + #include "UtilsJsonRpc.h" + #include "UtilsIarm.h" + + #include "UtilsSynchroIarm.hpp" + + #define HDMI_HOT_PLUG_EVENT_CONNECTED 0 + #define HDMI_HOT_PLUG_EVENT_DISCONNECTED 1 + + #define API_VERSION_NUMBER_MAJOR 1 + #define API_VERSION_NUMBER_MINOR 0 + #define API_VERSION_NUMBER_PATCH 9 + + using PowerState = WPEFramework::Exchange::IPowerManager::PowerState; + + namespace WPEFramework + { + namespace Plugin + { + SERVICE_REGISTRATION(HdcpProfileImplementation, 1, 0); + HdcpProfileImplementation *HdcpProfileImplementation::_instance = nullptr; + + PowerManagerInterfaceRef HdcpProfileImplementation::_powerManagerPlugin; + + + HdcpProfileImplementation::HdcpProfileImplementation() + : _adminLock(), mShell(nullptr) + { + LOGINFO("Create HdcpProfileImplementation Instance"); + HdcpProfileImplementation::_instance = this; + } + + HdcpProfileImplementation::~HdcpProfileImplementation() + { + LOGINFO("Call HdcpProfileImplementation destructor\n"); + HdcpProfileImplementation::_instance = nullptr; + mShell = nullptr; + } + + void HdcpProfileImplementation::InitializePowerManager(PluginHost::IShell *service) + { + _powerManagerPlugin = PowerManagerInterfaceBuilder(_T("org.rdk.PowerManager")) + .withIShell(service) + .withRetryIntervalMS(200) + .withRetryCount(25) + .createInterface(); + } + + void HdcpProfileImplementation::InitializeIARM() + { + Utils::IARM::init(); + + IARM_Result_t res; + IARM_CHECK( Utils::Synchro::RegisterLockedIarmEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG, dsHdmiEventHandler) ); + IARM_CHECK( Utils::Synchro::RegisterLockedIarmEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDCP_STATUS, dsHdmiEventHandler) ); + } + + void HdcpProfileImplementation::DeinitializeIARM() + { + if (Utils::IARM::isConnected()) + { + IARM_Result_t res; + IARM_CHECK( Utils::Synchro::RemoveLockedEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG, dsHdmiEventHandler) ); + IARM_CHECK( Utils::Synchro::RemoveLockedEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDCP_STATUS, dsHdmiEventHandler) ); + } + } + + void HdcpProfileImplementation::onHdmiOutputHotPlug(int connectStatus) + { + if (HDMI_HOT_PLUG_EVENT_CONNECTED == connectStatus) + { + LOGINFO("HDMI_HOT_PLUG Status[%d]",connectStatus); + } + onHdcpProfileDisplayConnectionChanged(); + } + + void HdcpProfileImplementation::onHdcpProfileDisplayConnectionChanged() + { + HDCPStatus hdcpstatus; + GetHDCPStatusInternal(hdcpstatus); + dispatchEvent(HDCPPROFILE_EVENT_DISPLAYCONNECTIONCHANGED, hdcpstatus); + logHdcpStatus("onHdcpProfileDisplayConnectionChanged", hdcpstatus); + } + + void HdcpProfileImplementation::logHdcpStatus (const char *trigger, HDCPStatus& status) + { + LOGWARN("[%s]-HDCPStatus::isConnected: %s", trigger, status.isConnected ? "true" : "false"); + LOGWARN("[%s]-HDCPStatus::isHDCPEnabled: %s", trigger, status.isHDCPEnabled ? "true" : "false"); + LOGWARN("[%s]-HDCPStatus::isHDCPCompliant: %s", trigger, status.isHDCPCompliant ? "true" : "false"); + LOGWARN("[%s]-HDCPStatus::supportedHDCPVersion: %s", trigger, status.supportedHDCPVersion.c_str()); + LOGWARN("[%s]-HDCPStatus::receiverHDCPVersion: %s", trigger, status.receiverHDCPVersion.c_str()); + LOGWARN("[%s]-HDCPStatus::currentHDCPVersion: %s", trigger, status.currentHDCPVersion.c_str()); + LOGWARN("[%s]-HDCPStatus::hdcpReason: %d", trigger, status.hdcpReason); + LOGWARN("[%s]-HDCPStatus Response: %s, %s, %s, %s, %s, %s, %d", trigger, + status.isConnected ? "true" : "false", + status.isHDCPEnabled ? "true" : "false", + status.isHDCPCompliant ? "true" : "false", + status.supportedHDCPVersion.c_str(), + status.receiverHDCPVersion.c_str(), + status.currentHDCPVersion.c_str(), + status.hdcpReason); + } + + void HdcpProfileImplementation::onHdmiOutputHDCPStatusEvent(int hdcpStatus) + { + LOGINFO("hdcpStatus[%d]",hdcpStatus); + onHdcpProfileDisplayConnectionChanged(); + } + + void HdcpProfileImplementation::dsHdmiEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len) + { + uint32_t res = Core::ERROR_GENERAL; + PowerState pwrStateCur = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; + PowerState pwrStatePrev = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; + + if(!HdcpProfileImplementation::_instance) + return; + + if (IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG == eventId) + { + IARM_Bus_DSMgr_EventData_t *eventData = (IARM_Bus_DSMgr_EventData_t *)data; + int hdmi_hotplug_event = eventData->data.hdmi_hpd.event; + LOGINFO("Received IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG event data:%d \r\n", hdmi_hotplug_event); + + HdcpProfileImplementation::_instance->onHdmiOutputHotPlug(hdmi_hotplug_event); + } + else if (IARM_BUS_DSMGR_EVENT_HDCP_STATUS == eventId) + { + ASSERT (_powerManagerPlugin); + if (_powerManagerPlugin){ + res = _powerManagerPlugin->GetPowerState(pwrStateCur, pwrStatePrev); + if (Core::ERROR_NONE != res) + { + LOGWARN("Failed to Invoke RPC method: GetPowerState"); + } + else + { + IARM_Bus_DSMgr_EventData_t *eventData = (IARM_Bus_DSMgr_EventData_t *)data; + int hdcpStatus = eventData->data.hdmi_hdcp.hdcpStatus; + LOGINFO("Received IARM_BUS_DSMGR_EVENT_HDCP_STATUS event data:%d param.curState: %d \r\n", hdcpStatus,pwrStateCur); + HdcpProfileImplementation::_instance->onHdmiOutputHDCPStatusEvent(hdcpStatus); + } + } + } + } + + /** + * Register a notification callback + */ + Core::hresult HdcpProfileImplementation::Register(Exchange::IHdcpProfile::INotification *notification) + { + ASSERT(nullptr != notification); + + _adminLock.Lock(); + printf("HdcpProfileImplementation::Register: notification = %p", notification); + LOGINFO("Register notification"); + + // Make sure we can't register the same notification callback multiple times + if (std::find(_hdcpProfileNotification.begin(), _hdcpProfileNotification.end(), notification) == _hdcpProfileNotification.end()) + { + _hdcpProfileNotification.push_back(notification); + notification->AddRef(); + } + else + { + LOGERR("same notification is registered already"); + } + + _adminLock.Unlock(); + + return Core::ERROR_NONE; + } + + /** + * Unregister a notification callback + */ + Core::hresult HdcpProfileImplementation::Unregister(Exchange::IHdcpProfile::INotification *notification) + { + Core::hresult status = Core::ERROR_GENERAL; + + ASSERT(nullptr != notification); + + _adminLock.Lock(); + + // we just unregister one notification once + auto itr = std::find(_hdcpProfileNotification.begin(), _hdcpProfileNotification.end(), notification); + if (itr != _hdcpProfileNotification.end()) + { + (*itr)->Release(); + LOGINFO("Unregister notification"); + _hdcpProfileNotification.erase(itr); + status = Core::ERROR_NONE; + } + else + { + LOGERR("notification not found"); + } + + _adminLock.Unlock(); + + return status; + } + + uint32_t HdcpProfileImplementation::Configure(PluginHost::IShell* service) + { + uint32_t result = Core::ERROR_NONE; + _service = service; + _service->AddRef(); + ASSERT(service != nullptr); + InitializeIARM(); + InitializePowerManager(service); + return result; + } + + void HdcpProfileImplementation::dispatchEvent(Event event, const HDCPStatus &hdcpstatus) + { + Core::IWorkerPool::Instance().Submit(Job::Create(this, event, hdcpstatus)); + } + + void HdcpProfileImplementation::Dispatch(Event event,const HDCPStatus& hdcpstatus) + { + _adminLock.Lock(); + + std::list::const_iterator index(_hdcpProfileNotification.begin()); + + switch (event) + { + case HDCPPROFILE_EVENT_DISPLAYCONNECTIONCHANGED: + { + while (index != _hdcpProfileNotification.end()) + { + (*index)->OnDisplayConnectionChanged(hdcpstatus); + ++index; + } + } + break; + + default: + LOGWARN("Event[%u] not handled", event); + break; + } + _adminLock.Unlock(); + } + + bool HdcpProfileImplementation::GetHDCPStatusInternal(HDCPStatus& hdcpstatus) + { + bool isConnected = false; + bool isHDCPCompliant = false; + bool isHDCPEnabled = true; + int eHDCPEnabledStatus = dsHDCP_STATUS_UNPOWERED; + dsHdcpProtocolVersion_t hdcpProtocol = dsHDCP_VERSION_MAX; + dsHdcpProtocolVersion_t hdcpReceiverProtocol = dsHDCP_VERSION_MAX; + dsHdcpProtocolVersion_t hdcpCurrentProtocol = dsHDCP_VERSION_MAX; + + try + { + std::string strVideoPort = device::Host::getInstance().getDefaultVideoPortName(); + device::VideoOutputPort vPort = device::VideoOutputPortConfig::getInstance().getPort(strVideoPort.c_str()); + isConnected = vPort.isDisplayConnected(); + hdcpProtocol = (dsHdcpProtocolVersion_t)vPort.getHDCPProtocol(); + eHDCPEnabledStatus = vPort.getHDCPStatus(); + if(isConnected) + { + isHDCPCompliant = (eHDCPEnabledStatus == dsHDCP_STATUS_AUTHENTICATED); + isHDCPEnabled = vPort.isContentProtected(); + hdcpReceiverProtocol = (dsHdcpProtocolVersion_t)vPort.getHDCPReceiverProtocol(); + hdcpCurrentProtocol = (dsHdcpProtocolVersion_t)vPort.getHDCPCurrentProtocol(); + } + else + { + isHDCPCompliant = false; + isHDCPEnabled = false; + } + } + catch (const std::exception& e) + { + LOGWARN("DS exception caught from %s\r\n", __FUNCTION__); + } + + hdcpstatus.isConnected = isConnected; + hdcpstatus.isHDCPCompliant = isHDCPCompliant; + hdcpstatus.isHDCPEnabled = isHDCPEnabled; + hdcpstatus.hdcpReason = eHDCPEnabledStatus; + + if(hdcpProtocol == dsHDCP_VERSION_2X) + { + hdcpstatus.supportedHDCPVersion = "2.2"; + } + else + { + hdcpstatus.supportedHDCPVersion = "1.4"; + } + + if(hdcpReceiverProtocol == dsHDCP_VERSION_2X) + { + hdcpstatus.receiverHDCPVersion = "2.2"; + } + else + { + hdcpstatus.receiverHDCPVersion = "1.4"; + } + + if(hdcpCurrentProtocol == dsHDCP_VERSION_2X) + { + hdcpstatus.currentHDCPVersion = "2.2"; + } + else + { + hdcpstatus.currentHDCPVersion = "1.4"; + } + return true; + } + + Core::hresult HdcpProfileImplementation::GetHDCPStatus(HDCPStatus& hdcpstatus,bool& success) + { + success = GetHDCPStatusInternal(hdcpstatus); + return Core::ERROR_NONE; + } + + Core::hresult HdcpProfileImplementation::GetSettopHDCPSupport(string& supportedHDCPVersion,bool& isHDCPSupported,bool& success) + { + dsHdcpProtocolVersion_t hdcpProtocol = dsHDCP_VERSION_MAX; + + try + { + std::string strVideoPort = device::Host::getInstance().getDefaultVideoPortName(); + device::VideoOutputPort vPort = device::VideoOutputPortConfig::getInstance().getPort(strVideoPort.c_str()); + hdcpProtocol = (dsHdcpProtocolVersion_t)vPort.getHDCPProtocol(); + } + catch (const std::exception& e) + { + LOGWARN("DS exception caught from %s\r\n", __FUNCTION__); + } + + if(hdcpProtocol == dsHDCP_VERSION_2X) + { + supportedHDCPVersion = "2.2"; + LOGWARN("supportedHDCPVersion :2.2"); + } + else + { + supportedHDCPVersion = "1.4"; + LOGWARN("supportedHDCPVersion :1.4"); + } + + isHDCPSupported = true; + + success = true; + return Core::ERROR_NONE; + } + + + } // namespace Plugin + } // namespace WPEFramework diff --git a/HdcpProfile/HdcpProfileImplementation.h b/HdcpProfile/HdcpProfileImplementation.h new file mode 100644 index 00000000..8e0530d4 --- /dev/null +++ b/HdcpProfile/HdcpProfileImplementation.h @@ -0,0 +1,146 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2025 RDK Management + * + * 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. + */ + + #pragma once + + #include "Module.h" + #include + #include + #include + #include + + #include + #include + #include + #include + + #include "libIBus.h" + + #include "PowerManagerInterface.h" + + namespace WPEFramework + { + namespace Plugin + { + + class HdcpProfileImplementation : public Exchange::IHdcpProfile, public Exchange::IConfiguration + // , public Exchange::IConfiguration + { + public: + // We do not allow this plugin to be copied !! + HdcpProfileImplementation(); + ~HdcpProfileImplementation() override; + + static HdcpProfileImplementation *instance(HdcpProfileImplementation *HdcpProfileImpl = nullptr); + + // We do not allow this plugin to be copied !! + HdcpProfileImplementation(const HdcpProfileImplementation &) = delete; + HdcpProfileImplementation &operator=(const HdcpProfileImplementation &) = delete; + + + BEGIN_INTERFACE_MAP(HdcpProfileImplementation) + INTERFACE_ENTRY(Exchange::IHdcpProfile) + INTERFACE_ENTRY(Exchange::IConfiguration) + END_INTERFACE_MAP + + public: + enum Event + { + HDCPPROFILE_EVENT_DISPLAYCONNECTIONCHANGED + }; + class EXTERNAL Job : public Core::IDispatch + { + protected: + Job(HdcpProfileImplementation *HdcpProfileImplementation, Event event, HDCPStatus ¶ms) + : _hdcpProfileImplementation(HdcpProfileImplementation), _event(event), _params(params) + { + if (_hdcpProfileImplementation != nullptr) + { + _hdcpProfileImplementation->AddRef(); + } + } + + public: + Job() = delete; + Job(const Job &) = delete; + Job &operator=(const Job &) = delete; + ~Job() + { + if (_hdcpProfileImplementation != nullptr) + { + _hdcpProfileImplementation->Release(); + } + } + + public: + static Core::ProxyType Create(HdcpProfileImplementation *hdcpProfileImplementation, Event event, HDCPStatus params) + { + #ifndef USE_THUNDER_R4 + return (Core::proxy_cast(Core::ProxyType::Create(hdcpProfileImplementation, event, params))); + #else + return (Core::ProxyType(Core::ProxyType::Create(hdcpProfileImplementation, event, params))); + #endif + } + virtual void Dispatch() + { + _hdcpProfileImplementation->Dispatch(_event, _params); + } + + private: + HdcpProfileImplementation *_hdcpProfileImplementation; + const Event _event; + HDCPStatus _params; + }; + + + public: + Core::hresult Register(Exchange::IHdcpProfile::INotification *notification) override; + Core::hresult Unregister(Exchange::IHdcpProfile::INotification *notification) override; + + Core::hresult GetHDCPStatus(HDCPStatus& hdcpstatus,bool& success) override; + Core::hresult GetSettopHDCPSupport(string& supportedHDCPVersion,bool& isHDCPSupported,bool& success) override; + bool GetHDCPStatusInternal(HDCPStatus& hdcpstatus); + void InitializePowerManager(PluginHost::IShell *service); + void InitializeIARM(); + void DeinitializeIARM(); + static void dsHdmiEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len); + void onHdmiOutputHotPlug(int connectStatus); + void onHdmiOutputHDCPStatusEvent(int); + void logHdcpStatus (const char *trigger, HDCPStatus& status); + void onHdcpProfileDisplayConnectionChanged(); + static PowerManagerInterfaceRef _powerManagerPlugin; + uint32_t Configure(PluginHost::IShell* service) override; + + private: + mutable Core::CriticalSection _adminLock; + PluginHost::IShell *mShell; + std::list _hdcpProfileNotification; // List of registered notifications + PluginHost::IShell* _service; + void dispatchEvent(Event, const HDCPStatus ¶ms); + void Dispatch(Event event, const HDCPStatus ¶ms); + + + public: + static HdcpProfileImplementation *_instance; + + // friend class Job; + }; + + } // namespace Plugin + } // namespace WPEFramework \ No newline at end of file