diff --git a/build_dependencies.sh b/build_dependencies.sh index 090f105a..566fca25 100644 --- a/build_dependencies.sh +++ b/build_dependencies.sh @@ -47,7 +47,7 @@ cd rfc autoreconf -i ./configure --enable-rfctool=yes --enable-tr181set=yes cd rfcapi -make librfcapi_la_CPPFLAGS="-I/usr/include/cjson" +make CXXFLAGS="-DUSE_IARMBUS" librfcapi_la_CPPFLAGS="-I/usr/include/cjson" make install export RFC_PATH=$ROOT/rfc diff --git a/ds/Makefile b/ds/Makefile index e7c41ddd..132782e2 100644 --- a/ds/Makefile +++ b/ds/Makefile @@ -20,9 +20,11 @@ RM := rm -rf CFLAGS += -std=c++0x -g -fPIC -D_REENTRANT -Wall LIBNAME := ds LIBNAMEFULL := lib$(LIBNAME).so -LIBNAMECLI := lib$(LIBNAME)-cli.so +LIBNAMECLI := lib$(LIBNAME)-cli.so INSTALL := $(PWD)/install OBJS := $(patsubst %.cpp,%.o,$(wildcard *.cpp)) +# In future add a conditional to choose implementation class based on build configuration +OBJS += iarm/IarmHostImpl.o #$(PWD)/config should be first include path # to override generic configs ifneq ($(STANDALONE_BUILD_ENABLED),y) diff --git a/ds/host.cpp b/ds/host.cpp index d621e479..b114f880 100644 --- a/ds/host.cpp +++ b/ds/host.cpp @@ -2,7 +2,7 @@ * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * - * Copyright 2016 RDK Management + * 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. @@ -28,25 +28,20 @@ #include -#include -#include -#include "iarmProxy.hpp" +#include + #include "audioOutputPortConfig.hpp" #include "videoOutputPortConfig.hpp" #include "list.hpp" #include "host.hpp" #include "videoDeviceConfig.hpp" -#include "dsVideoPort.h" -#include "dsVideoDevice.h" #include "dsAudio.h" -#include "dsDisplay.h" -#include "dslogger.h" #include "dsHost.h" -#include "dsTypes.h" #include "unsupportedOperationException.hpp" -#include "hostEDID.hpp" #include "dsInternal.h" +#include "iarm/IarmHostImpl.hpp" + /** * @file host.cpp * @brief The host module is the central module of the Device Settings module. @@ -56,24 +51,20 @@ using namespace std; namespace device { - - const int Host::kPowerOn = dsPOWER_ON; - const int Host::kPowerOff = dsPOWER_OFF; - const int Host::kPowerStandby = dsPOWER_STANDBY; - - - Host::Host() - { - // TODO Auto-generated destructor stub - } - - Host::~Host() { - if (true) - { - IARMProxy::getInstance().UnRegisterPowerEventHandler(); - } - } +const int Host::kPowerOn = dsPOWER_ON; +const int Host::kPowerOff = dsPOWER_OFF; +const int Host::kPowerStandby = dsPOWER_STANDBY; + +Host::Host() + : m_impl(nullptr) +{ +} + +Host::~Host() +{ + m_impl = nullptr; +} /** * @addtogroup dssettingshostapi @@ -103,145 +94,6 @@ namespace device return instance; } - -/** - * @fn void Host::addPowerModeListener(PowerModeChangeListener *l) - * @brief This API is used to register listeners for Power Mode change event. - * The listener object is created by application and should be released by the application once the listener is removed. - * Listeners will be notified with the new mode via the listener's powerModeChanged() callback. - * - * @param[in] PowerModeChangeListener Pointer to Power Mode change listener - * - * @return None - */ - void Host::addPowerModeListener(PowerModeChangeListener *l) - { - std::list < PowerModeChangeListener* > ::iterator it; - - it = find (powerEvntListeners.begin(),powerEvntListeners.end(), l); - if (it == powerEvntListeners.end()) - { - powerEvntListeners.push_back (l); - cout << "Added Power Mode listener...!\n"; - } - else - { - cout << "Already register for Power Mode Change\n"; - } - return ; - } - - -/** - * @fn void Host::removePowerModeChangeListener(PowerModeChangeListener *l) - * @brief This API is used to remove a listener from Power Mode change listener list. - * - * @param[in]PowerModeChangeListener The listener to remove. - * - * @return None - */ - void Host::removePowerModeChangeListener(PowerModeChangeListener *l) - { - std::list < PowerModeChangeListener* > ::iterator it ; - it = find (powerEvntListeners.begin(),powerEvntListeners.end(), l); - if (it == powerEvntListeners.end()) - { - cout << "Not Registered for Power Mode change yet...!\n"; - } - else - { - powerEvntListeners.erase (it); - cout << "Removed from Power Mode listener group..!\n"; - } - return; - } - - -/** - * @fn void Host::addDisplayConnectionListener (DisplayConnectionChangeListener *l) - * @brief This API is used to register listeners for Display connection change event. - * The listener will be notified if Display device is connected/disconnected from the video output port. - * The notification only carries the state change of the connection. - * It does not carry any other system state change that may have been triggered by the connection. - * The application is responsible to query the various parts of system to detect any such change. - * For example, when a TV device is replaced, the application shall query the video output port again upon the connection - * for the new resolution supported by the TV. - * The listener object is created by application and should be released by the application once the listener is removed. - * - * @param[in] DisplayConnectionChangeListener Pointer to Display connection change listener - * - * @return None - */ - void Host::addDisplayConnectionListener (DisplayConnectionChangeListener *l) - { - std::list < DisplayConnectionChangeListener* > ::iterator it; - - it = find (dispEvntListeners.begin(), dispEvntListeners.end(), l); - if (it == dispEvntListeners.end()) - { - dispEvntListeners.push_back (l); - cout << "Added Display listener...!\n"; - } - else - { - cout << "Already registered to the Display listener\n"; - } - return ; - } - - -/** - * @fn void Host::removeDisplayConnectionListener (DisplayConnectionChangeListener *l) - * @brief This API is used to remove listeners from the Display connection change event list. - * - * @param[in] DisplayConnectionChangeListener The listener to remove - * - * @return None - */ - void Host::removeDisplayConnectionListener (DisplayConnectionChangeListener *l) - { - std::list < DisplayConnectionChangeListener* > ::iterator it ; - it = find (dispEvntListeners.begin(), dispEvntListeners.end(), l); - if (it == dispEvntListeners.end()) - { - cout << "Not Registered to Display Listener yet...!\n"; - } - else - { - dispEvntListeners.erase (it); - cout << "Removed from the Display listener...!\n"; - } - return; - } - - -/** - * @fn void Host::notifyPowerChange (const int mode) - * @brief This function is used to get the current power state. - * - * @param[in] mode Power mode of the decoder. - * @return None. - */ - void Host::notifyPowerChange (const int mode) - { - std::list < PowerModeChangeListener* > ::iterator it; - for ( it = powerEvntListeners.begin() ; it != powerEvntListeners.end(); it++ ) - { - (*it)->powerModeChanged (mode); - } - } - - void Host::notifyDisplayConnectionChange (int portHandle, bool newConnectionStatus) - { - std::list < DisplayConnectionChangeListener* > ::iterator it; - for ( it = dispEvntListeners.begin() ; it != dispEvntListeners.end(); it++ ) - { - (*it)->displayConnectionChanged(getVideoOutputPort(portHandle), newConnectionStatus); - getVideoOutputPort(portHandle).setDisplayConnected(newConnectionStatus); - } - } - - /** * @fn bool Host::setPowerMode(int mode) * @brief This API is used to change the power mode of the device. @@ -913,11 +765,101 @@ namespace device printf ("%s:%d - Set Audio Mixer levels for audio input: %d with volume = %d\n", __PRETTY_FUNCTION__, __LINE__,aInput, volume); } +DefaultImpl& Host::impl() +{ + // lazy instantiation + if (!m_impl) { + m_impl = std::unique_ptr(new DefaultImpl()); + } + return *m_impl; +} + +/** + * @fn void Host::Register(ICompositeInEvents *Evtnotification) + * @brief This API is used to register the Events + * + * @return dsError_t + */ +dsError_t Host::Register(ICompositeInEvents *listener) +{ + return impl().Register(listener); +} + +/** + * @fn void Host::UnRegister(ICompositeInEvents *Evtnotification) + * @brief This API is used to UnRegister the Events + * + * @return dsError_t + */ +dsError_t Host::UnRegister(ICompositeInEvents *listener) +{ + return impl().UnRegister(listener); } +/** + * @fn void Host::Register(IDisplayEvents *Evtnotification) + * @brief This API is used to register the Events + * + * @return dsError_t + */ +dsError_t Host::Register(IDisplayEvents *listener) +{ + return impl().Register(listener); +} + +/** + * @fn void Host::UnRegister(IDisplayEvents *Evtnotification) + * @brief This API is used to UnRegister the Events + * + * @return dsError_t + */ +dsError_t Host::UnRegister(IDisplayEvents *listener) +{ + return impl().UnRegister(listener); +} + +dsError_t Host::Register(IVideoDeviceEvents* listener) +{ + return impl().Register(listener); +} + +dsError_t Host::UnRegister(IVideoDeviceEvents* listener) +{ + return impl().UnRegister(listener); +} + +dsError_t Host::Register(IVideoOutputPortEvents* listener) +{ + return impl().Register(listener); +} + +dsError_t Host::UnRegister(IVideoOutputPortEvents* listener) +{ + return impl().UnRegister(listener); +} + +dsError_t Host::Register(IAudioOutputPortEvents* listener) +{ + return impl().Register(listener); +} + +dsError_t Host::UnRegister(IAudioOutputPortEvents* listener) +{ + return impl().UnRegister(listener); +} + +dsError_t Host::Register(IDisplayDeviceEvents* listener) { + return impl().Register(listener); +} + +dsError_t Host::UnRegister(IDisplayDeviceEvents* listener) { + return impl().UnRegister(listener); +} /** @} */ +} // namespace device /** @} */ + /** @} */ diff --git a/ds/iarm/IarmHostImpl.cpp b/ds/iarm/IarmHostImpl.cpp new file mode 100755 index 00000000..a0107962 --- /dev/null +++ b/ds/iarm/IarmHostImpl.cpp @@ -0,0 +1,861 @@ +#include +#include +#include +#include + +#include "IarmHostImpl.hpp" + +#include "dsMgr.h" +#include "dslogger.h" + +#include "libIBus.h" + +namespace device { + +struct EventHandlerMapping { + IARM_EventId_t eventId; + IARM_EventHandler_t handler; +}; + +// unregisterIarmEvents can be called by registerIarmEvents in case of failure. +// Hence defined before registerIarmEvents +template +static bool unregisterIarmEvents(const EventHandlerMapping (&handlers)[N]) +{ + bool unregistered = true; + + for (const auto& eh : handlers) { + if (IARM_RESULT_SUCCESS != IARM_Bus_UnRegisterEventHandler(IARM_BUS_DSMGR_NAME, eh.eventId)) { + INT_ERROR("Failed to unregister IARM event handler for %d", eh.eventId); + unregistered = false; + // don't break here, try to unregister all handlers + } + } + return unregistered; +} + +template +static bool registerIarmEvents(const EventHandlerMapping (&handlers)[N]) +{ + bool registered = true; + + for (const auto& eh : handlers) { + if (IARM_RESULT_SUCCESS != IARM_Bus_RegisterEventHandler(IARM_BUS_DSMGR_NAME, eh.eventId, eh.handler)) { + INT_ERROR("Failed to register IARM event handler for %d", eh.eventId); + registered = false; + // no point in continuing as we will attempt to unregister anyway + break; + } + } + + if (!registered) { + // in case of failure / partial failure + // we should unregister any handlers that were registered + unregisterIarmEvents(handlers); + } + + return registered; +} + +inline bool isValidOwner(const char* owner) +{ + if (std::string(IARM_BUS_DSMGR_NAME) != std::string(owner)) { + INT_ERROR("Invalid owner %s, expected %s", owner, IARM_BUS_DSMGR_NAME); + return false; + } + return true; +} + +// IARMGroupXYZ are c to c++ shim (all methods are static) +// Required to perform group event register and unregister with IARM +// Thread safety to be ensured by the caller +class IARMGroupVideoDevice { +public: + static bool RegisterIarmEvents() + { + return registerIarmEvents(handlers); + } + + static bool UnRegisterIarmEvents() + { + return unregisterIarmEvents(handlers); + } + +private: + static void iarmDisplayFrameratePreChangeHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_DISPLAY_FRAMRATE_PRECHANGE received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + std::string framerate(eventData->data.DisplayFrameRateChange.framerate); + + IarmHostImpl::Dispatch([&framerate](IVideoDeviceEvents* listener) { + listener->OnDisplayFrameratePreChange(framerate); + }); + } else { + INT_ERROR("Invalid data received for display framerate pre-change"); + } + } + + static void iarmDisplayFrameratePostChangeHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_DISPLAY_FRAMRATE_POSTCHANGE received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + std::string framerate(eventData->data.DisplayFrameRateChange.framerate); + + IarmHostImpl::Dispatch([&framerate](IVideoDeviceEvents* listener) { + listener->OnDisplayFrameratePostChange(framerate); + }); + } else { + INT_ERROR("Invalid data received for display framerate post-change"); + } + } + + static void iarmZoomSettingsChangedHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_ZOOM_SETTINGS received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + dsVideoZoom_t zoomSetting = static_cast(eventData->data.dfc.zoomsettings); + + IarmHostImpl::Dispatch([zoomSetting](IVideoDeviceEvents* listener) { + listener->OnZoomSettingsChanged(zoomSetting); + }); + } else { + INT_ERROR("Invalid data received for zoom settings change"); + } + }; + + static constexpr EventHandlerMapping handlers[] = { + { IARM_BUS_DSMGR_EVENT_DISPLAY_FRAMRATE_PRECHANGE, &IARMGroupVideoDevice::iarmDisplayFrameratePreChangeHandler }, + { IARM_BUS_DSMGR_EVENT_DISPLAY_FRAMRATE_POSTCHANGE, &IARMGroupVideoDevice::iarmDisplayFrameratePostChangeHandler }, + { IARM_BUS_DSMGR_EVENT_ZOOM_SETTINGS, &IARMGroupVideoDevice::iarmZoomSettingsChangedHandler }, + }; +}; + +class IARMGroupVideoOutputPort { +public: + static bool RegisterIarmEvents() + { + return registerIarmEvents(handlers); + } + + static bool UnRegisterIarmEvents() + { + return unregisterIarmEvents(handlers); + } + +private: + static void iarmResolutionPreChangeHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_RES_PRECHANGE received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + int width = eventData->data.resn.width; + int height = eventData->data.resn.height; + + IarmHostImpl::Dispatch([width, height](IVideoOutputPortEvents* listener) { + listener->OnResolutionPreChange(width, height); + }); + } else { + INT_ERROR("Invalid data received for resolution pre-change"); + } + } + + static void iarmResolutionPostChangeHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_RES_POSTCHANGE received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + int width = eventData->data.resn.width; + int height = eventData->data.resn.height; + + IarmHostImpl::Dispatch([width, height](IVideoOutputPortEvents* listener) { + listener->OnResolutionPostChange(width, height); + }); + } else { + INT_ERROR("Invalid data received for resolution post-change"); + } + } + + static void iarmHDCPStatusChangeHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_HDCP_STATUS received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + dsHdcpStatus_t hdcpStatus = static_cast(eventData->data.hdmi_hdcp.hdcpStatus); + IarmHostImpl::Dispatch([hdcpStatus](IVideoOutputPortEvents* listener) { + listener->OnHDCPStatusChange(hdcpStatus); + }); + } else { + INT_ERROR("Invalid data received for HDCP status change"); + } + } + + static void iarmVideoFormatUpdateHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_VIDEO_FORMAT_UPDATE received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + dsHDRStandard_t videoFormat = eventData->data.VideoFormatInfo.videoFormat; + + IarmHostImpl::Dispatch([videoFormat](IVideoOutputPortEvents* listener) { + listener->OnVideoFormatUpdate(videoFormat); + }); + } else { + INT_ERROR("Invalid data received for video format update"); + } + } + + static constexpr EventHandlerMapping handlers[] = { + { IARM_BUS_DSMGR_EVENT_RES_PRECHANGE, &IARMGroupVideoOutputPort::iarmResolutionPreChangeHandler }, + { IARM_BUS_DSMGR_EVENT_RES_POSTCHANGE, &IARMGroupVideoOutputPort::iarmResolutionPostChangeHandler }, + { IARM_BUS_DSMGR_EVENT_HDCP_STATUS, &IARMGroupVideoOutputPort::iarmHDCPStatusChangeHandler }, + { IARM_BUS_DSMGR_EVENT_VIDEO_FORMAT_UPDATE, &IARMGroupVideoOutputPort::iarmVideoFormatUpdateHandler }, + }; +}; + +class IARMGroupAudioOutputPort { +public: + static bool RegisterIarmEvents() + { + return registerIarmEvents(handlers); + } + + static bool UnRegisterIarmEvents() + { + return unregisterIarmEvents(handlers); + } + +private: + static void iarmAssociatedAudioMixingChangedHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_AUDIO_ASSOCIATED_AUDIO_MIXING_CHANGED received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + bool mixing = eventData->data.AssociatedAudioMixingInfo.mixing; + + IarmHostImpl::Dispatch([mixing](IAudioOutputPortEvents* listener) { + listener->OnAssociatedAudioMixingChanged(mixing); + }); + } else { + INT_ERROR("Invalid data received for associated audio mixing change"); + } + }; + + static void iarmAudioFaderControlChangedHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_AUDIO_FADER_CONTROL_CHANGED received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + int mixerBalance = eventData->data.FaderControlInfo.mixerbalance; + + IarmHostImpl::Dispatch([mixerBalance](IAudioOutputPortEvents* listener) { + listener->OnAudioFaderControlChanged(mixerBalance); + }); + } else { + INT_ERROR("Invalid data received for audio fader control change"); + } + }; + + static void iarmAudioPrimaryLanguageChangedHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_AUDIO_PRIMARY_LANGUAGE_CHANGED received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + std::string primaryLanguage(eventData->data.AudioLanguageInfo.audioLanguage); + + IarmHostImpl::Dispatch([&primaryLanguage](IAudioOutputPortEvents* listener) { + listener->OnAudioPrimaryLanguageChanged(primaryLanguage); + }); + } else { + INT_ERROR("Invalid data received for primary language change"); + } + }; + + static void iarmAudioSecondaryLanguageChangedHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_AUDIO_SECONDARY_LANGUAGE_CHANGED received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + std::string secondaryLanguage(eventData->data.AudioLanguageInfo.audioLanguage); + + IarmHostImpl::Dispatch([&secondaryLanguage](IAudioOutputPortEvents* listener) { + listener->OnAudioSecondaryLanguageChanged(secondaryLanguage); + }); + } else { + INT_ERROR("Invalid data received for secondary language change"); + } + }; + + static void iarmAudioOutHotPlugHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_AUDIO_OUT_HOTPLUG received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + if (eventData) { + dsAudioPortType_t portType = eventData->data.audio_out_connect.portType; + int uiPortNumber = eventData->data.audio_out_connect.uiPortNo; + bool isPortConnected = eventData->data.audio_out_connect.isPortConnected; + + IarmHostImpl::Dispatch([portType, uiPortNumber, isPortConnected](IAudioOutputPortEvents* listener) { + listener->OnAudioOutHotPlug(portType, uiPortNumber, isPortConnected); + }); + } else { + INT_ERROR("Invalid data received for audio out hot plug change"); + } + }; + + static void iarmDolbyAtmosCapabilitiesChangedHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_ATMOS_CAPS_CHANGED received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + if (eventData) { + dsATMOSCapability_t atmosCapability = eventData->data.AtmosCapsChange.caps; + bool status = eventData->data.AtmosCapsChange.status; + + IarmHostImpl::Dispatch([atmosCapability, status](IAudioOutputPortEvents* listener) { + listener->OnDolbyAtmosCapabilitiesChanged(atmosCapability, status); + }); + + } else { + INT_ERROR("Invalid data received for Dolby Atmos capabilities change"); + } + }; + + // TODO: requires dsMgr.h header for dsAudioPortState_t ? + static void iarmAudioPortStateChangedHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_AUDIO_PORT_STATE received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + dsAudioPortState_t audioPortState = eventData->data.AudioPortStateInfo.audioPortState; + + IarmHostImpl::Dispatch([audioPortState](IAudioOutputPortEvents* listener) { + // TODO: + // listener->OnAudioPortStateChanged(audioPortState); + }); + } else { + INT_ERROR("Invalid data received for audio port state change"); + } + }; + + static void iarmAudioModeEventHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_AUDIO_MODE received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + dsAudioPortType_t audioPortType = static_cast(eventData->data.Audioport.type); + dsAudioStereoMode_t audioStereoMode = static_cast(eventData->data.Audioport.mode); + + IarmHostImpl::Dispatch([audioPortType, audioStereoMode](IAudioOutputPortEvents* listener) { + listener->OnAudioModeEvent(audioPortType, audioStereoMode); + }); + } else { + INT_ERROR("Invalid data received for audio mode change"); + } + }; + + static void iarmAudioLevelChangedEventHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_AUDIO_LEVEL_CHANGED received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + int audioLevel = eventData->data.AudioLevelInfo.level; + + IarmHostImpl::Dispatch([audioLevel](IAudioOutputPortEvents* listener) { + listener->OnAudioLevelChangedEvent(audioLevel); + }); + } else { + INT_ERROR("Invalid data received for audio level change"); + } + }; + + static void iarmAudioFormatUpdateHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_AUDIO_FORMAT_UPDATE received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + + if (eventData) { + dsAudioFormat_t audioFormat = eventData->data.AudioFormatInfo.audioFormat; + + IarmHostImpl::Dispatch([audioFormat](IAudioOutputPortEvents* listener) { + listener->OnAudioFormatUpdate(audioFormat); + }); + } else { + INT_ERROR("Invalid data received for audio format update"); + } + }; + +private: + static constexpr EventHandlerMapping handlers[] = { + { IARM_BUS_DSMGR_EVENT_AUDIO_ASSOCIATED_AUDIO_MIXING_CHANGED, &IARMGroupAudioOutputPort::iarmAssociatedAudioMixingChangedHandler }, + { IARM_BUS_DSMGR_EVENT_AUDIO_FADER_CONTROL_CHANGED, &IARMGroupAudioOutputPort::iarmAudioFaderControlChangedHandler }, + { IARM_BUS_DSMGR_EVENT_AUDIO_PRIMARY_LANGUAGE_CHANGED, &IARMGroupAudioOutputPort::iarmAudioPrimaryLanguageChangedHandler }, + { IARM_BUS_DSMGR_EVENT_AUDIO_SECONDARY_LANGUAGE_CHANGED, &IARMGroupAudioOutputPort::iarmAudioSecondaryLanguageChangedHandler }, + { IARM_BUS_DSMGR_EVENT_AUDIO_OUT_HOTPLUG, &IARMGroupAudioOutputPort::iarmAudioOutHotPlugHandler }, + { IARM_BUS_DSMGR_EVENT_ATMOS_CAPS_CHANGED, &IARMGroupAudioOutputPort::iarmDolbyAtmosCapabilitiesChangedHandler }, + { IARM_BUS_DSMGR_EVENT_AUDIO_PORT_STATE, &IARMGroupAudioOutputPort::iarmAudioPortStateChangedHandler }, + { IARM_BUS_DSMGR_EVENT_AUDIO_MODE, &IARMGroupAudioOutputPort::iarmAudioModeEventHandler }, + { IARM_BUS_DSMGR_EVENT_AUDIO_LEVEL_CHANGED, &IARMGroupAudioOutputPort::iarmAudioLevelChangedEventHandler }, + { IARM_BUS_DSMGR_EVENT_AUDIO_FORMAT_UPDATE, &IARMGroupAudioOutputPort::iarmAudioFormatUpdateHandler }, + }; +}; + +class IARMGroupComposite { +public: + static bool RegisterIarmEvents() + { + return registerIarmEvents(handlers); + } + + static bool UnRegisterIarmEvents() + { + return unregisterIarmEvents(handlers); + } + +private: + static void iarmCompositeInHotPlugHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_COMPOSITE_IN_HOTPLUG received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + if (eventData) { + dsCompositeInPort_t compositePort = eventData->data.composite_in_connect.port; + bool isConnected = eventData->data.composite_in_connect.isPortConnected; + IarmHostImpl::Dispatch([compositePort, isConnected](ICompositeInEvents* listener) { + listener->OnCompositeInHotPlug(compositePort,isConnected); + }); + } else { + INT_ERROR("Invalid data received for Composite Status Handler in iarmCompositeInHotPlugHandler"); + } + } + + static void iarmCompositeInSignalStatusHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_COMPOSITE_IN_SIGNAL_STATUS received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + if (eventData) { + dsCompositeInPort_t compositePort = eventData->data.composite_in_sig_status.port; + dsCompInSignalStatus_t compositeSigStatus = eventData->data.composite_in_sig_status.status; + IarmHostImpl::Dispatch([compositePort,compositeSigStatus](ICompositeInEvents* listener) { + listener->OnCompositeInSignalStatus(compositePort,compositeSigStatus); + }); + } else { + INT_ERROR("Invalid data received for Composite Status Handler in iarmCompositeInSignalStatusHandler"); + } + } + + static void iarmCompositeInStatusHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_COMPOSITE_IN_STATUS received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + if (eventData) { + dsCompositeInPort_t compositePort = eventData->data.composite_in_status.port; + bool isPresented = eventData->data.composite_in_status.isPresented; + IarmHostImpl::Dispatch([compositePort,isPresented](ICompositeInEvents* listener) { + listener->OnCompositeInStatus(compositePort,isPresented); + }); + } else { + INT_ERROR("Invalid data received for Composite Status Handler in iarmCompositeInStatusHandler"); + } + } + + + static void iarmCompositeInVideoModeUpdateHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_COMPOSITE_IN_VIDEO_MODE_UPDATE received owner = %s, eventId = %d", owner, eventId); + if (!isValidOwner(owner)) { + return; + } + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + if (eventData) { + dsCompositeInPort_t compositePort = eventData->data.composite_in_video_mode.port; + dsVideoPortResolution_t videoResolution{}; + memset(videoResolution.name, 0, sizeof(videoResolution.name)); + videoResolution.pixelResolution = eventData->data.composite_in_video_mode.resolution.pixelResolution; + videoResolution.interlaced = eventData->data.composite_in_video_mode.resolution.interlaced; + videoResolution.frameRate = eventData->data.composite_in_video_mode.resolution.frameRate; + IarmHostImpl::Dispatch([compositePort,videoResolution](ICompositeInEvents* listener) { + listener->OnCompositeInVideoModeUpdate(compositePort,videoResolution); + }); + } else { + INT_ERROR("Invalid data received for Composite Video Mode Update in iarmCompositeInVideoModeUpdateHandler"); + } + } + +private: + static constexpr EventHandlerMapping handlers[] = { + { IARM_BUS_DSMGR_EVENT_COMPOSITE_IN_HOTPLUG, &IARMGroupComposite::iarmCompositeInHotPlugHandler }, + { IARM_BUS_DSMGR_EVENT_COMPOSITE_IN_SIGNAL_STATUS, &IARMGroupComposite::iarmCompositeInSignalStatusHandler }, + { IARM_BUS_DSMGR_EVENT_COMPOSITE_IN_STATUS, &IARMGroupComposite::iarmCompositeInStatusHandler }, + { IARM_BUS_DSMGR_EVENT_COMPOSITE_IN_VIDEO_MODE_UPDATE, &IARMGroupComposite::iarmCompositeInVideoModeUpdateHandler }, + }; +}; + + +class IARMGroupDisplay { +public: + static bool RegisterIarmEvents() + { + return registerIarmEvents(handlers); + } + + static bool UnRegisterIarmEvents() + { + return unregisterIarmEvents(handlers); + } + +private: + static void iarmDisplayDisplayRxSense(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_RX_SENSE received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + if (eventData) { + dsDisplayEvent_t displayStatusEvent = static_cast(eventData->data.hdmi_rxsense.status); + IarmHostImpl::Dispatch([displayStatusEvent](IDisplayEvents* listener) { + listener->OnDisplayRxSense(displayStatusEvent); + }); + } else { + INT_ERROR("Invalid data received for Composite Status Handler in iarmDisplayDisplayRxSense"); + } + } + + static void iarmDisplayHDCPStatusChange(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_HDCP_STATUS received owner = %s, eventId = %d", owner, eventId); + if (!isValidOwner(owner)) { + return; + } + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + if (eventData) { + dsHdcpStatus_t hdcpStatus = static_cast(eventData->data.hdmi_hdcp.hdcpStatus); + IarmHostImpl::Dispatch([hdcpStatus](IDisplayEvents* listener) { + /* To check Parameter Required or Not*/ + listener->OnDisplayHDCPStatus(); + }); + } else { + INT_ERROR("Invalid data received for Composite Video Mode Update in iarmDisplayHDCPStatusChange"); + } + } + +private: + static constexpr EventHandlerMapping handlers[] = { + { IARM_BUS_DSMGR_EVENT_RX_SENSE, &IARMGroupDisplay::iarmDisplayDisplayRxSense }, + { IARM_BUS_DSMGR_EVENT_HDCP_STATUS, &IARMGroupDisplay::iarmDisplayHDCPStatusChange }, + }; +}; + +class IARMGroupDisplayDevice { +public: + static bool RegisterIarmEvents() + { + IARM_Result_t result = IARM_Bus_RegisterEventHandler(IARM_BUS_DSMGR_NAME, IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG, + &IARMGroupDisplayDevice::iarmDisplayHDMIHotPlugHandler); + + if (result != IARM_RESULT_SUCCESS) { + INT_ERROR("Failed to register IARM event handler for IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG"); + } + return (result == IARM_RESULT_SUCCESS); + } + + static bool UnRegisterIarmEvents() + { + IARM_Result_t result = IARM_Bus_UnRegisterEventHandler(IARM_BUS_DSMGR_NAME, IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG); + if (result != IARM_RESULT_SUCCESS) { + INT_ERROR("Failed to unregister IARM event handler for IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG"); + } + return (result == IARM_RESULT_SUCCESS); + } + +private: + static void iarmDisplayHDMIHotPlugHandler(const char* owner, IARM_EventId_t eventId, void* data, size_t len) + { + INT_INFO("IARM_BUS_DSMGR_EVENT_HDMI_HOTPLUG received owner = %s, eventId = %d", owner, eventId); + + if (!isValidOwner(owner)) { + return; + } + + IARM_Bus_DSMgr_EventData_t* eventData = (IARM_Bus_DSMgr_EventData_t*)data; + if (eventData) { + dsDisplayEvent_t displayEvent = static_cast(eventData->data.hdmi_hpd.event); + + IarmHostImpl::Dispatch([displayEvent](IDisplayDeviceEvents* listener) { + listener->OnDisplayHDMIHotPlug(displayEvent); + }); + } else { + INT_ERROR("Invalid data received for HDMI hot plug change"); + } + }; +}; + +// static data +constexpr EventHandlerMapping IARMGroupVideoDevice::handlers[]; +constexpr EventHandlerMapping IARMGroupVideoOutputPort::handlers[]; +constexpr EventHandlerMapping IARMGroupAudioOutputPort::handlers[]; +constexpr EventHandlerMapping IARMGroupComposite::handlers[]; +constexpr EventHandlerMapping IARMGroupDisplay::handlers[]; + +std::mutex IarmHostImpl::s_mutex; +IarmHostImpl::CallbackList IarmHostImpl::s_videoDeviceListeners; +IarmHostImpl::CallbackList IarmHostImpl::s_videoOutputPortListeners; +IarmHostImpl::CallbackList IarmHostImpl::s_audioOutputPortListeners; +IarmHostImpl::CallbackList IarmHostImpl::s_compositeListeners; +IarmHostImpl::CallbackList IarmHostImpl::s_displayListeners; +IarmHostImpl::CallbackList IarmHostImpl::s_displayDeviceListeners; + +IarmHostImpl::~IarmHostImpl() +{ + std::lock_guard lock(s_mutex); + + s_videoDeviceListeners.Release(); + s_videoOutputPortListeners.Release(); + s_audioOutputPortListeners.Release(); + s_compositeListeners.Release(); + s_displayListeners.Release(); + s_displayDeviceListeners.Release(); +} + +template +/* static */ void IarmHostImpl::Dispatch(const std::list& listeners, F&& fn) +{ + std::stringstream ss; + std::lock_guard lock(s_mutex); + + for (auto* listener : listeners) { + auto start = std::chrono::steady_clock::now(); + + fn(listener); + + auto end = std::chrono::steady_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + ss << "\t client =" << listener << ", elapsed = " << elapsed.count() << " ms\n"; + } + + INT_INFO("%s Dispatch done to %zu listeners\n%s", typeid(T).name(), listeners.size(), ss.str().c_str()); +} + +dsError_t IarmHostImpl::Register(IVideoDeviceEvents* listener) +{ + std::lock_guard lock(s_mutex); + return s_videoDeviceListeners.Register(listener); +} + +dsError_t IarmHostImpl::UnRegister(IVideoDeviceEvents* listener) +{ + std::lock_guard lock(s_mutex); + return s_videoDeviceListeners.UnRegister(listener); +} + +// Dispatcher for IARMGroupVideoDevice +/* static */ void IarmHostImpl::Dispatch(std::function&& fn) +{ + Dispatch(s_videoDeviceListeners, std::move(fn)); +} + +dsError_t IarmHostImpl::Register(IVideoOutputPortEvents* listener) +{ + std::lock_guard lock(s_mutex); + return s_videoOutputPortListeners.Register(listener); +} + +dsError_t IarmHostImpl::UnRegister(IVideoOutputPortEvents* listener) +{ + std::lock_guard lock(s_mutex); + return s_videoOutputPortListeners.UnRegister(listener); +} + +// Dispatcher for IVideoOutputPortEvents +/* static */ void IarmHostImpl::Dispatch(std::function&& fn) +{ + Dispatch(s_videoOutputPortListeners, std::move(fn)); +} + +dsError_t IarmHostImpl::Register(IAudioOutputPortEvents* listener) +{ + std::lock_guard lock(s_mutex); + return s_audioOutputPortListeners.Register(listener); +} + +dsError_t IarmHostImpl::UnRegister(IAudioOutputPortEvents* listener) +{ + std::lock_guard lock(s_mutex); + return s_audioOutputPortListeners.UnRegister(listener); +} + +// Dispatcher for IAudioOutputPortEvents +/* static */ void IarmHostImpl::Dispatch(std::function&& fn) +{ + Dispatch(s_audioOutputPortListeners, std::move(fn)); +} + +dsError_t IarmHostImpl::Register(ICompositeInEvents* listener) +{ + std::lock_guard lock(s_mutex); + return s_compositeListeners.Register(listener); +} + +dsError_t IarmHostImpl::UnRegister(ICompositeInEvents* listener) +{ + std::lock_guard lock(s_mutex); + return s_compositeListeners.UnRegister(listener); +} + +// Dispatcher for IARMGroupComposite +/* static */ void IarmHostImpl::Dispatch(std::function&& fn) +{ + Dispatch(s_compositeListeners, std::move(fn)); +} + +dsError_t IarmHostImpl::Register(IDisplayEvents* listener) +{ + std::lock_guard lock(s_mutex); + return s_displayListeners.Register(listener); +} + +dsError_t IarmHostImpl::UnRegister(IDisplayEvents* listener) +{ + std::lock_guard lock(s_mutex); + return s_displayListeners.UnRegister(listener); +} + +// Dispatcher for IARMGroupComposite +/* static */ void IarmHostImpl::Dispatch(std::function&& fn) +{ + Dispatch(s_displayListeners, std::move(fn)); +} +dsError_t IarmHostImpl::Register(IDisplayDeviceEvents* listener) +{ + std::lock_guard lock(s_mutex); + return s_displayDeviceListeners.Register(listener); +} + +dsError_t IarmHostImpl::UnRegister(IDisplayDeviceEvents* listener) +{ + std::lock_guard lock(s_mutex); + return s_displayDeviceListeners.UnRegister(listener); +} + +// Dispatcher for IDisplayDeviceEvents +/* static */ void IarmHostImpl::Dispatch(std::function&& fn) +{ + Dispatch(s_displayDeviceListeners, std::move(fn)); +} + +} // namespace device diff --git a/ds/iarm/IarmHostImpl.hpp b/ds/iarm/IarmHostImpl.hpp new file mode 100755 index 00000000..5b27f8af --- /dev/null +++ b/ds/iarm/IarmHostImpl.hpp @@ -0,0 +1,229 @@ +/* + * 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 +#include +#include +#include + +#include "dsError.h" +#include "dslogger.h" +#include "host.hpp" + +namespace device { + +// Forward declaration for IARM Implementation Groups +class IARMGroupVideoDevice; +class IARMGroupVideoOutputPort; +class IARMGroupAudioOutputPort; +class IARMGroupDisplayDevice; +class IARMGroupComposite; +class IARMGroupDisplay; + +using IVideoDeviceEvents = Host::IVideoDeviceEvents; +using IVideoOutputPortEvents = Host::IVideoOutputPortEvents; +using IAudioOutputPortEvents = Host::IAudioOutputPortEvents; +using IDisplayDeviceEvents = Host::IDisplayDeviceEvents; +using ICompositeInEvents = device::Host::ICompositeInEvents; +using IDisplayEvents = device::Host::IDisplayEvents; + +class IarmHostImpl { + + // Manages a list of listeners and corresponding IARM Event Group operations. + // Private internal class, not to be used directly by clients. + template + class CallbackList : public std::list { + public: + CallbackList() + : m_registered(false) + { + } + + ~CallbackList() + { + // As best practise caller is supposed to call Release() explicitly + // this is just for safety (see IarmHostImpl destructor) + Release(); + } + + // disable copy and move semantics + CallbackList(const CallbackList&) = delete; + CallbackList& operator=(const CallbackList&) = delete; + CallbackList(CallbackList&&) = delete; + CallbackList& operator=(CallbackList&&) = delete; + + // @brief Register a listener, also register IARM events if not already registered + // if the listener is already registered, listener will not be added again + // if IARM event registration fails, listener will not be added + dsError_t Register(T listener) + { + if (nullptr == listener) { + INT_ERROR("%s listener is null", typeid(T).name()); + return dsERR_INVALID_PARAM; // Error: Listener is null + } + + if (!m_registered) { + m_registered = IARMGroup::RegisterIarmEvents(); + + if (!m_registered) { + INT_ERROR("Failed to register IARMGroup %s", typeid(IARMGroup).name()); + return dsERR_OPERATION_FAILED; // Error: Failed to register IARM group + } + } + + auto it = std::find(this->begin(), this->end(), listener); + if (it != this->end()) { + // Listener already registered + INT_ERROR("%s %p is already registered", typeid(T).name(), listener); + return dsERR_NONE; // Success: Listener already registered + } + + this->push_back(listener); + + INT_INFO("%s %p registered", typeid(T).name(), listener); + + return dsERR_NONE; + } + + // @brief UnRegister a listener, also unregister IARM events if no listeners are left + // if the listener is not registered, it will not be removed + dsError_t UnRegister(T listener) + { + if (nullptr == listener) { + INT_ERROR("%s listener is null", typeid(T).name()); + return dsERR_INVALID_PARAM; // Error: Listener is null + } + + auto it = std::find(this->begin(), this->end(), listener); + if (it == this->end()) { + // Listener not found + INT_ERROR("%s %p is not registered", typeid(T).name(), listener); + return dsERR_RESOURCE_NOT_AVAILABLE; // Error: Listener not found + } + + this->erase(it); + + INT_INFO("%s %p unregistered", typeid(T).name(), listener); + + if (this->empty() && m_registered) { + m_registered = !IARMGroup::UnRegisterIarmEvents(); + } + + return dsERR_NONE; // Success + } + + // @brief Release all listeners and unregister IARM events + // This will clear the list and unregister IARM events if no listeners are left + dsError_t Release() + { + if (m_registered) { + m_registered = !IARMGroup::UnRegisterIarmEvents(); + } + + this->clear(); + INT_INFO("CallbackList[T=%s] released, status: %d", typeid(T).name(), m_registered); + return dsERR_NONE; // Success + } + + private: + bool m_registered = false; // To track if IARM events are registered + }; + +public: + IarmHostImpl() = default; + ~IarmHostImpl(); + + // @brief Register a listener for video device events + // @param listener: class object implementing the listener + dsError_t Register(IVideoDeviceEvents* listener); + + // @brief UnRegister a listener for video device events + // @param listener: class object implementing the listener + dsError_t UnRegister(IVideoDeviceEvents* listener); + + // @brief Register a listener for video port events + // @param listener: class object implementing the listener + dsError_t Register(IVideoOutputPortEvents* listener); + + // @brief UnRegister a listener for video port events + // @param listener: class object implementing the listener + dsError_t UnRegister(IVideoOutputPortEvents* listener); + + // @brief Register a listener for audio port events + // @param listener: class object implementing the listener + dsError_t Register(IAudioOutputPortEvents* listener); + + // @brief UnRegister a listener for audio port events + // @param listener: class object implementing the listener + dsError_t UnRegister(IAudioOutputPortEvents* listener); + + // @brief Register a listener for Composite events + // @param listener: class object implementing the listener + dsError_t Register(ICompositeInEvents* listener); + + // @brief UnRegister a listener for Composite events + // @param listener: class object implementing the listener + dsError_t UnRegister(ICompositeInEvents* listener); + + // @brief Register a listener for Composite events + // @param listener: class object implementing the listener + dsError_t Register(IDisplayEvents* listener); + + // @brief UnRegister a listener for Composite events + // @param listener: class object implementing the listener + dsError_t UnRegister(IDisplayEvents* listener); + + // @brief Register a listener for display device events + // @param listener: class object implementing the listener + dsError_t Register(IDisplayDeviceEvents* listener); + + // @brief UnRegister a listener for display device events + // @param listener: class object implementing the listener + dsError_t UnRegister(IDisplayDeviceEvents* listener); + +private: + static std::mutex s_mutex; + + static CallbackList s_videoDeviceListeners; + static CallbackList s_videoOutputPortListeners; + static CallbackList s_audioOutputPortListeners; + static CallbackList s_compositeListeners; + static CallbackList s_displayListeners; + static CallbackList s_displayDeviceListeners; + + template + static void Dispatch(const std::list& listeners, F&& fn); + + static void Dispatch(std::function&& fn); + static void Dispatch(std::function&& fn); + static void Dispatch(std::function&& fn); + static void Dispatch(std::function&& fn); + static void Dispatch(std::function&& fn); + static void Dispatch(std::function&& fn); + + // Dispatch is private, so all IARMGroup implementations will need to be friends + friend class IARMGroupVideoDevice; + friend class IARMGroupVideoOutputPort; + friend class IARMGroupAudioOutputPort; + friend class IARMGroupComposite; + friend class IARMGroupDisplay; + friend class IARMGroupDisplayDevice; +}; +} // namespace device diff --git a/ds/include/host.hpp b/ds/include/host.hpp index d14d42dc..09346c71 100644 --- a/ds/include/host.hpp +++ b/ds/include/host.hpp @@ -2,7 +2,7 @@ * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * - * Copyright 2016 RDK Management + * 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. @@ -15,42 +15,41 @@ * 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. -*/ - - + */ /** -* @defgroup devicesettings -* @{ -* @defgroup ds -* @{ -**/ - + * @defgroup devicesettings + * @{ + * @defgroup ds + * @{ + **/ #ifndef _DS_HOST_HPP_ #define _DS_HOST_HPP_ +#include +#include -#include -#include "powerModeChangeListener.hpp" -#include "displayConnectionChangeListener.hpp" #include "audioOutputPort.hpp" -#include "videoOutputPort.hpp" -#include "videoDevice.hpp" +#include "dsAVDTypes.h" +#include "dsDisplay.h" +#include "dsError.h" +#include "list.hpp" #include "sleepMode.hpp" -#include "list.hpp" - -#include -#include - +#include "videoDevice.hpp" +#include "videoOutputPort.hpp" /** * @file host.hpp - * @brief It contains class,structures referenced by host.cpp file. + * @brief It contains class, structures referenced by host.cpp file. */ using namespace std; namespace device { +// Forward declaration of the implementation class +class IarmHostImpl; +// In future add a conditional to choose implementation class based on build configuration +using DefaultImpl = IarmHostImpl; /** * @class Host @@ -63,63 +62,225 @@ class Host { static const int kPowerOff; static const int kPowerStandby; - bool setPowerMode(int mode); - int getPowerMode(); + + struct ICompositeInEvents { + // @brief Composite In Hotplug event + // @text onCompositeInHotPlug + // @param port: Port of the hotplug + // @param isConnected: Is it connected (true) or not(false) + virtual void OnCompositeInHotPlug(dsCompositeInPort_t port, bool isConnected) { }; + + // @brief Composite In Signal status + // @text onCompositeInSignalStatus + // @param port: Port of the hotplug + // @param signalStatus: Signal status + virtual void OnCompositeInSignalStatus(dsCompositeInPort_t port, dsCompInSignalStatus_t signalStatus) { }; + + // @brief Composite In status + // @text onCompositeInStatus + // @param activePort: Active port + // @param isPresented: is it presented to user + virtual void OnCompositeInStatus(dsCompositeInPort_t activePort, bool isPresented) { }; + + + // @brief Composite In Video Mode Update + // @text OnCompositeInVideoModeUpdate + // @param activePort: Active port + // @param videoResolution: See DisplayVideoPortResolution + virtual void OnCompositeInVideoModeUpdate(dsCompositeInPort_t activePort, dsVideoPortResolution_t videoResolution) { }; + }; + + dsError_t Register(ICompositeInEvents *listener); + dsError_t UnRegister(ICompositeInEvents *listener); + + struct IDisplayEvents{ + + // @brief Display RX Sense event + // @text onDisplayRxSense + // @param displayEvent: DS_DISPLAY_RXSENSE_ON or DS_DISPLAY_RXSENSE_OFF + virtual void OnDisplayRxSense(dsDisplayEvent_t displayEvent) { }; + + // @brief Display HDCP Status + // @text OnDisplayHDCPStatus + virtual void OnDisplayHDCPStatus() { }; + }; + dsError_t Register(IDisplayEvents *listener); + dsError_t UnRegister(IDisplayEvents *listener); + + + struct IVideoDeviceEvents { + // @brief Display Frame rate Pre-change notification + // @param frameRate: new framerate + virtual void OnDisplayFrameratePreChange(const std::string& frameRate) { }; + + // @brief Display Frame rate Post-change notification + // @param frameRate: new framerate + virtual void OnDisplayFrameratePostChange(const std::string& frameRate) { }; + + // @brief Zoom settings changed + // @text OnZoomSettingsChanged + // @param zoomSetting: Currently applied zoom setting + virtual void OnZoomSettingsChanged(dsVideoZoom_t zoomSetting) { }; + }; + + // @brief Register a listener for video device events + // @param listener: class object implementing the listener + dsError_t Register(IVideoDeviceEvents* listener); + + // @brief UnRegister a listener for video device events + // @param listener: class object implementing the listener + dsError_t UnRegister(IVideoDeviceEvents* listener); + + struct IVideoOutputPortEvents { + + // @brief On Resolution Pre changed + // @param width: width of the resolution + // @param height: height of the resolution + virtual void OnResolutionPreChange(int width, int height) { }; + + // @brief On Resolution Post change + // @param width: width of the resolution + // @param height: height of the resolution + virtual void OnResolutionPostChange(int width, int height) { }; + + // @brief On HDCP Status change + // @param hdcpStatus: HDCP Status + virtual void OnHDCPStatusChange(dsHdcpStatus_t hdcpStatus) { }; + + // @brief On Video Format update + // @param videoFormatHDR: Video format HDR standard + virtual void OnVideoFormatUpdate(dsHDRStandard_t videoFormatHDR) { }; + }; + + // @brief Register a listener for video port events + // @param listener: class object implementing the listener + dsError_t Register(IVideoOutputPortEvents* listener); + + // @brief UnRegister a listener for video port events + // @param listener: class object implementing the listener + dsError_t UnRegister(IVideoOutputPortEvents* listener); + + struct IAudioOutputPortEvents { + + // @brief Associated Audio mixing changed + // @param mixing: true or false + virtual void OnAssociatedAudioMixingChanged(bool mixing) { }; + + // @brief Audio Fader balance changed + // @param mixerBalance: applied mixer balance value + virtual void OnAudioFaderControlChanged(int mixerBalance) { }; + + // @brief Primary language for Audio changed + // @param primaryLanguage: current primary language for audio + virtual void OnAudioPrimaryLanguageChanged(const std::string& primaryLanguage) { }; + + // @brief Secondary language for Audio changed + // @param secondaryLanguage: current secondary language for audio + virtual void OnAudioSecondaryLanguageChanged(const std::string& secondaryLanguage) { }; + + // @brief Audio output hot plug event + // @param portType: Type of audio port see AudioPortType + // @param uiPortNumber: The port number assigned by UI + // @param isPortConnected: true (connected) or false (not connected) + virtual void OnAudioOutHotPlug(dsAudioPortType_t portType, int uiPortNumber, bool isPortConnected) { }; + + // @brief Dolby Atmos capabilities changed + // @param atmosCapability: the Dolby Atmos capability + // @param status: true (available) or false (not available) + virtual void OnDolbyAtmosCapabilitiesChanged(dsATMOSCapability_t atmosCapability, bool status) { }; + + // @brief Audio port state changed + // @param audioPortState: audio port state + // TODO: requires dsMgr.h header include ?? + // virtual void OnAudioPortStateChanged(dsAudioPortState_t audioPortState) { }; + + // @brief Audio mode for the respective audio port - raised for every type of port + // @param audioPortType: audio port type see dsAudioPortType_t + // @param audioStereoMode: audio stereo mode - see dsAudioStereoMode_t + virtual void OnAudioModeEvent(dsAudioPortType_t audioPortType, dsAudioStereoMode_t audioStereoMode) { }; + + // @brief Audio level changed + // @param audioiLevel: audio level value + virtual void OnAudioLevelChangedEvent(int audioLevel) { }; + + // @brief Audio Output format changed + // @param audioFormat: Type of audio format see AudioFormat + virtual void OnAudioFormatUpdate(dsAudioFormat_t audioFormat) { }; + }; + + // @brief Register a listener for audio port events + // @param listener: class object implementing the listener + dsError_t Register(IAudioOutputPortEvents* listener); + + // @brief UnRegister a listener for audio port events + // @param listener: class object implementing the listener + dsError_t UnRegister(IAudioOutputPortEvents* listener); + + struct IDisplayDeviceEvents { + // @brief Display HDMI (out) Hot plug event + // @param displayEvent: display event type see dsDisplayEvent_t + virtual void OnDisplayHDMIHotPlug(dsDisplayEvent_t displayEvent) { }; + }; + + // @brief Register a listener for display device events + // @param listener: class object implementing the listener + dsError_t Register(IDisplayDeviceEvents* listener); + + // @brief UnRegister a listener for display device events + // @param listener: class object implementing the listener + dsError_t UnRegister(IDisplayDeviceEvents* listener); + + bool setPowerMode(int mode); + int getPowerMode(); SleepMode getPreferredSleepMode(); int setPreferredSleepMode(const SleepMode); - List getAvailableSleepModes(); - void addPowerModeListener(PowerModeChangeListener *l); - void removePowerModeChangeListener(PowerModeChangeListener *l); - void addDisplayConnectionListener(DisplayConnectionChangeListener *l); - void removeDisplayConnectionListener(DisplayConnectionChangeListener *l); + List getAvailableSleepModes(); - static Host& getInstance(void); + static Host& getInstance(void); List getVideoOutputPorts(); List getAudioOutputPorts(); List getVideoDevices(); - VideoOutputPort &getVideoOutputPort(const std::string &name); - VideoOutputPort &getVideoOutputPort(int id); - AudioOutputPort &getAudioOutputPort(const std::string &name); - AudioOutputPort &getAudioOutputPort(int id); - void notifyPowerChange(const int mode); + VideoOutputPort& getVideoOutputPort(const std::string& name); + VideoOutputPort& getVideoOutputPort(int id); + AudioOutputPort& getAudioOutputPort(const std::string& name); + AudioOutputPort& getAudioOutputPort(int id); float getCPUTemperature(); - uint32_t getVersion(void); + uint32_t getVersion(void); void setVersion(uint32_t versionNumber); - void getHostEDID(std::vector &edid) const; + void getHostEDID(std::vector& edid) const; std::string getSocIDFromSDK(); - void getSinkDeviceAtmosCapability(dsATMOSCapability_t & atmosCapability); + void getSinkDeviceAtmosCapability(dsATMOSCapability_t& atmosCapability); void setAudioAtmosOutputMode(bool enable); void setAssociatedAudioMixing(const bool mixing); - void getAssociatedAudioMixing(bool *mixing); + void getAssociatedAudioMixing(bool* mixing); void setFaderControl(const int mixerbalance); - void getFaderControl(int *mixerBalance); + void getFaderControl(int* mixerBalance); void setPrimaryLanguage(const std::string pLang); - void getPrimaryLanguage(std::string &pLang); + void getPrimaryLanguage(std::string& pLang); void setSecondaryLanguage(const std::string sLang); - void getSecondaryLanguage(std::string &sLang); + void getSecondaryLanguage(std::string& sLang); bool isHDMIOutPortPresent(); std::string getDefaultVideoPortName(); std::string getDefaultAudioPortName(); - void getCurrentAudioFormat(dsAudioFormat_t &audioFormat); - void getMS12ConfigDetails(std::string &configType); - void setAudioMixerLevels (dsAudioInput_t aInput, int volume); + void getCurrentAudioFormat(dsAudioFormat_t& audioFormat); + void getMS12ConfigDetails(std::string& configType); + void setAudioMixerLevels(dsAudioInput_t aInput, int volume); + private: - Host(); - virtual ~Host(); - //To Make the instance as thread-safe, using = delete, the result is, automatically generated methods (constructor, for example) from the compiler will not be created and, therefore, can not be called - Host (const Host&)= delete; - Host& operator=(const Host&)= delete; - - std::list < PowerModeChangeListener* > powerEvntListeners; - std::list < DisplayConnectionChangeListener* > dispEvntListeners; - void notifyDisplayConnectionChange(int portHandle, bool newConnectionStatus); + std::unique_ptr m_impl; + Host(); + virtual ~Host(); + // Avoid copies + Host(const Host&) = delete; + Host& operator=(const Host&) = delete; + + DefaultImpl& impl(); }; } #endif /* _DS_HOST_HPP_ */ - /** @} */ /** @} */