diff --git a/.github/workflows/L1-tests.yml b/.github/workflows/L1-tests.yml index 259d11b7..0aaf227c 100755 --- a/.github/workflows/L1-tests.yml +++ b/.github/workflows/L1-tests.yml @@ -2,9 +2,9 @@ name: L1-tests on: push: - branches: [ main, develop, 'sprint/**', 'release/**', 'topic/RDK*' ] + branches: [ main, develop, 'sprint/**', 'release/**' ] pull_request: - branches: [ main, develop, 'sprint/**', 'release/**', 'topic/RDK*' ] + branches: [ main, develop, 'sprint/**', 'release/**' ] env: BUILD_TYPE: Debug @@ -121,6 +121,14 @@ jobs: with: path: entservices-inputoutput + - name: Checkout googletest + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/checkout@v3 + with: + repository: google/googletest + path: googletest + ref: v1.15.0 + - name: Apply patches ThunderTools run: | cd $GITHUB_WORKSPACE/ThunderTools @@ -342,6 +350,22 @@ jobs: && cmake --install build/mocks + - name: Build googletest + if: steps.cache.outputs.cache-hit != 'true' + run: > + cmake -G Ninja + -S "$GITHUB_WORKSPACE/googletest" + -B build/googletest + -DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/install/usr" + -DCMAKE_MODULE_PATH="$GITHUB_WORKSPACE/install/tools/cmake" + -DGENERIC_CMAKE_MODULE_PATH="$GITHUB_WORKSPACE/install/tools/cmake" + -DBUILD_TYPE=Debug + -DBUILD_GMOCK=ON + && + cmake --build build/googletest -j8 + && + cmake --install build/googletest + - name: Build entservices-inputoutput run: > cmake -G Ninja @@ -368,6 +392,8 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests -I $GITHUB_WORKSPACE/Thunder/Source -I $GITHUB_WORKSPACE/Thunder/Source/core + -I $GITHUB_WORKSPACE/install/usr/include + -I $GITHUB_WORKSPACE/install/usr/include/WPEFramework -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Iarm.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Rfc.h @@ -406,9 +432,11 @@ jobs: -DDS_FOUND=ON -DHAS_FRONT_PANEL=ON -DRDK_SERVICES_L1_TEST=ON + -DPLUGIN_AVINPUT=ON + -DPLUGIN_HDMIINPUT=ON -DPLUGIN_HDCPPROFILE=ON -DPLUGIN_HDMICECSOURCE=ON - -DPLUGIN_HDMICECSINK=ON + -DPLUGIN_HDMICECSINK=OFF -DUSE_THUNDER_R4=ON -DHIDE_NON_EXTERNAL_SYMBOLS=OFF && @@ -443,6 +471,8 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests -I $GITHUB_WORKSPACE/Thunder/Source -I $GITHUB_WORKSPACE/Thunder/Source/core + -I $GITHUB_WORKSPACE/install/usr/include + -I $GITHUB_WORKSPACE/install/usr/include/WPEFramework -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Iarm.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Rfc.h @@ -459,7 +489,7 @@ jobs: -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/thunder/Communicator.h --coverage -Wall -Wno-unused-result -Wno-deprecated-declarations -Wno-error=format= - -Wl,-wrap,system -Wl,-wrap,popen -Wl,-wrap,syslog + -Wl,-wrap,system -Wl,-wrap,popen -Wl,-wrap,syslog -Wl,--no-as-needed -DENABLE_TELEMETRY_LOGGING -DUSE_IARMBUS -DENABLE_SYSTEM_GET_STORE_DEMO_LINK @@ -480,9 +510,11 @@ jobs: -DCMAKE_DISABLE_FIND_PACKAGE_CEC=ON -DCMAKE_BUILD_TYPE=Debug -DDS_FOUND=ON + -DPLUGIN_AVINPUT=ON + -DPLUGIN_HDMIINPUT=ON -DPLUGIN_HDCPPROFILE=ON -DPLUGIN_HDMICECSOURCE=ON - -DPLUGIN_HDMICECSINK=ON + -DPLUGIN_HDMICECSINK=OFF -DRDK_SERVICES_L1_TEST=ON -DUSE_THUNDER_R4=ON -DHIDE_NON_EXTERNAL_SYMBOLS=OFF diff --git a/.github/workflows/L2-tests.yml b/.github/workflows/L2-tests.yml index 7224e70b..4d1bd361 100755 --- a/.github/workflows/L2-tests.yml +++ b/.github/workflows/L2-tests.yml @@ -1,9 +1,10 @@ name: L2-tests -#enable the workflow incase of any plugin/testcase changes -#Add "Tests/L2Tests" subdirectory in CMakeLists.txt, when enabling L2Tests on: - workflow_dispatch: + push: + branches: [ main, develop, 'sprint/**', 'release/**' ] + pull_request: + branches: [ main, develop, 'sprint/**', 'release/**' ] env: BUILD_TYPE: Debug @@ -90,6 +91,14 @@ jobs: ref: develop token: ${{ secrets.RDKCM_RDKE }} + - name: Checkout googletest + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/checkout@v3 + with: + repository: google/googletest + path: googletest + ref: v1.15.0 + - name: Apply patches ThunderTools run: | cd $GITHUB_WORKSPACE/ThunderTools @@ -248,6 +257,22 @@ jobs: && cmake --install build/mocks + - name: Build googletest + if: steps.cache.outputs.cache-hit != 'true' + run: > + cmake -G Ninja + -S "$GITHUB_WORKSPACE/googletest" + -B build/googletest + -DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/install/usr" + -DCMAKE_MODULE_PATH="$GITHUB_WORKSPACE/install/tools/cmake" + -DGENERIC_CMAKE_MODULE_PATH="$GITHUB_WORKSPACE/install/tools/cmake" + -DBUILD_TYPE=Debug + -DBUILD_GMOCK=ON + && + cmake --build build/googletest -j8 + && + cmake --install build/googletest + - name: Build entservices-inputoutput run: > cmake @@ -274,6 +299,8 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/rdk/iarmmgrs-hal -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices/proc + -I $GITHUB_WORKSPACE/install/usr/include + -I $GITHUB_WORKSPACE/install/usr/include/WPEFramework -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Iarm.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Rfc.h @@ -365,6 +392,8 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices/proc -I $GITHUB_WORKSPACE/entservices-deviceanddisplay/helpers + -I $GITHUB_WORKSPACE/install/usr/include + -I $GITHUB_WORKSPACE/install/usr/include/WPEFramework -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Iarm.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Rfc.h @@ -384,6 +413,7 @@ jobs: -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvSettingsODM.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvTypes.h -Werror -Wall -Wno-unused-result -Wno-deprecated-declarations -Wno-error=format= + -Wl,--no-as-needed -DUSE_IARMBUS -DRDK_SERVICE_L2_TEST -DDISABLE_SECURITY_TOKEN diff --git a/AVInput/AVInput.cpp b/AVInput/AVInput.cpp index 8c71c7a6..c7586702 100644 --- a/AVInput/AVInput.cpp +++ b/AVInput/AVInput.cpp @@ -48,6 +48,9 @@ #define AVINPUT_METHOD_GET_EDID_VERSION "getEdidVersion" #define AVINPUT_METHOD_SET_EDID_ALLM_SUPPORT "setEdid2AllmSupport" #define AVINPUT_METHOD_GET_EDID_ALLM_SUPPORT "getEdid2AllmSupport" +#define AVINPUT_METHOD_SET_VRR_SUPPORT "setVRRSupport" +#define AVINPUT_METHOD_GET_VRR_SUPPORT "getVRRSupport" +#define AVINPUT_METHOD_GET_VRR_FRAME_RATE "getVRRFrameRate" #define AVINPUT_METHOD_GET_HDMI_COMPATIBILITY_VERSION "getHdmiVersion" #define AVINPUT_METHOD_SET_MIXER_LEVELS "setMixerLevels" #define AVINPUT_METHOD_START_INPUT "startInput" @@ -65,6 +68,12 @@ #define AVINPUT_EVENT_ON_GAME_FEATURE_STATUS_CHANGED "gameFeatureStatusUpdate" #define AVINPUT_EVENT_ON_AVI_CONTENT_TYPE_CHANGED "aviContentTypeUpdate" +#define STR_ALLM "ALLM" +#define VRR_TYPE_HDMI "VRR-HDMI" +#define VRR_TYPE_FREESYNC "VRR-FREESYNC" +#define VRR_TYPE_FREESYNC_PREMIUM "VRR-FREESYNC-PREMIUM" +#define VRR_TYPE_FREESYNC_PREMIUM_PRO "VRR-FREESYNC-PREMIUM-PRO" + static bool isAudioBalanceSet = false; static int planeType = 0; @@ -156,7 +165,11 @@ void AVInput::InitializeIARM() IARM_BUS_DSMGR_NAME, IARM_BUS_DSMGR_EVENT_HDMI_IN_ALLM_STATUS, dsAVGameFeatureStatusEventHandler)); - IARM_CHECK(IARM_Bus_RegisterEventHandler( + IARM_CHECK(IARM_Bus_RegisterEventHandler( + IARM_BUS_DSMGR_NAME, + IARM_BUS_DSMGR_EVENT_HDMI_IN_VRR_STATUS, + dsAVGameFeatureStatusEventHandler)); + IARM_CHECK(IARM_Bus_RegisterEventHandler( IARM_BUS_DSMGR_NAME, IARM_BUS_DSMGR_EVENT_COMPOSITE_IN_HOTPLUG, dsAVEventHandler)); @@ -198,6 +211,9 @@ void AVInput::DeinitializeIARM() IARM_CHECK(IARM_Bus_RemoveEventHandler( IARM_BUS_DSMGR_NAME, IARM_BUS_DSMGR_EVENT_HDMI_IN_ALLM_STATUS, dsAVGameFeatureStatusEventHandler)); + IARM_CHECK(IARM_Bus_RemoveEventHandler( + IARM_BUS_DSMGR_NAME, + IARM_BUS_DSMGR_EVENT_HDMI_IN_VRR_STATUS, dsAVGameFeatureStatusEventHandler)); IARM_CHECK(IARM_Bus_RemoveEventHandler( IARM_BUS_DSMGR_NAME, IARM_BUS_DSMGR_EVENT_COMPOSITE_IN_HOTPLUG, dsAVEventHandler)); @@ -231,6 +247,9 @@ void AVInput::RegisterAll() Register(_T(AVINPUT_METHOD_SET_MIXER_LEVELS), &AVInput::setMixerLevels, this); Register(_T(AVINPUT_METHOD_SET_EDID_ALLM_SUPPORT), &AVInput::setEdid2AllmSupportWrapper, this); Register(_T(AVINPUT_METHOD_GET_EDID_ALLM_SUPPORT), &AVInput::getEdid2AllmSupportWrapper, this); + Register(_T(AVINPUT_METHOD_SET_VRR_SUPPORT), &AVInput::setVRRSupportWrapper, this); + Register(_T(AVINPUT_METHOD_GET_VRR_SUPPORT), &AVInput::getVRRSupportWrapper, this); + Register(_T(AVINPUT_METHOD_GET_VRR_FRAME_RATE), &AVInput::getVRRFrameRateWrapper, this); Register(_T(AVINPUT_METHOD_GET_HDMI_COMPATIBILITY_VERSION), &AVInput::getHdmiVersionWrapper, this); Register(_T(AVINPUT_METHOD_START_INPUT), &AVInput::startInput, this); Register(_T(AVINPUT_METHOD_STOP_INPUT), &AVInput::stopInput, this); @@ -239,6 +258,7 @@ void AVInput::RegisterAll() Register(_T(AVINPUT_METHOD_GAME_FEATURE_STATUS), &AVInput::getGameFeatureStatusWrapper, this); m_primVolume = DEFAULT_PRIM_VOL_LEVEL; m_inputVolume = DEFAULT_INPUT_VOL_LEVEL; + m_currentVrrType = dsVRR_NONE; } void AVInput::UnregisterAll() @@ -251,6 +271,9 @@ void AVInput::UnregisterAll() Unregister(_T(AVINPUT_METHOD_READ_EDID)); Unregister(_T(AVINPUT_METHOD_READ_RAWSPD)); Unregister(_T(AVINPUT_METHOD_READ_SPD)); + Unregister(_T(AVINPUT_METHOD_SET_VRR_SUPPORT)); + Unregister(_T(AVINPUT_METHOD_GET_VRR_SUPPORT)); + Unregister(_T(AVINPUT_METHOD_GET_VRR_FRAME_RATE)); Unregister(_T(AVINPUT_METHOD_SET_EDID_VERSION)); Unregister(_T(AVINPUT_METHOD_GET_EDID_VERSION)); Unregister(_T(AVINPUT_METHOD_START_INPUT)); @@ -868,7 +891,30 @@ void AVInput::AVInputVideoModeUpdate( int port , dsVideoPortResolution_t resolut params["frameRateN"] = 60000; params["frameRateD"] = 1001; break; - + case dsVIDEO_FRAMERATE_100: + params["frameRateN"] = 100000; + params["frameRateD"] = 1000; + break; + case dsVIDEO_FRAMERATE_119dot88: + params["frameRateN"] = 120000; + params["frameRateD"] = 1001; + break; + case dsVIDEO_FRAMERATE_120: + params["frameRateN"] = 120000; + params["frameRateD"] = 1000; + break; + case dsVIDEO_FRAMERATE_200: + params["frameRateN"] = 200000; + params["frameRateD"] = 1000; + break; + case dsVIDEO_FRAMERATE_239dot76: + params["frameRateN"] = 240000; + params["frameRateD"] = 1001; + break; + case dsVIDEO_FRAMERATE_240: + params["frameRateN"] = 240000; + params["frameRateD"] = 100; + break; default: params["frameRateN"] = 60000; params["frameRateD"] = 1000; @@ -1001,18 +1047,71 @@ void AVInput::dsAVGameFeatureStatusEventHandler(const char *owner, IARM_EventId_ AVInput::_instance->AVInputALLMChange(hdmi_in_port, allm_mode); } + if (IARM_BUS_DSMGR_EVENT_HDMI_IN_VRR_STATUS == eventId) + { + IARM_Bus_DSMgr_EventData_t *eventData = (IARM_Bus_DSMgr_EventData_t *)data; + int hdmi_in_port = eventData->data.hdmi_in_vrr_mode.port; + dsVRRType_t new_vrrType = eventData->data.hdmi_in_vrr_mode.vrr_type; + LOGWARN("Received IARM_BUS_DSMGR_EVENT_HDMI_IN_VRR_STATUS event port: %d, VRR Type: %d", hdmi_in_port,new_vrrType); + + if(new_vrrType == dsVRR_NONE) + { + if(AVInput::_instance->m_currentVrrType != dsVRR_NONE){ + AVInput::_instance->AVInputVRRChange(hdmi_in_port, AVInput::_instance->m_currentVrrType, false); + } + } + else + { + if(AVInput::_instance->m_currentVrrType != dsVRR_NONE){ + AVInput::_instance->AVInputVRRChange(hdmi_in_port, AVInput::_instance->m_currentVrrType, false); + } + AVInput::_instance->AVInputVRRChange(hdmi_in_port, new_vrrType, true); + } + AVInput::_instance->m_currentVrrType = new_vrrType; + } } void AVInput::AVInputALLMChange( int port , bool allm_mode) { JsonObject params; params["id"] = port; - params["gameFeature"] = "ALLM"; + params["gameFeature"] = STR_ALLM; params["mode"] = allm_mode; sendNotify(AVINPUT_EVENT_ON_GAME_FEATURE_STATUS_CHANGED, params); } +void AVInput::AVInputVRRChange( int port , dsVRRType_t vrr_type, bool vrr_mode) +{ + JsonObject params; + switch(vrr_type) + { + case dsVRR_HDMI_VRR: + params["id"] = port; + params["gameFeature"] = VRR_TYPE_HDMI; + params["mode"] = vrr_mode; + break; + case dsVRR_AMD_FREESYNC: + params["id"] = port; + params["gameFeature"] = VRR_TYPE_FREESYNC; + params["mode"] = vrr_mode; + break; + case dsVRR_AMD_FREESYNC_PREMIUM: + params["id"] = port; + params["gameFeature"] = VRR_TYPE_FREESYNC_PREMIUM; + params["mode"] = vrr_mode; + break; + case dsVRR_AMD_FREESYNC_PREMIUM_PRO: + params["id"] = port; + params["gameFeature"] = VRR_TYPE_FREESYNC_PREMIUM_PRO; + params["mode"] = vrr_mode; + break; + default: + break; + } + sendNotify(AVINPUT_EVENT_ON_GAME_FEATURE_STATUS_CHANGED, params); +} + uint32_t AVInput::getSupportedGameFeatures(const JsonObject& parameters, JsonObject& response) { LOGINFOMETHOD(); @@ -1061,15 +1160,55 @@ uint32_t AVInput::getGameFeatureStatusWrapper(const JsonObject& parameters, Json returnResponse(false); } - if (strcmp (sGameFeature.c_str(), "ALLM") == 0) + if (strcmp (sGameFeature.c_str(), STR_ALLM) == 0) { bool allm = getALLMStatus(portId); LOGWARN("AVInput::getGameFeatureStatusWrapper ALLM MODE:%d", allm); response["mode"] = allm; } + else if(strcmp (sGameFeature.c_str(), VRR_TYPE_HDMI) == 0) + { + bool hdmi_vrr = false; + dsHdmiInVrrStatus_t vrrStatus; + getVRRStatus(portId, &vrrStatus); + if(vrrStatus.vrrType == dsVRR_HDMI_VRR) + hdmi_vrr = true; + LOGWARN("AVInput::getGameFeatureStatusWrapper HDMI VRR MODE:%d", hdmi_vrr); + response["mode"] = hdmi_vrr; + } + else if(strcmp (sGameFeature.c_str(), VRR_TYPE_FREESYNC) == 0) + { + bool freesync = false; + dsHdmiInVrrStatus_t vrrStatus; + getVRRStatus(portId, &vrrStatus); + if(vrrStatus.vrrType == dsVRR_AMD_FREESYNC) + freesync = true; + LOGWARN("AVInput::getGameFeatureStatusWrapper FREESYNC MODE:%d", freesync); + response["mode"] = freesync; + } + else if(strcmp (sGameFeature.c_str(), VRR_TYPE_FREESYNC_PREMIUM) == 0) + { + bool freesync_premium = false; + dsHdmiInVrrStatus_t vrrStatus; + getVRRStatus(portId, &vrrStatus); + if(vrrStatus.vrrType == dsVRR_AMD_FREESYNC_PREMIUM) + freesync_premium = true; + LOGWARN("AVInput::getGameFeatureStatusWrapper FREESYNC PREMIUM MODE:%d", freesync_premium); + response["mode"] = freesync_premium; + } + else if(strcmp (sGameFeature.c_str(), VRR_TYPE_FREESYNC_PREMIUM_PRO) == 0) + { + bool freesync_premium_pro = false; + dsHdmiInVrrStatus_t vrrStatus; + getVRRStatus(portId, &vrrStatus); + if(vrrStatus.vrrType == dsVRR_AMD_FREESYNC_PREMIUM_PRO) + freesync_premium_pro = true; + LOGWARN("AVInput::getGameFeatureStatusWrapper FREESYNC PREMIUM PRO MODE:%d", freesync_premium_pro); + response["mode"] = freesync_premium_pro; + } else { - LOGWARN("AVInput::getGameFeatureStatusWrapper Mode is not supported. Supported mode: ALLM"); + LOGWARN("AVInput::getGameFeatureStatusWrapper Mode is not supported. Supported mode: ALLM, VRR-HDMI, VRR-FREESYNC-PREMIUM"); returnResponse(false); } returnResponse(true); @@ -1091,6 +1230,22 @@ bool AVInput::getALLMStatus(int iPort) return allm; } +bool AVInput::getVRRStatus(int iPort, dsHdmiInVrrStatus_t *vrrStatus) +{ + bool ret = true; + try + { + device::HdmiInput::getInstance().getVRRStatus (iPort, vrrStatus); + LOGWARN("AVInput::getVRRStatus VRR TYPE: %d, VRR FRAMERATE: %f", vrrStatus->vrrType,vrrStatus->vrrAmdfreesyncFramerate_Hz); + } + catch (const device::Exception& err) + { + LOG_DEVICE_EXCEPTION1(std::to_string(iPort)); + ret = false; + } + return ret; +} + uint32_t AVInput::getRawSPDWrapper(const JsonObject& parameters, JsonObject& response) { LOGINFOMETHOD(); @@ -1363,6 +1518,125 @@ uint32_t AVInput::getEdid2AllmSupportWrapper(const JsonObject& parameters, JsonO } } +bool AVInput::getVRRSupport(int portId,bool *vrrSupportValue) +{ + bool ret = true; + try + { + device::HdmiInput::getInstance().getVRRSupport (portId, vrrSupportValue); + LOGINFO("AVInput - getVRRSupport:%d", *vrrSupportValue); + } + catch (const device::Exception& err) + { + LOG_DEVICE_EXCEPTION1(std::to_string(portId)); + ret = false; + } + return ret; +} + +uint32_t AVInput::getVRRSupportWrapper(const JsonObject& parameters, JsonObject& response) +{ + LOGINFOMETHOD(); + returnIfParamNotFound(parameters, "portId"); + string sPortId = parameters["portId"].String(); + + int portId = 0; + bool vrrSupport = true; + + try { + portId = stoi(sPortId); + }catch (const std::exception& err) { + LOGWARN("sPortId invalid paramater: %s ", sPortId.c_str()); + returnResponse(false); + } + + bool result = getVRRSupport(portId, &vrrSupport); + if(result == true) + { + response["vrrSupport"] = vrrSupport; + returnResponse(true); + } + else + { + returnResponse(false); + } +} + +bool AVInput::setVRRSupport(int portId, bool vrrSupport) +{ + bool ret = true; + try + { + device::HdmiInput::getInstance().setVRRSupport (portId, vrrSupport); + LOGWARN("AVInput - vrrSupport:%d", vrrSupport); + } + catch (const device::Exception& err) + { + LOG_DEVICE_EXCEPTION1(std::to_string(portId)); + ret = false; + } + return ret; + +} + +uint32_t AVInput::setVRRSupportWrapper(const JsonObject& parameters, JsonObject& response) +{ + LOGINFOMETHOD(); + + returnIfParamNotFound(parameters, "portId"); + returnIfParamNotFound(parameters, "vrrSupport"); + + int portId = 0; + string sPortId = parameters["portId"].String(); + bool vrrSupport = parameters["vrrSupport"].Boolean(); + + try { + portId = stoi(sPortId); + }catch (const std::exception& err) { + LOGWARN("sPortId invalid paramater: %s ", sPortId.c_str()); + returnResponse(false); + } + + bool result = setVRRSupport(portId, vrrSupport); + if(result == true) + { + returnResponse(true); + } + else + { + returnResponse(false); + } +} + +uint32_t AVInput::getVRRFrameRateWrapper(const JsonObject& parameters, JsonObject& response) +{ + LOGINFOMETHOD(); + returnIfParamNotFound(parameters, "portId"); + string sPortId = parameters["portId"].String(); + + int portId = 0; + dsHdmiInVrrStatus_t vrrStatus; + vrrStatus.vrrAmdfreesyncFramerate_Hz = 0; + + try { + portId = stoi(sPortId); + }catch (const std::exception& err) { + LOGWARN("sPortId invalid paramater: %s ", sPortId.c_str()); + returnResponse(false); + } + + bool result = getVRRStatus(portId, &vrrStatus); + if(result == true) + { + response["currentVRRVideoFrameRate"] = vrrStatus.vrrAmdfreesyncFramerate_Hz; + returnResponse(true); + } + else + { + returnResponse(false); + } +} + uint32_t AVInput::setEdidVersionWrapper(const JsonObject& parameters, JsonObject& response) { LOGINFOMETHOD(); diff --git a/AVInput/AVInput.h b/AVInput/AVInput.h index 22b61827..b6c86142 100644 --- a/AVInput/AVInput.h +++ b/AVInput/AVInput.h @@ -47,6 +47,8 @@ class AVInput: public PluginHost::IPlugin, public PluginHost::JSONRPC int m_primVolume; int m_inputVolume; //Player Volume + + dsVRRType_t m_currentVrrType; public: // IPlugin methods // ------------------------------------------------------------------------------------------------------- @@ -79,6 +81,9 @@ class AVInput: public PluginHost::IPlugin, public PluginHost::JSONRPC uint32_t getEdidVersionWrapper(const JsonObject& parameters, JsonObject& response); uint32_t setEdid2AllmSupportWrapper(const JsonObject& parameters, JsonObject& response); uint32_t getEdid2AllmSupportWrapper(const JsonObject& parameters, JsonObject& response); + uint32_t setVRRSupportWrapper(const JsonObject& parameters, JsonObject& response); + uint32_t getVRRSupportWrapper(const JsonObject& parameters, JsonObject& response); + uint32_t getVRRFrameRateWrapper(const JsonObject& parameters, JsonObject& response); uint32_t startInput(const JsonObject& parameters, JsonObject& response); uint32_t stopInput(const JsonObject& parameters, JsonObject& response); uint32_t setVideoRectangleWrapper(const JsonObject& parameters, JsonObject& response); @@ -95,10 +100,14 @@ class AVInput: public PluginHost::IPlugin, public PluginHost::JSONRPC std::string getSPD(int iPort); int setEdidVersion(int iPort, int iEdidVer); int getEdidVersion(int iPort); + bool setVRRSupport(int portId, bool vrrSupport); + bool getVRRSupport(int portId, bool *vrrSupportValue); bool setVideoRectangle(int x, int y, int width, int height, int type); bool getALLMStatus(int iPort); + bool getVRRStatus(int iPort, dsHdmiInVrrStatus_t *vrrStatus); void AVInputHotplug(int input , int connect, int type); + void AVInputVRRChange( int port , dsVRRType_t vrr_type, bool vrr_mode); static void dsAVEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len); void AVInputSignalChange( int port , int signalStatus, int type); diff --git a/AVOutput/AVOutputTV.cpp b/AVOutput/AVOutputTV.cpp index e95b81e7..3f0e8e59 100644 --- a/AVOutput/AVOutputTV.cpp +++ b/AVOutput/AVOutputTV.cpp @@ -2203,14 +2203,17 @@ namespace Plugin { uint32_t AVOutputTV::getSupportedDolbyVisionModes(const JsonObject& parameters, JsonObject& response) { LOGINFO("Entry\n"); - tvDolbyMode_t dvModes[tvMode_Max]; - tvDolbyMode_t *dvModesPtr = dvModes; // Pointer to statically allocated tvDolbyMode_t array + tvDolbyMode_t dvModes[tvMode_Max] = { tvDolbyMode_Invalid }; + tvDolbyMode_t *dvModesPtr[tvMode_Max] = { 0 }; unsigned short totalAvailable = 0; - + for (int i = 0; i < tvMode_Max; i++) + { + dvModesPtr[i] = &dvModes[i]; + } // Set an initial value to indicate the mode type dvModes[0] = tvDolbyMode_Dark; - tvError_t ret = GetTVSupportedDolbyVisionModes(&dvModesPtr, &totalAvailable); + tvError_t ret = GetTVSupportedDolbyVisionModes(dvModesPtr, &totalAvailable); if(ret != tvERROR_NONE) { returnResponse(false); } @@ -2423,9 +2426,14 @@ namespace Plugin { uint32_t AVOutputTV::getSupportedPictureModes(const JsonObject& parameters, JsonObject& response) { LOGINFO("Entry\n"); - pic_modes_t *pictureModes; + pic_modes_t pictureModes[PIC_MODES_SUPPORTED_MAX]; + pic_modes_t *pictureModesPtr[PIC_MODES_SUPPORTED_MAX]={0}; unsigned short totalAvailable = 0; - tvError_t ret = GetTVSupportedPictureModes(&pictureModes,&totalAvailable); + for (int i = 0; i < PIC_MODES_SUPPORTED_MAX; i++) + { + pictureModesPtr[i] = &pictureModes[i]; + } + tvError_t ret = GetTVSupportedPictureModes(pictureModesPtr,&totalAvailable); if(ret != tvERROR_NONE) { returnResponse(false); } diff --git a/AVOutput/AVOutputTV.h b/AVOutput/AVOutputTV.h index 5e493068..612aebf8 100644 --- a/AVOutput/AVOutputTV.h +++ b/AVOutput/AVOutputTV.h @@ -27,7 +27,6 @@ #include "tvTypes.h" #include "tvSettings.h" -#include "tvSettingsExtODM.h" #include #include "Module.h" #include "tvError.h" @@ -270,7 +269,6 @@ class AVOutputTV : public AVOutputBase { private: - tvContentFormatType_t getContentFormatIndex(tvVideoHDRFormat_t formatToConvert); int getPictureModeIndex(std::string pqmode); int getSourceIndex(std::string source); int getFormatIndex(std::string format); @@ -308,7 +306,6 @@ class AVOutputTV : public AVOutputBase { string convertSourceIndexToString(int source); string convertVideoFormatToString(int format); string convertPictureIndexToString(int pqmode); - tvContentFormatType_t convertFormatStringToTVContentFormat(const char *format); //std::string convertSourceIndexToString(int sourceIndex); //std::string convertVideoFormatToString( int formatIndex ); void convertUserScaleBacklightToDriverScale(int format,int * params); @@ -340,10 +337,8 @@ class AVOutputTV : public AVOutputBase { int getLocalparam( std::string forParam,paramIndex_t indexInfo,int & value,tvPQParameterIndex_t pqParamIndex,bool sync=false); tvDataComponentColor_t getComponentColorEnum(std::string colorName); - int getDolbyParams(tvContentFormatType_t format, std::string &s, std::string source = ""); tvError_t getParamsCaps(std::string param, capVectors_t &vecInfo); int GetPanelID(char *panelid); - int ConvertHDRFormatToContentFormat(tvhdr_type_t hdrFormat); int ReadCapablitiesFromConf(std::string param, capDetails_t& info); void getDimmingModeStringFromEnum(int value, std::string &toStore); void getColorTempStringFromEnum(int value, std::string &toStore); diff --git a/AVOutput/AVOutputTVHelper.cpp b/AVOutput/AVOutputTVHelper.cpp index 7e3b28c5..527569a9 100644 --- a/AVOutput/AVOutputTVHelper.cpp +++ b/AVOutput/AVOutputTVHelper.cpp @@ -32,36 +32,6 @@ static bool m_isDalsEnabled = false; namespace WPEFramework { namespace Plugin { - tvContentFormatType_t AVOutputTV::getContentFormatIndex(tvVideoHDRFormat_t formatToConvert) - { - /* default to SDR always*/ - tvContentFormatType_t ret = tvContentFormatType_NONE; - switch(formatToConvert) { - case tvVideoHDRFormat_HLG: - ret = tvContentFormatType_HLG; - break; - - case tvVideoHDRFormat_HDR10: - ret = tvContentFormatType_HDR10; - break; - - case tvVideoHDRFormat_HDR10PLUS: - ret = tvContentFormatType_HDR10PLUS; - break; - - case tvVideoHDRFormat_DV: - ret = tvContentFormatType_DOVI; - break; - - case tvVideoHDRFormat_SDR: - case tvVideoHDRFormat_NONE: - default: - ret = tvContentFormatType_SDR; - break; - } - return ret; - } - int AVOutputTV::getPictureModeIndex(std::string pqparam) { int index = -1; @@ -265,14 +235,19 @@ namespace Plugin { int AVOutputTV::getDolbyModeIndex(const char * dolbyMode) { int mode = 0; - tvDolbyMode_t dolbyModes[tvMode_Max]; - tvDolbyMode_t *dolbyModesPtr = dolbyModes; // Pointer to statically allocated tvDolbyMode_t array + tvDolbyMode_t dolbyModes[tvMode_Max] = { tvDolbyMode_Invalid }; + tvDolbyMode_t *dolbyModesPtr[tvMode_Max] = { 0 }; unsigned short totalAvailable = 0; + for (int i = 0; i < tvMode_Max; i++) + { + dolbyModesPtr[i] = &dolbyModes[i]; + } + // Set an initial value to indicate the mode type dolbyModes[0] = tvDolbyMode_Dark; - tvError_t ret = GetTVSupportedDolbyVisionModes(&dolbyModesPtr, &totalAvailable); + tvError_t ret = GetTVSupportedDolbyVisionModes(dolbyModesPtr, &totalAvailable); if (ret == tvERROR_NONE) { for (int count = 0; count < totalAvailable; count++) { if(strncasecmp(dolbyMode, getDolbyModeStringFromEnum(dolbyModes[count]).c_str(), strlen(dolbyMode))==0) { @@ -321,13 +296,13 @@ namespace Plugin { { tvDimmingMode_t index = tvDimmingMode_MAX; - if(mode.compare("local") == 0 ) { + if(mode.compare("Local") == 0 ) { index=tvDimmingMode_Local; } - else if(mode.compare("fixed") == 0 ) { + else if(mode.compare("Fixed") == 0 ) { index=tvDimmingMode_Fixed; } - else if(mode.compare("global") == 0 ) { + else if(mode.compare("Global") == 0 ) { index=tvDimmingMode_Global; } else { @@ -925,26 +900,6 @@ namespace Plugin { return ret; } - tvContentFormatType_t AVOutputTV::convertFormatStringToTVContentFormat(const char *format) - { - tvContentFormatType_t ret = tvContentFormatType_SDR; - - if( strncmp(format,"sdr",strlen(format)) == 0 || strncmp(format,"SDR",strlen(format)) == 0 ) { - ret = tvContentFormatType_SDR; - } - else if( strncmp(format,"hdr10",strlen(format)) == 0 || strncmp(format,"HDR10",strlen(format))==0 ) { - ret = tvContentFormatType_HDR10; - } - else if( strncmp(format,"hlg",strlen(format)) == 0 || strncmp(format,"HLG",strlen(format)) == 0 ) { - ret = tvContentFormatType_HLG; - } - else if( strncmp(format,"dolby",strlen(format)) == 0 || strncmp(format,"DOLBY",strlen(format)) == 0 ) { - ret=tvContentFormatType_DOVI; - } - - return ret; - } - tvError_t AVOutputTV::updateAVoutputTVParamToHAL(std::string forParam, paramIndex_t indexInfo, int value,bool setNotDelete) { tvError_t ret = tvERROR_NONE; @@ -1514,13 +1469,13 @@ namespace Plugin { return 0; } else if( forParam.compare("DimmingMode") == 0 ) { - if (strncmp(param.value, "fixed", strlen(param.value))==0) { + if (strncmp(param.value, "Fixed", strlen(param.value))==0) { value=tvDimmingMode_Fixed; } - else if (strncmp(param.value, "local", strlen(param.value))==0) { + else if (strncmp(param.value, "Local", strlen(param.value))==0) { value=tvDimmingMode_Local; } - else if (strncmp(param.value, "global", strlen(param.value))==0) { + else if (strncmp(param.value, "Global", strlen(param.value))==0) { value=tvDimmingMode_Global; } return 0; @@ -1654,38 +1609,12 @@ namespace Plugin { return 0; } - int AVOutputTV::ConvertHDRFormatToContentFormat(tvhdr_type_t hdrFormat) - { - int ret=tvContentFormatType_SDR; - switch(hdrFormat) - { - case HDR_TYPE_SDR: - ret=tvContentFormatType_SDR; - break; - case HDR_TYPE_HDR10: - ret=tvContentFormatType_HDR10; - break; - case HDR_TYPE_HDR10PLUS: - ret=tvContentFormatType_HDR10PLUS; - break; - case HDR_TYPE_DOVI: - ret=tvContentFormatType_DOVI; - break; - case HDR_TYPE_HLG: - ret=tvContentFormatType_HLG; - break; - default: - break; - } - return ret; - } - void AVOutputTV::getDimmingModeStringFromEnum(int value, std::string &toStore) { const char *color_temp_string[] = { - [tvDimmingMode_Fixed] = "fixed", - [tvDimmingMode_Local] = "local", - [tvDimmingMode_Global] = "global", + [tvDimmingMode_Fixed] = "Fixed", + [tvDimmingMode_Local] = "Local", + [tvDimmingMode_Global] = "Global", }; toStore.clear(); toStore+=color_temp_string[value]; diff --git a/AVOutput/CHANGELOG.md b/AVOutput/CHANGELOG.md index a3afa122..e5f68a0f 100644 --- a/AVOutput/CHANGELOG.md +++ b/AVOutput/CHANGELOG.md @@ -14,6 +14,14 @@ All notable changes to this RDK Service will be documented in this file. * Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. +## [1.1.2] - 2025-07-01 +### Fixed +- Phase2 ODM + +## [1.1.1] - 2025-06-26 +### Fixed +- Fixed dimmingMode failures + ## [1.1.0] - 2025-03-14 ### Added - Add additional features on AVOutput diff --git a/CHANGELOG.md b/CHANGELOG.md index 73149475..6d0c412b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,58 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.3.2](https://github.com/rdkcentral/entservices-inputoutput/compare/1.3.1...1.3.2) + +- RDKEMW-5510: Integrate the ODM Phase 2 middleware changes into RDKE [`#160`](https://github.com/rdkcentral/entservices-inputoutput/pull/160) +- Merge tag '1.3.1' into develop [`8083548`](https://github.com/rdkcentral/entservices-inputoutput/commit/808354842ca703cbcd49d04ee6ceeca5911d1653) + +#### [1.3.1](https://github.com/rdkcentral/entservices-inputoutput/compare/1.3.0...1.3.1) + +> 26 June 2025 + +- RDKEMW-5512: Implement a fix for the SaveTVDimmingMode failure [`#157`](https://github.com/rdkcentral/entservices-inputoutput/pull/157) +- RDKEMW-1015 - Update gtest [`#155`](https://github.com/rdkcentral/entservices-inputoutput/pull/155) +- 1.3.1 release changelog updates [`88527ce`](https://github.com/rdkcentral/entservices-inputoutput/commit/88527cedd22c2ca3d58c8b625ed9f90ba1128066) +- Merge tag '1.3.0' into develop [`2499e0b`](https://github.com/rdkcentral/entservices-inputoutput/commit/2499e0b71c2fbb9e9a303a342fbc4965da5b52c9) + +#### [1.3.0](https://github.com/rdkcentral/entservices-inputoutput/compare/1.2.0...1.3.0) + +> 20 June 2025 + +- Feature/rdkemw 1015 comrpc [`#129`](https://github.com/rdkcentral/entservices-inputoutput/pull/129) +- RDK-57440: Causing config issue for higher versions of cmake [`#146`](https://github.com/rdkcentral/entservices-inputoutput/pull/146) +- RDK-57440 - Changelog updates for 1.3.0 [`cc4f369`](https://github.com/rdkcentral/entservices-inputoutput/commit/cc4f36979ba5a25a4ae96005b7e2c6dce1523044) +- Merge tag '1.2.0' into develop [`7b1dccc`](https://github.com/rdkcentral/entservices-inputoutput/commit/7b1dccc6d7bbba3fdf649c900ad15996e6424a27) + +#### [1.2.0](https://github.com/rdkcentral/entservices-inputoutput/compare/1.1.1...1.2.0) + +> 17 June 2025 + +- RDKEMW-4135:Coverity integration with Entservices repo [`#147`](https://github.com/rdkcentral/entservices-inputoutput/pull/147) +- RDKEMW-4116 : VRR Feature Middleware changes. [`#103`](https://github.com/rdkcentral/entservices-inputoutput/pull/103) +- topic/RDK-58099: HdmiCecSink syntax error [`#142`](https://github.com/rdkcentral/entservices-inputoutput/pull/142) +- [RDKEMW-2711] RDKEMW-4650: Enabling the L1/L2 test in the Testframework [`#130`](https://github.com/rdkcentral/entservices-inputoutput/pull/130) +- Update AVInput.cpp [`78f58ff`](https://github.com/rdkcentral/entservices-inputoutput/commit/78f58ffebdd7dc34588a2202722758881503600c) +- Added L1Tests [`8986170`](https://github.com/rdkcentral/entservices-inputoutput/commit/8986170c1956a7a678b78c142cd0430bae459c58) +- Update AVInput.cpp [`dcee164`](https://github.com/rdkcentral/entservices-inputoutput/commit/dcee164f26692b92e7d7fadf9b36e1523cd84d69) + +#### [1.1.1](https://github.com/rdkcentral/entservices-inputoutput/compare/1.1.0...1.1.1) + +> 11 June 2025 + +- RDKEMW-5124: Higher framerate support in Thunder [`#134`](https://github.com/rdkcentral/entservices-inputoutput/pull/134) +- RDK-57440: Enable HdcpProfile for contract test [`#132`](https://github.com/rdkcentral/entservices-inputoutput/pull/132) +- [RDKEMW-2711] RDKEMW-4232: Moving the L2 Test files to specific entservices for inputoutput repo [`#123`](https://github.com/rdkcentral/entservices-inputoutput/pull/123) +- RDKEMW-4196: Cleanup and remove pwrmgr references from workflows [`#126`](https://github.com/rdkcentral/entservices-inputoutput/pull/126) +- RDKEMW-4220: Fix wpeframework crash on reactivating plugin and powerstate change [`#104`](https://github.com/rdkcentral/entservices-inputoutput/pull/104) +- RDKEMW-4139: Coverity integration with Entservices-inputoutput repo [`#116`](https://github.com/rdkcentral/entservices-inputoutput/pull/116) +- 1.1.1 release change log updates [`6b11c5b`](https://github.com/rdkcentral/entservices-inputoutput/commit/6b11c5b379c1bfdfc533fc090d73245d4cfe264e) +- Merge tag '1.1.0' into develop [`2ce89ed`](https://github.com/rdkcentral/entservices-inputoutput/commit/2ce89edb2c300ecc3275fab6673b48823578d053) + #### [1.1.0](https://github.com/rdkcentral/entservices-inputoutput/compare/1.0.12...1.1.0) +> 20 May 2025 + - RDK-52028 : Add CMS,WB,ALS to AVOutput (#6139) [`#23`](https://github.com/rdkcentral/entservices-inputoutput/pull/23) - [RDKEMW-2711] RDKEMW-4232: Moving the L2 Test files to entservices-inputoutput [`#107`](https://github.com/rdkcentral/entservices-inputoutput/pull/107) - [RDKEMW-2711] RDKEMW-3851: L1 - Move plugins Unit test to inputoutput repo [`#92`](https://github.com/rdkcentral/entservices-inputoutput/pull/92) @@ -14,6 +64,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - RDK-55554 : Gtest for HdmiCecSource and sink [`#78`](https://github.com/rdkcentral/entservices-inputoutput/pull/78) - RDK-55373:[RDKServices] Coverity integration with middleware componen… [`#96`](https://github.com/rdkcentral/entservices-inputoutput/pull/96) - RDK-55373:[RDKServices] Coverity integration with middleware component workflow [`#94`](https://github.com/rdkcentral/entservices-inputoutput/pull/94) +- 1.1.0 release changelog updates [`d6c91fa`](https://github.com/rdkcentral/entservices-inputoutput/commit/d6c91fa3fb9bda7e296ce9321921cc8882b2d50d) - Merge tag '1.0.12' into develop [`2019c9f`](https://github.com/rdkcentral/entservices-inputoutput/commit/2019c9f8d72eba911fe9030cf4476ce99c2127de) #### [1.0.12](https://github.com/rdkcentral/entservices-inputoutput/compare/1.0.11...1.0.12) @@ -74,10 +125,15 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - Enabling workflow for L1 and L2 [`4049a2e`](https://github.com/rdkcentral/entservices-inputoutput/commit/4049a2eb188efede1c1547be50847d29ddcb9e03) - Merge tag '1.0.6' into develop [`f46b084`](https://github.com/rdkcentral/entservices-inputoutput/commit/f46b084ed21e61d89e20868eacdea4ba8198266d) -#### [1.0.6](https://github.com/rdkcentral/entservices-inputoutput/compare/1.0.5...1.0.6) +#### [1.0.6](https://github.com/rdkcentral/entservices-inputoutput/compare/1.0.6-RDK7.1...1.0.6) > 27 March 2025 +#### [1.0.6-RDK7.1](https://github.com/rdkcentral/entservices-inputoutput/compare/1.0.5...1.0.6-RDK7.1) + +> 22 May 2025 + +- RDKEMW-4220: Fix wpeframework crash on reactivating plugin and powerstate change [`#104`](https://github.com/rdkcentral/entservices-inputoutput/pull/104) - Removed Cec host header [`#35`](https://github.com/rdkcentral/entservices-inputoutput/pull/35) - 1.0.9 release change log updates [`8abd094`](https://github.com/rdkcentral/entservices-inputoutput/commit/8abd09439355af4041436e562c4590769b55bc0c) - Merge tag '1.0.5' into develop [`3b26eeb`](https://github.com/rdkcentral/entservices-inputoutput/commit/3b26eebfdf0e992e369e5cd3cdc981748c9cdb69) diff --git a/HdmiCecSink/CMakeLists.txt b/HdmiCecSink/CMakeLists.txt index b244641e..11e12e6f 100644 --- a/HdmiCecSink/CMakeLists.txt +++ b/HdmiCecSink/CMakeLists.txt @@ -16,6 +16,7 @@ # limitations under the License. set(PLUGIN_NAME HdmiCecSink) set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) +set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) set(PLUGIN_HDMICECSINK_STARTUPORDER "" CACHE STRING "To configure startup order of HdmiCecSink plugin") @@ -26,10 +27,18 @@ add_library(${MODULE_NAME} SHARED HdmiCecSink.cpp Module.cpp) +add_library(${PLUGIN_IMPLEMENTATION} SHARED + HdmiCecSinkImplementation.cpp + Module.cpp) + set_target_properties(${MODULE_NAME} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED YES) +set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED YES) + target_compile_definitions(${MODULE_NAME} PRIVATE MODULE_NAME=Plugin_${PLUGIN_NAME}) find_package(DS) @@ -41,13 +50,23 @@ target_include_directories(${MODULE_NAME} PRIVATE ${CEC_INCLUDE_DIRS}) target_include_directories(${MODULE_NAME} PRIVATE ${DS_INCLUDE_DIRS}) set_source_files_properties(HdmiCecSink.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") + +target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${IARMBUS_INCLUDE_DIRS} ../helpers) +target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${CEC_INCLUDE_DIRS}) +target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${DS_INCLUDE_DIRS}) +set_source_files_properties(HdmiCecSinkImplementation.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") + target_link_libraries(${MODULE_NAME} PUBLIC ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${IARMBUS_LIBRARIES} ${CEC_LIBRARIES} ${DS_LIBRARIES} ) +target_link_libraries(${PLUGIN_IMPLEMENTATION} PUBLIC ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${IARMBUS_LIBRARIES} ${CEC_LIBRARIES} ${DS_LIBRARIES} ) if (NOT RDK_SERVICES_L1_TEST) - target_compile_options(${MODULE_NAME} PRIVATE -Wno-error=deprecated) + target_compile_options(${PLUGIN_IMPLEMENTATION} PRIVATE -Wno-error=deprecated) endif () install(TARGETS ${MODULE_NAME} DESTINATION lib/${STORAGE_DIRECTORY}/plugins) +install(TARGETS ${PLUGIN_IMPLEMENTATION} + DESTINATION lib/${STORAGE_DIRECTORY}/plugins) + write_config(${PLUGIN_NAME}) diff --git a/HdmiCecSink/HdmiCecSink.conf.in b/HdmiCecSink/HdmiCecSink.conf.in index de8e1cdf..646c4430 100644 --- a/HdmiCecSink/HdmiCecSink.conf.in +++ b/HdmiCecSink/HdmiCecSink.conf.in @@ -2,3 +2,10 @@ precondition = ["Platform"] callsign = "org.rdk.HdmiCecSink" autostart = "false" startuporder = "@PLUGIN_HDMICECSINK_STARTUPORDER@" + +configuration = JSON() +rootobject = JSON() + +rootobject.add("mode", "@PLUGIN_HDMICECSINK_MODE@") +rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") +configuration.add("root", rootobject) \ No newline at end of file diff --git a/HdmiCecSink/HdmiCecSink.config b/HdmiCecSink/HdmiCecSink.config index 13ed0788..7257c9e8 100644 --- a/HdmiCecSink/HdmiCecSink.config +++ b/HdmiCecSink/HdmiCecSink.config @@ -5,3 +5,13 @@ set (callsign "org.rdk.HdmiCecSink") if(PLUGIN_HDMICECSINK_STARTUPORDER) set (startuporder ${PLUGIN_HDMICECSINK_STARTUPORDER}) endif() + + +map() + key(root) + map() + kv(mode ${PLUGIN_HDMICECSOURCE_MODE}) + kv(locator lib${PLUGIN_IMPLEMENTATION}.so) + end() +end() +ans(configuration) diff --git a/HdmiCecSink/HdmiCecSink.cpp b/HdmiCecSink/HdmiCecSink.cpp index 26aef24c..a7e08588 100644 --- a/HdmiCecSink/HdmiCecSink.cpp +++ b/HdmiCecSink/HdmiCecSink.cpp @@ -19,159 +19,14 @@ #include "HdmiCecSink.h" -#include "ccec/Connection.hpp" -#include "ccec/CECFrame.hpp" -#include "ccec/MessageEncoder.hpp" -#include "host.hpp" -#include "UtilsgetRFCConfig.h" - -#include "dsMgr.h" -#include "dsRpc.h" -#include "dsDisplay.h" -#include "videoOutputPort.hpp" -#include "manager.hpp" -#include "websocket/URL.h" - #include "UtilsIarm.h" #include "UtilsJsonRpc.h" #include "UtilssyncPersistFile.h" #include "UtilsSearchRDKProfile.h" -#define HDMICECSINK_METHOD_SET_ENABLED "setEnabled" -#define HDMICECSINK_METHOD_GET_ENABLED "getEnabled" -#define HDMICECSINK_METHOD_OTP_SET_ENABLED "setOTPEnabled" -#define HDMICECSINK_METHOD_OTP_GET_ENABLED "getOTPEnabled" -#define HDMICECSINK_METHOD_SET_OSD_NAME "setOSDName" -#define HDMICECSINK_METHOD_GET_OSD_NAME "getOSDName" -#define HDMICECSINK_METHOD_SET_VENDOR_ID "setVendorId" -#define HDMICECSINK_METHOD_GET_VENDOR_ID "getVendorId" -#define HDMICECSINK_METHOD_PRINT_DEVICE_LIST "printDeviceList" -#define HDMICECSINK_METHOD_SET_ACTIVE_PATH "setActivePath" -#define HDMICECSINK_METHOD_SET_ROUTING_CHANGE "setRoutingChange" -#define HDMICECSINK_METHOD_GET_DEVICE_LIST "getDeviceList" -#define HDMICECSINK_METHOD_GET_ACTIVE_SOURCE "getActiveSource" -#define HDMICECSINK_METHOD_SET_ACTIVE_SOURCE "setActiveSource" -#define HDMICECSINK_METHOD_GET_ACTIVE_ROUTE "getActiveRoute" -#define HDMICECSINK_METHOD_SET_MENU_LANGUAGE "setMenuLanguage" -#define HDMICECSINK_METHOD_REQUEST_ACTIVE_SOURCE "requestActiveSource" -#define HDMICECSINK_METHOD_SETUP_ARC "setupARCRouting" -#define HDMICECSINK_METHOD_REQUEST_SHORT_AUDIO_DESCRIPTOR "requestShortAudioDescriptor" -#define HDMICECSINK_METHOD_SEND_STANDBY_MESSAGE "sendStandbyMessage" -#define HDMICECSINK_METHOD_SEND_AUDIO_DEVICE_POWER_ON "sendAudioDevicePowerOnMessage" -#define HDMICECSINK_METHOD_SEND_KEY_PRESS "sendKeyPressEvent" -#define HDMICECSINK_METHOD_SEND_USER_CONTROL_PRESSED "sendUserControlPressed" -#define HDMICECSINK_METHOD_SEND_USER_CONTROL_RELEASED "sendUserControlReleased" -#define HDMICECSINK_METHOD_SEND_GIVE_AUDIO_STATUS "sendGetAudioStatusMessage" -#define HDMICECSINK_METHOD_GET_AUDIO_DEVICE_CONNECTED_STATUS "getAudioDeviceConnectedStatus" -#define HDMICECSINK_METHOD_REQUEST_AUDIO_DEVICE_POWER_STATUS "requestAudioDevicePowerStatus" -#define HDMICECSINK_METHOD_SET_LATENCY_INFO "setLatencyInfo" - -#define TEST_ADD 0 -#define HDMICECSINK_REQUEST_MAX_RETRY 3 -#define HDMICECSINK_REQUEST_MAX_WAIT_TIME_MS 2000 -#define HDMICECSINK_PING_INTERVAL_MS 10000 -#define HDMICECSINK_WAIT_FOR_HDMI_IN_MS 1000 -#define HDMICECSINK_REQUEST_INTERVAL_TIME_MS 500 -#define HDMICECSINK_NUMBER_TV_ADDR 2 -#define HDMICECSINK_UPDATE_POWER_STATUS_INTERVA_MS (60 * 1000) -#define HDMISINK_ARC_START_STOP_MAX_WAIT_MS 4000 -#define HDMICECSINK_UPDATE_AUDIO_STATUS_INTERVAL_MS 500 - - -#define SAD_FMT_CODE_AC3 2 -#define SAD_FMT_CODE_ENHANCED_AC3 10 - -#define SYSTEM_AUDIO_MODE_ON 0x01 -#define SYSTEM_AUDIO_MODE_OFF 0x00 -#define AUDIO_DEVICE_POWERSTATE_OFF 1 - -#define DEFAULT_VIDEO_LATENCY 100 -#define DEFAULT_LATENCY_FLAGS 3 -#define DEFAULT_AUDIO_OUTPUT_DELAY 100 - -//Device Type is TV - Bit 7 is set to 1 -#define ALL_DEVICE_TYPES 128 - -//RC Profile of TV is 3 - Typical TV Remote -#define RC_PROFILE_TV 10 - -//Device Features supported by TV - ARC Tx -#define DEVICE_FEATURES_TV 4 #define TR181_HDMICECSINK_CEC_VERSION "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.HdmiCecSink.CECVersion" -enum { - DEVICE_POWER_STATE_ON = 0, - DEVICE_POWER_STATE_OFF = 1 -}; - - -enum { - HDMICECSINK_EVENT_ACTIVE_SOURCE_CHANGE = 1, - HDMICECSINK_EVENT_WAKEUP_FROM_STANDBY, - HDMICECSINK_EVENT_TEXT_VIEW_ON_MSG, - HDMICECSINK_EVENT_IMAGE_VIEW_ON_MSG, - HDMICECSINK_EVENT_DEVICE_ADDED, - HDMICECSINK_EVENT_DEVICE_REMOVED, - HDMICECSINK_EVENT_DEVICE_INFO_UPDATED, - HDMICECSINK_EVENT_INACTIVE_SOURCE, - HDMICECSINK_EVENT_ARC_INITIATION_EVENT, - HDMICECSINK_EVENT_ARC_TERMINATION_EVENT, - HDMICECSINK_EVENT_SHORT_AUDIODESCRIPTOR_EVENT, - HDMICECSINK_EVENT_STANDBY_MSG_EVENT, - HDMICECSINK_EVENT_SYSTEM_AUDIO_MODE, - HDMICECSINK_EVENT_REPORT_AUDIO_STATUS, - HDMICECSINK_EVENT_AUDIO_DEVICE_CONNECTED_STATUS, - HDMICECSINK_EVENT_CEC_ENABLED, - HDMICECSINK_EVENT_AUDIO_DEVICE_POWER_STATUS, - HDMICECSINK_EVENT_FEATURE_ABORT_EVENT, -}; - -static const char *eventString[] = { - "None", - "onActiveSourceChange", - "onWakeupFromStandby", - "onTextViewOnMsg", - "onImageViewOnMsg", - "onDeviceAdded", - "onDeviceRemoved", - "onDeviceInfoUpdated", - "onInActiveSource", - "arcInitiationEvent", - "arcTerminationEvent", - "shortAudiodesciptorEvent", - "standbyMessageReceived", - "setSystemAudioModeEvent", - "reportAudioStatusEvent", - "reportAudioDeviceConnectedStatus", - "reportCecEnabledEvent", - "reportAudioDevicePowerStatus", - "reportFeatureAbortEvent" -}; - - -#define CEC_SETTING_ENABLED_FILE "/opt/persistent/ds/cecData_2.json" -#define CEC_SETTING_OTP_ENABLED "cecOTPEnabled" -#define CEC_SETTING_ENABLED "cecEnabled" -#define CEC_SETTING_OSD_NAME "cecOSDName" -#define CEC_SETTING_VENDOR_ID "cecVendorId" - -static std::vector defaultVendorId = {0x00,0x19,0xFB}; -static VendorID appVendorId = {defaultVendorId.at(0),defaultVendorId.at(1),defaultVendorId.at(2)}; -static VendorID lgVendorId = {0x00,0xE0,0x91}; -static PhysicalAddress physical_addr = {0x0F,0x0F,0x0F,0x0F}; -static LogicalAddress logicalAddress = 0xF; -static Language defaultLanguage = "eng"; -static OSDName osdName = "TV Box"; -static int32_t powerState = DEVICE_POWER_STATE_OFF; -static std::vector formatid = {0,0}; -static std::vector audioFormatCode = { SAD_FMT_CODE_ENHANCED_AC3,SAD_FMT_CODE_AC3 }; -static uint8_t numberofdescriptor = 2; -static int32_t HdmiArcPortID = -1; -static float cecVersion = 1.4; -static AllDeviceTypes allDevicetype = ALL_DEVICE_TYPES; -static std::vector rcProfile = {RC_PROFILE_TV}; -static std::vector deviceFeatures = {DEVICE_FEATURES_TV}; #define API_VERSION_NUMBER_MAJOR 1 #define API_VERSION_NUMBER_MINOR 3 @@ -179,7 +34,7 @@ static std::vector deviceFeatures = {DEVICE_FEATURES_TV}; namespace WPEFramework { - namespace { + namespace { static Plugin::Metadata metadata( // Version (Major, Minor, Patch) @@ -195,3365 +50,119 @@ namespace WPEFramework namespace Plugin { - SERVICE_REGISTRATION(HdmiCecSink, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - HdmiCecSink* HdmiCecSink::_instance = nullptr; - static int libcecInitStatus = 0; - -//=========================================== HdmiCecSinkFrameListener ========================================= - void HdmiCecSinkFrameListener::notify(const CECFrame &in) const { - const uint8_t *buf = NULL; - char strBuffer[512] = {0}; - size_t len = 0; - - in.getBuffer(&buf, &len); - for (unsigned int i = 0; i < len; i++) { - snprintf(strBuffer + (i*3) , sizeof(strBuffer) - (i*3), "%02X ",(uint8_t) *(buf + i)); - } - LOGINFO(" >>>>> Received CEC Frame: :%s \n",strBuffer); - - MessageDecoder(processor).decode(in); - } - -//=========================================== HdmiCecSinkProcessor ========================================= - void HdmiCecSinkProcessor::process (const ActiveSource &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: ActiveSource %s : %s : %s \n",GetOpName(msg.opCode()),msg.physicalAddress.name().c_str(),msg.physicalAddress.toString().c_str()); - if(!(header.to == LogicalAddress(LogicalAddress::BROADCAST))){ - LOGINFO("Ignore Direct messages, accepts only broadcast messages"); - return; - } - HdmiCecSink::_instance->addDevice(header.from.toInt()); - HdmiCecSink::_instance->updateActiveSource(header.from.toInt(), msg); - } - void HdmiCecSinkProcessor::process (const InActiveSource &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: InActiveSource %s : %s : %s \n",GetOpName(msg.opCode()),msg.physicalAddress.name().c_str(),msg.physicalAddress.toString().c_str()); - if(header.to.toInt() == LogicalAddress::BROADCAST){ - LOGINFO("Ignore Broadcast messages, accepts only direct messages"); - return; - } - - HdmiCecSink::_instance->updateInActiveSource(header.from.toInt(), msg); - } - - void HdmiCecSinkProcessor::process (const ImageViewOn &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: ImageViewOn from %s\n", header.from.toString().c_str()); - if(header.to.toInt() == LogicalAddress::BROADCAST){ - LOGINFO("Ignore Broadcast messages, accepts only direct messages"); - return; - } - HdmiCecSink::_instance->addDevice(header.from.toInt()); - HdmiCecSink::_instance->updateImageViewOn(header.from.toInt()); - } - void HdmiCecSinkProcessor::process (const TextViewOn &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: TextViewOn\n"); - if(header.to.toInt() == LogicalAddress::BROADCAST){ - LOGINFO("Ignore Broadcast messages, accepts only direct messages"); - return; - } - HdmiCecSink::_instance->addDevice(header.from.toInt()); - HdmiCecSink::_instance->updateTextViewOn(header.from.toInt()); - } - void HdmiCecSinkProcessor::process (const RequestActiveSource &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: RequestActiveSource\n"); - if(!(header.to == LogicalAddress(LogicalAddress::BROADCAST))){ - LOGINFO("Ignore Direct messages, accepts only broadcast messages"); - return; - } - - HdmiCecSink::_instance->setActiveSource(true); - } - void HdmiCecSinkProcessor::process (const Standby &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: Standby from %s\n", header.from.toString().c_str()); - HdmiCecSink::_instance->SendStandbyMsgEvent(header.from.toInt()); - } - void HdmiCecSinkProcessor::process (const GetCECVersion &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: GetCECVersion sending CECVersion response \n"); - if(header.to.toInt() == LogicalAddress::BROADCAST){ - LOGINFO("Ignore Broadcast messages, accepts only direct messages"); - return; - } - try - { - if(cecVersion == 2.0) { - conn.sendToAsync(header.from, MessageEncoder().encode(CECVersion(Version::V_2_0))); - } - else{ - conn.sendToAsync(header.from, MessageEncoder().encode(CECVersion(Version::V_1_4))); - } - } - catch(...) - { - LOGWARN("Exception while sending CECVersion "); - } - } - void HdmiCecSinkProcessor::process (const CECVersion &msg, const Header &header) - { - bool updateStatus; - printHeader(header); - LOGINFO("Command: CECVersion Version : %s \n",msg.version.toString().c_str()); - - HdmiCecSink::_instance->addDevice(header.from.toInt()); - updateStatus = HdmiCecSink::_instance->deviceList[header.from.toInt()].m_isVersionUpdated; - LOGINFO("updateStatus %d\n",updateStatus); - HdmiCecSink::_instance->deviceList[header.from.toInt()].update(msg.version); - if(!updateStatus) - HdmiCecSink::_instance->sendDeviceUpdateInfo(header.from.toInt()); - } - void HdmiCecSinkProcessor::process (const SetMenuLanguage &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: SetMenuLanguage Language : %s \n",msg.language.toString().c_str()); - } - void HdmiCecSinkProcessor::process (const GiveOSDName &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: GiveOSDName sending SetOSDName : %s\n",osdName.toString().c_str()); - if(header.to.toInt() == LogicalAddress::BROADCAST){ - LOGINFO("Ignore Broadcast messages, accepts only direct messages"); - return; - } - try - { - conn.sendToAsync(header.from, MessageEncoder().encode(SetOSDName(osdName))); - } - catch(...) - { - LOGWARN("Exception while sending SetOSDName"); - } - } - void HdmiCecSinkProcessor::process (const GivePhysicalAddress &msg, const Header &header) - { - LOGINFO("Command: GivePhysicalAddress\n"); - if (!(header.to == LogicalAddress(LogicalAddress::BROADCAST))) - { - try - { - LOGINFO(" sending ReportPhysicalAddress response physical_addr :%s logicalAddress :%x \n",physical_addr.toString().c_str(), logicalAddress.toInt()); - conn.sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(ReportPhysicalAddress(physical_addr,logicalAddress.toInt())), 500); - } - catch(...) - { - LOGWARN("Exception while sending ReportPhysicalAddress "); - } - } - } - void HdmiCecSinkProcessor::process (const GiveDeviceVendorID &msg, const Header &header) - { - printHeader(header); - if(header.to == LogicalAddress(LogicalAddress::BROADCAST)){ - LOGINFO("Ignore Broadcast messages, accepts only direct messages"); - return; - } - try - { - LOGINFO("Command: GiveDeviceVendorID sending VendorID response :%s\n",appVendorId.toString().c_str()); - conn.sendToAsync(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(appVendorId))); - } - catch(...) - { - LOGWARN("Exception while sending DeviceVendorID"); - } - - } - void HdmiCecSinkProcessor::process (const SetOSDString &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: SetOSDString OSDString : %s\n",msg.osdString.toString().c_str()); - } - void HdmiCecSinkProcessor::process (const SetOSDName &msg, const Header &header) - { - printHeader(header); - bool updateStatus ; - LOGINFO("Command: SetOSDName OSDName : %s\n",msg.osdName.toString().c_str()); - if(header.to.toInt() == LogicalAddress::BROADCAST){ - LOGINFO("Ignore Broadcast messages, accepts only direct messages"); - return; - } - - HdmiCecSink::_instance->addDevice(header.from.toInt()); - updateStatus = HdmiCecSink::_instance->deviceList[header.from.toInt()].m_isOSDNameUpdated; - LOGINFO("updateStatus %d\n",updateStatus); - HdmiCecSink::_instance->deviceList[header.from.toInt()].update(msg.osdName); - if(HdmiCecSink::_instance->deviceList[header.from.toInt()].m_isRequestRetry > 0 && - HdmiCecSink::_instance->deviceList[header.from.toInt()].m_isRequested == CECDeviceParams::REQUEST_OSD_NAME) { - HdmiCecSink::_instance->deviceList[header.from.toInt()].m_isRequestRetry = 0; - } - if(!updateStatus) - HdmiCecSink::_instance->sendDeviceUpdateInfo(header.from.toInt()); - } - void HdmiCecSinkProcessor::process (const RoutingChange &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: RoutingChange From : %s To: %s \n",msg.from.toString().c_str(),msg.to.toString().c_str()); - } - void HdmiCecSinkProcessor::process (const RoutingInformation &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: RoutingInformation Routing Information to Sink : %s\n",msg.toSink.toString().c_str()); - } - void HdmiCecSinkProcessor::process (const SetStreamPath &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: SetStreamPath Set Stream Path to Sink : %s\n",msg.toSink.toString().c_str()); - } - void HdmiCecSinkProcessor::process (const GetMenuLanguage &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: GetMenuLanguage\n"); - if(header.to.toInt() == LogicalAddress::BROADCAST){ - LOGINFO("Ignore Broadcast messages, accepts only direct messages"); - return; - } - HdmiCecSink::_instance->sendMenuLanguage(); - } - void HdmiCecSinkProcessor::process (const ReportPhysicalAddress &msg, const Header &header) - { - printHeader(header); - bool updateDeviceTypeStatus; - bool updatePAStatus; - LOGINFO("Command: ReportPhysicalAddress\n"); - if(!(header.to == LogicalAddress(LogicalAddress::BROADCAST))){ - LOGINFO("Ignore Direct messages, accepts only broadcast messages"); - return; - } - - if(!HdmiCecSink::_instance) - return; - HdmiCecSink::_instance->addDevice(header.from.toInt()); - updateDeviceTypeStatus = HdmiCecSink::_instance->deviceList[header.from.toInt()].m_isDeviceTypeUpdated; - updatePAStatus = HdmiCecSink::_instance->deviceList[header.from.toInt()].m_isPAUpdated; - LOGINFO("updateDeviceTypeStatus %d updatePAStatus %d \n",updateDeviceTypeStatus,updatePAStatus); - if(HdmiCecSink::_instance->deviceList[header.from.toInt()].m_physicalAddr.toString() != msg.physicalAddress.toString() && updatePAStatus){ - updatePAStatus= false; - LOGINFO("There is a change in physical address from current PA %s to newly reported PA %s\n",HdmiCecSink::_instance->deviceList[header.from.toInt()].m_physicalAddr.toString().c_str(),msg.physicalAddress.toString().c_str()); - } - HdmiCecSink::_instance->deviceList[header.from.toInt()].update(msg.physicalAddress); - HdmiCecSink::_instance->deviceList[header.from.toInt()].update(msg.deviceType); - if(HdmiCecSink::_instance->deviceList[header.from.toInt()].m_isRequestRetry > 0 && - HdmiCecSink::_instance->deviceList[header.from.toInt()].m_isRequested == CECDeviceParams::REQUEST_PHISICAL_ADDRESS) { - HdmiCecSink::_instance->deviceList[header.from.toInt()].m_isRequestRetry = 0; - } - HdmiCecSink::_instance->updateDeviceChain(header.from, msg.physicalAddress); - if (!updateDeviceTypeStatus || !updatePAStatus) - HdmiCecSink::_instance->sendDeviceUpdateInfo(header.from.toInt()); - } - void HdmiCecSinkProcessor::process (const DeviceVendorID &msg, const Header &header) - { - bool updateStatus ; - printHeader(header); - LOGINFO("Command: DeviceVendorID VendorID : %s\n",msg.vendorId.toString().c_str()); - if(!(header.to == LogicalAddress(LogicalAddress::BROADCAST))){ - LOGINFO("Ignore Direct messages, accepts only broadcast messages"); - return; - } - - HdmiCecSink::_instance->addDevice(header.from.toInt()); - updateStatus = HdmiCecSink::_instance->deviceList[header.from.toInt()].m_isVendorIDUpdated; - LOGINFO("updateStatus %d\n",updateStatus); - HdmiCecSink::_instance->deviceList[header.from.toInt()].update(msg.vendorId); - if (!updateStatus) - HdmiCecSink::_instance->sendDeviceUpdateInfo(header.from.toInt()); - } - void HdmiCecSinkProcessor::process (const GiveDevicePowerStatus &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: GiveDevicePowerStatus sending powerState :%d \n",powerState); - if(header.to.toInt() == LogicalAddress::BROADCAST){ - LOGINFO("Ignore Broadcast messages, accepts only direct messages"); - return; - } - try - { - conn.sendTo(header.from, MessageEncoder().encode(ReportPowerStatus(PowerStatus(powerState)))); - } - catch(...) - { - LOGWARN("Exception while sending ReportPowerStatus"); - } - } - void HdmiCecSinkProcessor::process (const ReportPowerStatus &msg, const Header &header) - { - uint32_t oldPowerStatus,newPowerStatus; - printHeader(header); - LOGINFO("Command: ReportPowerStatus Power Status from:%s status : %s \n",header.from.toString().c_str(),msg.status.toString().c_str()); - if(header.to.toInt() == LogicalAddress::BROADCAST){ - LOGINFO("Ignore Broadcast messages, accepts only direct messages"); - return; - } - oldPowerStatus = HdmiCecSink::_instance->deviceList[header.from.toInt()].m_powerStatus.toInt(); - HdmiCecSink::_instance->addDevice(header.from.toInt()); - HdmiCecSink::_instance->deviceList[header.from.toInt()].update(msg.status); - newPowerStatus = HdmiCecSink::_instance->deviceList[header.from.toInt()].m_powerStatus.toInt(); - LOGINFO(" oldPowerStatus %d newpower status %d \n",oldPowerStatus,newPowerStatus); - if ((oldPowerStatus != newPowerStatus) ) - { - HdmiCecSink::_instance->sendDeviceUpdateInfo(header.from.toInt()); - } - - if((header.from.toInt() == LogicalAddress::AUDIO_SYSTEM) && (HdmiCecSink::_instance->m_audioDevicePowerStatusRequested)) { - HdmiCecSink::_instance->reportAudioDevicePowerStatusInfo(header.from.toInt(), newPowerStatus); - } - - } - void HdmiCecSinkProcessor::process (const FeatureAbort &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: FeatureAbort opcode=%s, Reason = %s\n", msg.feature.toString().c_str(), msg.reason.toString().c_str()); - if(header.to.toInt() == LogicalAddress::BROADCAST){ - LOGINFO("Ignore Broadcast messages, accepts only direct messages"); - return; - } - - if(header.from.toInt() < LogicalAddress::UNREGISTERED && - msg.reason.toInt() == AbortReason::UNRECOGNIZED_OPCODE) - { - switch(msg.feature.opCode()) - { - case GET_CEC_VERSION : - { - /* If we get a Feature abort for CEC Version then default to 1.4b */ - HdmiCecSink::_instance->deviceList[header.from.toInt()].update(Version(Version::V_1_4)); - } - break; - case GIVE_DEVICE_VENDOR_ID : - { - /* If we get a Feature abort for CEC Version then default to 1.4b */ - HdmiCecSink::_instance->deviceList[header.from.toInt()].update(VendorID((uint8_t *)"FA", 2)); - } - break; - - case GIVE_OSD_NAME : - { - HdmiCecSink::_instance->deviceList[header.from.toInt()].update(OSDName("")); - } - break; - - case GIVE_DEVICE_POWER_STATUS : - { - HdmiCecSink::_instance->deviceList[header.from.toInt()].update(PowerStatus(PowerStatus::POWER_STATUS_FEATURE_ABORT)); - } - break; - } - - HdmiCecSink::_instance->deviceList[header.from.toInt()].m_featureAborts.push_back(msg); - } - - LogicalAddress logicaladdress = header.from.toInt(); - OpCode featureOpcode = msg.feature; - AbortReason abortReason = msg.reason; - - HdmiCecSink::_instance->reportFeatureAbortEvent(logicaladdress,featureOpcode,abortReason); - - if(msg.feature.opCode() == REQUEST_SHORT_AUDIO_DESCRIPTOR) - { - JsonArray audiodescriptor; - audiodescriptor.Add(0); - HdmiCecSink::_instance->Send_ShortAudioDescriptor_Event(audiodescriptor); - } - - } - void HdmiCecSinkProcessor::process (const Abort &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: Abort\n"); - if (!(header.to == LogicalAddress(LogicalAddress::BROADCAST))) - { - AbortReason reason = AbortReason::UNRECOGNIZED_OPCODE; - LogicalAddress logicaladdress =header.from.toInt(); - OpCode feature = msg.opCode(); - HdmiCecSink::_instance->sendFeatureAbort(logicaladdress, feature,reason); - } - else - { - LOGINFO("Command: Abort broadcast msg so ignore\n"); - } - } - void HdmiCecSinkProcessor::process (const Polling &msg, const Header &header) { - printHeader(header); - LOGINFO("Command: Polling\n"); - } - - void HdmiCecSinkProcessor::process (const InitiateArc &msg, const Header &header) - { - printHeader(header); - if((!(header.from.toInt() == 0x5)) || (header.to.toInt() == LogicalAddress::BROADCAST)){ - LOGINFO("Ignoring the message coming from addresses other than 0X5 or a braodcast message"); - return; - } - PhysicalAddress physical_addr_invalid = {0x0F,0x0F,0x0F,0x0F}; - PhysicalAddress physical_addr_arc_port = {0x0F,0x0F,0x0F,0x0F}; - - LOGINFO("Command: INITIATE_ARC \n"); - if(!HdmiCecSink::_instance || HdmiArcPortID == -1) - return; - - if (HdmiArcPortID == 0 ) - physical_addr_arc_port = {0x01,0x00,0x00,0x00}; - if (HdmiArcPortID == 1 ) - physical_addr_arc_port = {0x02,0x00,0x00,0x00}; - if (HdmiArcPortID == 2 ) - physical_addr_arc_port = {0x03,0x00,0x00,0x00}; - - if( (HdmiCecSink::_instance->deviceList[0x5].m_physicalAddr.toString() == physical_addr_arc_port.toString()) || (HdmiCecSink::_instance->deviceList[0x5].m_physicalAddr.toString() == physical_addr_invalid.toString()) ) { - LOGINFO("Command: INITIATE_ARC InitiateArc success %s \n",HdmiCecSink::_instance->deviceList[0x5].m_physicalAddr.toString().c_str()); - HdmiCecSink::_instance->Process_InitiateArc(); - } else { - LOGINFO("Command: INITIATE_ARC InitiateArc ignore %s \n",HdmiCecSink::_instance->deviceList[0x5].m_physicalAddr.toString().c_str()); - } - } - void HdmiCecSinkProcessor::process (const TerminateArc &msg, const Header &header) - { - printHeader(header); - if((!(header.from.toInt() == 0x5)) || (header.to.toInt() == LogicalAddress::BROADCAST)){ - LOGINFO("Ignoring the message coming from addresses other than 0X5 or a braodcast message"); - return; - } - if(!HdmiCecSink::_instance) - return; - HdmiCecSink::_instance->Process_TerminateArc(); - } - void HdmiCecSinkProcessor::process (const ReportShortAudioDescriptor &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: ReportShortAudioDescriptor %s : %d \n",GetOpName(msg.opCode()),numberofdescriptor); - HdmiCecSink::_instance->Process_ShortAudioDescriptor_msg(msg); - } - - void HdmiCecSinkProcessor::process (const SetSystemAudioMode &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: SetSystemAudioMode %s audio status %d audio status is %s \n",GetOpName(msg.opCode()),msg.status.toInt(),msg.status.toString().c_str()); - HdmiCecSink::_instance->Process_SetSystemAudioMode_msg(msg); - } - void HdmiCecSinkProcessor::process (const ReportAudioStatus &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: ReportAudioStatus %s audio Mute status %d means %s and current Volume level is %d \n",GetOpName(msg.opCode()),msg.status.getAudioMuteStatus(),msg.status.toString().c_str(),msg.status.getAudioVolume()); - if(header.to.toInt() == LogicalAddress::BROADCAST){ - LOGINFO("Ignore Broadcast messages, accepts only direct messages"); - return; - } - HdmiCecSink::_instance->Process_ReportAudioStatus_msg(msg); - } - void HdmiCecSinkProcessor::process (const GiveFeatures &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: GiveFeatures \n"); - try - { - if(cecVersion == 2.0) { - conn.sendToAsync(LogicalAddress(LogicalAddress::BROADCAST),MessageEncoder().encode(ReportFeatures(Version::V_2_0,allDevicetype,rcProfile,deviceFeatures))); - } - } - catch(...) - { - LOGWARN("Exception while sending ReportFeatures"); - } - } - void HdmiCecSinkProcessor::process (const RequestCurrentLatency &msg, const Header &header) - { - printHeader(header); - LOGINFO("Command: Request Current Latency :%s, physical address: %s",GetOpName(msg.opCode()),msg.physicaladdress.toString().c_str()); - - if(msg.physicaladdress.toString() == physical_addr.toString()) { - HdmiCecSink::_instance->setLatencyInfo(); - } - else { - LOGINFO("Physical Address does not match with TV's physical address"); - return; - } - } -//=========================================== HdmiCecSink ========================================= - - HdmiCecSink::HdmiCecSink() - : PluginHost::JSONRPC() - , _pwrMgrNotification(*this) - , _registeredEventHandlers(false) - { - LOGWARN("Initlaizing HdmiCecSink"); - } + SERVICE_REGISTRATION(HdmiCecSink, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - HdmiCecSink::~HdmiCecSink() - { - } const std::string HdmiCecSink::Initialize(PluginHost::IShell *service) { - InitializePowerManager(service); - profileType = searchRdkProfile(); - - if (profileType == STB || profileType == NOT_FOUND) - { - LOGINFO("Invalid profile type for TV \n"); - return (std::string("Not supported")); - } - - HdmiCecSink::_instance = this; - smConnection=NULL; - cecEnableStatus = false; - HdmiCecSink::_instance->m_numberOfDevices = 0; - m_logicalAddressAllocated = LogicalAddress::UNREGISTERED; - m_currentActiveSource = -1; - m_isHdmiInConnected = false; - hdmiCecAudioDeviceConnected = false; - m_isAudioStatusInfoUpdated = false; - m_audioStatusReceived = false; - m_audioStatusTimerStarted = false; - m_audioDevicePowerStatusRequested = false; - m_pollNextState = POLL_THREAD_STATE_NONE; - m_pollThreadState = POLL_THREAD_STATE_NONE; - m_video_latency = DEFAULT_VIDEO_LATENCY; - m_latency_flags = DEFAULT_LATENCY_FLAGS ; - m_audio_output_delay = DEFAULT_AUDIO_OUTPUT_DELAY; - - Register(HDMICECSINK_METHOD_SET_ENABLED, &HdmiCecSink::setEnabledWrapper, this); - Register(HDMICECSINK_METHOD_GET_ENABLED, &HdmiCecSink::getEnabledWrapper, this); - Register(HDMICECSINK_METHOD_SET_OSD_NAME, &HdmiCecSink::setOSDNameWrapper, this); - Register(HDMICECSINK_METHOD_GET_OSD_NAME, &HdmiCecSink::getOSDNameWrapper, this); - Register(HDMICECSINK_METHOD_SET_VENDOR_ID, &HdmiCecSink::setVendorIdWrapper, this); - Register(HDMICECSINK_METHOD_GET_VENDOR_ID, &HdmiCecSink::getVendorIdWrapper, this); - Register(HDMICECSINK_METHOD_PRINT_DEVICE_LIST, &HdmiCecSink::printDeviceListWrapper, this); - Register(HDMICECSINK_METHOD_SET_ACTIVE_PATH, &HdmiCecSink::setActivePathWrapper, this); - Register(HDMICECSINK_METHOD_SET_ROUTING_CHANGE, &HdmiCecSink::setRoutingChangeWrapper, this); - Register(HDMICECSINK_METHOD_GET_DEVICE_LIST, &HdmiCecSink::getDeviceListWrapper, this); - Register(HDMICECSINK_METHOD_GET_ACTIVE_SOURCE, &HdmiCecSink::getActiveSourceWrapper, this); - Register(HDMICECSINK_METHOD_SET_ACTIVE_SOURCE, &HdmiCecSink::setActiveSourceWrapper, this); - Register(HDMICECSINK_METHOD_GET_ACTIVE_ROUTE, &HdmiCecSink::getActiveRouteWrapper, this); - Register(HDMICECSINK_METHOD_REQUEST_ACTIVE_SOURCE, &HdmiCecSink::requestActiveSourceWrapper, this); - Register(HDMICECSINK_METHOD_SETUP_ARC, &HdmiCecSink::setArcEnableDisableWrapper, this); - Register(HDMICECSINK_METHOD_SET_MENU_LANGUAGE, &HdmiCecSink::setMenuLanguageWrapper, this); - Register(HDMICECSINK_METHOD_REQUEST_SHORT_AUDIO_DESCRIPTOR, &HdmiCecSink::requestShortAudioDescriptorWrapper, this); - Register(HDMICECSINK_METHOD_SEND_STANDBY_MESSAGE, &HdmiCecSink::sendStandbyMessageWrapper, this); - Register(HDMICECSINK_METHOD_SEND_AUDIO_DEVICE_POWER_ON, &HdmiCecSink::sendAudioDevicePowerOnMsgWrapper, this); - Register(HDMICECSINK_METHOD_SEND_KEY_PRESS,&HdmiCecSink::sendRemoteKeyPressWrapper,this); - Register(HDMICECSINK_METHOD_SEND_USER_CONTROL_PRESSED,&HdmiCecSink::sendUserControlPressedWrapper,this); - Register(HDMICECSINK_METHOD_SEND_USER_CONTROL_RELEASED,&HdmiCecSink::sendUserControlReleasedWrapper,this); - Register(HDMICECSINK_METHOD_SEND_GIVE_AUDIO_STATUS,&HdmiCecSink::sendGiveAudioStatusWrapper,this); - Register(HDMICECSINK_METHOD_GET_AUDIO_DEVICE_CONNECTED_STATUS,&HdmiCecSink::getAudioDeviceConnectedStatusWrapper,this); - Register(HDMICECSINK_METHOD_REQUEST_AUDIO_DEVICE_POWER_STATUS,&HdmiCecSink::requestAudioDevicePowerStatusWrapper,this); - Register(HDMICECSINK_METHOD_SET_LATENCY_INFO, &HdmiCecSink::setLatencyInfoWrapper, this); - logicalAddressDeviceType = "None"; - logicalAddress = 0xFF; - // load persistence setting - loadSettings(); - - int err; - dsHdmiInGetNumberOfInputsParam_t hdmiInput; - InitializeIARM(); - m_sendKeyEventThreadExit = false; - m_sendKeyEventThread = std::thread(threadSendKeyEvent); - - m_currentArcRoutingState = ARC_STATE_ARC_TERMINATED; - m_semSignaltoArcRoutingThread.acquire(); - m_arcRoutingThread = std::thread(threadArcRouting); - - m_audioStatusDetectionTimer.connect( std::bind( &HdmiCecSink::audioStatusTimerFunction, this ) ); - m_audioStatusDetectionTimer.setSingleShot(true); - m_arcStartStopTimer.connect( std::bind( &HdmiCecSink::arcStartStopTimerFunction, this ) ); - m_arcStartStopTimer.setSingleShot(true); - // get power state: - Core::hresult res = Core::ERROR_GENERAL; - PowerState pwrStateCur = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; - PowerState pwrStatePrev = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; - - ASSERT (_powerManagerPlugin); - if (_powerManagerPlugin) { - res = _powerManagerPlugin->GetPowerState(pwrStateCur, pwrStatePrev); - if (Core::ERROR_NONE == res) { - powerState = (pwrStateCur == WPEFramework::Exchange::IPowerManager::POWER_STATE_ON) ? DEVICE_POWER_STATE_ON : DEVICE_POWER_STATE_OFF; - LOGINFO("Current state is PowerManagerPlugin: (%d) powerState :%d \n", pwrStateCur, powerState); - } - } - - err = IARM_Bus_Call(IARM_BUS_DSMGR_NAME, - IARM_BUS_DSMGR_API_dsHdmiInGetNumberOfInputs, - (void *)&hdmiInput, - sizeof(hdmiInput)); + profileType = searchRdkProfile(); - if (err == IARM_RESULT_SUCCESS && hdmiInput.result == dsERR_NONE) + if (profileType == STB || profileType == NOT_FOUND) { - LOGINFO("Number of Inputs [%d] \n", hdmiInput.numHdmiInputs ); - m_numofHdmiInput = hdmiInput.numHdmiInputs; - }else{ - LOGINFO("Not able to get Numebr of inputs so defaulting to 3 \n"); - m_numofHdmiInput = 3; - } - - LOGINFO("initalize inputs \n"); - - for (int i = 0; i < m_numofHdmiInput; i++){ - HdmiPortMap hdmiPort((uint8_t)i); - LOGINFO(" Add to vector [%d] \n", i); - hdmiInputs.push_back(hdmiPort); - } - - LOGINFO("Check the HDMI State \n"); - - CheckHdmiInState(); - if (cecSettingEnabled) - { - try - { - CECEnable(); - } - catch(...) - { - LOGWARN("Exception while enabling CEC settings .\r\n"); - } - } - getCecVersion(); - LOGINFO(" HdmiCecSink plugin Initialize completed \n"); - return (std::string()); - - } - - void HdmiCecSink::Deinitialize(PluginHost::IShell* /* service */) - { - if(_powerManagerPlugin) - { - _powerManagerPlugin->Unregister(_pwrMgrNotification.baseInterface()); - _powerManagerPlugin.Reset(); - } - _registeredEventHandlers = false; - - profileType = searchRdkProfile(); - - if (profileType == STB || profileType == NOT_FOUND) - { - LOGINFO("Invalid profile type for TV \n"); - return ; - } - - CECDisable(); - m_currentArcRoutingState = ARC_STATE_ARC_EXIT; - - m_semSignaltoArcRoutingThread.release(); - - try - { - if (m_arcRoutingThread.joinable()) - m_arcRoutingThread.join(); - } - catch(const std::system_error& e) - { - LOGERR("system_error exception in thread join %s", e.what()); - } - catch(const std::exception& e) - { - LOGERR("exception in thread join %s", e.what()); - } - - { - m_sendKeyEventThreadExit = true; - std::unique_lock lk(m_sendKeyEventMutex); - m_sendKeyEventThreadRun = true; - m_sendKeyCV.notify_one(); - } - - try - { - if (m_sendKeyEventThread.joinable()) - m_sendKeyEventThread.join(); - } - catch(const std::system_error& e) - { - LOGERR("system_error exception in thread join %s", e.what()); - } - catch(const std::exception& e) - { - LOGERR("exception in thread join %s", e.what()); - } - - HdmiCecSink::_instance = nullptr; - DeinitializeIARM(); - LOGWARN(" HdmiCecSink Deinitialize() Done"); - } - - const void HdmiCecSink::InitializeIARM() - { - if (Utils::IARM::init()) - { - IARM_Result_t res; - IARM_CHECK( IARM_Bus_RegisterEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDMI_IN_HOTPLUG, dsHdmiEventHandler) ); + LOGINFO("Invalid profile type for TV \n"); + return (std::string("Not supported")); } - } - - void HdmiCecSink::DeinitializeIARM() - { - if (Utils::IARM::isConnected()) - { - IARM_Result_t res; - IARM_CHECK( IARM_Bus_RemoveEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDMI_IN_HOTPLUG, dsHdmiEventHandler) ); - } - } - - void HdmiCecSink::InitializePowerManager(PluginHost::IShell *service) - { - _powerManagerPlugin = PowerManagerInterfaceBuilder(_T("org.rdk.PowerManager")) - .withIShell(service) - .withRetryIntervalMS(200) - .withRetryCount(25) - .createInterface(); - registerEventHandlers(); - } - void HdmiCecSink::registerEventHandlers() - { - ASSERT (_powerManagerPlugin); - if(!_registeredEventHandlers && _powerManagerPlugin) { - _registeredEventHandlers = true; - _powerManagerPlugin->Register(_pwrMgrNotification.baseInterface()); - } - } + string msg = ""; - void HdmiCecSink::dsHdmiEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len) - { - if(!HdmiCecSink::_instance) - return; + ASSERT(nullptr != service); + ASSERT(nullptr == _service); + ASSERT(nullptr == _hdmiCecSink); + ASSERT(0 == _connectionId); - if (IARM_BUS_DSMGR_EVENT_HDMI_IN_HOTPLUG == eventId) - { - IARM_Bus_DSMgr_EventData_t *eventData = (IARM_Bus_DSMgr_EventData_t *)data; - bool isHdmiConnected = eventData->data.hdmi_in_connect.isPortConnected; - dsHdmiInPort_t portId = eventData->data.hdmi_in_connect.port; - LOGINFO("Received IARM_BUS_DSMGR_EVENT_HDMI_IN_HOTPLUG event port: %d data:%d \r\n",portId, isHdmiConnected); - HdmiCecSink::_instance->onHdmiHotPlug(portId,isHdmiConnected); - } - } - void HdmiCecSink::onPowerModeChanged(const PowerState currentState, const PowerState newState) - { - if(!HdmiCecSink::_instance) - return; + _service = service; + _service->AddRef(); + _service->Register(&_notification); + _hdmiCecSink = _service->Root(_connectionId, 5000, _T("HdmiCecSinkImplementation")); - LOGINFO("Event IARM_BUS_PWRMGR_EVENT_MODECHANGED: State Changed %d -- > %d\r", - currentState, newState); - LOGWARN(" m_logicalAddressAllocated 0x%x CEC enable status %d \n",_instance->m_logicalAddressAllocated,_instance->cecEnableStatus); - if(newState == WPEFramework::Exchange::IPowerManager::POWER_STATE_ON) + if(nullptr != _hdmiCecSink) { - powerState = DEVICE_POWER_STATE_ON; + _hdmiCecSink->Configure(service); + _hdmiCecSink->Register(&_notification); + Exchange::JHdmiCecSink::Register(*this, _hdmiCecSink); + LOGINFO("HdmiCecSink plugin is available. Successfully activated HdmiCecSink Plugin"); } else { - powerState = DEVICE_POWER_STATE_OFF; - if((_instance->m_currentArcRoutingState == ARC_STATE_REQUEST_ARC_INITIATION) || (_instance->m_currentArcRoutingState == ARC_STATE_ARC_INITIATED)) - { - LOGINFO("%s: Stop ARC \n",__FUNCTION__); - _instance->stopArc(); + msg = "HdmiCecSink plugin is not available"; + LOGINFO("HdmiCecSink plugin is not available. Failed to activate HdmiCecSink Plugin"); } - } - if (_instance->cecEnableStatus) - { - if ( _instance->m_logicalAddressAllocated != LogicalAddress::UNREGISTERED ) - { - _instance->deviceList[_instance->m_logicalAddressAllocated].m_powerStatus = PowerStatus(powerState); - - if ( powerState != DEVICE_POWER_STATE_ON ) - { - /* reset the current active source when TV on going to standby */ - HdmiCecSink::_instance->m_currentActiveSource = -1; - } - /* Initiate a ping straight away */ - HdmiCecSink::_instance->m_pollNextState = POLL_THREAD_STATE_PING; - HdmiCecSink::_instance->m_ThreadExitCV.notify_one(); - } - } - else + if (0 != msg.length()) { - LOGWARN("CEC not Enabled\n"); + Deinitialize(service); } - } - - - void HdmiCecSink::sendStandbyMessage() - { - if(!HdmiCecSink::_instance) - return; - if(!(HdmiCecSink::_instance->smConnection)) - return; - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED){ - LOGERR("Logical Address NOT Allocated Or its not valid"); - return; - } - - _instance->smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(Standby()), 1000); - } - - void HdmiCecSink::onHdmiHotPlug(int portId , int connectStatus) - { - LOGINFO("onHdmiHotPlug Status : %d ", connectStatus); - if(!connectStatus) - { - LOGINFO(" removeDevice port: %d Logical address :%d \r\n",portId,hdmiInputs[portId].m_logicalAddr.toInt() ); - _instance->removeDevice(hdmiInputs[portId].m_logicalAddr.toInt()); - } - CheckHdmiInState(); - if(cecEnableStatus) { - LOGINFO("cecEnableStatus : %d Trigger CEC Ping !!! \n", cecEnableStatus); - m_pollNextState = POLL_THREAD_STATE_PING; - m_ThreadExitCV.notify_one(); - } - if( HdmiArcPortID >= 0 ) { - updateArcState(); - } - return; - } - void HdmiCecSink::updateArcState() - { - if ( m_currentArcRoutingState != ARC_STATE_ARC_TERMINATED ) - { - if (!(hdmiInputs[HdmiArcPortID].m_isConnected)) - { - std::lock_guard lock(_instance->m_arcRoutingStateMutex); - m_currentArcRoutingState = ARC_STATE_ARC_TERMINATED; - } - else - { - LOGINFO("updateArcState :not updating ARC state current arc state %d ",m_currentArcRoutingState); - } - } - } - void HdmiCecSink::arcStartStopTimerFunction() - { - JsonObject params; - - if (m_arcstarting) - { - LOGINFO("arcStartStopTimerFunction ARC start timer expired"); - LOGINFO("notify_device setting that Initiate ARC failed to get the ARC_STATE_ARC_INITIATED state\n"); - params["status"] = string("failure"); - sendNotify(eventString[HDMICECSINK_EVENT_ARC_INITIATION_EVENT], params); - } - else - { - LOGINFO("arcStartStopTimerFunction ARC stop timer expired"); - LOGINFO("notify_device setting that Terminate ARC failed to get the ARC_STATE_ARC_TERMINATED state\n"); - params["status"] = string("failure"); - sendNotify(eventString[HDMICECSINK_EVENT_ARC_TERMINATION_EVENT], params); - - - } - /* bring the state machine to the clean state for a new start */ - std::lock_guard lock(_instance->m_arcRoutingStateMutex); - m_currentArcRoutingState = ARC_STATE_ARC_TERMINATED; - } - void HdmiCecSink::Send_ShortAudioDescriptor_Event(JsonArray audiodescriptor) - { - JsonObject params; + // On success return empty, to indicate there is no error text. + return msg; + } - LOGINFO("Notify the DS "); - params["ShortAudioDescriptor"]= JsonValue(audiodescriptor); - sendNotify(eventString[HDMICECSINK_EVENT_SHORT_AUDIODESCRIPTOR_EVENT], params); - } - void HdmiCecSink::Process_ShortAudioDescriptor_msg(const ReportShortAudioDescriptor &msg) + void HdmiCecSink::Deinitialize(PluginHost::IShell* /* service */) { - uint8_t numberofdescriptor = msg.numberofdescriptor; - uint32_t descriptor =0; - JsonArray audiodescriptor; - - if (numberofdescriptor) - { - for( uint8_t i=0; i < numberofdescriptor; i++) - { - descriptor = msg.shortAudioDescriptor[i].getAudiodescriptor(); - - LOGINFO("descriptor%d 0x%x\n",i,descriptor); - audiodescriptor.Add(descriptor); - - } - } - else - { - audiodescriptor.Add(descriptor); - } - HdmiCecSink::_instance->Send_ShortAudioDescriptor_Event(audiodescriptor); - } + + profileType = searchRdkProfile(); - void HdmiCecSink::updateCurrentLatency(int videoLatency, bool lowLatencyMode,int audioOutputCompensated, int audioOutputDelay = 0) + if (profileType == STB || profileType == NOT_FOUND) { - uint8_t latencyFlags = 0; - latencyFlags = ((lowLatencyMode & 0x1) << 2) | (audioOutputCompensated & 0x3); - LOGINFO("Video Latency : %d , Low Latency Mode : %d ,Audio Output Compensated value : %d , Audio Output Delay : %d , Latency Flags: %d ", videoLatency, lowLatencyMode, audioOutputCompensated, audioOutputDelay, latencyFlags); - m_video_latency = (videoLatency/2) + 1; - m_latency_flags = latencyFlags; - m_audio_output_delay = (audioOutputDelay/2) + 1; - setLatencyInfo(); + LOGINFO("Invalid profile type for TV \n"); + return ; } - void HdmiCecSink::setLatencyInfo() - { - if(!HdmiCecSink::_instance) - return; - - if(!(_instance->smConnection)) - return; - - LOGINFO("Send Report Current Latency message \n"); - _instance->smConnection->sendTo(LogicalAddress::BROADCAST,MessageEncoder().encode(ReportCurrentLatency(physical_addr,m_video_latency,m_latency_flags,m_audio_output_delay))); - - } - - void HdmiCecSink::Process_SetSystemAudioMode_msg(const SetSystemAudioMode &msg) - { - JsonObject params; - if(!HdmiCecSink::_instance) - return; - - //DD: Check cecSettingEnabled to prevent race conditions which gives immediate UI setting status - //SetSystemAudioMode message may come from AVR/Soundbar while CEC disable is in-progress - if ( cecSettingEnabled != true ) - { - LOGINFO("Process SetSystemAudioMode from Audio device: Cec is disabled-> EnableCEC first"); - return; - } - - if ( (msg.status.toInt() == SYSTEM_AUDIO_MODE_OFF) && (m_currentArcRoutingState == ARC_STATE_ARC_INITIATED)) - { - /* ie system audio mode off -> amplifier goign to standby but still ARC is in initiated state,stop ARC and - bring the ARC state machine to terminated state*/ - LOGINFO("system audio mode off message but arc is not in terminated state so stopping ARC"); - stopArc(); - - } - - params["audioMode"] = msg.status.toString().c_str(); - if (msg.status.toInt() == SYSTEM_AUDIO_MODE_ON) { - LOGINFO("panel power state is %s", powerState ? "Off" : "On"); - if (powerState == DEVICE_POWER_STATE_ON ) { - LOGINFO("Notifying system audio mode ON event"); - sendNotify(eventString[HDMICECSINK_EVENT_SYSTEM_AUDIO_MODE], params); - } else { - LOGINFO("Not notifying system audio mode ON event"); - } - } else { - LOGINFO("Notifying system audio Mode OFF event"); - sendNotify(eventString[HDMICECSINK_EVENT_SYSTEM_AUDIO_MODE], params); - } - } - void HdmiCecSink::Process_ReportAudioStatus_msg(const ReportAudioStatus msg) - { - JsonObject params; - if(!HdmiCecSink::_instance) - return; - if (m_audioStatusTimerStarted) - { - m_audioStatusReceived = true; - m_isAudioStatusInfoUpdated = true; - m_audioStatusTimerStarted = false; - if (m_audioStatusDetectionTimer.isActive()) - { - LOGINFO("AudioStatus received from the Audio Device and the timer is still active. So stopping the timer!\n"); - m_audioStatusDetectionTimer.stop(); - } - LOGINFO("AudioStatus received from the Audio Device. Updating the AudioStatus info! m_isAudioStatusInfoUpdated :%d, m_audioStatusReceived :%d, m_audioStatusTimerStarted:%d ", m_isAudioStatusInfoUpdated,m_audioStatusReceived,m_audioStatusTimerStarted); - } - LOGINFO("Command: ReportAudioStatus %s audio Mute status %d means %s and current Volume level is %d \n",GetOpName(msg.opCode()),msg.status.getAudioMuteStatus(),msg.status.toString().c_str(),msg.status.getAudioVolume()); - params["muteStatus"] = msg.status.getAudioMuteStatus(); - params["volumeLevel"] = msg.status.getAudioVolume(); - sendNotify(eventString[HDMICECSINK_EVENT_REPORT_AUDIO_STATUS], params); - - } - void HdmiCecSink::sendKeyPressEvent(const int logicalAddress, int keyCode) - { - if(!(_instance->smConnection)) - return; - LOGINFO(" sendKeyPressEvent logicalAddress 0x%x keycode 0x%x\n",logicalAddress,keyCode); - switch(keyCode) - { - case VOLUME_UP: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_VOLUME_UP)),100); - break; - case VOLUME_DOWN: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_VOLUME_DOWN)), 100); - break; - case MUTE: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_MUTE)), 100); - break; - case UP: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_UP)), 100); - break; - case DOWN: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_DOWN)), 100); - break; - case LEFT: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_LEFT)), 100); - break; - case RIGHT: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_RIGHT)), 100); - break; - case SELECT: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_SELECT)), 100); - break; - case HOME: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_HOME)), 100); - break; - case BACK: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_BACK)), 100); - break; - case NUMBER_0: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_0)), 100); - break; - case NUMBER_1: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_1)), 100); - break; - case NUMBER_2: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_2)), 100); - break; - case NUMBER_3: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_3)), 100); - break; - case NUMBER_4: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_4)), 100); - break; - case NUMBER_5: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_5)), 100); - break; - case NUMBER_6: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_6)), 100); - break; - case NUMBER_7: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_7)), 100); - break; - case NUMBER_8: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_8)), 100); - break; - case NUMBER_9: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_9)), 100); - break; + bool enabled = false; + bool ret = false; + HdmiCecSink::_hdmiCecSink->GetEnabled(enabled,ret); - } - } + if(ret && enabled) + { + Exchange::IHdmiCecSink::HdmiCecSinkSuccess success; + HdmiCecSink::_hdmiCecSink->SetEnabled(false,success); + } - void HdmiCecSink::sendUserControlPressed(const int logicalAddress, int keyCode) - { - if(!(_instance->smConnection)) - return; - LOGINFO(" sendUserControlPressed logicalAddress 0x%x keycode 0x%x\n",logicalAddress,keyCode); - switch(keyCode) - { - case VOLUME_UP: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_VOLUME_UP)),100); - break; - case VOLUME_DOWN: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_VOLUME_DOWN)), 100); - break; - case MUTE: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_MUTE)), 100); - break; - case UP: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_UP)), 100); - break; - case DOWN: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_DOWN)), 100); - break; - case LEFT: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_LEFT)), 100); - break; - case RIGHT: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_RIGHT)), 100); - break; - case SELECT: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_SELECT)), 100); - break; - case HOME: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_HOME)), 100); - break; - case BACK: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_BACK)), 100); - break; - case NUMBER_0: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_0)), 100); - break; - case NUMBER_1: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_1)), 100); - break; - case NUMBER_2: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_2)), 100); - break; - case NUMBER_3: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_3)), 100); - break; - case NUMBER_4: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_4)), 100); - break; - case NUMBER_5: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_5)), 100); - break; - case NUMBER_6: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_6)), 100); - break; - case NUMBER_7: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_7)), 100); - break; - case NUMBER_8: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_8)), 100); - break; - case NUMBER_9: - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_9)), 100); - break; + if(nullptr != _hdmiCecSink) + { + _hdmiCecSink->Unregister(&_notification); + Exchange::JHdmiCecSink::Unregister(*this); + _hdmiCecSink->Release(); + _hdmiCecSink = nullptr; - } + RPC::IRemoteConnection* connection = _service->RemoteConnection(_connectionId); + if (connection != nullptr) + { + try{ + connection->Terminate(); + } + catch(const std::exception& e) + { + std::string errorMessage = "Failed to terminate connection: "; + errorMessage += e.what(); + LOGWARN("%s",errorMessage.c_str()); } - void HdmiCecSink::sendKeyReleaseEvent(const int logicalAddress) - { - if(!(_instance->smConnection)) - return; - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlReleased()), 100); - - } - - void HdmiCecSink::sendUserControlReleased(const int logicalAddress) - { - if(!(_instance->smConnection)) - return; - LOGINFO(" User Control Released \n"); - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlReleased()), 100); - } - - void HdmiCecSink::sendDeviceUpdateInfo(const int logicalAddress) - { - JsonObject params; - params["logicalAddress"] = JsonValue(logicalAddress); - sendNotify(eventString[HDMICECSINK_EVENT_DEVICE_INFO_UPDATED], params); - } - void HdmiCecSink::systemAudioModeRequest() - { - if ( cecEnableStatus != true ) - { - LOGINFO("systemAudioModeRequest: Cec is disabled-> EnableCEC first"); - return; - } - - if(!HdmiCecSink::_instance) - return; - if(!(_instance->smConnection)) - return; - LOGINFO(" Send systemAudioModeRequest "); - _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(SystemAudioModeRequest(physical_addr)), 1000); + connection->Release(); + } + } + _connectionId = 0; + _service->Unregister(&_notification); + _service->Release(); + _service = nullptr; + LOGINFO("HdmiCecSink plugin is deactivated. Successfully deactivated HdmiCecSink Plugin"); } - void HdmiCecSink::sendGiveAudioStatusMsg() - { - if(!HdmiCecSink::_instance) - return; - if(!(_instance->smConnection)) - return; - LOGINFO(" Send GiveAudioStatus "); - _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(GiveAudioStatus()), 100); - } - void HdmiCecSink::reportAudioDevicePowerStatusInfo(const int logicalAddress, const int powerStatus) + string HdmiCecSink::Information() const { - JsonObject params; - params["powerStatus"] = JsonValue(powerStatus); - LOGINFO("Panle power state is %s", powerState ? "Off" : "On"); - if (powerStatus != AUDIO_DEVICE_POWERSTATE_OFF) { - if (powerState == DEVICE_POWER_STATE_ON ) { - LOGINFO("Notify DS!!! logicalAddress = %d , Audio device power status = %d \n", logicalAddress, powerStatus); - sendNotify(eventString[HDMICECSINK_EVENT_AUDIO_DEVICE_POWER_STATUS], params); - } else { - LOGINFO("Not notifying audio device power state to DS"); - } - } else { - LOGINFO("Notify DS!!! logicalAddress = %d , Audio device power status = %d \n", logicalAddress, powerStatus); - sendNotify(eventString[HDMICECSINK_EVENT_AUDIO_DEVICE_POWER_STATUS], params); - } + return("This HdmiCecSink PLugin Facilitates the HDMI CEC Sink Control"); } - void HdmiCecSink::SendStandbyMsgEvent(const int logicalAddress) + void HdmiCecSink::Deactivated(RPC::IRemoteConnection* connection) { - JsonObject params; - if(!HdmiCecSink::_instance) - return; - params["logicalAddress"] = JsonValue(logicalAddress); - sendNotify(eventString[HDMICECSINK_EVENT_STANDBY_MSG_EVENT], params); - } - uint32_t HdmiCecSink::setEnabledWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - - bool enabled = false; - - if (parameters.HasLabel("enabled")) - { - getBoolParameter("enabled", enabled); - } - else - { - returnResponse(false); - } - - setEnabled(enabled); - returnResponse(true); - } - - uint32_t HdmiCecSink::getEnabledWrapper(const JsonObject& parameters, JsonObject& response) - { - response["enabled"] = getEnabled(); - returnResponse(true); - } - - uint32_t HdmiCecSink::getAudioDeviceConnectedStatusWrapper(const JsonObject& parameters, JsonObject& response) - { - response["connected"] = getAudioDeviceConnectedStatus(); - returnResponse(true); - } - - uint32_t HdmiCecSink::requestAudioDevicePowerStatusWrapper(const JsonObject& parameters, JsonObject& response) - { - requestAudioDevicePowerStatus(); - returnResponse(true); - } - - uint32_t HdmiCecSink::getActiveSourceWrapper(const JsonObject& parameters, JsonObject& response) - { - char routeString[1024] = {'\0'}; - int length = 0; - std::stringstream temp; - - if ( HdmiCecSink::_instance->m_currentActiveSource != -1 ) - { - int n = HdmiCecSink::_instance->m_currentActiveSource; - response["available"] = true; - response["logicalAddress"] = HdmiCecSink::_instance->deviceList[n].m_logicalAddress.toInt(); - response["physicalAddress"] = HdmiCecSink::_instance->deviceList[n].m_physicalAddr.toString().c_str(); - response["deviceType"] = HdmiCecSink::_instance->deviceList[n].m_deviceType.toString().c_str(); - response["cecVersion"] = HdmiCecSink::_instance->deviceList[n].m_cecVersion.toString().c_str(); - response["osdName"] = HdmiCecSink::_instance->deviceList[n].m_osdName.toString().c_str(); - response["vendorID"] = HdmiCecSink::_instance->deviceList[n].m_vendorID.toString().c_str(); - response["powerStatus"] = HdmiCecSink::_instance->deviceList[n].m_powerStatus.toString().c_str(); - - if ( HdmiCecSink::_instance->deviceList[n].m_physicalAddr.getByteValue(0) != 0 ) - { - snprintf(&routeString[length], sizeof(routeString) - length, "%s%d", "HDMI",(HdmiCecSink::_instance->deviceList[n].m_physicalAddr.getByteValue(0) - 1)); - } - else if ( HdmiCecSink::_instance->deviceList[n].m_physicalAddr.getByteValue(0) == 0 ) - { - snprintf(&routeString[length], sizeof(routeString) - length, "%s", "TV"); - } - - temp << (char *)routeString; - response["port"] = temp.str(); - - } - else - { - response["available"] = false; - } - - returnResponse(true); - } - - uint32_t HdmiCecSink::getDeviceListWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - - response["numberofdevices"] = HdmiCecSink::_instance->m_numberOfDevices; - LOGINFO("getDeviceListWrapper m_numberOfDevices :%d \n", HdmiCecSink::_instance->m_numberOfDevices); - JsonArray deviceList; - - for (int n = 0; n <= LogicalAddress::UNREGISTERED; n++) - { - - if ( n != HdmiCecSink::_instance->m_logicalAddressAllocated && - HdmiCecSink::_instance->deviceList[n].m_isDevicePresent ) - { - JsonObject device; - - device["logicalAddress"] = HdmiCecSink::_instance->deviceList[n].m_logicalAddress.toInt(); - device["physicalAddress"] = HdmiCecSink::_instance->deviceList[n].m_physicalAddr.toString().c_str(); - device["deviceType"] = HdmiCecSink::_instance->deviceList[n].m_deviceType.toString().c_str(); - device["cecVersion"] = HdmiCecSink::_instance->deviceList[n].m_cecVersion.toString().c_str(); - device["osdName"] = HdmiCecSink::_instance->deviceList[n].m_osdName.toString().c_str(); - device["vendorID"] = HdmiCecSink::_instance->deviceList[n].m_vendorID.toString().c_str(); - device["powerStatus"] = HdmiCecSink::_instance->deviceList[n].m_powerStatus.toString().c_str(); - int hdmiPortNumber = -1; - LOGINFO("getDeviceListWrapper m_numofHdmiInput:%d looking for Logical Address :%d \n", m_numofHdmiInput, HdmiCecSink::_instance->deviceList[n].m_logicalAddress.toInt()); - for (int i=0; i < m_numofHdmiInput; i++) - { - LOGINFO("getDeviceListWrapper connected : %d, portid:%d LA: %d \n", hdmiInputs[i].m_isConnected, hdmiInputs[i].m_portID, hdmiInputs[i].m_logicalAddr.toInt()); - if(hdmiInputs[i].m_isConnected && hdmiInputs[i].m_logicalAddr.toInt() == HdmiCecSink::_instance->deviceList[n].m_logicalAddress.toInt()) - { - hdmiPortNumber = hdmiInputs[i].m_portID; - LOGINFO("got portid :%d break \n", hdmiPortNumber); - break; - } - } - device["portNumber"] = hdmiPortNumber; - deviceList.Add(device); - } - } - - response["deviceList"] = deviceList; - - returnResponse(true); - } - - - uint32_t HdmiCecSink::setOSDNameWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - - if (parameters.HasLabel("name")) - { - std::string osd = parameters["name"].String(); - LOGINFO("setOSDNameWrapper osdName: %s",osd.c_str()); - osdName = osd.c_str(); - Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_OSD_NAME, JsonValue(osd.c_str())); - } - else + if (connection->Id() == _connectionId) { - returnResponse(false); + ASSERT(_service != nullptr); + Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); } - returnResponse(true); - } - - uint32_t HdmiCecSink::getOSDNameWrapper(const JsonObject& parameters, JsonObject& response) - { - response["name"] = osdName.toString(); - LOGINFO("getOSDNameWrapper osdName : %s \n",osdName.toString().c_str()); - returnResponse(true); } - uint32_t HdmiCecSink::printDeviceListWrapper(const JsonObject& parameters, JsonObject& response) - { - printDeviceList(); - response["printed"] = true; - returnResponse(true); - } - - uint32_t HdmiCecSink::setActiveSourceWrapper(const JsonObject& parameters, JsonObject& response) - { - setActiveSource(false); - returnResponse(true); - } - - uint32_t HdmiCecSink::setActivePathWrapper(const JsonObject& parameters, JsonObject& response) - { - if (parameters.HasLabel("activePath")) - { - std::string id = parameters["activePath"].String(); - PhysicalAddress phy_addr = PhysicalAddress(id); - - LOGINFO("Addr = %s, length = %zu", id.c_str(), id.length()); - - setStreamPath(phy_addr); - returnResponse(true); - } - else - { - returnResponse(false); - } - } - - uint32_t HdmiCecSink::getActiveRouteWrapper(const JsonObject& parameters, JsonObject& response) - { - std::vector route; - char routeString[1024] = {'\0'}; - int length = 0; - JsonArray pathList; - std::stringstream temp; - - if (HdmiCecSink::_instance->m_currentActiveSource != -1 && - HdmiCecSink::_instance->m_currentActiveSource != HdmiCecSink::_instance->m_logicalAddressAllocated ) - { - HdmiCecSink::_instance->getActiveRoute(LogicalAddress(HdmiCecSink::_instance->m_currentActiveSource), route); - - if (route.size()) - { - response["available"] = true; - response["length"] = route.size(); - - for (unsigned int i=0; i < route.size(); i++) - { - if ( route[i] != LogicalAddress::UNREGISTERED ) - { - JsonObject device; - - device["logicalAddress"] = HdmiCecSink::_instance->deviceList[route[i]].m_logicalAddress.toInt(); - device["physicalAddress"] = HdmiCecSink::_instance->deviceList[route[i]].m_physicalAddr.toString().c_str(); - device["deviceType"] = HdmiCecSink::_instance->deviceList[route[i]].m_deviceType.toString().c_str(); - device["osdName"] = HdmiCecSink::_instance->deviceList[route[i]].m_osdName.toString().c_str(); - device["vendorID"] = HdmiCecSink::_instance->deviceList[route[i]].m_vendorID.toString().c_str(); - - pathList.Add(device); - - snprintf(&routeString[length], sizeof(routeString) - length, "%s", _instance->deviceList[route[i]].m_logicalAddress.toString().c_str()); - length += _instance->deviceList[route[i]].m_logicalAddress.toString().length(); - snprintf(&routeString[length], sizeof(routeString) - length, "(%s", _instance->deviceList[route[i]].m_osdName.toString().c_str()); - length += _instance->deviceList[route[i]].m_osdName.toString().length(); - snprintf(&routeString[length], sizeof(routeString) - length, "%s", ")-->"); - length += strlen(")-->"); - if( i + 1 == route.size() ) - { - snprintf(&routeString[length], sizeof(routeString) - length, "%s%d", "HDMI",(HdmiCecSink::_instance->deviceList[route[i]].m_physicalAddr.getByteValue(0) - 1)); - } - } - } - - response["pathList"] = pathList; - temp << (char *)routeString; - response["ActiveRoute"] = temp.str(); - LOGINFO("ActiveRoute = [%s]", routeString); - } - - } - else if ( HdmiCecSink::_instance->m_currentActiveSource == HdmiCecSink::_instance->m_logicalAddressAllocated ) - { - response["available"] = true; - response["ActiveRoute"] = "TV"; - } - else - { - response["available"] = false; - } - - returnResponse(true); - } - - uint32_t HdmiCecSink::requestActiveSourceWrapper(const JsonObject& parameters, JsonObject& response) - { - requestActiveSource(); - returnResponse(true); - } - - uint32_t HdmiCecSink::setRoutingChangeWrapper(const JsonObject& parameters, JsonObject& response) - { - std::string oldPortID; - std::string newPortID; - - returnIfParamNotFound(parameters, "oldPort"); - returnIfParamNotFound(parameters, "newPort"); - - oldPortID = parameters["oldPort"].String(); - newPortID = parameters["newPort"].String(); - - - if ((oldPortID.find("HDMI",0) != std::string::npos || - oldPortID.find("TV",0) != std::string::npos ) && - ( newPortID.find("HDMI", 0) != std::string::npos || - newPortID.find("TV", 0) != std::string::npos )) - { - setRoutingChange(oldPortID, newPortID); - returnResponse(true); - } - else - { - returnResponse(false); - } - } - - - uint32_t HdmiCecSink::setMenuLanguageWrapper(const JsonObject& parameters, JsonObject& response) - { - std::string lang; - - returnIfParamNotFound(parameters, "language"); - - lang = parameters["language"].String(); - - setCurrentLanguage(Language(lang.data())); - sendMenuLanguage(); - returnResponse(true); - } - - - uint32_t HdmiCecSink::setVendorIdWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - - if (parameters.HasLabel("vendorid")) - { - std::string id = parameters["vendorid"].String(); - unsigned int vendorID = 0x00; - try - { - vendorID = stoi(id,NULL,16); - } - catch (...) - { - LOGWARN("Exception in setVendorIdWrapper set default value\n"); - vendorID = 0x0019FB; - } - appVendorId = {(uint8_t)(vendorID >> 16 & 0xff),(uint8_t)(vendorID>> 8 & 0xff),(uint8_t) (vendorID & 0xff)}; - LOGINFO("appVendorId : %s vendorID :%x \n",appVendorId.toString().c_str(), vendorID ); - - Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_VENDOR_ID, JsonValue(vendorID)); - } - else - { - returnResponse(false); - } - returnResponse(true); - } - uint32_t HdmiCecSink::setArcEnableDisableWrapper(const JsonObject& parameters, JsonObject& response) - { - - bool enabled = false; - - if (parameters.HasLabel("enabled")) - { - getBoolParameter("enabled", enabled); - } - else - { - returnResponse(false); - } - if(enabled) - { - startArc(); - } - else - { - stopArc(); - - } - - returnResponse(true); - } - uint32_t HdmiCecSink::getVendorIdWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFO("getVendorIdWrapper appVendorId : %s \n",appVendorId.toString().c_str()); - response["vendorid"] = appVendorId.toString() ; - returnResponse(true); - } - - uint32_t HdmiCecSink::requestShortAudioDescriptorWrapper(const JsonObject& parameters, JsonObject& response) - { - requestShortaudioDescriptor(); - returnResponse(true); - } - uint32_t HdmiCecSink::sendStandbyMessageWrapper(const JsonObject& parameters, JsonObject& response) - { - sendStandbyMessage(); - returnResponse(true); - } - - uint32_t HdmiCecSink::sendAudioDevicePowerOnMsgWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFO("%s invoked. \n",__FUNCTION__); - systemAudioModeRequest(); - returnResponse(true); - } - uint32_t HdmiCecSink::sendRemoteKeyPressWrapper(const JsonObject& parameters, JsonObject& response) - { - returnIfParamNotFound(parameters, "logicalAddress"); - returnIfParamNotFound(parameters, "keyCode"); - string logicalAddress = parameters["logicalAddress"].String(); - string keyCode = parameters["keyCode"].String(); - SendKeyInfo keyInfo; - keyInfo.logicalAddr = stoi(logicalAddress); - keyInfo.keyCode = stoi(keyCode); - keyInfo.UserControl = "sendKeyPressEvent"; - std::unique_lock lk(m_sendKeyEventMutex); - m_SendKeyQueue.push(keyInfo); - m_sendKeyEventThreadRun = true; - m_sendKeyCV.notify_one(); - LOGINFO("Post send key press event to queue size:%zu \n",m_SendKeyQueue.size()); - returnResponse(true); - } - - uint32_t HdmiCecSink::sendUserControlPressedWrapper(const JsonObject& parameters, JsonObject& response) - { - returnIfParamNotFound(parameters, "logicalAddress"); - returnIfParamNotFound(parameters, "keyCode"); - string logicalAddress = parameters["logicalAddress"].String(); - string keyCode = parameters["keyCode"].String(); - SendKeyInfo keyInfo; - keyInfo.logicalAddr = stoi(logicalAddress); - keyInfo.keyCode = stoi(keyCode); - keyInfo.UserControl = "sendUserControlPressed"; - std::unique_lock lk(m_sendKeyEventMutex); - m_SendKeyQueue.push(keyInfo); - m_sendKeyEventThreadRun = true; - m_sendKeyCV.notify_one(); - LOGINFO("User control pressed, queue size:%zu \n",m_SendKeyQueue.size()); - returnResponse(true); - } - - uint32_t HdmiCecSink::sendUserControlReleasedWrapper(const JsonObject& parameters, JsonObject& response) - { - returnIfParamNotFound(parameters, "logicalAddress"); - string logicalAddress = parameters["logicalAddress"].String(); - SendKeyInfo keyInfo; - keyInfo.logicalAddr = stoi(logicalAddress); - keyInfo.keyCode = 0; - keyInfo.UserControl = "sendUserControlReleased"; - std::unique_lock lk(m_sendKeyEventMutex); - m_SendKeyQueue.push(keyInfo); - m_sendKeyEventThreadRun = true; - m_sendKeyCV.notify_one(); - LOGINFO("User Control Released, queue size:%zu \n",m_SendKeyQueue.size()); - returnResponse(true); - } - - uint32_t HdmiCecSink::sendGiveAudioStatusWrapper(const JsonObject& parameters, JsonObject& response) - { - sendGiveAudioStatusMsg(); - returnResponse(true); - } - uint32_t HdmiCecSink::setLatencyInfoWrapper(const JsonObject& parameters, JsonObject& response) - { - int video_latency,audio_output_compensated,audio_output_delay; - bool low_latency_mode; - - returnIfParamNotFound(parameters, "videoLatency"); - returnIfParamNotFound(parameters, "lowLatencyMode"); - returnIfParamNotFound(parameters, "audioOutputCompensated"); - returnIfParamNotFound(parameters, "audioOutputDelay"); - video_latency = stoi(parameters["videoLatency"].String()); - low_latency_mode = stoi(parameters["lowLatencyMode"].String()); - audio_output_compensated = stoi(parameters["audioOutputCompensated"].String()); - audio_output_delay = stoi(parameters["audioOutputDelay"].String()); - - updateCurrentLatency(video_latency, low_latency_mode,audio_output_compensated, audio_output_delay); - returnResponse(true); - } - bool HdmiCecSink::loadSettings() - { - Core::File file; - file = CEC_SETTING_ENABLED_FILE; - - if( file.Open()) - { - JsonObject parameters; - parameters.IElement::FromFile(file); - bool isConfigAdded = false; - - if( parameters.HasLabel(CEC_SETTING_ENABLED)) - { - getBoolParameter(CEC_SETTING_ENABLED, cecSettingEnabled); - LOGINFO("CEC_SETTING_ENABLED present value:%d",cecSettingEnabled); - } - else - { - parameters[CEC_SETTING_ENABLED] = true; - cecSettingEnabled = true; - isConfigAdded = true; - LOGINFO("CEC_SETTING_ENABLED not present set dafult true:\n "); - } - - if( parameters.HasLabel(CEC_SETTING_OTP_ENABLED)) - { - getBoolParameter(CEC_SETTING_OTP_ENABLED, cecOTPSettingEnabled); - LOGINFO("CEC_SETTING_OTP_ENABLED present value :%d",cecOTPSettingEnabled); - } - else - { - parameters[CEC_SETTING_OTP_ENABLED] = true; - cecOTPSettingEnabled = true; - isConfigAdded = true; - LOGINFO("CEC_SETTING_OTP_ENABLED not present set dafult true:\n "); - } - if( parameters.HasLabel(CEC_SETTING_OSD_NAME)) - { - std::string osd_name; - getStringParameter(CEC_SETTING_OSD_NAME, osd_name); - osdName = osd_name.c_str(); - LOGINFO("CEC_SETTING_OSD_NAME present osd_name :%s",osdName.toString().c_str()); - } - else - { - parameters[CEC_SETTING_OSD_NAME] = osdName.toString(); - LOGINFO("CEC_SETTING_OSD_NMAE not present set dafult value :%s\n ",osdName.toString().c_str()); - isConfigAdded = true; - } - unsigned int vendorId = (defaultVendorId.at(0) <<16) | ( defaultVendorId.at(1) << 8 ) | defaultVendorId.at(2); - if( parameters.HasLabel(CEC_SETTING_VENDOR_ID)) - { - getNumberParameter(CEC_SETTING_VENDOR_ID, vendorId); - LOGINFO("CEC_SETTING_VENDOR_ID present :%x ",vendorId); - } - else - { - LOGINFO("CEC_SETTING_VENDOR_ID not present set dafult value :%x \n ",vendorId); - parameters[CEC_SETTING_VENDOR_ID] = vendorId; - isConfigAdded = true; - } - - appVendorId = {(uint8_t)(vendorId >> 16 & 0xff),(uint8_t)(vendorId >> 8 & 0xff),(uint8_t) (vendorId & 0xff)}; - LOGINFO("appVendorId : %s vendorId :%x \n",appVendorId.toString().c_str(), vendorId ); - - if(isConfigAdded) - { - LOGINFO("isConfigAdded true so update file:\n "); - file.Destroy(); - file.Create(); - parameters.IElement::ToFile(file); - - } - - file.Close(); - } - else - { - LOGINFO("CEC_SETTING_ENABLED_FILE file not present create with default settings "); - file.Open(false); - if (!file.IsOpen()) - file.Create(); - - JsonObject parameters; - unsigned int vendorId = (defaultVendorId.at(0) <<16) | ( defaultVendorId.at(1) << 8 ) | defaultVendorId.at(2); - parameters[CEC_SETTING_ENABLED] = true; - parameters[CEC_SETTING_OSD_NAME] = osdName.toString(); - parameters[CEC_SETTING_VENDOR_ID] = vendorId; - - cecSettingEnabled = true; - cecOTPSettingEnabled = true; - parameters.IElement::ToFile(file); - - file.Close(); - - } - - return cecSettingEnabled; - } - - void HdmiCecSink::setEnabled(bool enabled) - { - LOGINFO("Entered setEnabled: %d cecSettingEnabled :%d ",enabled, cecSettingEnabled); - - if (cecSettingEnabled != enabled) - { - Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_ENABLED, JsonValue(enabled)); - cecSettingEnabled = enabled; - } - if(true == enabled) - { - CECEnable(); - } - else - { - CECDisable(); - } - return; - } - - void HdmiCecSink::updateImageViewOn(const int logicalAddress) - { - JsonObject params; - if(!HdmiCecSink::_instance) - return; - - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED || - logicalAddress == LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - if (_instance->deviceList[logicalAddress].m_isDevicePresent && - _instance->deviceList[_instance->m_logicalAddressAllocated].m_powerStatus.toInt() == PowerStatus::STANDBY) - - { - /* Bringing TV out of standby is handled by application.notify UI to bring the TV out of standby */ - sendNotify(eventString[HDMICECSINK_EVENT_WAKEUP_FROM_STANDBY], params); - } - - sendNotify(eventString[HDMICECSINK_EVENT_IMAGE_VIEW_ON_MSG], params); - } - - void HdmiCecSink::updateTextViewOn(const int logicalAddress) - { - JsonObject params; - if(!HdmiCecSink::_instance) - return; - - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED || - logicalAddress == LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - if (_instance->deviceList[logicalAddress].m_isDevicePresent && - _instance->deviceList[_instance->m_logicalAddressAllocated].m_powerStatus.toInt() == PowerStatus::STANDBY) - { - /* Bringing TV out of standby is handled by application.notify UI to bring the TV out of standby */ - sendNotify(eventString[HDMICECSINK_EVENT_WAKEUP_FROM_STANDBY], params); - } - - sendNotify(eventString[HDMICECSINK_EVENT_TEXT_VIEW_ON_MSG], params); - } - - - void HdmiCecSink::updateDeviceChain(const LogicalAddress &logicalAddress, const PhysicalAddress &phy_addr) - { - if(!HdmiCecSink::_instance) - return; - - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - if (_instance->deviceList[logicalAddress.toInt()].m_isDevicePresent && - logicalAddress.toInt() != _instance->m_logicalAddressAllocated) - { - for (int i=0; i < m_numofHdmiInput; i++) - { - LOGINFO(" addr = %d, portID = %d", phy_addr.getByteValue(0), hdmiInputs[i].m_portID); - if (phy_addr.getByteValue(0) == (hdmiInputs[i].m_portID + 1)) { - hdmiInputs[i].addChild(logicalAddress, phy_addr); - } - } - } - } - - void HdmiCecSink::getActiveRoute(const LogicalAddress &logicalAddress, std::vector &route) - { - if(!HdmiCecSink::_instance) - return; - - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED || - logicalAddress.toInt() == LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - if (_instance->deviceList[logicalAddress.toInt()].m_isDevicePresent && - logicalAddress.toInt() != _instance->m_logicalAddressAllocated && - _instance->deviceList[logicalAddress.toInt()].m_isActiveSource ) - { - route.clear(); - for (int i=0; i < m_numofHdmiInput; i++) - { - LOGINFO("physicalAddress = [%d], portID = %d", _instance->deviceList[logicalAddress.toInt()].m_physicalAddr.getByteValue(0), hdmiInputs[i].m_portID); - if (_instance->deviceList[logicalAddress.toInt()].m_physicalAddr.getByteValue(0) == (hdmiInputs[i].m_portID + 1)) { - hdmiInputs[i].getRoute(_instance->deviceList[logicalAddress.toInt()].m_physicalAddr, route); - } - } - } - else { - LOGERR("Not in correct state to Find Route"); - } - } - - - void HdmiCecSink::CheckHdmiInState() - { - int err; - bool isAnyPortConnected = false; - - dsHdmiInGetStatusParam_t params; - err = IARM_Bus_Call(IARM_BUS_DSMGR_NAME, - IARM_BUS_DSMGR_API_dsHdmiInGetStatus, - (void *)¶ms, - sizeof(params)); - - if(err == IARM_RESULT_SUCCESS && params.result == dsERR_NONE ) - { - for( int i = 0; i < m_numofHdmiInput; i++ ) - { - LOGINFO("Is HDMI In Port [%d] connected [%d] \n",i, params.status.isPortConnected[i]); - if ( params.status.isPortConnected[i] ) - { - isAnyPortConnected = true; - } - - LOGINFO("update Port Status [%d] \n", i); - hdmiInputs[i].update(params.status.isPortConnected[i]); - } - } - - if ( isAnyPortConnected ) { - m_isHdmiInConnected = true; - } else { - m_isHdmiInConnected = false; - } - } - - void HdmiCecSink::requestActiveSource() - { - if(!HdmiCecSink::_instance) - return; - - if(!(_instance->smConnection)) - return; - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - _instance->smConnection->sendTo(LogicalAddress::BROADCAST, - MessageEncoder().encode(RequestActiveSource()), 500); - } - - void HdmiCecSink::setActiveSource(bool isResponse) - { - if(!HdmiCecSink::_instance) - return; - - if(!(_instance->smConnection)) - return; - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - if (isResponse && (_instance->m_currentActiveSource != _instance->m_logicalAddressAllocated) ) - { - LOGWARN("TV is not current Active Source"); - return; - } - - _instance->smConnection->sendTo(LogicalAddress::BROADCAST, - MessageEncoder().encode(ActiveSource(_instance->deviceList[_instance->m_logicalAddressAllocated].m_physicalAddr)), 500); - _instance->m_currentActiveSource = _instance->m_logicalAddressAllocated; - } - - void HdmiCecSink::setCurrentLanguage(const Language &lang) - { - if(!HdmiCecSink::_instance) - return; - - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - _instance->deviceList[_instance->m_logicalAddressAllocated].m_currentLanguage = lang; - } - - void HdmiCecSink::sendMenuLanguage() - { - Language lang = ""; - if(!HdmiCecSink::_instance) - return; - - if(!(_instance->smConnection)) - return; - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - lang = _instance->deviceList[_instance->m_logicalAddressAllocated].m_currentLanguage; - - _instance->smConnection->sendTo(LogicalAddress::BROADCAST, MessageEncoder().encode(SetMenuLanguage(lang)), 100); - } - - void HdmiCecSink::updateInActiveSource(const int logical_address, const InActiveSource &source ) - { - JsonObject params; - if(!HdmiCecSink::_instance) - return; - - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - if( logical_address != _instance->m_logicalAddressAllocated ) - { - _instance->deviceList[logical_address].m_isActiveSource = false; - - if ( _instance->m_currentActiveSource == logical_address ) - { - _instance->m_currentActiveSource = -1; - } - - params["logicalAddress"] = JsonValue(logical_address); - params["phsicalAddress"] = source.physicalAddress.toString().c_str(); - sendNotify(eventString[HDMICECSINK_EVENT_INACTIVE_SOURCE], params); - } - } - - void HdmiCecSink::updateActiveSource(const int logical_address, const ActiveSource &source ) - { - JsonObject params; - if(!HdmiCecSink::_instance) - return; - - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - if( logical_address != _instance->m_logicalAddressAllocated ) - { - if ( _instance->m_currentActiveSource != -1 ) - { - _instance->deviceList[_instance->m_currentActiveSource].m_isActiveSource = false; - } - - _instance->deviceList[logical_address].m_isActiveSource = true; - _instance->deviceList[logical_address].update(source.physicalAddress); - _instance->m_currentActiveSource = logical_address; - - if (_instance->deviceList[logical_address].m_isDevicePresent && - _instance->deviceList[_instance->m_logicalAddressAllocated].m_powerStatus.toInt() == PowerStatus::STANDBY) - { - /* Bringing TV out of standby is handled by application.notify UI to bring the TV out of standby */ - sendNotify(eventString[HDMICECSINK_EVENT_WAKEUP_FROM_STANDBY], params); - } - - params["logicalAddress"] = JsonValue(logical_address); - params["physicalAddress"] = _instance->deviceList[logical_address].m_physicalAddr.toString().c_str(); - sendNotify(eventString[HDMICECSINK_EVENT_ACTIVE_SOURCE_CHANGE], params); - } - } - - void HdmiCecSink::requestShortaudioDescriptor() - { - if ( cecEnableStatus != true ) - { - LOGINFO("requestShortaudioDescriptor: cec is disabled-> EnableCEC first"); - return; - } - - if(!HdmiCecSink::_instance) - return; - - if(!(_instance->smConnection)) - return; - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - LOGINFO(" Send requestShortAudioDescriptor Message "); - _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(RequestShortAudioDescriptor(formatid,audioFormatCode,numberofdescriptor)), 1000); - - } - - void HdmiCecSink::requestAudioDevicePowerStatus() - { - if ( cecEnableStatus != true ) - { - LOGWARN("cec is disabled-> EnableCEC first"); - return; - } - - if(!HdmiCecSink::_instance) - return; - - if(!(_instance->smConnection)) - return; - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - LOGINFO(" Send GiveDevicePowerStatus Message to Audio system in the network \n"); - _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM, MessageEncoder().encode(GiveDevicePowerStatus()), 500); - - m_audioDevicePowerStatusRequested = true; - } - - void HdmiCecSink::sendFeatureAbort(const LogicalAddress logicalAddress, const OpCode feature, const AbortReason reason) - { - - if(!HdmiCecSink::_instance) - return; - if(!(_instance->smConnection)) - return; - LOGINFO(" Sending FeatureAbort to %s for opcode %s with reason %s ",logicalAddress.toString().c_str(),feature.toString().c_str(),reason.toString().c_str()); - _instance->smConnection->sendTo(logicalAddress, MessageEncoder().encode(FeatureAbort(feature,reason)), 500); - } - - void HdmiCecSink::reportFeatureAbortEvent(const LogicalAddress logicalAddress, const OpCode featureOpcode, const AbortReason abortReason) - { - LOGINFO(" Notifying the UI FeatureAbort from the %s for the opcode %s with the reason %s ",logicalAddress.toString().c_str(),featureOpcode.toString().c_str(),abortReason.toString().c_str()); - JsonObject params; - params["LogicalAddress"] = logicalAddress.toInt(); - params["opcode"] = featureOpcode.opCode(); - params["FeatureAbortReason"] = abortReason.toInt(); - sendNotify(eventString[HDMICECSINK_EVENT_FEATURE_ABORT_EVENT], params); - } - - void HdmiCecSink::pingDevices(std::vector &connected , std::vector &disconnected) - { - int i; - - if(!HdmiCecSink::_instance) - return; - if(!(_instance->smConnection)) - return; - - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - for(i=0; i< LogicalAddress::UNREGISTERED; i++ ) { - if ( i != _instance->m_logicalAddressAllocated ) - { - //LOGWARN("PING for 0x%x \r\n",i); - try { - _instance->smConnection->ping(LogicalAddress(_instance->m_logicalAddressAllocated), LogicalAddress(i), Throw_e()); - } - catch(CECNoAckException &e) - { - if ( _instance->deviceList[i].m_isDevicePresent ) { - disconnected.push_back(i); - } - //LOGWARN("Ping device: 0x%x caught %s \r\n", i, e.what()); - usleep(50000); - continue; - } - catch(Exception &e) - { - LOGWARN("Ping device: 0x%x caught %s \r\n", i, e.what()); - usleep(50000); - continue; - } - - /* If we get ACK, then the device is present in the network*/ - if ( !_instance->deviceList[i].m_isDevicePresent ) - { - connected.push_back(i); - //LOGWARN("Ping success, added device: 0x%x \r\n", i); - } - usleep(50000); - } - } - } - - int HdmiCecSink::requestType( const int logicalAddress ) { - int requestType = CECDeviceParams::REQUEST_NONE; - - if ( !_instance->deviceList[logicalAddress].m_isPAUpdated || !_instance->deviceList[logicalAddress].m_isDeviceTypeUpdated ) { - requestType = CECDeviceParams::REQUEST_PHISICAL_ADDRESS; - }else if ( !_instance->deviceList[logicalAddress].m_isOSDNameUpdated ) { - requestType = CECDeviceParams::REQUEST_OSD_NAME; - }else if ( !_instance->deviceList[logicalAddress].m_isVersionUpdated ) { - requestType = CECDeviceParams::REQUEST_CEC_VERSION; - }else if ( !_instance->deviceList[logicalAddress].m_isVendorIDUpdated ) { - requestType = CECDeviceParams::REQUEST_DEVICE_VENDOR_ID; - }else if ( !_instance->deviceList[logicalAddress].m_isPowerStatusUpdated ) { - requestType = CECDeviceParams::REQUEST_POWER_STATUS; - } - - return requestType; - } - - void HdmiCecSink::printDeviceList() { - int i; - - if(!HdmiCecSink::_instance) - return; - - for(i=0; i< 16; i++) - { - if (HdmiCecSink::_instance->deviceList[i].m_isDevicePresent) { - LOGWARN("------ Device ID = %d--------", i); - HdmiCecSink::_instance->deviceList[i].printVariable(); - LOGWARN("-----------------------------"); - } - } - } - - void HdmiCecSink::setStreamPath( const PhysicalAddress &physical_addr) { - - if(!HdmiCecSink::_instance) - return; - - if(!(_instance->smConnection)) - return; - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED){ - LOGERR("Logical Address NOT Allocated Or its not valid"); - return; - } - - _instance->smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(SetStreamPath(physical_addr)), 500); - } - - void HdmiCecSink::setRoutingChange(const std::string &from, const std::string &to) { - PhysicalAddress oldPhyAddr = {0xF,0xF,0xF,0xF}; - PhysicalAddress newPhyAddr = {0xF,0xF,0xF,0xF}; - int oldPortID = -1; - int newPortID = -1; - - if(!HdmiCecSink::_instance) - return; - - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED){ - LOGERR("Logical Address NOT Allocated Or its not valid"); - return; - } - - if( from.find("TV",0) != std::string::npos ) - { - oldPhyAddr = _instance->deviceList[_instance->m_logicalAddressAllocated].m_physicalAddr; - _instance->m_currentActiveSource = -1; - } - else - { - oldPortID = stoi(from.substr(4,1),NULL,16); - if ( oldPortID < _instance->m_numofHdmiInput ) - { - oldPhyAddr = _instance->hdmiInputs[oldPortID].m_physicalAddr; - } - else - { - LOGERR("Invalid HDMI Old Port ID"); - return; - } - } - - if( to.find("TV",0) != std::string::npos ) - { - newPhyAddr = _instance->deviceList[_instance->m_logicalAddressAllocated].m_physicalAddr; - /*set active source as TV */ - _instance->m_currentActiveSource = _instance->m_logicalAddressAllocated; - } - else - { - newPortID = stoi(to.substr(4,1),NULL,16); - - if ( newPortID < _instance->m_numofHdmiInput ) - { - newPhyAddr = _instance->hdmiInputs[newPortID].m_physicalAddr; - } - else - { - LOGERR("Invalid HDMI New Port ID"); - return; - } - } - - if(!(_instance->smConnection)) - return; - _instance->smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(RoutingChange(oldPhyAddr, newPhyAddr)), 500); - } - - void HdmiCecSink::addDevice(const int logicalAddress) { - JsonObject params; - - if(!HdmiCecSink::_instance) - return; - - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - if ( !HdmiCecSink::_instance->deviceList[logicalAddress].m_isDevicePresent ) - { - HdmiCecSink::_instance->deviceList[logicalAddress].m_isDevicePresent = true; - HdmiCecSink::_instance->deviceList[logicalAddress].m_logicalAddress = LogicalAddress(logicalAddress); - HdmiCecSink::_instance->m_numberOfDevices++; - HdmiCecSink::_instance->m_pollNextState = POLL_THREAD_STATE_INFO; - - if(logicalAddress == 0x5) - { - LOGINFO(" logicalAddress =%d , Audio device detected, Notify Device Settings", logicalAddress ); - params["status"] = string("success"); - params["audioDeviceConnected"] = string("true"); - hdmiCecAudioDeviceConnected = true; - sendNotify(eventString[HDMICECSINK_EVENT_AUDIO_DEVICE_CONNECTED_STATUS], params); - } - - sendNotify(eventString[HDMICECSINK_EVENT_DEVICE_ADDED], JsonObject()); - } - } - - void HdmiCecSink::removeDevice(const int logicalAddress) { - JsonObject params; - - if(!HdmiCecSink::_instance) - return; - - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED){ - LOGERR("Logical Address NOT Allocated"); - return; - } - - if (_instance->deviceList[logicalAddress].m_isDevicePresent) - { - _instance->m_numberOfDevices--; - - for (int i=0; i < m_numofHdmiInput; i++) - { - if (_instance->deviceList[logicalAddress].m_physicalAddr.getByteValue(0) == (hdmiInputs[i].m_portID + 1)) { - hdmiInputs[i].removeChild(_instance->deviceList[logicalAddress].m_physicalAddr); - hdmiInputs[i].update(LogicalAddress(LogicalAddress::UNREGISTERED)); - } - } - - if(logicalAddress == 0x5) - { - LOGINFO(" logicalAddress =%d , Audio device removed, Notify Device Settings", logicalAddress ); - params["status"] = string("success"); - params["audioDeviceConnected"] = string("false"); - hdmiCecAudioDeviceConnected = false; - if (m_audioStatusDetectionTimer.isActive()){ - m_audioStatusDetectionTimer.stop(); - } - m_isAudioStatusInfoUpdated = false; - m_audioStatusReceived = false; - m_audioStatusTimerStarted = false; - LOGINFO("Audio device removed, reset the audio status info. m_isAudioStatusInfoUpdated :%d, m_audioStatusReceived :%d, m_audioStatusTimerStarted:%d ", m_isAudioStatusInfoUpdated,m_audioStatusReceived,m_audioStatusTimerStarted); - sendNotify(eventString[HDMICECSINK_EVENT_AUDIO_DEVICE_CONNECTED_STATUS], params) - } - - _instance->deviceList[logicalAddress].m_isRequestRetry = 0; - _instance->deviceList[logicalAddress].clear(); - sendNotify(eventString[HDMICECSINK_EVENT_DEVICE_REMOVED], JsonObject()); - } - } - - void HdmiCecSink::request(const int logicalAddress) { - int requestType; - - if(!HdmiCecSink::_instance) - return; - if(!(_instance->smConnection)) - return; - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED || logicalAddress >= LogicalAddress::UNREGISTERED + TEST_ADD ){ - LOGERR("Logical Address NOT Allocated Or its not valid"); - return; - } - - requestType = _instance->requestType(logicalAddress); - _instance->deviceList[logicalAddress].m_isRequested = requestType; - - switch (requestType) - { - case CECDeviceParams::REQUEST_PHISICAL_ADDRESS : - { - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(GivePhysicalAddress()), 200); - } - break; - - case CECDeviceParams::REQUEST_CEC_VERSION : - { - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(GetCECVersion()), 100); - } - break; - - case CECDeviceParams::REQUEST_DEVICE_VENDOR_ID : - { - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(GiveDeviceVendorID()), 100); - } - break; - - case CECDeviceParams::REQUEST_OSD_NAME : - { - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(GiveOSDName()), 500); - } - break; - - case CECDeviceParams::REQUEST_POWER_STATUS : - { - _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(GiveDevicePowerStatus()), 100); - } - break; - default: - { - _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; - } - break; - } - - _instance->deviceList[logicalAddress].m_requestTime = std::chrono::system_clock::now(); - LOGINFO("request type %d", _instance->deviceList[logicalAddress].m_isRequested); - } - - int HdmiCecSink::requestStatus(const int logicalAddress) { - std::chrono::duration elapsed; - bool isElapsed = false; - - if(!HdmiCecSink::_instance) - return -1; - - - if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED || logicalAddress >= LogicalAddress::UNREGISTERED + TEST_ADD ) { - LOGERR("Logical Address NOT Allocated Or its not valid"); - return -1; - } - - switch ( _instance->deviceList[logicalAddress].m_isRequested ) { - case CECDeviceParams::REQUEST_PHISICAL_ADDRESS : - { - if( _instance->deviceList[logicalAddress].m_isPAUpdated && - _instance->deviceList[logicalAddress].m_isDeviceTypeUpdated ) - { - _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; - } - } - break; - - case CECDeviceParams::REQUEST_CEC_VERSION : - { - if( _instance->deviceList[logicalAddress].m_isVersionUpdated ) - { - _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; - } - } - break; - - case CECDeviceParams::REQUEST_DEVICE_VENDOR_ID : - { - if( _instance->deviceList[logicalAddress].m_isVendorIDUpdated ) - { - _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; - } - } - break; - - case CECDeviceParams::REQUEST_OSD_NAME : - { - if( _instance->deviceList[logicalAddress].m_isOSDNameUpdated ) - { - _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; - } - } - break; - - case CECDeviceParams::REQUEST_POWER_STATUS : - { - if( _instance->deviceList[logicalAddress].m_isPowerStatusUpdated ) - { - _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; - } - } - break; - default: - break; - } - - if ( _instance->deviceList[logicalAddress].m_isRequested != CECDeviceParams::REQUEST_NONE ) - { - elapsed = std::chrono::system_clock::now() - _instance->deviceList[logicalAddress].m_requestTime; - - if ( elapsed.count() > HDMICECSINK_REQUEST_MAX_WAIT_TIME_MS ) - { - LOGINFO("request elapsed "); - isElapsed = true; - } - } - - if (isElapsed) - { - /* For some request it should be retry, like report physical address etc for other we can have default values */ - switch( _instance->deviceList[logicalAddress].m_isRequested ) - { - case CECDeviceParams::REQUEST_PHISICAL_ADDRESS : - { - LOGINFO("Retry for REQUEST_PHISICAL_ADDRESS = %d", _instance->deviceList[logicalAddress].m_isRequestRetry); - /* Update with Invalid Physical Address */ - if ( _instance->deviceList[logicalAddress].m_isRequestRetry++ >= HDMICECSINK_REQUEST_MAX_RETRY ) - { - LOGINFO("Max retry for REQUEST_PHISICAL_ADDRESS = %d", _instance->deviceList[logicalAddress].m_isRequestRetry); - _instance->deviceList[logicalAddress].update(PhysicalAddress(0xF,0xF,0xF,0xF)); - _instance->deviceList[logicalAddress].update(DeviceType(DeviceType::RESERVED)); - _instance->deviceList[logicalAddress].m_isRequestRetry = 0; - } - } - break; - - case CECDeviceParams::REQUEST_CEC_VERSION : - { - /*Defaulting to 1.4*/ - _instance->deviceList[logicalAddress].update(Version(Version::V_1_4)); - } - break; - - case CECDeviceParams::REQUEST_DEVICE_VENDOR_ID : - { - _instance->deviceList[logicalAddress].update(VendorID(0,0,0)); - } - break; - - case CECDeviceParams::REQUEST_OSD_NAME : - { - if ( _instance->deviceList[logicalAddress].m_isRequestRetry++ >= HDMICECSINK_REQUEST_MAX_RETRY ) - { - LOGINFO("Max retry for REQUEST_OSD_NAME = %d", _instance->deviceList[logicalAddress].m_isRequestRetry); - _instance->deviceList[logicalAddress].update(OSDName("")); - _instance->deviceList[logicalAddress].m_isRequestRetry = 0; - } - } - break; - - case CECDeviceParams::REQUEST_POWER_STATUS : - { - _instance->deviceList[logicalAddress].update(PowerStatus(PowerStatus::POWER_STATUS_NOT_KNOWN)); - } - break; - default: - break; - } - - - _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; - } - - if( _instance->deviceList[logicalAddress].m_isRequested == CECDeviceParams::REQUEST_NONE) - { - LOGINFO("Request Done"); - return CECDeviceParams::REQUEST_DONE; - } - - //LOGINFO("Request NOT Done"); - return CECDeviceParams::REQUEST_NOT_DONE; - } - - void HdmiCecSink::threadRun() - { - std::vector connected; - std::vector disconnected; - int logicalAddressRequested = LogicalAddress::UNREGISTERED + TEST_ADD; - bool isExit = false; - - if(!HdmiCecSink::_instance) - return; - - if(!(_instance->smConnection)) - return; - LOGINFO("Entering ThreadRun: _instance->m_pollThreadExit %d isExit %d _instance->m_pollThreadState %d _instance->m_pollNextState %d",_instance->m_pollThreadExit,isExit,_instance->m_pollThreadState,_instance->m_pollNextState ); - _instance->m_sleepTime = HDMICECSINK_PING_INTERVAL_MS; - - while(1) - { - - if (_instance->m_pollThreadExit || isExit ){ - LOGWARN("Thread Exits _instance->m_pollThreadExit %d isExit %d _instance->m_pollThreadState %d _instance->m_pollNextState %d",_instance->m_pollThreadExit,isExit,_instance->m_pollThreadState,_instance->m_pollNextState ); - break; - } - - if ( _instance->m_pollNextState != POLL_THREAD_STATE_NONE ) - { - _instance->m_pollThreadState = _instance->m_pollNextState; - _instance->m_pollNextState = POLL_THREAD_STATE_NONE; - } - - switch (_instance->m_pollThreadState) { - - case POLL_THREAD_STATE_POLL : - { - //LOGINFO("POLL_THREAD_STATE_POLL"); - _instance->allocateLogicalAddress(DeviceType::TV); - if ( _instance->m_logicalAddressAllocated != LogicalAddress::UNREGISTERED) - { - try{ - - logicalAddress = LogicalAddress(_instance->m_logicalAddressAllocated); - LibCCEC::getInstance().addLogicalAddress(logicalAddress); - _instance->smConnection->setSource(logicalAddress); - _instance->m_numberOfDevices = 0; - _instance->deviceList[_instance->m_logicalAddressAllocated].m_deviceType = DeviceType::TV; - _instance->deviceList[_instance->m_logicalAddressAllocated].m_isDevicePresent = true; - _instance->deviceList[_instance->m_logicalAddressAllocated].update(physical_addr); - _instance->deviceList[_instance->m_logicalAddressAllocated].m_cecVersion = Version::V_1_4; - _instance->deviceList[_instance->m_logicalAddressAllocated].m_vendorID = appVendorId; - _instance->deviceList[_instance->m_logicalAddressAllocated].m_powerStatus = PowerStatus(powerState); - _instance->deviceList[_instance->m_logicalAddressAllocated].m_currentLanguage = defaultLanguage; - _instance->deviceList[_instance->m_logicalAddressAllocated].m_osdName = osdName.toString().c_str(); - if(cecVersion == 2.0) { - _instance->deviceList[_instance->m_logicalAddressAllocated].m_cecVersion = Version::V_2_0; - _instance->smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), - MessageEncoder().encode(ReportFeatures(Version::V_2_0,allDevicetype,rcProfile,deviceFeatures)), 500); - } - _instance->smConnection->addFrameListener(_instance->msgFrameListener); - _instance->smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), - MessageEncoder().encode(ReportPhysicalAddress(physical_addr, _instance->deviceList[_instance->m_logicalAddressAllocated].m_deviceType)), 100); - - _instance->m_sleepTime = 0; - _instance->m_pollThreadState = POLL_THREAD_STATE_PING; - } - catch(InvalidStateException &e){ - LOGWARN("InvalidStateException caught while allocated logical address. %s", e.what()); - _instance->m_pollThreadState = POLL_THREAD_STATE_EXIT; - } - catch(IOException &e){ - LOGWARN("IOException caught while allocated logical address. %s", e.what()); - _instance->m_pollThreadState = POLL_THREAD_STATE_EXIT; - } - catch(...){ - LOGWARN("Exception caught while allocated logical address."); - _instance->m_pollThreadState = POLL_THREAD_STATE_EXIT; - } - } - else - { - LOGINFO("Not able allocate Logical Address for TV"); - _instance->m_pollThreadState = POLL_THREAD_STATE_EXIT; - } - } - break; - - case POLL_THREAD_STATE_PING : - { - //LOGINFO("POLL_THREAD_STATE_PING"); - _instance->m_pollThreadState = POLL_THREAD_STATE_INFO; - connected.clear(); - disconnected.clear(); - _instance->pingDevices(connected, disconnected); - - if ( disconnected.size() ){ - for( unsigned int i=0; i< disconnected.size(); i++ ) - { - LOGWARN("Disconnected Devices [%zu]", disconnected.size()); - _instance->removeDevice(disconnected[i]); - } - } - - if (connected.size()) { - LOGWARN("Connected Devices [%zu]", connected.size()); - for( unsigned int i=0; i< connected.size(); i++ ) - { - _instance->addDevice(connected[i]); - /* If new device is connected, then try to aquire the information */ - _instance->m_pollThreadState = POLL_THREAD_STATE_INFO; - _instance->m_sleepTime = 0; - } - } - else - { - for(int i=0;im_logicalAddressAllocated && - _instance->deviceList[i].m_isDevicePresent && - !_instance->deviceList[i].isAllUpdated() ) - { - _instance->m_pollNextState = POLL_THREAD_STATE_INFO; - _instance->m_sleepTime = 0; - } - } - /* Check for any update required */ - _instance->m_pollThreadState = POLL_THREAD_STATE_UPDATE; - _instance->m_sleepTime = 0; - } - } - break; - - case POLL_THREAD_STATE_INFO : - { - //LOGINFO("POLL_THREAD_STATE_INFO"); - - if ( logicalAddressRequested == LogicalAddress::UNREGISTERED + TEST_ADD ) - { - int i = 0; - for(;im_logicalAddressAllocated && - _instance->deviceList[i].m_isDevicePresent && - !_instance->deviceList[i].isAllUpdated() ) - { - //LOGINFO("POLL_THREAD_STATE_INFO -> request for %d", i); - logicalAddressRequested = i; - _instance->request(logicalAddressRequested); - _instance->m_sleepTime = HDMICECSINK_REQUEST_INTERVAL_TIME_MS; - break; - } - } - - if ( i == LogicalAddress::UNREGISTERED) - { - /*So there is no update required, try to ping after some seconds*/ - _instance->m_pollThreadState = POLL_THREAD_STATE_IDLE; - _instance->m_sleepTime = 0; - //LOGINFO("POLL_THREAD_STATE_INFO -> state change to Ping", i); - } - } - else - { - /*So there is request sent for logical address, so wait and check the status */ - if ( _instance->requestStatus(logicalAddressRequested) == CECDeviceParams::REQUEST_DONE ) - { - logicalAddressRequested = LogicalAddress::UNREGISTERED; - } - else - { - _instance->m_sleepTime = HDMICECSINK_REQUEST_INTERVAL_TIME_MS; - } - } - } - break; - - /* updating the power status and if required we can add other information later*/ - case POLL_THREAD_STATE_UPDATE : - { - //LOGINFO("POLL_THREAD_STATE_UPDATE"); - - for(int i=0;im_logicalAddressAllocated && - _instance->deviceList[i].m_isDevicePresent && - _instance->deviceList[i].m_isPowerStatusUpdated ) - { - std::chrono::duration elapsed = std::chrono::system_clock::now() - _instance->deviceList[i].m_lastPowerUpdateTime; - - if ( elapsed.count() > HDMICECSINK_UPDATE_POWER_STATUS_INTERVA_MS ) - { - _instance->deviceList[i].m_isPowerStatusUpdated = false; - _instance->m_pollNextState = POLL_THREAD_STATE_INFO; - _instance->m_sleepTime = 0; - } - } - } - - _instance->m_pollThreadState = POLL_THREAD_STATE_IDLE; - _instance->m_sleepTime = 0; - } - break; - - case POLL_THREAD_STATE_IDLE : - { - //LOGINFO("POLL_THREAD_STATE_IDLE"); - _instance->m_sleepTime = HDMICECSINK_PING_INTERVAL_MS; - _instance->m_pollThreadState = POLL_THREAD_STATE_PING; - } - break; - - case POLL_THREAD_STATE_WAIT : - { - /* Wait for Hdmi is connected, in case it disconnected */ - //LOGINFO("19Aug2020-[01] -> POLL_THREAD_STATE_WAIT"); - _instance->m_sleepTime = HDMICECSINK_WAIT_FOR_HDMI_IN_MS; - - if ( _instance->m_isHdmiInConnected == true ) - { - _instance->m_pollThreadState = POLL_THREAD_STATE_POLL; - } - } - break; - - case POLL_THREAD_STATE_EXIT : - { - isExit = true; - _instance->m_sleepTime = 0; - } - break; - } - - std::unique_lock lk(_instance->m_pollExitMutex); - if ( _instance->m_ThreadExitCV.wait_for(lk, std::chrono::milliseconds(_instance->m_sleepTime)) == std::cv_status::timeout ) - continue; - else - LOGINFO("Thread is going to Exit m_pollThreadExit %d\n", _instance->m_pollThreadExit ); - - } - } - - void HdmiCecSink::allocateLAforTV() - { - bool gotLogicalAddress = false; - int addr = LogicalAddress::TV; - int i, j; - if (!(_instance->smConnection)) - return; - - for (i = 0; i< HDMICECSINK_NUMBER_TV_ADDR; i++) - { - /* poll for TV logical address - retry 5 times*/ - for (j = 0; j < 5; j++) - { - try { - smConnection->poll(LogicalAddress(addr), Throw_e()); - } - catch(CECNoAckException &e ) - { - LOGWARN("Poll caught %s \r\n",e.what()); - gotLogicalAddress = true; - break; - } - catch(Exception &e) - { - LOGWARN("Poll caught %s \r\n",e.what()); - usleep(250000); - } - } - if (gotLogicalAddress) - { - break; - } - addr = LogicalAddress::SPECIFIC_USE; - } - - if ( gotLogicalAddress ) - { - m_logicalAddressAllocated = addr; - } - else - { - m_logicalAddressAllocated = LogicalAddress::UNREGISTERED; - } - - LOGWARN("Logical Address for TV 0x%x \r\n",m_logicalAddressAllocated); - } - - void HdmiCecSink::allocateLogicalAddress(int deviceType) - { - if( deviceType == DeviceType::TV ) - { - allocateLAforTV(); - } - } - - void HdmiCecSink::CECEnable(void) - { - std::lock_guard lock(m_enableMutex); - JsonObject params; - LOGINFO("Entered CECEnable"); - if (cecEnableStatus) - { - LOGWARN("CEC Already Enabled"); - return; - } - - if(0 == libcecInitStatus) - { - try - { - LibCCEC::getInstance().init("HdmiCecSink"); - } - catch(InvalidStateException &e){ - LOGWARN("InvalidStateException caught in LibCCEC::init %s", e.what()); - } - catch(IOException &e){ - LOGWARN("IOException caught in LibCCEC::init %s", e.what()); - } - catch(...){ - LOGWARN("Exception caught in LibCCEC::init"); - } - } - libcecInitStatus++; - - //Acquire CEC Addresses - getPhysicalAddress(); - - smConnection = new Connection(LogicalAddress::UNREGISTERED,false,"ServiceManager::Connection::"); - smConnection->open(); - allocateLogicalAddress(DeviceType::TV); - LOGINFO("logical address allocalted: %x \n",m_logicalAddressAllocated); - if ( m_logicalAddressAllocated != LogicalAddress::UNREGISTERED && smConnection) - { - logicalAddress = LogicalAddress(m_logicalAddressAllocated); - LOGINFO(" add logical address %x \n",m_logicalAddressAllocated); - LibCCEC::getInstance().addLogicalAddress(logicalAddress); - smConnection->setSource(logicalAddress); - } - msgProcessor = new HdmiCecSinkProcessor(*smConnection); - msgFrameListener = new HdmiCecSinkFrameListener(*msgProcessor); - if(smConnection) - { - LOGWARN("Start Thread %p", smConnection ); - m_pollThreadState = POLL_THREAD_STATE_POLL; - m_pollNextState = POLL_THREAD_STATE_NONE; - m_pollThreadExit = false; - m_pollThread = std::thread(threadRun); - } - cecEnableStatus = true; - - params["cecEnable"] = string("true"); - sendNotify(eventString[HDMICECSINK_EVENT_CEC_ENABLED], params); - - return; - } - - void HdmiCecSink::CECDisable(void) - { - std::lock_guard lock(m_enableMutex); - JsonObject params; - LOGINFO("Entered CECDisable "); - if(!cecEnableStatus) - { - LOGWARN("CEC Already Disabled "); - return; - } - - if(m_currentArcRoutingState != ARC_STATE_ARC_TERMINATED) - { - stopArc(); - while(m_currentArcRoutingState != ARC_STATE_ARC_TERMINATED) - { - usleep(500000); - } - } - - LOGINFO(" CECDisable ARC stopped "); - cecEnableStatus = false; - if (smConnection != NULL) - { - LOGWARN("Stop Thread %p", smConnection ); - m_pollThreadExit = true; - m_ThreadExitCV.notify_one(); - - try - { - if (m_pollThread.joinable()) - { - LOGWARN("Join Thread %p", smConnection ); - m_pollThread.join(); - } - } - catch(const std::system_error& e) - { - LOGERR("system_error exception in thread join %s", e.what()); - } - catch(const std::exception& e) - { - LOGERR("exception in thread join %s", e.what()); - } - - m_pollThreadState = POLL_THREAD_STATE_NONE; - m_pollNextState = POLL_THREAD_STATE_NONE; - - LOGWARN("Deleted Thread %p", smConnection ); - - smConnection->close(); - delete smConnection; - smConnection = NULL; - } - - m_logicalAddressAllocated = LogicalAddress::UNREGISTERED; - m_currentArcRoutingState = ARC_STATE_ARC_TERMINATED; - if (m_audioStatusDetectionTimer.isActive()){ - m_audioStatusDetectionTimer.stop(); - } - m_isAudioStatusInfoUpdated = false; - m_audioStatusReceived = false; - m_audioStatusTimerStarted = false; - LOGINFO("CEC Disabled, reset the audio status info. m_isAudioStatusInfoUpdated :%d, m_audioStatusReceived :%d, m_audioStatusTimerStarted:%d ", m_isAudioStatusInfoUpdated,m_audioStatusReceived,m_audioStatusTimerStarted); - - - for(int i=0; i< 16; i++) - { - if (_instance->deviceList[i].m_isDevicePresent) - { - _instance->deviceList[i].clear(); - } - } - - if(1 == libcecInitStatus) - { - try - { - LibCCEC::getInstance().term(); - } - catch(InvalidStateException &e){ - LOGWARN("InvalidStateException caught in LibCCEC::term %s", e.what()); - } - catch(IOException &e){ - LOGWARN("IOException caught in LibCCEC::term %s", e.what()); - } - catch(...){ - LOGWARN("Exception caught in LibCCEC::term"); - } - } - - libcecInitStatus--; - LOGWARN("CEC Disabled %d",libcecInitStatus); - - params["cecEnable"] = string("false"); - sendNotify(eventString[HDMICECSINK_EVENT_CEC_ENABLED], params); - - return; - } - - - void HdmiCecSink::getPhysicalAddress() - { - LOGINFO("Entered getPhysicalAddress "); - - uint32_t physAddress = 0x0F0F0F0F; - - try { - LibCCEC::getInstance().getPhysicalAddress(&physAddress); - physical_addr = {(uint8_t)((physAddress >> 24) & 0xFF),(uint8_t)((physAddress >> 16) & 0xFF),(uint8_t) ((physAddress >> 8) & 0xFF),(uint8_t)((physAddress) & 0xFF)}; - LOGINFO("getPhysicalAddress: physicalAddress: %s ", physical_addr.toString().c_str()); - } - catch (const std::exception& e) - { - LOGWARN("exception caught from getPhysicalAddress"); - } - return; - } - - bool HdmiCecSink::getEnabled() - { - - - LOGINFO("getEnabled :%d ",cecEnableStatus); - if(true == cecEnableStatus) - return true; - else - return false; - } - - bool HdmiCecSink::getAudioDeviceConnectedStatus() - { - LOGINFO("getAudioDeviceConnectedStatus :%d ", hdmiCecAudioDeviceConnected); - if(true == hdmiCecAudioDeviceConnected) - return true; - else - return false; - } - //Arc Routing related functions - void HdmiCecSink::startArc() - { - if ( cecEnableStatus != true ) - { - LOGINFO("Initiate_Arc Cec is disabled-> EnableCEC first"); - return; - } - if(!HdmiCecSink::_instance) - return; - - LOGINFO("Current ARC State : %d\n", m_currentArcRoutingState); - - _instance->requestArcInitiation(); - - // start initiate ARC timer 3 sec - if (m_arcStartStopTimer.isActive()) - { - m_arcStartStopTimer.stop(); - } - m_arcstarting = true; - m_arcStartStopTimer.start((HDMISINK_ARC_START_STOP_MAX_WAIT_MS)); - - } - void HdmiCecSink::requestArcInitiation() - { - { - std::lock_guard lock(m_arcRoutingStateMutex); - m_currentArcRoutingState = ARC_STATE_REQUEST_ARC_INITIATION; - } - LOGINFO("requestArcInitiation release sem"); - _instance->m_semSignaltoArcRoutingThread.release(); - - } - void HdmiCecSink::stopArc() - { - if ( cecEnableStatus != true ) - { - LOGINFO("Initiate_Arc Cec is disabled-> EnableCEC first"); - return; - } - if(!HdmiCecSink::_instance) - return; - if(m_currentArcRoutingState == ARC_STATE_REQUEST_ARC_TERMINATION || m_currentArcRoutingState == ARC_STATE_ARC_TERMINATED) - { - LOGINFO("ARC is either Termination in progress or already Terminated"); - return; - } - - _instance->requestArcTermination(); - /* start a timer for 3 sec to get the desired ARC_STATE_ARC_TERMINATED */ - if (m_arcStartStopTimer.isActive()) - { - m_arcStartStopTimer.stop(); - } - /* m_arcstarting = true means starting the ARC start timer ,false means ARC stopping timer*/ - m_arcstarting = false; - m_arcStartStopTimer.start((HDMISINK_ARC_START_STOP_MAX_WAIT_MS)); - - - } - void HdmiCecSink::requestArcTermination() - { - { - std::lock_guard lock(m_arcRoutingStateMutex); - m_currentArcRoutingState = ARC_STATE_REQUEST_ARC_TERMINATION; - } - LOGINFO("requestArcTermination release sem"); - _instance->m_semSignaltoArcRoutingThread.release(); - - } - - void HdmiCecSink::Process_InitiateArc() - { - JsonObject params; - - LOGINFO("Command: INITIATE_ARC \n"); - - if(!HdmiCecSink::_instance) - return; - - //DD: Check cecSettingEnabled to prevent race conditions which gives immediate UI setting status - //Initiate ARC message may come from AVR/Soundbar while CEC disable is in-progress - if ( cecSettingEnabled != true ) - { - LOGINFO("Process InitiateArc from Audio device: Cec is disabled-> EnableCEC first"); - return; - } - - LOGINFO("Got : INITIATE_ARC and current Arcstate is %d\n",_instance->m_currentArcRoutingState); - - if (m_arcStartStopTimer.isActive()) - { - m_arcStartStopTimer.stop(); - } - if (powerState == DEVICE_POWER_STATE_ON ) { - LOGINFO("Notifying Arc Initiation event as power state is %s", powerState ? "Off" : "On"); - { - std::lock_guard lock(_instance->m_arcRoutingStateMutex); - _instance->m_currentArcRoutingState = ARC_STATE_ARC_INITIATED; - } - _instance->m_semSignaltoArcRoutingThread.release(); - LOGINFO("Got : ARC_INITIATED and notify Device setting"); - params["status"] = string("success"); - sendNotify(eventString[HDMICECSINK_EVENT_ARC_INITIATION_EVENT], params); - } else { - LOGINFO("Not notifying Arc Initiation event as power state is %s", powerState ? "Off" : "On"); - } - - } - void HdmiCecSink::Process_TerminateArc() - { - JsonObject params; - - LOGINFO("Command: TERMINATE_ARC current arc state %d \n",HdmiCecSink::_instance->m_currentArcRoutingState); - if (m_arcStartStopTimer.isActive()) - { - m_arcStartStopTimer.stop(); - } - { - std::lock_guard lock(m_arcRoutingStateMutex); - HdmiCecSink::_instance->m_currentArcRoutingState = ARC_STATE_ARC_TERMINATED; - } - _instance->m_semSignaltoArcRoutingThread.release(); - - // trigger callback to Device setting informing to TERMINATE_ARC - LOGINFO("Got : ARC_TERMINATED and notify Device setting"); - params["status"] = string("success"); - sendNotify(eventString[HDMICECSINK_EVENT_ARC_TERMINATION_EVENT], params); - } - - void HdmiCecSink::threadSendKeyEvent() - { - if(!HdmiCecSink::_instance) - return; - - SendKeyInfo keyInfo = {-1,-1}; - - while(!_instance->m_sendKeyEventThreadExit) - { - keyInfo.logicalAddr = -1; - keyInfo.keyCode = -1; - { - // Wait for a message to be added to the queue - std::unique_lock lk(_instance->m_sendKeyEventMutex); - _instance->m_sendKeyCV.wait(lk, []{return (_instance->m_sendKeyEventThreadRun == true);}); - } - - if (_instance->m_sendKeyEventThreadExit == true) - { - LOGINFO(" threadSendKeyEvent Exiting"); - _instance->m_sendKeyEventThreadRun = false; - break; - } - - if (_instance->m_SendKeyQueue.empty()) { - _instance->m_sendKeyEventThreadRun = false; - continue; - } - - keyInfo = _instance->m_SendKeyQueue.front(); - _instance->m_SendKeyQueue.pop(); - - if(keyInfo.UserControl == "sendUserControlPressed" ) - { - LOGINFO("sendUserControlPressed : logical addr:0x%x keyCode: 0x%x queue size :%zu \n",keyInfo.logicalAddr,keyInfo.keyCode,_instance->m_SendKeyQueue.size()); - _instance->sendUserControlPressed(keyInfo.logicalAddr,keyInfo.keyCode); - } - else if(keyInfo.UserControl == "sendUserControlReleased") - { - LOGINFO("sendUserControlReleased : logical addr:0x%x queue size :%zu \n",keyInfo.logicalAddr,_instance->m_SendKeyQueue.size()); - _instance->sendUserControlReleased(keyInfo.logicalAddr); - } - else - { - LOGINFO("sendKeyPressEvent : logical addr:0x%x keyCode: 0x%x queue size :%zu \n",keyInfo.logicalAddr,keyInfo.keyCode,_instance->m_SendKeyQueue.size()); - _instance->sendKeyPressEvent(keyInfo.logicalAddr,keyInfo.keyCode); - _instance->sendKeyReleaseEvent(keyInfo.logicalAddr); - } - - if((_instance->m_SendKeyQueue.size()<=1 || (_instance->m_SendKeyQueue.size() % 2 == 0)) && ((keyInfo.keyCode == VOLUME_UP) || (keyInfo.keyCode == VOLUME_DOWN) || (keyInfo.keyCode == MUTE)) ) - { - if(keyInfo.keyCode == MUTE) - { - _instance->sendGiveAudioStatusMsg(); - } - else - { - LOGINFO("m_isAudioStatusInfoUpdated :%d, m_audioStatusReceived :%d, m_audioStatusTimerStarted:%d ",_instance->m_isAudioStatusInfoUpdated,_instance->m_audioStatusReceived,_instance->m_audioStatusTimerStarted); - if (!_instance->m_isAudioStatusInfoUpdated) - { - if ( !(_instance->m_audioStatusDetectionTimer.isActive())) - { - LOGINFO("Audio status info not updated. Starting the Timer!"); - _instance->m_audioStatusTimerStarted = true; - _instance->m_audioStatusDetectionTimer.start((HDMICECSINK_UPDATE_AUDIO_STATUS_INTERVAL_MS)); - } - LOGINFO("m_isAudioStatusInfoUpdated :%d, m_audioStatusReceived :%d, m_audioStatusTimerStarted:%d ", _instance->m_isAudioStatusInfoUpdated,_instance->m_audioStatusReceived,_instance->m_audioStatusTimerStarted); - } - else - { - if (!_instance->m_audioStatusReceived){ - _instance->sendGiveAudioStatusMsg(); - } - } - } - } - - }//while(!_instance->m_sendKeyEventThreadExit) - }//threadSendKeyEvent - - void HdmiCecSink::audioStatusTimerFunction() - { - m_audioStatusTimerStarted = false; - m_isAudioStatusInfoUpdated = true; - LOGINFO("Timer Expired. Requesting the AudioStatus since not received.\n"); - sendGiveAudioStatusMsg(); - LOGINFO("m_isAudioStatusInfoUpdated :%d, m_audioStatusReceived :%d, m_audioStatusTimerStarted:%d ", m_isAudioStatusInfoUpdated,m_audioStatusReceived,m_audioStatusTimerStarted); - } - - void HdmiCecSink::threadArcRouting() - { - bool isExit = false; - uint32_t currentArcRoutingState; - - if(!HdmiCecSink::_instance) - return; - - LOGINFO("Running threadArcRouting"); - _instance->getHdmiArcPortID(); - - while(1) - { - - _instance->m_semSignaltoArcRoutingThread.acquire(); - - - - { - LOGINFO(" threadArcRouting Got semaphore"); - std::lock_guard lock(_instance->m_arcRoutingStateMutex); - - currentArcRoutingState = _instance->m_currentArcRoutingState; - - LOGINFO(" threadArcRouting Got Sem arc state %d",currentArcRoutingState); - } - - switch (currentArcRoutingState) - { - - case ARC_STATE_REQUEST_ARC_INITIATION : - { - - _instance->systemAudioModeRequest(); - _instance->Send_Request_Arc_Initiation_Message(); - - } - break; - case ARC_STATE_ARC_INITIATED : - { - _instance->Send_Report_Arc_Initiated_Message(); - } - break; - case ARC_STATE_REQUEST_ARC_TERMINATION : - { - - _instance->Send_Request_Arc_Termination_Message(); - - } - break; - case ARC_STATE_ARC_TERMINATED : - { - _instance->Send_Report_Arc_Terminated_Message(); - } - break; - case ARC_STATE_ARC_EXIT : - { - isExit = true; - } - break; - } - - if (isExit == true) - { - LOGINFO(" threadArcRouting EXITing"); - break; - } - }//while(1) - }//threadArcRouting - - void HdmiCecSink::Send_Request_Arc_Initiation_Message() - { - if(!HdmiCecSink::_instance) - return; - if(!(_instance->smConnection)) - return; - LOGINFO(" Send_Request_Arc_Initiation_Message "); - _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(RequestArcInitiation()), 1000); - - } - void HdmiCecSink::Send_Report_Arc_Initiated_Message() - { - if(!HdmiCecSink::_instance) - return; - if(!(_instance->smConnection)) - return; - _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(ReportArcInitiation()), 1000); - - } - void HdmiCecSink::Send_Request_Arc_Termination_Message() - { - - if(!HdmiCecSink::_instance) - return; - if(!(_instance->smConnection)) - return; - _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(RequestArcTermination()), 1000); - } - - void HdmiCecSink::Send_Report_Arc_Terminated_Message() - { - if(!HdmiCecSink::_instance) - return; - if(!(_instance->smConnection)) - return; - _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(ReportArcTermination()), 1000); - - } - - void HdmiCecSink::getHdmiArcPortID() - { - int err; - dsGetHDMIARCPortIdParam_t param; - err = IARM_Bus_Call(IARM_BUS_DSMGR_NAME, - (char *)IARM_BUS_DSMGR_API_dsGetHDMIARCPortId, - (void *)¶m, - sizeof(param)); - if (IARM_RESULT_SUCCESS == err) - { - LOGINFO("HDMI ARC port ID HdmiArcPortID=[%d] \n", param.portId); - HdmiArcPortID = param.portId; - } - } - - void HdmiCecSink::getCecVersion() - { - RFC_ParamData_t param = {0}; - WDMP_STATUS status = getRFCParameter((char*)"thunderapi", TR181_HDMICECSINK_CEC_VERSION, ¶m); - if(WDMP_SUCCESS == status && param.type == WDMP_STRING) { - LOGINFO("CEC Version from RFC = [%s] \n", param.value); - cecVersion = atof(param.value); - } - else { - LOGINFO("Error while fetching CEC Version from RFC "); - } - } - } // namespace Plugin } // namespace WPEFrameworklk diff --git a/HdmiCecSink/HdmiCecSink.h b/HdmiCecSink/HdmiCecSink.h index 418fb134..e0f61176 100644 --- a/HdmiCecSink/HdmiCecSink.h +++ b/HdmiCecSink/HdmiCecSink.h @@ -20,456 +20,27 @@ #pragma once #include -#include "ccec/FrameListener.hpp" -#include "ccec/Connection.hpp" +#include +#include -#include "libIARM.h" -#include "ccec/Assert.hpp" -#include "ccec/Messages.hpp" -#include "ccec/MessageDecoder.hpp" -#include "ccec/MessageProcessor.hpp" +#include #undef Assert // this define from Connection.hpp conflicts with WPEFramework #include "Module.h" -#include "tptimer.h" -#include -#include -#include -#include -#include "UtilsLogging.h" -#include -#include "PowerManagerInterface.h" +#include "UtilsBIT.h" +#include "UtilsThreadRAII.h" -using namespace WPEFramework; -using PowerState = WPEFramework::Exchange::IPowerManager::PowerState; -using ThermalTemperature = WPEFramework::Exchange::IPowerManager::ThermalTemperature; +#include +#include +#include +using namespace WPEFramework; namespace WPEFramework { namespace Plugin { - class HdmiCecSinkFrameListener : public FrameListener - { - public: - HdmiCecSinkFrameListener(MessageProcessor &processor) : processor(processor) {} - void notify(const CECFrame &in) const; - ~HdmiCecSinkFrameListener() {} - private: - MessageProcessor &processor; - }; - - class HdmiCecSinkProcessor : public MessageProcessor - { - public: - HdmiCecSinkProcessor(Connection &conn) : conn(conn) {} - void process (const ActiveSource &msg, const Header &header); - void process (const InActiveSource &msg, const Header &header); - void process (const ImageViewOn &msg, const Header &header); - void process (const TextViewOn &msg, const Header &header); - void process (const RequestActiveSource &msg, const Header &header); - void process (const Standby &msg, const Header &header); - void process (const GetCECVersion &msg, const Header &header); - void process (const CECVersion &msg, const Header &header); - void process (const SetMenuLanguage &msg, const Header &header); - void process (const GiveOSDName &msg, const Header &header); - void process (const GivePhysicalAddress &msg, const Header &header); - void process (const GiveDeviceVendorID &msg, const Header &header); - void process (const SetOSDString &msg, const Header &header); - void process (const SetOSDName &msg, const Header &header); - void process (const RoutingChange &msg, const Header &header); - void process (const RoutingInformation &msg, const Header &header); - void process (const SetStreamPath &msg, const Header &header); - void process (const GetMenuLanguage &msg, const Header &header); - void process (const ReportPhysicalAddress &msg, const Header &header); - void process (const DeviceVendorID &msg, const Header &header); - void process (const GiveDevicePowerStatus &msg, const Header &header); - void process (const ReportPowerStatus &msg, const Header &header); - void process (const FeatureAbort &msg, const Header &header); - void process (const Abort &msg, const Header &header); - void process (const Polling &msg, const Header &header); - void process (const InitiateArc &msg, const Header &header); - void process (const TerminateArc &msg, const Header &header); - void process (const ReportShortAudioDescriptor &msg, const Header &header); - void process (const SetSystemAudioMode &msg, const Header &header); - void process (const ReportAudioStatus &msg, const Header &header); - void process (const GiveFeatures &msg, const Header &header); - void process (const RequestCurrentLatency &msg, const Header &header); - private: - Connection conn; - void printHeader(const Header &header) - { - printf("Header : From : %s \n", header.from.toString().c_str()); - printf("Header : to : %s \n", header.to.toString().c_str()); - } - - }; - - class CECDeviceParams { - public: - - enum { - REQUEST_NONE = 0, - REQUEST_PHISICAL_ADDRESS = 1, - REQUEST_CEC_VERSION, - REQUEST_DEVICE_VENDOR_ID, - REQUEST_POWER_STATUS, - REQUEST_OSD_NAME, - }; - - enum { - REQUEST_DONE = 0, - REQUEST_NOT_DONE, - REQUEST_TIME_ELAPSED, - }; - - DeviceType m_deviceType; - LogicalAddress m_logicalAddress; - PhysicalAddress m_physicalAddr; - Version m_cecVersion; - VendorID m_vendorID; - OSDName m_osdName; - PowerStatus m_powerStatus; - bool m_isDevicePresent; - bool m_isDeviceDisconnected; - Language m_currentLanguage; - bool m_isActiveSource; - bool m_isDeviceTypeUpdated; - bool m_isPAUpdated; - bool m_isVersionUpdated; - bool m_isOSDNameUpdated; - bool m_isVendorIDUpdated; - bool m_isPowerStatusUpdated; - int m_isRequested; - int m_isRequestRetry; - std::chrono::system_clock::time_point m_requestTime; - std::vector m_featureAborts; - std::chrono::system_clock::time_point m_lastPowerUpdateTime; - - CECDeviceParams() - : m_deviceType(0), m_logicalAddress(0),m_physicalAddr(0x0f,0x0f,0x0f,0x0f),m_cecVersion(0),m_vendorID(0,0,0),m_osdName(""),m_powerStatus(0),m_currentLanguage("") - { - m_isDevicePresent = false; - m_isActiveSource = false; - m_isPAUpdated = false; - m_isVersionUpdated = false; - m_isOSDNameUpdated = false; - m_isVendorIDUpdated = false; - m_isPowerStatusUpdated = false; - m_isDeviceDisconnected = false; - m_isDeviceTypeUpdated = false; - m_isRequestRetry = 0; - } - - void clear( ) - { - m_deviceType = 0; - m_logicalAddress = 0; - m_physicalAddr = PhysicalAddress(0x0f,0x0f,0x0f,0x0f); - m_cecVersion = 0; - m_vendorID = VendorID(0,0,0); - m_osdName = ""; - m_powerStatus = 0; - m_currentLanguage = ""; - m_isDevicePresent = false; - m_isActiveSource = false; - m_isPAUpdated = false; - m_isVersionUpdated = false; - m_isOSDNameUpdated = false; - m_isVendorIDUpdated = false; - m_isPowerStatusUpdated = false; - m_isDeviceDisconnected = false; - m_isDeviceTypeUpdated = false; - } - - void printVariable() - { - LOGWARN("Device LogicalAddress %s", m_logicalAddress.toString().c_str()); - LOGWARN("Device Type %s", m_deviceType.toString().c_str()); - LOGWARN("Device Present %d", m_isDevicePresent); - LOGWARN("Active Source %d", m_isActiveSource); - LOGWARN("PA Updated %d", m_isPAUpdated); - LOGWARN("Version Updated %d", m_isVersionUpdated); - LOGWARN("OSDName Updated %d", m_isOSDNameUpdated); - LOGWARN("PowerStatus Updated %d", m_isPowerStatusUpdated); - LOGWARN("VendorID Updated %d", m_isPowerStatusUpdated); - LOGWARN("CEC Version : %s", m_cecVersion.toString().c_str()); - LOGWARN("Vendor ID : %s", m_vendorID.toString().c_str()); - LOGWARN("PhisicalAddress : %s", m_physicalAddr.toString().c_str()); - LOGWARN("OSDName : %s", m_osdName.toString().c_str()); - LOGWARN("Power Status : %s", m_powerStatus.toString().c_str()); - LOGWARN("Language : %s", m_currentLanguage.toString().c_str()); - } - - bool isAllUpdated() { - if( !m_isPAUpdated - || !m_isVersionUpdated - || !m_isOSDNameUpdated - || !m_isVendorIDUpdated - || !m_isPowerStatusUpdated - || !m_isDeviceTypeUpdated ){ - return false; - } - return true; - } - - void update( const DeviceType &deviceType ) { - m_deviceType = deviceType; - m_isDeviceTypeUpdated = true; - } - - void update( const PhysicalAddress &physical_addr ) { - m_physicalAddr = physical_addr; - m_isPAUpdated = true; - } - - void update ( const VendorID &vendorId) { - m_vendorID = vendorId; - m_isVendorIDUpdated = true; - } - - void update ( const Version &version ) { - m_cecVersion = version; - m_isVersionUpdated = true; - } - - void update ( const OSDName &osdName ) { - m_osdName = osdName; - m_isOSDNameUpdated = true; - } - - void update ( const PowerStatus &status ) { - m_powerStatus = status; - m_isPowerStatusUpdated = true; - m_lastPowerUpdateTime = std::chrono::system_clock::now(); - } - }; - - class DeviceNode { - public: - uint8_t m_childsLogicalAddr[LogicalAddress::UNREGISTERED]; - - DeviceNode() { - int i; - for (i = 0; i < LogicalAddress::UNREGISTERED; i++ ) - { - m_childsLogicalAddr[i] = LogicalAddress::UNREGISTERED; - } - } - - } ; - typedef struct sendKeyInfo - { - int logicalAddr; - int keyCode; - string UserControl; - }SendKeyInfo; - - class HdmiPortMap { - public: - uint8_t m_portID; - bool m_isConnected; - LogicalAddress m_logicalAddr; - PhysicalAddress m_physicalAddr; - DeviceNode m_deviceChain[3]; - - HdmiPortMap(uint8_t portID) : m_portID(portID), - m_logicalAddr(LogicalAddress::UNREGISTERED), - m_physicalAddr(portID+1,0,0,0) - { - m_isConnected = false; - } - - void update(bool isConnected) - { - m_isConnected = isConnected; - } - - void update( const LogicalAddress &addr ) - { - m_logicalAddr = addr; - } - - void addChild( const LogicalAddress &logical_addr, const PhysicalAddress &physical_addr ) - { - LOGINFO(" logicalAddr = %d, phisicalAddr = %s", m_logicalAddr.toInt(), physical_addr.toString().c_str()); - - if ( m_logicalAddr.toInt() != LogicalAddress::UNREGISTERED && - m_logicalAddr.toInt() != logical_addr.toInt() ) - { - LOGINFO(" update own logicalAddr = %d, new devcie logicalAddress = %d", m_logicalAddr.toInt(), logical_addr.toInt() ); - /* check matching with this port's physical address */ - if( physical_addr.getByteValue(0) == m_physicalAddr.getByteValue(0) && - physical_addr.getByteValue(1) != 0 ) - { - if ( physical_addr.getByteValue(3) != 0 ) - { - m_deviceChain[2].m_childsLogicalAddr[physical_addr.getByteValue(3) - 1] = logical_addr.toInt(); - } - else if ( physical_addr.getByteValue(2) != 0 ) - { - m_deviceChain[1].m_childsLogicalAddr[physical_addr.getByteValue(2) - 1] = logical_addr.toInt(); - } - else if ( physical_addr.getByteValue(1) != 0 ) - { - m_deviceChain[0].m_childsLogicalAddr[physical_addr.getByteValue(1) - 1] = logical_addr.toInt(); - } - } - } - else if ( physical_addr == m_physicalAddr ) - { - update(logical_addr); - LOGINFO(" update own logicalAddr = %d", m_logicalAddr.toInt()); - } - } - - void removeChild( PhysicalAddress &physical_addr ) - { - if ( m_logicalAddr.toInt() != LogicalAddress::UNREGISTERED ) - { - /* check matching with this port's physical address */ - if( physical_addr.getByteValue(0) == m_physicalAddr.getByteValue(0) && - physical_addr.getByteValue(1) != 0 ) - { - if ( physical_addr.getByteValue(3) != 0 ) - { - m_deviceChain[2].m_childsLogicalAddr[physical_addr.getByteValue(3) - 1] = LogicalAddress::UNREGISTERED; - } - else if ( physical_addr.getByteValue(2) != 0 ) - { - m_deviceChain[1].m_childsLogicalAddr[physical_addr.getByteValue(2) - 1] = LogicalAddress::UNREGISTERED; - } - else if ( physical_addr.getByteValue(1) != 0 ) - { - m_deviceChain[0].m_childsLogicalAddr[physical_addr.getByteValue(1) - 1] = LogicalAddress::UNREGISTERED; - } - } - } - } - - void getRoute( PhysicalAddress &physical_addr, std::vector & route ) - { - LOGINFO(" logicalAddr = %d, phsical = %s", m_logicalAddr.toInt(), physical_addr.toString().c_str()); - - if ( m_logicalAddr.toInt() != LogicalAddress::UNREGISTERED ) - { - LOGINFO(" search for logicalAddr = %d", m_logicalAddr.toInt()); - /* check matching with this port's physical address */ - if( physical_addr.getByteValue(0) == m_physicalAddr.getByteValue(0) && - physical_addr.getByteValue(1) != 0 ) - { - if ( physical_addr.getByteValue(3) != 0 ) - { - route.push_back(m_deviceChain[2].m_childsLogicalAddr[physical_addr.getByteValue(3) - 1]); - } - - if ( physical_addr.getByteValue(2) != 0 ) - { - route.push_back(m_deviceChain[1].m_childsLogicalAddr[physical_addr.getByteValue(2) - 1]); - } - - if ( physical_addr.getByteValue(1) != 0 ) - { - route.push_back(m_deviceChain[0].m_childsLogicalAddr[physical_addr.getByteValue(1) - 1]); - } - - route.push_back(m_logicalAddr.toInt()); - } - else - { - route.push_back(m_logicalAddr.toInt()); - LOGINFO("logicalAddr = %d, physical = %s", m_logicalAddr.toInt(), m_physicalAddr.toString().c_str()); - } - } - } - }; - - class binary_semaphore { - - public: - - explicit binary_semaphore(int init_count = count_max) - - : count_(init_count) {} - - - - // P-operation / acquire - - void wait() - - { - - std::unique_lock lk(m_); - - cv_.wait(lk, [=]{ return 0 < count_; }); - - --count_; - - } - - bool try_wait() - - { - - std::lock_guard lk(m_); - - if (0 < count_) { - - --count_; - - return true; - - } else { - - return false; - - } - - } - - // V-operation / release - - void signal() - - { - - std::lock_guard lk(m_); - - if (count_ < count_max) { - - ++count_; - - cv_.notify_one(); - - } - - } - - - - // Lockable requirements - - void acquire() { wait(); } - - bool try_lock() { return try_wait(); } - - void release() { signal(); } - - - -private: - - static const int count_max = 1; - - int count_; - - std::mutex m_; - - std::condition_variable cv_; - -}; // 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. @@ -484,262 +55,211 @@ namespace WPEFramework { // will receive a JSONRPC message as a notification, in case this method is called. class HdmiCecSink : public PluginHost::IPlugin, public PluginHost::JSONRPC { - enum { - POLL_THREAD_STATE_NONE, - POLL_THREAD_STATE_IDLE, - POLL_THREAD_STATE_POLL, - POLL_THREAD_STATE_PING, - POLL_THREAD_STATE_INFO, - POLL_THREAD_STATE_WAIT, - POLL_THREAD_STATE_CLEAN, - POLL_THREAD_STATE_UPDATE, - POLL_THREAD_STATE_EXIT, - }; - enum { - ARC_STATE_REQUEST_ARC_INITIATION, - ARC_STATE_ARC_INITIATED, - ARC_STATE_REQUEST_ARC_TERMINATION, - ARC_STATE_ARC_TERMINATED, - ARC_STATE_ARC_EXIT - }; - enum { - VOLUME_UP = 0x41, - VOLUME_DOWN = 0x42, - MUTE = 0x43, - UP = 0x01, - DOWN = 0x02, - LEFT = 0x03, - RIGHT = 0x04, - SELECT = 0x00, - HOME = 0x09, - BACK = 0x0D, - NUMBER_0 = 0x20, - NUMBER_1 = 0x21, - NUMBER_2 = 0x22, - NUMBER_3 = 0x23, - NUMBER_4 = 0x24, - NUMBER_5 = 0x25, - NUMBER_6 = 0x26, - NUMBER_7 = 0x27, - NUMBER_8 = 0x28, - NUMBER_9 = 0x29 - }; - public: - HdmiCecSink(); - virtual ~HdmiCecSink(); - virtual const string Initialize(PluginHost::IShell* shell) override; - virtual void Deinitialize(PluginHost::IShell* service) override; - virtual string Information() const override { return {}; } - static HdmiCecSink* _instance; - CECDeviceParams deviceList[16]; - std::vector hdmiInputs; - int m_currentActiveSource; - void updateInActiveSource(const int logical_address, const InActiveSource &source ); - void updateActiveSource(const int logical_address, const ActiveSource &source ); - void updateTextViewOn(const int logicalAddress); - void updateImageViewOn(const int logicalAddress); - void updateDeviceChain(const LogicalAddress &logicalAddress, const PhysicalAddress &phy_addr); - void getActiveRoute(const LogicalAddress &logicalAddress, std::vector &route); - void removeDevice(const int logicalAddress); - void addDevice(const int logicalAddress); - void printDeviceList(); - void setStreamPath( const PhysicalAddress &physical_addr); - void setRoutingChange(const std::string &from, const std::string &to); - void sendStandbyMessage(); - void setCurrentLanguage(const Language &lang); - void sendMenuLanguage(); - void setActiveSource(bool isResponse); - void requestActiveSource(); - void startArc(); - void stopArc(); - void Process_InitiateArc(); - void Process_TerminateArc(); - void updateArcState(); - void requestShortaudioDescriptor(); - void Send_ShortAudioDescriptor_Event(JsonArray audiodescriptor); - void Process_ShortAudioDescriptor_msg(const ReportShortAudioDescriptor &msg); - void Process_SetSystemAudioMode_msg(const SetSystemAudioMode &msg); - void sendDeviceUpdateInfo(const int logicalAddress); - void sendFeatureAbort(const LogicalAddress logicalAddress, const OpCode feature, const AbortReason reason); - void reportFeatureAbortEvent(const LogicalAddress logicalAddress, const OpCode feature, const AbortReason reason); - void systemAudioModeRequest(); - void SendStandbyMsgEvent(const int logicalAddress); - void requestAudioDevicePowerStatus(); - void reportAudioDevicePowerStatusInfo(const int logicalAddress, const int powerStatus); - void updateCurrentLatency(int videoLatency, bool lowLatencyMode, int audioOutputCompensated, int audioOutputDelay); - void setLatencyInfo(); - void Process_ReportAudioStatus_msg(const ReportAudioStatus msg); - void sendKeyPressEvent(const int logicalAddress, int keyCode); - void sendKeyReleaseEvent(const int logicalAddress); - void sendUserControlPressed(const int logicalAddress, int keyCode); - void sendUserControlReleased(const int logicalAddress); - void onPowerModeChanged(const PowerState currentState, const PowerState newState); - void registerEventHandlers(); - void sendGiveAudioStatusMsg(); - void getHdmiArcPortID(); - int m_numberOfDevices; /* Number of connected devices othethan own device */ - bool m_audioDevicePowerStatusRequested; - - BEGIN_INTERFACE_MAP(HdmiCecSink) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - END_INTERFACE_MAP - - private: - class PowerManagerNotification : public Exchange::IPowerManager::IModeChangedNotification { private: - PowerManagerNotification(const PowerManagerNotification&) = delete; - PowerManagerNotification& operator=(const PowerManagerNotification&) = delete; + class Notification : public RPC::IRemoteConnection::INotification, + public Exchange::IHdmiCecSink::INotification + { + private: + Notification() = delete; + Notification(const Notification&) = delete; + Notification& operator=(const Notification&) = delete; + + public: + explicit Notification(HdmiCecSink* parent) + : _parent(*parent) + { + ASSERT(parent != nullptr); + } + + virtual ~Notification() + { + } + + BEGIN_INTERFACE_MAP(Notification) + INTERFACE_ENTRY(Exchange::IHdmiCecSink::INotification) + INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) + END_INTERFACE_MAP + + void Activated(RPC::IRemoteConnection*) override + { + } + + void Deactivated(RPC::IRemoteConnection *connection) override + { + _parent.Deactivated(connection); + } + + void ArcInitiationEvent(const string success) override + { + LOGINFO("ArcInitiationEvent"); + LOGINFO("success: %s", success.c_str()); + Exchange::JHdmiCecSink::Event::ArcInitiationEvent(_parent, success); + } + + void ArcTerminationEvent(const string success) override + { + LOGINFO("ArcTerminationEvent"); + LOGINFO("success: %s", success.c_str()); + Exchange::JHdmiCecSink::Event::ArcTerminationEvent(_parent, success); + } + + void OnActiveSourceChange(const int logicalAddress, const string physicalAddress) override + { + LOGINFO("OnActiveSourceChange"); + LOGINFO("logicalAddress: %d, physicalAddress: %s", logicalAddress, physicalAddress.c_str()); + Exchange::JHdmiCecSink::Event::OnActiveSourceChange(_parent, logicalAddress, physicalAddress); + } + + void OnDeviceAdded(const int logicalAddress) override + { + LOGINFO("OnDeviceAdded"); + LOGINFO("logicalAddress: %d", logicalAddress); + Exchange::JHdmiCecSink::Event::OnDeviceAdded(_parent, logicalAddress); + } + + void OnDeviceInfoUpdated(const int logicalAddress) override + { + LOGINFO("OnDeviceInfoUpdated"); + LOGINFO("logicalAddress: %d", logicalAddress); + Exchange::JHdmiCecSink::Event::OnDeviceInfoUpdated(_parent, logicalAddress); + } + + void OnDeviceRemoved(const int logicalAddress) override + { + LOGINFO("OnDeviceRemoved"); + LOGINFO("logicalAddress: %d", logicalAddress); + Exchange::JHdmiCecSink::Event::OnDeviceRemoved(_parent, logicalAddress); + } + + void OnImageViewOnMsg(const int logicalAddress) override + { + LOGINFO("OnImageViewOnMsg"); + LOGINFO("logicalAddress: %d", logicalAddress); + Exchange::JHdmiCecSink::Event::OnImageViewOnMsg(_parent, logicalAddress); + } + + void OnInActiveSource(const int logicalAddress, const string physicalAddress) override + { + LOGINFO("OnInActiveSource"); + LOGINFO("logicalAddress: %d, physicalAddress: %s", logicalAddress, physicalAddress.c_str()); + Exchange::JHdmiCecSink::Event::OnInActiveSource(_parent, logicalAddress, physicalAddress); + } + + void OnTextViewOnMsg(const int logicalAddress) override + { + LOGINFO("OnTextViewOnMsg"); + LOGINFO("logicalAddress: %d", logicalAddress); + Exchange::JHdmiCecSink::Event::OnTextViewOnMsg(_parent, logicalAddress); + } + + void OnWakeupFromStandby(const int logicalAddress) override + { + LOGINFO("OnWakeupFromStandby"); + LOGINFO("logicalAddress: %d", logicalAddress); + Exchange::JHdmiCecSink::Event::OnWakeupFromStandby(_parent, logicalAddress); + } + + void ReportAudioDeviceConnectedStatus(const string status, const string audioDeviceConnected) override + { + LOGINFO("ReportAudioDeviceConnectedStatus"); + LOGINFO("status: %s, audioDeviceConnected: %s", status.c_str(), audioDeviceConnected.c_str()); + Exchange::JHdmiCecSink::Event::ReportAudioDeviceConnectedStatus(_parent, status, audioDeviceConnected); + } + + void ReportAudioStatusEvent(const int muteStatus, const int volumeLevel) override + { + LOGINFO("ReportAudioStatusEvent"); + LOGINFO("muteStatus: %d, volumeLevel: %d", muteStatus, volumeLevel); + Exchange::JHdmiCecSink::Event::ReportAudioStatusEvent(_parent, muteStatus, volumeLevel); + } + + void ReportFeatureAbortEvent(const int logicalAddress, const int opcode, const int FeatureAbortReason) override + { + LOGINFO("ReportFeatureAbortEvent"); + LOGINFO("logicalAddress: %d, opcode: %d, FeatureAbortReason: %d", logicalAddress, opcode, FeatureAbortReason); + Exchange::JHdmiCecSink::Event::ReportFeatureAbortEvent(_parent, logicalAddress, opcode, FeatureAbortReason); + } + + void ReportCecEnabledEvent(const string cecEnable) override + { + LOGINFO("ReportCecEnabledEvent"); + LOGINFO("cecEnable: %s", cecEnable.c_str()); + Exchange::JHdmiCecSink::Event::ReportCecEnabledEvent(_parent, cecEnable); + } + + void SetSystemAudioModeEvent(const string audioMode) override + { + LOGINFO("SetSystemAudioModeEvent"); + LOGINFO("audioMode: %s", audioMode.c_str()); + Exchange::JHdmiCecSink::Event::SetSystemAudioModeEvent(_parent, audioMode); + } + + void ShortAudiodescriptorEvent(const string& jsonresponse) override + { + LOGINFO("ShortAudiodescriptorEvent"); + Exchange::JHdmiCecSink::Event::ShortAudiodescriptorEvent(_parent, jsonresponse); + } + + void StandbyMessageReceived(const int logicalAddress) override + { + LOGINFO("StandbyMessageReceived"); + LOGINFO("logicalAddress: %d", logicalAddress); + Exchange::JHdmiCecSink::Event::StandbyMessageReceived(_parent, logicalAddress); + } + + void ReportAudioDevicePowerStatus(const int powerStatus) override + { + LOGINFO("ReportAudioDevicePowerStatus"); + LOGINFO("powerStatus: %d", powerStatus); + Exchange::JHdmiCecSink::Event::ReportAudioDevicePowerStatus(_parent, powerStatus); + } + + private: + HdmiCecSink &_parent; + + }; public: - explicit PowerManagerNotification(HdmiCecSink& parent) - : _parent(parent) + // We do not allow this plugin to be copied !! + HdmiCecSink(const HdmiCecSink&) = delete; + HdmiCecSink& operator=(const HdmiCecSink&) = delete; + + HdmiCecSink() + : PluginHost::IPlugin() + , PluginHost::JSONRPC() + , _service(nullptr) + , _notification(this) + , _hdmiCecSink(nullptr) + , _connectionId(0) { - } - ~PowerManagerNotification() override = default; - public: - void OnPowerModeChanged(const PowerState currentState, const PowerState newState) override - { - _parent.onPowerModeChanged(currentState, newState); } - - template - T* baseInterface() + virtual ~HdmiCecSink() { - static_assert(std::is_base_of(), "base type mismatch"); - return static_cast(this); + } - - BEGIN_INTERFACE_MAP(PowerManagerNotification) - INTERFACE_ENTRY(Exchange::IPowerManager::IModeChangedNotification) + + BEGIN_INTERFACE_MAP(HdmiCecSink) + INTERFACE_ENTRY(PluginHost::IPlugin) + INTERFACE_ENTRY(PluginHost::IDispatcher) + INTERFACE_AGGREGATE(Exchange::IHdmiCecSink, _hdmiCecSink) END_INTERFACE_MAP + // IPlugin methods + // ------------------------------------------------------------------------------------------------------- + const string Initialize(PluginHost::IShell* service) override; + void Deinitialize(PluginHost::IShell* service) override; + string Information() const override; + //Begin methods + + private: + void Deactivated(RPC::IRemoteConnection* connection); + private: - HdmiCecSink& _parent; - }; - // We do not allow this plugin to be copied !! - HdmiCecSink(const HdmiCecSink&) = delete; - HdmiCecSink& operator=(const HdmiCecSink&) = delete; - - //Begin methods - uint32_t setEnabledWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getEnabledWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setOSDNameWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getOSDNameWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setVendorIdWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getVendorIdWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t printDeviceListWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setActivePathWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setRoutingChangeWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getDeviceListWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getActiveSourceWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setActiveSourceWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getActiveRouteWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t requestActiveSourceWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setArcEnableDisableWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setMenuLanguageWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t requestShortAudioDescriptorWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t sendStandbyMessageWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t sendAudioDevicePowerOnMsgWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t sendRemoteKeyPressWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t sendUserControlPressedWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t sendUserControlReleasedWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t sendGiveAudioStatusWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getAudioDeviceConnectedStatusWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t requestAudioDevicePowerStatusWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setLatencyInfoWrapper(const JsonObject& parameters, JsonObject& response); - void InitializePowerManager(PluginHost::IShell *service); - //End methods - std::string logicalAddressDeviceType; - bool cecSettingEnabled; - bool cecOTPSettingEnabled; - bool cecEnableStatus; - bool hdmiCecAudioDeviceConnected; - bool m_isHdmiInConnected; - int m_numofHdmiInput; - uint8_t m_deviceType; - int m_logicalAddressAllocated; - std::thread m_pollThread; - uint32_t m_pollThreadState; - uint32_t m_pollNextState; - bool m_pollThreadExit; - uint32_t m_sleepTime; - std::mutex m_pollExitMutex; - std::mutex m_enableMutex; - /* Send Key event related */ - bool m_sendKeyEventThreadExit; - bool m_sendKeyEventThreadRun; - bool m_isAudioStatusInfoUpdated; - bool m_audioStatusReceived; - bool m_audioStatusTimerStarted; - std::thread m_sendKeyEventThread; - std::mutex m_sendKeyEventMutex; - std::queue m_SendKeyQueue; - std::condition_variable m_sendKeyCV; - std::condition_variable m_ThreadExitCV; - - /* DALS - Latency Values */ - uint8_t m_video_latency; - uint8_t m_latency_flags; - uint8_t m_audio_output_delay; - - /* ARC related */ - std::thread m_arcRoutingThread; - uint32_t m_currentArcRoutingState; - std::mutex m_arcRoutingStateMutex; - binary_semaphore m_semSignaltoArcRoutingThread; - bool m_arcstarting; - TpTimer m_arcStartStopTimer; - TpTimer m_audioStatusDetectionTimer; - - Connection *smConnection; - std::vector m_connectedDevices; - HdmiCecSinkProcessor *msgProcessor; - HdmiCecSinkFrameListener *msgFrameListener; - PowerManagerInterfaceRef _powerManagerPlugin; - Core::Sink _pwrMgrNotification; - bool _registeredEventHandlers; - const void InitializeIARM(); - void DeinitializeIARM(); - void allocateLogicalAddress(int deviceType); - void allocateLAforTV(); - void pingDevices(std::vector &connected , std::vector &disconnected); - void CheckHdmiInState(); - void request(const int logicalAddress); - int requestType(const int logicalAddress); - int requestStatus(const int logicalAddress); - static void threadRun(); - void cecMonitoringThread(); - static void dsHdmiEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len); - void onHdmiHotPlug(int portId, int connectStatus); - bool loadSettings(); - void persistSettings(bool enableStatus); - void persistOTPSettings(bool enableStatus); - void persistOSDName(const char *name); - void persistVendorId(unsigned int vendorID); - void setEnabled(bool enabled); - bool getEnabled(); - bool getAudioDeviceConnectedStatus(); - void CECEnable(void); - void CECDisable(void); - void getPhysicalAddress(); - void getLogicalAddress(); - void cecAddressesChanged(int changeStatus); - - // Arc functions - - static void threadSendKeyEvent(); - static void threadArcRouting(); - void requestArcInitiation(); - void requestArcTermination(); - void Send_Request_Arc_Initiation_Message(); - void Send_Report_Arc_Initiated_Message(); - void Send_Request_Arc_Termination_Message(); - void Send_Report_Arc_Terminated_Message(); - void arcStartStopTimerFunction(); - void audioStatusTimerFunction(); - void getCecVersion(); + PluginHost::IShell* _service{}; + Core::Sink _notification; + Exchange::IHdmiCecSink* _hdmiCecSink; + uint32_t _connectionId; }; } // namespace Plugin } // namespace WPEFramework diff --git a/HdmiCecSink/HdmiCecSinkImplementation.cpp b/HdmiCecSink/HdmiCecSinkImplementation.cpp new file mode 100644 index 00000000..7363bb76 --- /dev/null +++ b/HdmiCecSink/HdmiCecSinkImplementation.cpp @@ -0,0 +1,3581 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2019 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 "HdmiCecSinkImplementation.h" + +#include "ccec/Connection.hpp" +#include "ccec/CECFrame.hpp" +#include "ccec/MessageEncoder.hpp" +#include "host.hpp" +#include "UtilsgetRFCConfig.h" + +#include "dsMgr.h" +#include "dsRpc.h" +#include "dsDisplay.h" +#include "videoOutputPort.hpp" +#include "manager.hpp" +#include "websocket/URL.h" + +#include "UtilsIarm.h" +#include "UtilsJsonRpc.h" +#include "UtilssyncPersistFile.h" +#include "UtilsSearchRDKProfile.h" + +#define TEST_ADD 0 +#define HDMICECSINK_REQUEST_MAX_RETRY 3 +#define HDMICECSINK_REQUEST_MAX_WAIT_TIME_MS 2000 +#define HDMICECSINK_PING_INTERVAL_MS 10000 +#define HDMICECSINK_WAIT_FOR_HDMI_IN_MS 1000 +#define HDMICECSINK_REQUEST_INTERVAL_TIME_MS 500 +#define HDMICECSINK_NUMBER_TV_ADDR 2 +#define HDMICECSINK_UPDATE_POWER_STATUS_INTERVA_MS (60 * 1000) +#define HDMISINK_ARC_START_STOP_MAX_WAIT_MS 4000 +#define HDMICECSINK_UPDATE_AUDIO_STATUS_INTERVAL_MS 500 + + +#define SAD_FMT_CODE_AC3 2 +#define SAD_FMT_CODE_ENHANCED_AC3 10 + +#define SYSTEM_AUDIO_MODE_ON 0x01 +#define SYSTEM_AUDIO_MODE_OFF 0x00 +#define AUDIO_DEVICE_POWERSTATE_OFF 1 + +#define DEFAULT_VIDEO_LATENCY 100 +#define DEFAULT_LATENCY_FLAGS 3 +#define DEFAULT_AUDIO_OUTPUT_DELAY 100 + +//Device Type is TV - Bit 7 is set to 1 +#define ALL_DEVICE_TYPES 128 + +//RC Profile of TV is 3 - Typical TV Remote +#define RC_PROFILE_TV 10 + +//Device Features supported by TV - ARC Tx +#define DEVICE_FEATURES_TV 4 + +#define TR181_HDMICECSINK_CEC_VERSION "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.HdmiCecSink.CECVersion" + + +#define CEC_SETTING_ENABLED_FILE "/opt/persistent/ds/cecData_2.json" +#define CEC_SETTING_OTP_ENABLED "cecOTPEnabled" +#define CEC_SETTING_ENABLED "cecEnabled" +#define CEC_SETTING_OSD_NAME "cecOSDName" +#define CEC_SETTING_VENDOR_ID "cecVendorId" + +enum { + DEVICE_POWER_STATE_ON = 0, + DEVICE_POWER_STATE_OFF = 1 +}; + +static std::vector defaultVendorId = {0x00,0x19,0xFB}; +static VendorID appVendorId = {defaultVendorId.at(0),defaultVendorId.at(1),defaultVendorId.at(2)}; +static VendorID lgVendorId = {0x00,0xE0,0x91}; +static PhysicalAddress physical_addr = {0x0F,0x0F,0x0F,0x0F}; +static LogicalAddress logicalAddress = 0xF; +static Language defaultLanguage = "eng"; +static OSDName osdName = "TV Box"; +static int32_t powerState = DEVICE_POWER_STATE_OFF; +static std::vector formatid = {0,0}; +static std::vector audioFormatCode = { SAD_FMT_CODE_ENHANCED_AC3,SAD_FMT_CODE_AC3 }; +static uint8_t numberofdescriptor = 2; +static int32_t HdmiArcPortID = -1; +static float cecVersion = 1.4; +static AllDeviceTypes allDevicetype = ALL_DEVICE_TYPES; +static std::vector rcProfile = {RC_PROFILE_TV}; +static std::vector deviceFeatures = {DEVICE_FEATURES_TV}; + +#define API_VERSION_NUMBER_MAJOR 1 +#define API_VERSION_NUMBER_MINOR 3 +#define API_VERSION_NUMBER_PATCH 7 + +using PowerState = WPEFramework::Exchange::IPowerManager::PowerState; + +namespace WPEFramework +{ + + namespace Plugin + { + SERVICE_REGISTRATION(HdmiCecSinkImplementation, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); + + HdmiCecSinkImplementation* HdmiCecSinkImplementation::_instance = nullptr; + static int libcecInitStatus = 0; + +//=========================================== HdmiCecSinkFrameListener ========================================= + void HdmiCecSinkFrameListener::notify(const CECFrame &in) const { + const uint8_t *buf = NULL; + char strBuffer[512] = {0}; + size_t len = 0; + + in.getBuffer(&buf, &len); + for (unsigned int i = 0; i < len; i++) { + snprintf(strBuffer + (i*3) , sizeof(strBuffer) - (i*3), "%02X ",(uint8_t) *(buf + i)); + } + LOGINFO(" >>>>> Received CEC Frame: :%s \n",strBuffer); + + MessageDecoder(processor).decode(in); + } + +//=========================================== HdmiCecSinkProcessor ========================================= + void HdmiCecSinkProcessor::process (const ActiveSource &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: ActiveSource %s : %s : %s \n",GetOpName(msg.opCode()),msg.physicalAddress.name().c_str(),msg.physicalAddress.toString().c_str()); + if(!(header.to == LogicalAddress(LogicalAddress::BROADCAST))){ + LOGINFO("Ignore Direct messages, accepts only broadcast messages"); + return; + } + HdmiCecSinkImplementation::_instance->addDevice(header.from.toInt()); + HdmiCecSinkImplementation::_instance->updateActiveSource(header.from.toInt(), msg); + } + void HdmiCecSinkProcessor::process (const InActiveSource &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: InActiveSource %s : %s : %s \n",GetOpName(msg.opCode()),msg.physicalAddress.name().c_str(),msg.physicalAddress.toString().c_str()); + if(header.to.toInt() == LogicalAddress::BROADCAST){ + LOGINFO("Ignore Broadcast messages, accepts only direct messages"); + return; + } + + HdmiCecSinkImplementation::_instance->updateInActiveSource(header.from.toInt(), msg); + } + + void HdmiCecSinkProcessor::process (const ImageViewOn &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: ImageViewOn from %s\n", header.from.toString().c_str()); + if(header.to.toInt() == LogicalAddress::BROADCAST){ + LOGINFO("Ignore Broadcast messages, accepts only direct messages"); + return; + } + HdmiCecSinkImplementation::_instance->addDevice(header.from.toInt()); + HdmiCecSinkImplementation::_instance->updateImageViewOn(header.from.toInt()); + } + void HdmiCecSinkProcessor::process (const TextViewOn &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: TextViewOn\n"); + if(header.to.toInt() == LogicalAddress::BROADCAST){ + LOGINFO("Ignore Broadcast messages, accepts only direct messages"); + return; + } + HdmiCecSinkImplementation::_instance->addDevice(header.from.toInt()); + HdmiCecSinkImplementation::_instance->updateTextViewOn(header.from.toInt()); + } + void HdmiCecSinkProcessor::process (const RequestActiveSourceMessage &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: RequestActiveSource\n"); + if(!(header.to == LogicalAddress(LogicalAddress::BROADCAST))){ + LOGINFO("Ignore Direct messages, accepts only broadcast messages"); + return; + } + + HdmiCecSinkImplementation::_instance->setActiveSource(true); + } + void HdmiCecSinkProcessor::process (const Standby &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: Standby from %s\n", header.from.toString().c_str()); + HdmiCecSinkImplementation::_instance->SendStandbyMsgEvent(header.from.toInt()); + } + void HdmiCecSinkProcessor::process (const GetCECVersion &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: GetCECVersion sending CECVersion response \n"); + if(header.to.toInt() == LogicalAddress::BROADCAST){ + LOGINFO("Ignore Broadcast messages, accepts only direct messages"); + return; + } + try + { + if(cecVersion == 2.0) { + conn.sendToAsync(header.from, MessageEncoder().encode(CECVersion(Version::V_2_0))); + } + else{ + conn.sendToAsync(header.from, MessageEncoder().encode(CECVersion(Version::V_1_4))); + } + } + catch(...) + { + LOGWARN("Exception while sending CECVersion "); + } + } + void HdmiCecSinkProcessor::process (const CECVersion &msg, const Header &header) + { + bool updateStatus; + printHeader(header); + LOGINFO("Command: CECVersion Version : %s \n",msg.version.toString().c_str()); + + HdmiCecSinkImplementation::_instance->addDevice(header.from.toInt()); + updateStatus = HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_isVersionUpdated; + LOGINFO("updateStatus %d\n",updateStatus); + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].update(msg.version); + if(!updateStatus) + HdmiCecSinkImplementation::_instance->sendDeviceUpdateInfo(header.from.toInt()); + } + void HdmiCecSinkProcessor::process (const SetMenuLanguageMessage &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: SetMenuLanguage Language : %s \n",msg.language.toString().c_str()); + } + void HdmiCecSinkProcessor::process (const GiveOSDName &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: GiveOSDName sending SetOSDName : %s\n",osdName.toString().c_str()); + if(header.to.toInt() == LogicalAddress::BROADCAST){ + LOGINFO("Ignore Broadcast messages, accepts only direct messages"); + return; + } + try + { + conn.sendToAsync(header.from, MessageEncoder().encode(SetOSDName(osdName))); + } + catch(...) + { + LOGWARN("Exception while sending SetOSDName"); + } + } + void HdmiCecSinkProcessor::process (const GivePhysicalAddress &msg, const Header &header) + { + LOGINFO("Command: GivePhysicalAddress\n"); + if (!(header.to == LogicalAddress(LogicalAddress::BROADCAST))) + { + try + { + LOGINFO(" sending ReportPhysicalAddress response physical_addr :%s logicalAddress :%x \n",physical_addr.toString().c_str(), logicalAddress.toInt()); + conn.sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(ReportPhysicalAddress(physical_addr,logicalAddress.toInt())), 500); + } + catch(...) + { + LOGWARN("Exception while sending ReportPhysicalAddress "); + } + } + } + void HdmiCecSinkProcessor::process (const GiveDeviceVendorID &msg, const Header &header) + { + printHeader(header); + if(header.to == LogicalAddress(LogicalAddress::BROADCAST)){ + LOGINFO("Ignore Broadcast messages, accepts only direct messages"); + return; + } + try + { + LOGINFO("Command: GiveDeviceVendorID sending VendorID response :%s\n",appVendorId.toString().c_str()); + conn.sendToAsync(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(DeviceVendorID(appVendorId))); + } + catch(...) + { + LOGWARN("Exception while sending DeviceVendorID"); + } + + } + void HdmiCecSinkProcessor::process (const SetOSDString &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: SetOSDString OSDString : %s\n",msg.osdString.toString().c_str()); + } + void HdmiCecSinkProcessor::process (const SetOSDName &msg, const Header &header) + { + printHeader(header); + bool updateStatus ; + LOGINFO("Command: SetOSDName OSDName : %s\n",msg.osdName.toString().c_str()); + if(header.to.toInt() == LogicalAddress::BROADCAST){ + LOGINFO("Ignore Broadcast messages, accepts only direct messages"); + return; + } + + HdmiCecSinkImplementation::_instance->addDevice(header.from.toInt()); + updateStatus = HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_isOSDNameUpdated; + LOGINFO("updateStatus %d\n",updateStatus); + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].update(msg.osdName); + if(HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_isRequestRetry > 0 && + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_isRequested == CECDeviceParams::REQUEST_OSD_NAME) { + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_isRequestRetry = 0; + } + if(!updateStatus) + HdmiCecSinkImplementation::_instance->sendDeviceUpdateInfo(header.from.toInt()); + } + void HdmiCecSinkProcessor::process (const RoutingChange &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: RoutingChange From : %s To: %s \n",msg.from.toString().c_str(),msg.to.toString().c_str()); + } + void HdmiCecSinkProcessor::process (const RoutingInformation &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: RoutingInformation Routing Information to Sink : %s\n",msg.toSink.toString().c_str()); + } + void HdmiCecSinkProcessor::process (const SetStreamPath &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: SetStreamPath Set Stream Path to Sink : %s\n",msg.toSink.toString().c_str()); + } + void HdmiCecSinkProcessor::process (const GetMenuLanguage &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: GetMenuLanguage\n"); + if(header.to.toInt() == LogicalAddress::BROADCAST){ + LOGINFO("Ignore Broadcast messages, accepts only direct messages"); + return; + } + HdmiCecSinkImplementation::_instance->sendMenuLanguage(); + } + void HdmiCecSinkProcessor::process (const ReportPhysicalAddress &msg, const Header &header) + { + printHeader(header); + bool updateDeviceTypeStatus; + bool updatePAStatus; + LOGINFO("Command: ReportPhysicalAddress\n"); + if(!(header.to == LogicalAddress(LogicalAddress::BROADCAST))){ + LOGINFO("Ignore Direct messages, accepts only broadcast messages"); + return; + } + + if(!HdmiCecSinkImplementation::_instance) + return; + HdmiCecSinkImplementation::_instance->addDevice(header.from.toInt()); + updateDeviceTypeStatus = HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_isDeviceTypeUpdated; + updatePAStatus = HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_isPAUpdated; + LOGINFO("updateDeviceTypeStatus %d updatePAStatus %d \n",updateDeviceTypeStatus,updatePAStatus); + if(HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_physicalAddr.toString() != msg.physicalAddress.toString() && updatePAStatus){ + updatePAStatus= false; + LOGINFO("There is a change in physical address from current PA %s to newly reported PA %s\n",HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_physicalAddr.toString().c_str(),msg.physicalAddress.toString().c_str()); + } + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].update(msg.physicalAddress); + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].update(msg.deviceType); + if(HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_isRequestRetry > 0 && + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_isRequested == CECDeviceParams::REQUEST_PHISICAL_ADDRESS) { + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_isRequestRetry = 0; + } + HdmiCecSinkImplementation::_instance->updateDeviceChain(header.from, msg.physicalAddress); + if (!updateDeviceTypeStatus || !updatePAStatus) + HdmiCecSinkImplementation::_instance->sendDeviceUpdateInfo(header.from.toInt()); + } + void HdmiCecSinkProcessor::process (const DeviceVendorID &msg, const Header &header) + { + bool updateStatus ; + printHeader(header); + LOGINFO("Command: DeviceVendorID VendorID : %s\n",msg.vendorId.toString().c_str()); + if(!(header.to == LogicalAddress(LogicalAddress::BROADCAST))){ + LOGINFO("Ignore Direct messages, accepts only broadcast messages"); + return; + } + + HdmiCecSinkImplementation::_instance->addDevice(header.from.toInt()); + updateStatus = HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_isVendorIDUpdated; + LOGINFO("updateStatus %d\n",updateStatus); + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].update(msg.vendorId); + if (!updateStatus) + HdmiCecSinkImplementation::_instance->sendDeviceUpdateInfo(header.from.toInt()); + } + void HdmiCecSinkProcessor::process (const GiveDevicePowerStatus &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: GiveDevicePowerStatus sending powerState :%d \n",powerState); + if(header.to.toInt() == LogicalAddress::BROADCAST){ + LOGINFO("Ignore Broadcast messages, accepts only direct messages"); + return; + } + try + { + conn.sendTo(header.from, MessageEncoder().encode(ReportPowerStatus(PowerStatus(powerState)))); + } + catch(...) + { + LOGWARN("Exception while sending ReportPowerStatus"); + } + } + void HdmiCecSinkProcessor::process (const ReportPowerStatus &msg, const Header &header) + { + uint32_t oldPowerStatus,newPowerStatus; + printHeader(header); + LOGINFO("Command: ReportPowerStatus Power Status from:%s status : %s \n",header.from.toString().c_str(),msg.status.toString().c_str()); + if(header.to.toInt() == LogicalAddress::BROADCAST){ + LOGINFO("Ignore Broadcast messages, accepts only direct messages"); + return; + } + oldPowerStatus = HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_powerStatus.toInt(); + HdmiCecSinkImplementation::_instance->addDevice(header.from.toInt()); + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].update(msg.status); + newPowerStatus = HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_powerStatus.toInt(); + LOGINFO(" oldPowerStatus %d newpower status %d \n",oldPowerStatus,newPowerStatus); + if ((oldPowerStatus != newPowerStatus) ) + { + HdmiCecSinkImplementation::_instance->sendDeviceUpdateInfo(header.from.toInt()); + } + + if((header.from.toInt() == LogicalAddress::AUDIO_SYSTEM) && (HdmiCecSinkImplementation::_instance->m_audioDevicePowerStatusRequested)) { + HdmiCecSinkImplementation::_instance->reportAudioDevicePowerStatusInfo(header.from.toInt(), newPowerStatus); + } + + } + void HdmiCecSinkProcessor::process (const FeatureAbort &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: FeatureAbort opcode=%s, Reason = %s\n", msg.feature.toString().c_str(), msg.reason.toString().c_str()); + if(header.to.toInt() == LogicalAddress::BROADCAST){ + LOGINFO("Ignore Broadcast messages, accepts only direct messages"); + return; + } + + if(header.from.toInt() < LogicalAddress::UNREGISTERED && + msg.reason.toInt() == AbortReason::UNRECOGNIZED_OPCODE) + { + switch(msg.feature.opCode()) + { + case GET_CEC_VERSION : + { + /* If we get a Feature abort for CEC Version then default to 1.4b */ + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].update(Version(Version::V_1_4)); + } + break; + case GIVE_DEVICE_VENDOR_ID : + { + /* If we get a Feature abort for CEC Version then default to 1.4b */ + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].update(VendorID((uint8_t *)"FA", 2)); + } + break; + + case GIVE_OSD_NAME : + { + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].update(OSDName("")); + } + break; + + case GIVE_DEVICE_POWER_STATUS : + { + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].update(PowerStatus(PowerStatus::POWER_STATUS_FEATURE_ABORT)); + } + break; + } + + HdmiCecSinkImplementation::_instance->deviceList[header.from.toInt()].m_featureAborts.push_back(msg); + } + + LogicalAddress logicaladdress = header.from.toInt(); + OpCode featureOpcode = msg.feature; + AbortReason abortReason = msg.reason; + + HdmiCecSinkImplementation::_instance->reportFeatureAbortEvent(logicaladdress,featureOpcode,abortReason); + + if(msg.feature.opCode() == REQUEST_SHORT_AUDIO_DESCRIPTOR) + { + JsonArray audiodescriptor; + audiodescriptor.Add(0); + HdmiCecSinkImplementation::_instance->Send_ShortAudioDescriptor_Event(audiodescriptor); + } + + } + void HdmiCecSinkProcessor::process (const Abort &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: Abort\n"); + if (!(header.to == LogicalAddress(LogicalAddress::BROADCAST))) + { + AbortReason reason = AbortReason::UNRECOGNIZED_OPCODE; + LogicalAddress logicaladdress =header.from.toInt(); + OpCode feature = msg.opCode(); + HdmiCecSinkImplementation::_instance->sendFeatureAbort(logicaladdress, feature,reason); + } + else + { + LOGINFO("Command: Abort broadcast msg so ignore\n"); + } + } + void HdmiCecSinkProcessor::process (const Polling &msg, const Header &header) { + printHeader(header); + LOGINFO("Command: Polling\n"); + } + + void HdmiCecSinkProcessor::process (const InitiateArc &msg, const Header &header) + { + printHeader(header); + if((!(header.from.toInt() == 0x5)) || (header.to.toInt() == LogicalAddress::BROADCAST)){ + LOGINFO("Ignoring the message coming from addresses other than 0X5 or a braodcast message"); + return; + } + PhysicalAddress physical_addr_invalid = {0x0F,0x0F,0x0F,0x0F}; + PhysicalAddress physical_addr_arc_port = {0x0F,0x0F,0x0F,0x0F}; + + LOGINFO("Command: INITIATE_ARC \n"); + if(!HdmiCecSinkImplementation::_instance || HdmiArcPortID == -1) + return; + + if (HdmiArcPortID == 0 ) + physical_addr_arc_port = {0x01,0x00,0x00,0x00}; + if (HdmiArcPortID == 1 ) + physical_addr_arc_port = {0x02,0x00,0x00,0x00}; + if (HdmiArcPortID == 2 ) + physical_addr_arc_port = {0x03,0x00,0x00,0x00}; + + if( (HdmiCecSinkImplementation::_instance->deviceList[0x5].m_physicalAddr.toString() == physical_addr_arc_port.toString()) || (HdmiCecSinkImplementation::_instance->deviceList[0x5].m_physicalAddr.toString() == physical_addr_invalid.toString()) ) { + LOGINFO("Command: INITIATE_ARC InitiateArc success %s \n",HdmiCecSinkImplementation::_instance->deviceList[0x5].m_physicalAddr.toString().c_str()); + HdmiCecSinkImplementation::_instance->Process_InitiateArc(); + } else { + LOGINFO("Command: INITIATE_ARC InitiateArc ignore %s \n",HdmiCecSinkImplementation::_instance->deviceList[0x5].m_physicalAddr.toString().c_str()); + } + } + void HdmiCecSinkProcessor::process (const TerminateArc &msg, const Header &header) + { + printHeader(header); + if((!(header.from.toInt() == 0x5)) || (header.to.toInt() == LogicalAddress::BROADCAST)){ + LOGINFO("Ignoring the message coming from addresses other than 0X5 or a braodcast message"); + return; + } + if(!HdmiCecSinkImplementation::_instance) + return; + HdmiCecSinkImplementation::_instance->Process_TerminateArc(); + } + void HdmiCecSinkProcessor::process (const ReportShortAudioDescriptor &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: ReportShortAudioDescriptor %s : %d \n",GetOpName(msg.opCode()),numberofdescriptor); + HdmiCecSinkImplementation::_instance->Process_ShortAudioDescriptor_msg(msg); + } + + void HdmiCecSinkProcessor::process (const SetSystemAudioMode &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: SetSystemAudioMode %s audio status %d audio status is %s \n",GetOpName(msg.opCode()),msg.status.toInt(),msg.status.toString().c_str()); + HdmiCecSinkImplementation::_instance->Process_SetSystemAudioMode_msg(msg); + } + void HdmiCecSinkProcessor::process (const ReportAudioStatus &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: ReportAudioStatus %s audio Mute status %d means %s and current Volume level is %d \n",GetOpName(msg.opCode()),msg.status.getAudioMuteStatus(),msg.status.toString().c_str(),msg.status.getAudioVolume()); + if(header.to.toInt() == LogicalAddress::BROADCAST){ + LOGINFO("Ignore Broadcast messages, accepts only direct messages"); + return; + } + HdmiCecSinkImplementation::_instance->Process_ReportAudioStatus_msg(msg); + } + void HdmiCecSinkProcessor::process (const GiveFeatures &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: GiveFeatures \n"); + try + { + if(cecVersion == 2.0) { + conn.sendToAsync(LogicalAddress(LogicalAddress::BROADCAST),MessageEncoder().encode(ReportFeatures(Version::V_2_0,allDevicetype,rcProfile,deviceFeatures))); + } + } + catch(...) + { + LOGWARN("Exception while sending ReportFeatures"); + } + } + void HdmiCecSinkProcessor::process (const RequestCurrentLatency &msg, const Header &header) + { + printHeader(header); + LOGINFO("Command: Request Current Latency :%s, physical address: %s",GetOpName(msg.opCode()),msg.physicaladdress.toString().c_str()); + + if(msg.physicaladdress.toString() == physical_addr.toString()) { + HdmiCecSinkImplementation::_instance->setLatencyInfo(); + } + else { + LOGINFO("Physical Address does not match with TV's physical address"); + return; + } + } +//=========================================== HdmiCecSinkImplementation ========================================= + + HdmiCecSinkImplementation::HdmiCecSinkImplementation() + : _pwrMgrNotification(*this) + , _registeredEventHandlers(false) + { + LOGWARN("Initlaizing HdmiCecSinkImplementation"); + } + + HdmiCecSinkImplementation::~HdmiCecSinkImplementation() + { + if(_powerManagerPlugin) + { + _powerManagerPlugin->Unregister(_pwrMgrNotification.baseInterface()); + _powerManagerPlugin.Reset(); + } + _registeredEventHandlers = false; + + profileType = searchRdkProfile(); + + if (profileType == STB || profileType == NOT_FOUND) + { + LOGINFO("Invalid profile type for TV \n"); + return ; + } + + CECDisable(); + m_currentArcRoutingState = ARC_STATE_ARC_EXIT; + + m_semSignaltoArcRoutingThread.release(); + + try + { + if (m_arcRoutingThread.joinable()) + m_arcRoutingThread.join(); + } + catch(const std::system_error& e) + { + LOGERR("system_error exception in thread join %s", e.what()); + } + catch(const std::exception& e) + { + LOGERR("exception in thread join %s", e.what()); + } + + { + m_sendKeyEventThreadExit = true; + std::unique_lock lk(m_sendKeyEventMutex); + m_sendKeyEventThreadRun = true; + m_sendKeyCV.notify_one(); + } + + try + { + if (m_sendKeyEventThread.joinable()) + m_sendKeyEventThread.join(); + } + catch(const std::system_error& e) + { + LOGERR("system_error exception in thread join %s", e.what()); + } + catch(const std::exception& e) + { + LOGERR("exception in thread join %s", e.what()); + } + + HdmiCecSinkImplementation::_instance = nullptr; + DeinitializeIARM(); + } + + Core::hresult HdmiCecSinkImplementation::Configure(PluginHost::IShell *service) + { + InitializePowerManager(service); + profileType = searchRdkProfile(); + + HdmiCecSinkImplementation::_instance = this; + smConnection=NULL; + cecEnableStatus = false; + HdmiCecSinkImplementation::_instance->m_numberOfDevices = 0; + m_logicalAddressAllocated = LogicalAddress::UNREGISTERED; + m_currentActiveSource = -1; + m_isHdmiInConnected = false; + hdmiCecAudioDeviceConnected = false; + m_isAudioStatusInfoUpdated = false; + m_audioStatusReceived = false; + m_audioStatusTimerStarted = false; + m_audioDevicePowerStatusRequested = false; + m_pollNextState = POLL_THREAD_STATE_NONE; + m_pollThreadState = POLL_THREAD_STATE_NONE; + m_video_latency = DEFAULT_VIDEO_LATENCY; + m_latency_flags = DEFAULT_LATENCY_FLAGS ; + m_audio_output_delay = DEFAULT_AUDIO_OUTPUT_DELAY; + + logicalAddressDeviceType = "None"; + logicalAddress = 0xFF; + // load persistence setting + loadSettings(); + + int err; + dsHdmiInGetNumberOfInputsParam_t hdmiInput; + InitializeIARM(); + m_sendKeyEventThreadExit = false; + m_sendKeyEventThread = std::thread(threadSendKeyEvent); + + m_currentArcRoutingState = ARC_STATE_ARC_TERMINATED; + m_semSignaltoArcRoutingThread.acquire(); + m_arcRoutingThread = std::thread(threadArcRouting); + + m_audioStatusDetectionTimer.connect( std::bind( &HdmiCecSinkImplementation::audioStatusTimerFunction, this ) ); + m_audioStatusDetectionTimer.setSingleShot(true); + m_arcStartStopTimer.connect( std::bind( &HdmiCecSinkImplementation::arcStartStopTimerFunction, this ) ); + m_arcStartStopTimer.setSingleShot(true); + + // get power state: + uint32_t res = Core::ERROR_GENERAL; + PowerState pwrStateCur = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; + PowerState pwrStatePrev = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; + + ASSERT (_powerManagerPlugin); + if (_powerManagerPlugin) { + res = _powerManagerPlugin->GetPowerState(pwrStateCur, pwrStatePrev); + if (Core::ERROR_NONE == res) { + powerState = (pwrStateCur == WPEFramework::Exchange::IPowerManager::POWER_STATE_ON) ? DEVICE_POWER_STATE_ON : DEVICE_POWER_STATE_OFF; + LOGINFO("Current state is PowerManagerPlugin: (%d) powerState :%d \n", pwrStateCur, powerState); + } + } + + err = IARM_Bus_Call(IARM_BUS_DSMGR_NAME, + IARM_BUS_DSMGR_API_dsHdmiInGetNumberOfInputs, + (void *)&hdmiInput, + sizeof(hdmiInput)); + + if (err == IARM_RESULT_SUCCESS && hdmiInput.result == dsERR_NONE) + { + LOGINFO("Number of Inputs [%d] \n", hdmiInput.numHdmiInputs ); + m_numofHdmiInput = hdmiInput.numHdmiInputs; + }else{ + LOGINFO("Not able to get Numebr of inputs so defaulting to 3 \n"); + m_numofHdmiInput = 3; + } + + LOGINFO("initalize inputs \n"); + + for (int i = 0; i < m_numofHdmiInput; i++){ + HdmiPortMap hdmiPort((uint8_t)i); + LOGINFO(" Add to vector [%d] \n", i); + hdmiInputs.push_back(hdmiPort); + } + + LOGINFO("Check the HDMI State \n"); + + CheckHdmiInState(); + if (cecSettingEnabled) + { + try + { + CECEnable(); + } + catch(...) + { + LOGWARN("Exception while enabling CEC settings .\r\n"); + } + } + getCecVersion(); + LOGINFO(" HdmiCecSinkImplementation plugin Initialize completed \n"); + return Core::ERROR_NONE; + + } + + Core::hresult HdmiCecSinkImplementation::Register(Exchange::IHdmiCecSink::INotification* notification) + { + LOGINFO("Register"); + if(notification != nullptr){ + _adminLock.Lock(); + if(std::find(_hdmiCecSinkNotifications.begin(), _hdmiCecSinkNotifications.end(), notification) == _hdmiCecSinkNotifications.end()) + { + _hdmiCecSinkNotifications.push_back(notification); + notification->AddRef(); + } + else + { + LOGERR("Same notification is registered already"); + } + _adminLock.Unlock(); + } + + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::Unregister(Exchange::IHdmiCecSink::INotification* notification) + { + LOGINFO("Unregister"); + if(notification != nullptr){ + _adminLock.Lock(); + std::list::iterator index = std::find(_hdmiCecSinkNotifications.begin(), _hdmiCecSinkNotifications.end(), notification); + if(index != _hdmiCecSinkNotifications.end()) + { + (*index)->Release(); + _hdmiCecSinkNotifications.erase(index); + } + else + { + LOGERR("Notification is not registered"); + } + _adminLock.Unlock(); + } + + return Core::ERROR_NONE; + } + + + const void HdmiCecSinkImplementation::InitializeIARM() + { + if (Utils::IARM::init()) + { + IARM_Result_t res; + IARM_CHECK( IARM_Bus_RegisterEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDMI_IN_HOTPLUG, dsHdmiEventHandler) ); + } + } + + void HdmiCecSinkImplementation::DeinitializeIARM() + { + if (Utils::IARM::isConnected()) + { + IARM_Result_t res; + IARM_CHECK( IARM_Bus_RemoveEventHandler(IARM_BUS_DSMGR_NAME,IARM_BUS_DSMGR_EVENT_HDMI_IN_HOTPLUG, dsHdmiEventHandler) ); + } + } + + void HdmiCecSinkImplementation::InitializePowerManager(PluginHost::IShell *service) + { + _powerManagerPlugin = PowerManagerInterfaceBuilder(_T("org.rdk.PowerManager")) + .withIShell(service) + .withRetryIntervalMS(200) + .withRetryCount(25) + .createInterface(); + registerEventHandlers(); + } + void HdmiCecSinkImplementation::registerEventHandlers() + { + ASSERT (_powerManagerPlugin); + + if(!_registeredEventHandlers && _powerManagerPlugin) { + _registeredEventHandlers = true; + _powerManagerPlugin->Register(_pwrMgrNotification.baseInterface()); + } + } + + void HdmiCecSinkImplementation::dsHdmiEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len) + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if (IARM_BUS_DSMGR_EVENT_HDMI_IN_HOTPLUG == eventId) + { + IARM_Bus_DSMgr_EventData_t *eventData = (IARM_Bus_DSMgr_EventData_t *)data; + bool isHdmiConnected = eventData->data.hdmi_in_connect.isPortConnected; + dsHdmiInPort_t portId = eventData->data.hdmi_in_connect.port; + LOGINFO("Received IARM_BUS_DSMGR_EVENT_HDMI_IN_HOTPLUG event port: %d data:%d \r\n",portId, isHdmiConnected); + HdmiCecSinkImplementation::_instance->onHdmiHotPlug(portId,isHdmiConnected); + } + } + + void HdmiCecSinkImplementation::onPowerModeChanged(const PowerState ¤tState, const PowerState &newState) + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + LOGINFO("Event IARM_BUS_PWRMGR_EVENT_MODECHANGED: State Changed %d -- > %d\r", + currentState, newState); + LOGWARN(" m_logicalAddressAllocated 0x%x CEC enable status %d \n",_instance->m_logicalAddressAllocated,_instance->cecEnableStatus); + if(newState == WPEFramework::Exchange::IPowerManager::POWER_STATE_ON) + { + powerState = DEVICE_POWER_STATE_ON; + } + else + { + powerState = DEVICE_POWER_STATE_OFF; + if((_instance->m_currentArcRoutingState == ARC_STATE_REQUEST_ARC_INITIATION) || (_instance->m_currentArcRoutingState == ARC_STATE_ARC_INITIATED)) + { + LOGINFO("%s: Stop ARC \n",__FUNCTION__); + _instance->stopArc(); + } + + } + if (_instance->cecEnableStatus) + { + if ( _instance->m_logicalAddressAllocated != LogicalAddress::UNREGISTERED ) + { + _instance->deviceList[_instance->m_logicalAddressAllocated].m_powerStatus = PowerStatus(powerState); + + if ( powerState != DEVICE_POWER_STATE_ON ) + { + /* reset the current active source when TV on going to standby */ + HdmiCecSinkImplementation::_instance->m_currentActiveSource = -1; + } + /* Initiate a ping straight away */ + HdmiCecSinkImplementation::_instance->m_pollNextState = POLL_THREAD_STATE_PING; + HdmiCecSinkImplementation::_instance->m_ThreadExitCV.notify_one(); + } + } + else + { + LOGWARN("CEC not Enabled\n"); + } + } + + + void HdmiCecSinkImplementation::sendStandbyMessage() + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + if(!(HdmiCecSinkImplementation::_instance->smConnection)) + return; + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED){ + LOGERR("Logical Address NOT Allocated Or its not valid"); + return; + } + + _instance->smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(Standby()), 1000); + } + + void HdmiCecSinkImplementation::onHdmiHotPlug(int portId , int connectStatus) + { + LOGINFO("onHdmiHotPlug Status : %d ", connectStatus); + if(!connectStatus) + { + LOGINFO(" removeDevice port: %d Logical address :%d \r\n",portId,hdmiInputs[portId].m_logicalAddr.toInt() ); + _instance->removeDevice(hdmiInputs[portId].m_logicalAddr.toInt()); + } + CheckHdmiInState(); + + if(cecEnableStatus) { + LOGINFO("cecEnableStatus : %d Trigger CEC Ping !!! \n", cecEnableStatus); + m_pollNextState = POLL_THREAD_STATE_PING; + m_ThreadExitCV.notify_one(); + } + if( HdmiArcPortID >= 0 ) { + updateArcState(); + } + return; + } + void HdmiCecSinkImplementation::updateArcState() + { + if ( m_currentArcRoutingState != ARC_STATE_ARC_TERMINATED ) + { + if (!(hdmiInputs[HdmiArcPortID].m_isConnected)) + { + std::lock_guard lock(_instance->m_arcRoutingStateMutex); + m_currentArcRoutingState = ARC_STATE_ARC_TERMINATED; + } + else + { + LOGINFO("updateArcState :not updating ARC state current arc state %d ",m_currentArcRoutingState); + } + } + } + void HdmiCecSinkImplementation::arcStartStopTimerFunction() + { + JsonObject params; + + if (m_arcstarting) + { + LOGINFO("arcStartStopTimerFunction ARC start timer expired"); + LOGINFO("notify_device setting that Initiate ARC failed to get the ARC_STATE_ARC_INITIATED state\n"); + params["status"] = string("failure"); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ArcInitiationEvent("failure"); + index++; + } + } + else + { + LOGINFO("arcStartStopTimerFunction ARC stop timer expired"); + LOGINFO("notify_device setting that Terminate ARC failed to get the ARC_STATE_ARC_TERMINATED state\n"); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ArcTerminationEvent("failure"); + index++; + } + } + /* bring the state machine to the clean state for a new start */ + std::lock_guard lock(_instance->m_arcRoutingStateMutex); + m_currentArcRoutingState = ARC_STATE_ARC_TERMINATED; + } + void HdmiCecSinkImplementation::Send_ShortAudioDescriptor_Event(JsonArray audiodescriptor) + { + + LOGINFO("Notify the DS "); + string shortAudioDescriptors; + + if (!audiodescriptor.ToString(shortAudioDescriptors)) { + LOGERR("Failed to stringify JsonArray"); + } + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ShortAudiodescriptorEvent(shortAudioDescriptors); + index++; + } + } + + void HdmiCecSinkImplementation::Process_ShortAudioDescriptor_msg(const ReportShortAudioDescriptor &msg) + { + uint8_t numberofdescriptor = msg.numberofdescriptor; + uint32_t descriptor =0; + JsonArray audiodescriptor; + + if (numberofdescriptor) + { + for( uint8_t i=0; i < numberofdescriptor; i++) + { + descriptor = msg.shortAudioDescriptor[i].getAudiodescriptor(); + + LOGINFO("descriptor%d 0x%x\n",i,descriptor); + audiodescriptor.Add(descriptor); + + } + } + else + { + audiodescriptor.Add(descriptor); + } + HdmiCecSinkImplementation::_instance->Send_ShortAudioDescriptor_Event(audiodescriptor); + } + + void HdmiCecSinkImplementation::updateCurrentLatency(int videoLatency, bool lowLatencyMode,int audioOutputCompensated, int audioOutputDelay = 0) + { + uint8_t latencyFlags = 0; + latencyFlags = ((lowLatencyMode & 0x1) << 2) | (audioOutputCompensated & 0x3); + LOGINFO("Video Latency : %d , Low Latency Mode : %d ,Audio Output Compensated value : %d , Audio Output Delay : %d , Latency Flags: %d ", videoLatency, lowLatencyMode, audioOutputCompensated, audioOutputDelay, latencyFlags); + m_video_latency = (videoLatency/2) + 1; + m_latency_flags = latencyFlags; + m_audio_output_delay = (audioOutputDelay/2) + 1; + setLatencyInfo(); + } + + void HdmiCecSinkImplementation::setLatencyInfo() + { + if(!HdmiCecSinkImplementation::_instance) + return; + + if(!(_instance->smConnection)) + return; + + LOGINFO("Send Report Current Latency message \n"); + _instance->smConnection->sendTo(LogicalAddress::BROADCAST,MessageEncoder().encode(ReportCurrentLatency(physical_addr,m_video_latency,m_latency_flags,m_audio_output_delay))); + + } + + void HdmiCecSinkImplementation::Process_SetSystemAudioMode_msg(const SetSystemAudioMode &msg) + { + if(!HdmiCecSinkImplementation::_instance) + return; + + //DD: Check cecSettingEnabled to prevent race conditions which gives immediate UI setting status + //SetSystemAudioMode message may come from AVR/Soundbar while CEC disable is in-progress + if ( cecSettingEnabled != true ) + { + LOGINFO("Process SetSystemAudioMode from Audio device: Cec is disabled-> EnableCEC first"); + return; + } + + if ( (msg.status.toInt() == SYSTEM_AUDIO_MODE_OFF) && (m_currentArcRoutingState == ARC_STATE_ARC_INITIATED)) + { + /* ie system audio mode off -> amplifier goign to standby but still ARC is in initiated state,stop ARC and + bring the ARC state machine to terminated state*/ + LOGINFO("system audio mode off message but arc is not in terminated state so stopping ARC"); + stopArc(); + + } + + if (msg.status.toInt() == SYSTEM_AUDIO_MODE_ON) { + LOGINFO("panel power state is %s", powerState ? "Off" : "On"); + if (powerState == DEVICE_POWER_STATE_ON ) { + LOGINFO("Notifying system audio mode ON event"); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->SetSystemAudioModeEvent(msg.status.toString()); + index++; + } + } else { + LOGINFO("Not notifying system audio mode ON event"); + } + } else { + LOGINFO("Notifying system audio Mode OFF event"); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->SetSystemAudioModeEvent(msg.status.toString()); + index++; + } + } + } + void HdmiCecSinkImplementation::Process_ReportAudioStatus_msg(const ReportAudioStatus msg) + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + if (m_audioStatusTimerStarted) + { + m_audioStatusReceived = true; + m_isAudioStatusInfoUpdated = true; + m_audioStatusTimerStarted = false; + if (m_audioStatusDetectionTimer.isActive()) + { + LOGINFO("AudioStatus received from the Audio Device and the timer is still active. So stopping the timer!\n"); + m_audioStatusDetectionTimer.stop(); + } + LOGINFO("AudioStatus received from the Audio Device. Updating the AudioStatus info! m_isAudioStatusInfoUpdated :%d, m_audioStatusReceived :%d, m_audioStatusTimerStarted:%d ", m_isAudioStatusInfoUpdated,m_audioStatusReceived,m_audioStatusTimerStarted); + } + LOGINFO("Command: ReportAudioStatus %s audio Mute status %d means %s and current Volume level is %d \n",GetOpName(msg.opCode()),msg.status.getAudioMuteStatus(),msg.status.toString().c_str(),msg.status.getAudioVolume()); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ReportAudioStatusEvent(msg.status.getAudioMuteStatus(), msg.status.getAudioVolume()); + index++; + } + + } + void HdmiCecSinkImplementation::sendKeyPressEvent(const int logicalAddress, int keyCode) + { + if(!(_instance->smConnection)) + return; + LOGINFO(" sendKeyPressEvent logicalAddress 0x%x keycode 0x%x\n",logicalAddress,keyCode); + switch(keyCode) + { + case VOLUME_UP: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_VOLUME_UP)),100); + break; + case VOLUME_DOWN: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_VOLUME_DOWN)), 100); + break; + case MUTE: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_MUTE)), 100); + break; + case UP: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_UP)), 100); + break; + case DOWN: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_DOWN)), 100); + break; + case LEFT: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_LEFT)), 100); + break; + case RIGHT: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_RIGHT)), 100); + break; + case SELECT: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_SELECT)), 100); + break; + case HOME: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_HOME)), 100); + break; + case BACK: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_BACK)), 100); + break; + case NUMBER_0: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_0)), 100); + break; + case NUMBER_1: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_1)), 100); + break; + case NUMBER_2: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_2)), 100); + break; + case NUMBER_3: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_3)), 100); + break; + case NUMBER_4: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_4)), 100); + break; + case NUMBER_5: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_5)), 100); + break; + case NUMBER_6: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_6)), 100); + break; + case NUMBER_7: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_7)), 100); + break; + case NUMBER_8: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_8)), 100); + break; + case NUMBER_9: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_9)), 100); + break; + + } + } + + void HdmiCecSinkImplementation::sendUserControlPressed(const int logicalAddress, int keyCode) + { + if(!(_instance->smConnection)) + return; + LOGINFO(" sendUserControlPressed logicalAddress 0x%x keycode 0x%x\n",logicalAddress,keyCode); + switch(keyCode) + { + case VOLUME_UP: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_VOLUME_UP)),100); + break; + case VOLUME_DOWN: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_VOLUME_DOWN)), 100); + break; + case MUTE: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_MUTE)), 100); + break; + case UP: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_UP)), 100); + break; + case DOWN: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_DOWN)), 100); + break; + case LEFT: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_LEFT)), 100); + break; + case RIGHT: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_RIGHT)), 100); + break; + case SELECT: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_SELECT)), 100); + break; + case HOME: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_HOME)), 100); + break; + case BACK: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_BACK)), 100); + break; + case NUMBER_0: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_0)), 100); + break; + case NUMBER_1: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_1)), 100); + break; + case NUMBER_2: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_2)), 100); + break; + case NUMBER_3: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_3)), 100); + break; + case NUMBER_4: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_4)), 100); + break; + case NUMBER_5: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_5)), 100); + break; + case NUMBER_6: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_6)), 100); + break; + case NUMBER_7: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_7)), 100); + break; + case NUMBER_8: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_8)), 100); + break; + case NUMBER_9: + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlPressed(UICommand::UI_COMMAND_NUM_9)), 100); + break; + + } + } + + void HdmiCecSinkImplementation::sendKeyReleaseEvent(const int logicalAddress) + { + if(!(_instance->smConnection)) + return; + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlReleased()), 100); + + } + + void HdmiCecSinkImplementation::sendUserControlReleased(const int logicalAddress) + { + if(!(_instance->smConnection)) + return; + LOGINFO(" User Control Released \n"); + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(UserControlReleased()), 100); + } + + void HdmiCecSinkImplementation::sendDeviceUpdateInfo(const int logicalAddress) + { + LOGINFO("Send Device Update Info \n"); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->OnDeviceInfoUpdated(logicalAddress); + index++; + } + } + void HdmiCecSinkImplementation::systemAudioModeRequest() + { + if ( cecEnableStatus != true ) + { + LOGINFO("systemAudioModeRequest: Cec is disabled-> EnableCEC first"); + return; + } + + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + if(!(_instance->smConnection)) + { + return; + } + LOGINFO(" Send systemAudioModeRequest "); + _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(SystemAudioModeRequest(physical_addr)), 1000); + + } + void HdmiCecSinkImplementation::sendGiveAudioStatusMsg() + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + if(!(_instance->smConnection)) + { + return; + } + LOGINFO(" Send GiveAudioStatus "); + _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(GiveAudioStatus()), 100); + + } + void HdmiCecSinkImplementation::reportAudioDevicePowerStatusInfo(const int logicalAddress, const int powerStatus) + { + JsonObject params; + params["powerStatus"] = JsonValue(powerStatus); + LOGINFO("Panle power state is %s", powerState ? "Off" : "On"); + if (powerStatus != AUDIO_DEVICE_POWERSTATE_OFF) { + if (powerState == DEVICE_POWER_STATE_ON ) { + LOGINFO("Notify DS!!! logicalAddress = %d , Audio device power status = %d \n", logicalAddress, powerStatus); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ReportAudioDevicePowerStatus(powerStatus); + index++; + } + } else { + LOGINFO("Not notifying audio device power state to DS"); + } + } else { + LOGINFO("Notify DS!!! logicalAddress = %d , Audio device power status = %d \n", logicalAddress, powerStatus); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ReportAudioDevicePowerStatus(powerStatus); + index++; + } + } + } + + void HdmiCecSinkImplementation::SendStandbyMsgEvent(const int logicalAddress) + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->StandbyMessageReceived(logicalAddress); + index++; + } + + } + Core::hresult HdmiCecSinkImplementation::SetEnabled(const bool &enabled, HdmiCecSinkSuccess &success) + { + + setEnabled(enabled); + success.success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::GetEnabled(bool &enabled, bool &success) + { + enabled = getEnabled(); + success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::GetAudioDeviceConnectedStatus(bool &connected, bool &success) + { + connected = getAudioDeviceConnectedStatus(); + success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::GetActiveSource(bool &available, uint8_t &logicalAddress, string &physicalAddress, string &deviceType, string &cecVersion, string &osdName, string &vendorID, string &powerStatus, string &port, bool &success) + { + char routeString[1024] = {'\0'}; + int length = 0; + std::stringstream temp; + + if ( HdmiCecSinkImplementation::_instance->m_currentActiveSource != -1 ) + { + int n = HdmiCecSinkImplementation::_instance->m_currentActiveSource; + available = true; + logicalAddress = HdmiCecSinkImplementation::_instance->deviceList[n].m_logicalAddress.toInt(); + physicalAddress = HdmiCecSinkImplementation::_instance->deviceList[n].m_physicalAddr.toString().c_str(); + deviceType = HdmiCecSinkImplementation::_instance->deviceList[n].m_deviceType.toString().c_str(); + cecVersion = HdmiCecSinkImplementation::_instance->deviceList[n].m_cecVersion.toString().c_str(); + osdName = HdmiCecSinkImplementation::_instance->deviceList[n].m_osdName.toString().c_str(); + vendorID = HdmiCecSinkImplementation::_instance->deviceList[n].m_vendorID.toString().c_str(); + powerStatus = HdmiCecSinkImplementation::_instance->deviceList[n].m_powerStatus.toString().c_str(); + + + if ( HdmiCecSinkImplementation::_instance->deviceList[n].m_physicalAddr.getByteValue(0) != 0 ) + { + snprintf(&routeString[length], sizeof(routeString) - length, "%s%d", "HDMI",(HdmiCecSinkImplementation::_instance->deviceList[n].m_physicalAddr.getByteValue(0) - 1)); + } + else if ( HdmiCecSinkImplementation::_instance->deviceList[n].m_physicalAddr.getByteValue(0) == 0 ) + { + snprintf(&routeString[length], sizeof(routeString) - length, "%s", "TV"); + } + + temp << (char *)routeString; + port = temp.str(); + + } + else + { + available = false; + } + + success = true; + return Core::ERROR_NONE; + + } + + Core::hresult HdmiCecSinkImplementation::GetDeviceList(uint32_t &numberofdevices, IHdmiCecSinkDeviceListIterator*& deviceList, bool &success) + { + + numberofdevices = HdmiCecSinkImplementation::_instance->m_numberOfDevices; + LOGINFO("getDeviceList m_numberOfDevices :%d \n", HdmiCecSinkImplementation::_instance->m_numberOfDevices); + std::vector localDevices; + Exchange::IHdmiCecSink::HdmiCecSinkDevices actual_hdmicecdevices = {0}; + + for (int n = 0; n <= LogicalAddress::UNREGISTERED; n++) + { + + if ( n != HdmiCecSinkImplementation::_instance->m_logicalAddressAllocated && + HdmiCecSinkImplementation::_instance->deviceList[n].m_isDevicePresent ) + { + + actual_hdmicecdevices.logicalAddress = HdmiCecSinkImplementation::_instance->deviceList[n].m_logicalAddress.toInt(); + actual_hdmicecdevices.physicalAddress = HdmiCecSinkImplementation::_instance->deviceList[n].m_physicalAddr.toString().c_str(); + actual_hdmicecdevices.deviceType = HdmiCecSinkImplementation::_instance->deviceList[n].m_deviceType.toString().c_str(); + actual_hdmicecdevices.cecVersion = HdmiCecSinkImplementation::_instance->deviceList[n].m_cecVersion.toString().c_str(); + actual_hdmicecdevices.osdName = HdmiCecSinkImplementation::_instance->deviceList[n].m_osdName.toString().c_str(); + actual_hdmicecdevices.vendorID = HdmiCecSinkImplementation::_instance->deviceList[n].m_vendorID.toString().c_str(); + actual_hdmicecdevices.powerStatus = HdmiCecSinkImplementation::_instance->deviceList[n].m_powerStatus.toString().c_str(); + int hdmiPortNumber = -1; + LOGINFO("getDeviceList m_numofHdmiInput:%d looking for Logical Address :%d \n", m_numofHdmiInput, HdmiCecSinkImplementation::_instance->deviceList[n].m_logicalAddress.toInt()); + for (int i=0; i < m_numofHdmiInput; i++) + { + LOGINFO("getDeviceList connected : %d, portid:%d LA: %d \n", hdmiInputs[i].m_isConnected, hdmiInputs[i].m_portID, hdmiInputs[i].m_logicalAddr.toInt()); + if(hdmiInputs[i].m_isConnected && hdmiInputs[i].m_logicalAddr.toInt() == HdmiCecSinkImplementation::_instance->deviceList[n].m_logicalAddress.toInt()) + { + hdmiPortNumber = hdmiInputs[i].m_portID; + LOGINFO("got portid :%d break \n", hdmiPortNumber); + break; + } + } + actual_hdmicecdevices.powerStatus = hdmiPortNumber; + localDevices.push_back(actual_hdmicecdevices); + } + } + + deviceList = (Core::Service>::Create(localDevices)); + success = true; + return Core::ERROR_NONE; + } + + + Core::hresult HdmiCecSinkImplementation::SetOSDName(const string &name, HdmiCecSinkSuccess &success) + { + + LOGINFO("SetOSDName osdName: %s",name.c_str()); + osdName = name.c_str(); + Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_OSD_NAME, JsonValue(name.c_str())); + + success.success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::GetOSDName(string &name, bool &success) + { + name = osdName.toString(); + LOGINFO("GetOSDName osdName : %s \n",osdName.toString().c_str()); + success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::PrintDeviceList(bool &printed, bool &success) + { + printDeviceList(); + printed = true; + success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::SetActiveSource(HdmiCecSinkSuccess &success) + { + setActiveSource(false); + success.success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::SetActivePath(const string &activePath, HdmiCecSinkSuccess &success) + { + string activePathStr = activePath; + PhysicalAddress phy_addr = PhysicalAddress(activePathStr); + LOGINFO("Addr = %s, length = %zu", activePathStr.c_str(), activePathStr.length()); + setStreamPath(phy_addr); + success.success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::GetActiveRoute(bool &available, uint8_t &length, IHdmiCecSinkActivePathIterator*& pathList, string &ActiveRoute, bool &success) + { + std::vector route; + char routeString[1024] = {'\0'}; + std::vector paths; + std::stringstream temp; + + if (HdmiCecSinkImplementation::_instance->m_currentActiveSource != -1 && + HdmiCecSinkImplementation::_instance->m_currentActiveSource != HdmiCecSinkImplementation::_instance->m_logicalAddressAllocated ) + { + HdmiCecSinkImplementation::_instance->getActiveRoute(LogicalAddress(HdmiCecSinkImplementation::_instance->m_currentActiveSource), route); + + if (route.size()) + { + available = true; + length = route.size(); + + for (unsigned int i=0; i < route.size(); i++) + { + if ( route[i] != LogicalAddress::UNREGISTERED ) + { + Exchange::IHdmiCecSink::HdmiCecSinkActivePath device; + + device.logicalAddress = HdmiCecSinkImplementation::_instance->deviceList[route[i]].m_logicalAddress.toInt(); + device.physicalAddress = HdmiCecSinkImplementation::_instance->deviceList[route[i]].m_physicalAddr.toString().c_str(); + device.deviceType = HdmiCecSinkImplementation::_instance->deviceList[route[i]].m_deviceType.toString().c_str(); + device.vendorID = HdmiCecSinkImplementation::_instance->deviceList[route[i]].m_osdName.toString().c_str(); + device.osdName = HdmiCecSinkImplementation::_instance->deviceList[route[i]].m_vendorID.toString().c_str(); + + paths.push_back(device); + + snprintf(&routeString[length], sizeof(routeString) - length, "%s", _instance->deviceList[route[i]].m_logicalAddress.toString().c_str()); + length += _instance->deviceList[route[i]].m_logicalAddress.toString().length(); + snprintf(&routeString[length], sizeof(routeString) - length, "(%s", _instance->deviceList[route[i]].m_osdName.toString().c_str()); + length += _instance->deviceList[route[i]].m_osdName.toString().length(); + snprintf(&routeString[length], sizeof(routeString) - length, "%s", ")-->"); + length += strlen(")-->"); + if( i + 1 == route.size() ) + { + snprintf(&routeString[length], sizeof(routeString) - length, "%s%d", "HDMI",(HdmiCecSinkImplementation::_instance->deviceList[route[i]].m_physicalAddr.getByteValue(0) - 1)); + } + } + } + + pathList = (Core::Service>::Create(paths)); + temp << (char *)routeString; + ActiveRoute = temp.str(); + LOGINFO("ActiveRoute = [%s]", routeString); + } + else{ + available = false; + } + + } + else if ( HdmiCecSinkImplementation::_instance->m_currentActiveSource == HdmiCecSinkImplementation::_instance->m_logicalAddressAllocated ) + { + available = true; + ActiveRoute = "TV"; + } + else + { + available = false; + } + + success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::RequestActiveSource(HdmiCecSinkSuccess &success) + { + requestActiveSource(); + success.success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::SetRoutingChange(const string &oldPort, const string &newPort, HdmiCecSinkSuccess &success) + { + if ((oldPort.find("HDMI",0) != std::string::npos || + oldPort.find("TV",0) != std::string::npos ) && + (newPort.find("HDMI", 0) != std::string::npos || + newPort.find("TV", 0) != std::string::npos )) + { + setRoutingChange(oldPort, newPort); + success.success = true; + } + else + { + success.success = false; + } + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::SetMenuLanguage(const string &language, HdmiCecSinkSuccess &success) + { + std::string lang; + + lang = language; + + setCurrentLanguage(Language(lang.data())); + success.success = true; + + return Core::ERROR_NONE; + + } + + + Core::hresult HdmiCecSinkImplementation::SetVendorId(const string &vendorId, HdmiCecSinkSuccess &success) + { + + unsigned int vendorID = 0x00; + try + { + vendorID = stoi(vendorId,NULL,16); + } + catch (...) + { + LOGWARN("Exception in setVendorId set default value\n"); + vendorID = 0x0019FB; + } + appVendorId = {(uint8_t)(vendorID >> 16 & 0xff),(uint8_t)(vendorID>> 8 & 0xff),(uint8_t) (vendorID & 0xff)}; + LOGINFO("appVendorId : %s vendorID :%x \n",appVendorId.toString().c_str(), vendorID ); + Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_VENDOR_ID, JsonValue(vendorID)); + + success.success = true; + return Core::ERROR_NONE; + } + Core::hresult HdmiCecSinkImplementation::SetupARCRouting(const bool &enabled, HdmiCecSinkSuccess &success) + { + if(enabled) + { + startArc(); + } + else + { + stopArc(); + } + + success.success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::GetVendorId(string &vendorid, bool &success) + { + LOGINFO("GetVendorId appVendorId : %s \n",appVendorId.toString().c_str()); + vendorid = appVendorId.toString() ; + success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::RequestShortAudioDescriptor(HdmiCecSinkSuccess &success) + { + requestShortaudioDescriptor(); + success.success = true; + return Core::ERROR_NONE; + } + Core::hresult HdmiCecSinkImplementation::SendStandbyMessage(HdmiCecSinkSuccess &success) + { + sendStandbyMessage(); + success.success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::SendAudioDevicePowerOnMessage(HdmiCecSinkSuccess &success) + { + LOGINFO("%s invoked. \n",__FUNCTION__); + systemAudioModeRequest(); + success.success = true; + return Core::ERROR_NONE; + } + Core::hresult HdmiCecSinkImplementation::SendKeyPressEvent(const uint32_t &logicalAddress, const uint32_t &keyCode, HdmiCecSinkSuccess &success) + { + SendKeyInfo keyInfo; + + keyInfo.logicalAddr = logicalAddress; + keyInfo.keyCode = keyCode; + keyInfo.UserControl = "sendKeyPressEvent"; + std::unique_lock lk(m_sendKeyEventMutex); + m_SendKeyQueue.push(keyInfo); + m_sendKeyEventThreadRun = true; + m_sendKeyCV.notify_one(); + LOGINFO("Post send key press event to queue size:%zu \n",m_SendKeyQueue.size()); + success.success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::SendUserControlPressed(const uint32_t &logicalAddress, const uint32_t &keyCode, HdmiCecSinkSuccess &success) + { + + SendKeyInfo keyInfo; + keyInfo.logicalAddr = logicalAddress; + keyInfo.keyCode = keyCode; + keyInfo.UserControl = "sendUserControlPressed"; + std::unique_lock lk(m_sendKeyEventMutex); + m_SendKeyQueue.push(keyInfo); + m_sendKeyEventThreadRun = true; + m_sendKeyCV.notify_one(); + LOGINFO("User control pressed, queue size:%zu \n",m_SendKeyQueue.size()); + success.success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::SendUserControlReleased(const uint32_t &logicalAddress, HdmiCecSinkSuccess &success) + { + SendKeyInfo keyInfo; + keyInfo.logicalAddr = logicalAddress; + keyInfo.keyCode = 0; + keyInfo.UserControl = "sendUserControlReleased"; + std::unique_lock lk(m_sendKeyEventMutex); + m_SendKeyQueue.push(keyInfo); + m_sendKeyEventThreadRun = true; + m_sendKeyCV.notify_one(); + LOGINFO("User Control Released, queue size:%zu \n",m_SendKeyQueue.size()); + success.success = true; + return Core::ERROR_NONE; + } + + Core::hresult HdmiCecSinkImplementation::SendGetAudioStatusMessage(HdmiCecSinkSuccess &success) + { + sendGiveAudioStatusMsg(); + success.success = true; + return Core::ERROR_NONE; + } + Core::hresult HdmiCecSinkImplementation::SetLatencyInfo(const string &videoLatency, const string &lowLatencyMode, const string &audioOutputCompensated, const string &audioOutputDelay, HdmiCecSinkSuccess &success) + { + int video_latency,audio_output_compensated,audio_output_delay; + bool low_latency_mode; + + LOGINFO("SetLatencyInfo videoLatency : %s lowLatencyMode : %s audioOutputCompensated : %s audioOutputDelay : %s \n",videoLatency.c_str(),lowLatencyMode.c_str(),audioOutputCompensated.c_str(),audioOutputDelay.c_str()); + video_latency = stoi(videoLatency); + low_latency_mode = stoi(lowLatencyMode); + audio_output_compensated = stoi(audioOutputCompensated); + audio_output_delay = stoi(audioOutputDelay); + + updateCurrentLatency(video_latency, low_latency_mode,audio_output_compensated, audio_output_delay); + success.success = true; + return Core::ERROR_NONE; + } + bool HdmiCecSinkImplementation::loadSettings() + { + Core::File file; + file = CEC_SETTING_ENABLED_FILE; + + if( file.Open()) + { + JsonObject parameters; + parameters.IElement::FromFile(file); + bool isConfigAdded = false; + + if( parameters.HasLabel(CEC_SETTING_ENABLED)) + { + getBoolParameter(CEC_SETTING_ENABLED, cecSettingEnabled); + LOGINFO("CEC_SETTING_ENABLED present value:%d",cecSettingEnabled); + } + else + { + parameters[CEC_SETTING_ENABLED] = true; + cecSettingEnabled = true; + isConfigAdded = true; + LOGINFO("CEC_SETTING_ENABLED not present set dafult true:\n "); + } + + if( parameters.HasLabel(CEC_SETTING_OTP_ENABLED)) + { + getBoolParameter(CEC_SETTING_OTP_ENABLED, cecOTPSettingEnabled); + LOGINFO("CEC_SETTING_OTP_ENABLED present value :%d",cecOTPSettingEnabled); + } + else + { + parameters[CEC_SETTING_OTP_ENABLED] = true; + cecOTPSettingEnabled = true; + isConfigAdded = true; + LOGINFO("CEC_SETTING_OTP_ENABLED not present set dafult true:\n "); + } + if( parameters.HasLabel(CEC_SETTING_OSD_NAME)) + { + std::string osd_name; + getStringParameter(CEC_SETTING_OSD_NAME, osd_name); + osdName = osd_name.c_str(); + LOGINFO("CEC_SETTING_OSD_NAME present osd_name :%s",osdName.toString().c_str()); + } + else + { + parameters[CEC_SETTING_OSD_NAME] = osdName.toString(); + LOGINFO("CEC_SETTING_OSD_NMAE not present set dafult value :%s\n ",osdName.toString().c_str()); + isConfigAdded = true; + } + unsigned int vendorId = (defaultVendorId.at(0) <<16) | ( defaultVendorId.at(1) << 8 ) | defaultVendorId.at(2); + if( parameters.HasLabel(CEC_SETTING_VENDOR_ID)) + { + getNumberParameter(CEC_SETTING_VENDOR_ID, vendorId); + LOGINFO("CEC_SETTING_VENDOR_ID present :%x ",vendorId); + } + else + { + LOGINFO("CEC_SETTING_VENDOR_ID not present set dafult value :%x \n ",vendorId); + parameters[CEC_SETTING_VENDOR_ID] = vendorId; + isConfigAdded = true; + } + + appVendorId = {(uint8_t)(vendorId >> 16 & 0xff),(uint8_t)(vendorId >> 8 & 0xff),(uint8_t) (vendorId & 0xff)}; + LOGINFO("appVendorId : %s vendorId :%x \n",appVendorId.toString().c_str(), vendorId ); + + if(isConfigAdded) + { + LOGINFO("isConfigAdded true so update file:\n "); + file.Destroy(); + file.Create(); + parameters.IElement::ToFile(file); + + } + + file.Close(); + } + else + { + LOGINFO("CEC_SETTING_ENABLED_FILE file not present create with default settings "); + file.Open(false); + if (!file.IsOpen()) + file.Create(); + + JsonObject parameters; + unsigned int vendorId = (defaultVendorId.at(0) <<16) | ( defaultVendorId.at(1) << 8 ) | defaultVendorId.at(2); + parameters[CEC_SETTING_ENABLED] = true; + parameters[CEC_SETTING_OSD_NAME] = osdName.toString(); + parameters[CEC_SETTING_VENDOR_ID] = vendorId; + + cecSettingEnabled = true; + cecOTPSettingEnabled = true; + parameters.IElement::ToFile(file); + + file.Close(); + + } + + return cecSettingEnabled; + } + + void HdmiCecSinkImplementation::setEnabled(bool enabled) + { + LOGINFO("Entered setEnabled: %d cecSettingEnabled :%d ",enabled, cecSettingEnabled); + + if (cecSettingEnabled != enabled) + { + Utils::persistJsonSettings (CEC_SETTING_ENABLED_FILE, CEC_SETTING_ENABLED, JsonValue(enabled)); + cecSettingEnabled = enabled; + } + if(true == enabled) + { + CECEnable(); + } + else + { + CECDisable(); + } + return; + } + + void HdmiCecSinkImplementation::updateImageViewOn(const int logicalAddress) + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED || + logicalAddress == LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + if (_instance->deviceList[logicalAddress].m_isDevicePresent && + _instance->deviceList[_instance->m_logicalAddressAllocated].m_powerStatus.toInt() == PowerStatus::STANDBY) + { + /* Bringing TV out of standby is handled by application.notify UI to bring the TV out of standby */ + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->OnWakeupFromStandby(logicalAddress); + index++; + } + } + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->OnInActiveSource(logicalAddress, _instance->deviceList[logicalAddress].m_physicalAddr.toString()); + index++; + } + } + + void HdmiCecSinkImplementation::updateTextViewOn(const int logicalAddress) + { + JsonObject params; + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED || + logicalAddress == LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + if (_instance->deviceList[logicalAddress].m_isDevicePresent && + _instance->deviceList[_instance->m_logicalAddressAllocated].m_powerStatus.toInt() == PowerStatus::STANDBY) + { + /* Bringing TV out of standby is handled by application.notify UI to bring the TV out of standby */ + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->OnWakeupFromStandby(logicalAddress); + index++; + } + } + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->OnTextViewOnMsg(logicalAddress); + index++; + } + } + + + void HdmiCecSinkImplementation::updateDeviceChain(const LogicalAddress &logicalAddress, const PhysicalAddress &phy_addr) + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + if (_instance->deviceList[logicalAddress.toInt()].m_isDevicePresent && + logicalAddress.toInt() != _instance->m_logicalAddressAllocated) + { + for (int i=0; i < m_numofHdmiInput; i++) + { + LOGINFO(" addr = %d, portID = %d", phy_addr.getByteValue(0), hdmiInputs[i].m_portID); + if (phy_addr.getByteValue(0) == (hdmiInputs[i].m_portID + 1)) { + hdmiInputs[i].addChild(logicalAddress, phy_addr); + } + } + } + } + + void HdmiCecSinkImplementation::getActiveRoute(const LogicalAddress &logicalAddress, std::vector &route) + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED || + logicalAddress.toInt() == LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + if (_instance->deviceList[logicalAddress.toInt()].m_isDevicePresent && + logicalAddress.toInt() != _instance->m_logicalAddressAllocated && + _instance->deviceList[logicalAddress.toInt()].m_isActiveSource ) + { + route.clear(); + for (int i=0; i < m_numofHdmiInput; i++) + { + LOGINFO("physicalAddress = [%d], portID = %d", _instance->deviceList[logicalAddress.toInt()].m_physicalAddr.getByteValue(0), hdmiInputs[i].m_portID); + if (_instance->deviceList[logicalAddress.toInt()].m_physicalAddr.getByteValue(0) == (hdmiInputs[i].m_portID + 1)) { + hdmiInputs[i].getRoute(_instance->deviceList[logicalAddress.toInt()].m_physicalAddr, route); + } + } + } + else { + LOGERR("Not in correct state to Find Route"); + } + } + + + void HdmiCecSinkImplementation::CheckHdmiInState() + { + int err; + bool isAnyPortConnected = false; + + dsHdmiInGetStatusParam_t params; + err = IARM_Bus_Call(IARM_BUS_DSMGR_NAME, + IARM_BUS_DSMGR_API_dsHdmiInGetStatus, + (void *)¶ms, + sizeof(params)); + + if(err == IARM_RESULT_SUCCESS && params.result == dsERR_NONE ) + { + for( int i = 0; i < m_numofHdmiInput; i++ ) + { + LOGINFO("Is HDMI In Port [%d] connected [%d] \n",i, params.status.isPortConnected[i]); + if ( params.status.isPortConnected[i] ) + { + isAnyPortConnected = true; + } + + LOGINFO("update Port Status [%d] \n", i); + hdmiInputs[i].update(params.status.isPortConnected[i]); + } + } + + if ( isAnyPortConnected ) { + m_isHdmiInConnected = true; + } else { + m_isHdmiInConnected = false; + } + } + + void HdmiCecSinkImplementation::requestActiveSource() + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if(!(_instance->smConnection)) + { + return; + } + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + + _instance->smConnection->sendTo(LogicalAddress::BROADCAST, + MessageEncoder().encode(RequestActiveSourceMessage()), 500); + } + + void HdmiCecSinkImplementation::setActiveSource(bool isResponse) + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if(!(_instance->smConnection)) + { + return; + } + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + if (isResponse && (_instance->m_currentActiveSource != _instance->m_logicalAddressAllocated) ) + { + LOGWARN("TV is not current Active Source"); + return; + } + + _instance->smConnection->sendTo(LogicalAddress::BROADCAST, + MessageEncoder().encode(ActiveSource(_instance->deviceList[_instance->m_logicalAddressAllocated].m_physicalAddr)), 500); + _instance->m_currentActiveSource = _instance->m_logicalAddressAllocated; + } + + void HdmiCecSinkImplementation::setCurrentLanguage(const Language &lang) + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + _instance->deviceList[_instance->m_logicalAddressAllocated].m_currentLanguage = lang; + } + + void HdmiCecSinkImplementation::sendMenuLanguage() + { + Language lang = ""; + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if(!(_instance->smConnection)) + { + return; + } + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + lang = _instance->deviceList[_instance->m_logicalAddressAllocated].m_currentLanguage; + + _instance->smConnection->sendTo(LogicalAddress::BROADCAST, MessageEncoder().encode(SetMenuLanguageMessage(lang)), 100); + } + + void HdmiCecSinkImplementation::updateInActiveSource(const int logical_address, const InActiveSource &source ) + { + JsonObject params; + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + if( logical_address != _instance->m_logicalAddressAllocated ) + { + _instance->deviceList[logical_address].m_isActiveSource = false; + + if ( _instance->m_currentActiveSource == logical_address ) + { + _instance->m_currentActiveSource = -1; + } + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->OnInActiveSource(logical_address, source.physicalAddress.toString()); + index++; + } + } + } + + void HdmiCecSinkImplementation::updateActiveSource(const int logical_address, const ActiveSource &source ) + { + JsonObject params; + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + if( logical_address != _instance->m_logicalAddressAllocated ) + { + if ( _instance->m_currentActiveSource != -1 ) + { + _instance->deviceList[_instance->m_currentActiveSource].m_isActiveSource = false; + } + + _instance->deviceList[logical_address].m_isActiveSource = true; + _instance->deviceList[logical_address].update(source.physicalAddress); + _instance->m_currentActiveSource = logical_address; + + if (_instance->deviceList[logical_address].m_isDevicePresent && + _instance->deviceList[_instance->m_logicalAddressAllocated].m_powerStatus.toInt() == PowerStatus::STANDBY) + { + /* Bringing TV out of standby is handled by application.notify UI to bring the TV out of standby */ + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->OnWakeupFromStandby(logical_address); + index++; + } + } + + string physicalAddress = _instance->deviceList[logical_address].m_physicalAddr.toString().c_str(); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->OnActiveSourceChange(logical_address, physicalAddress); + index++; + } + } + } + + void HdmiCecSinkImplementation::requestShortaudioDescriptor() + { + if ( cecEnableStatus != true ) + { + LOGINFO("requestShortaudioDescriptor: cec is disabled-> EnableCEC first"); + return; + } + + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if(!(_instance->smConnection)) + { + return; + } + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + LOGINFO(" Send requestShortAudioDescriptor Message "); + _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(RequestShortAudioDescriptorMessage(formatid,audioFormatCode,numberofdescriptor)), 1000); + + } + + void HdmiCecSinkImplementation::requestAudioDevicePowerStatus() + { + if ( cecEnableStatus != true ) + { + LOGWARN("cec is disabled-> EnableCEC first"); + return; + } + + if(!HdmiCecSinkImplementation::_instance) + return; + + if(!(_instance->smConnection)) + { + return; + } + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + LOGINFO(" Send GiveDevicePowerStatus Message to Audio system in the network \n"); + _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM, MessageEncoder().encode(GiveDevicePowerStatus()), 500); + + m_audioDevicePowerStatusRequested = true; + } + + void HdmiCecSinkImplementation::sendFeatureAbort(const LogicalAddress logicalAddress, const OpCode feature, const AbortReason reason) + { + + if(!HdmiCecSinkImplementation::_instance) + return; + if(!(_instance->smConnection)) + return; + LOGINFO(" Sending FeatureAbort to %s for opcode %s with reason %s ",logicalAddress.toString().c_str(),feature.toString().c_str(),reason.toString().c_str()); + _instance->smConnection->sendTo(logicalAddress, MessageEncoder().encode(FeatureAbort(feature,reason)), 500); + } + + void HdmiCecSinkImplementation::reportFeatureAbortEvent(const LogicalAddress logicalAddress, const OpCode featureOpcode, const AbortReason abortReason) + { + LOGINFO(" Notifying the UI FeatureAbort from the %s for the opcode %s with the reason %s ",logicalAddress.toString().c_str(),featureOpcode.toString().c_str(),abortReason.toString().c_str()); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ReportFeatureAbortEvent(logicalAddress.toInt(), featureOpcode.opCode(), abortReason.toInt()); + index++; + } + } + + void HdmiCecSinkImplementation::pingDevices(std::vector &connected , std::vector &disconnected) + { + int i; + + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + if(!(_instance->smConnection)) + return; + + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED ){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + for(i=0; i< LogicalAddress::UNREGISTERED; i++ ) { + if ( i != _instance->m_logicalAddressAllocated ) + { + //LOGWARN("PING for 0x%x \r\n",i); + try { + _instance->smConnection->ping(LogicalAddress(_instance->m_logicalAddressAllocated), LogicalAddress(i), Throw_e()); + } + catch(CECNoAckException &e) + { + if ( _instance->deviceList[i].m_isDevicePresent ) { + disconnected.push_back(i); + } + //LOGWARN("Ping device: 0x%x caught %s \r\n", i, e.what()); + usleep(50000); + continue; + } + catch(Exception &e) + { + LOGWARN("Ping device: 0x%x caught %s \r\n", i, e.what()); + usleep(50000); + continue; + } + + /* If we get ACK, then the device is present in the network*/ + if ( !_instance->deviceList[i].m_isDevicePresent ) + { + connected.push_back(i); + //LOGWARN("Ping success, added device: 0x%x \r\n", i); + } + usleep(50000); + } + } + } + + int HdmiCecSinkImplementation::requestType( const int logicalAddress ) { + int requestType = CECDeviceParams::REQUEST_NONE; + + if ( !_instance->deviceList[logicalAddress].m_isPAUpdated || !_instance->deviceList[logicalAddress].m_isDeviceTypeUpdated ) { + requestType = CECDeviceParams::REQUEST_PHISICAL_ADDRESS; + }else if ( !_instance->deviceList[logicalAddress].m_isOSDNameUpdated ) { + requestType = CECDeviceParams::REQUEST_OSD_NAME; + }else if ( !_instance->deviceList[logicalAddress].m_isVersionUpdated ) { + requestType = CECDeviceParams::REQUEST_CEC_VERSION; + }else if ( !_instance->deviceList[logicalAddress].m_isVendorIDUpdated ) { + requestType = CECDeviceParams::REQUEST_DEVICE_VENDOR_ID; + }else if ( !_instance->deviceList[logicalAddress].m_isPowerStatusUpdated ) { + requestType = CECDeviceParams::REQUEST_POWER_STATUS; + } + + return requestType; + } + + void HdmiCecSinkImplementation::printDeviceList() { + int i; + + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + for(i=0; i< 16; i++) + { + if (HdmiCecSinkImplementation::_instance->deviceList[i].m_isDevicePresent) { + LOGWARN("------ Device ID = %d--------", i); + HdmiCecSinkImplementation::_instance->deviceList[i].printVariable(); + LOGWARN("-----------------------------"); + } + } + } + + void HdmiCecSinkImplementation::setStreamPath( const PhysicalAddress &physical_addr) { + + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if(!(_instance->smConnection)) + { + return; + } + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED){ + LOGERR("Logical Address NOT Allocated Or its not valid"); + return; + } + + _instance->smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(SetStreamPath(physical_addr)), 500); + } + + void HdmiCecSinkImplementation::setRoutingChange(const std::string &from, const std::string &to) { + PhysicalAddress oldPhyAddr = {0xF,0xF,0xF,0xF}; + PhysicalAddress newPhyAddr = {0xF,0xF,0xF,0xF}; + int oldPortID = -1; + int newPortID = -1; + + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED){ + LOGERR("Logical Address NOT Allocated Or its not valid"); + return; + } + + if( from.find("TV",0) != std::string::npos ) + { + oldPhyAddr = _instance->deviceList[_instance->m_logicalAddressAllocated].m_physicalAddr; + _instance->m_currentActiveSource = -1; + } + else + { + oldPortID = stoi(from.substr(4,1),NULL,16); + if ( oldPortID < _instance->m_numofHdmiInput ) + { + oldPhyAddr = _instance->hdmiInputs[oldPortID].m_physicalAddr; + } + else + { + LOGERR("Invalid HDMI Old Port ID"); + return; + } + } + + if( to.find("TV",0) != std::string::npos ) + { + newPhyAddr = _instance->deviceList[_instance->m_logicalAddressAllocated].m_physicalAddr; + /*set active source as TV */ + _instance->m_currentActiveSource = _instance->m_logicalAddressAllocated; + } + else + { + newPortID = stoi(to.substr(4,1),NULL,16); + + if ( newPortID < _instance->m_numofHdmiInput ) + { + newPhyAddr = _instance->hdmiInputs[newPortID].m_physicalAddr; + } + else + { + LOGERR("Invalid HDMI New Port ID"); + return; + } + } + + if(!(_instance->smConnection)) + { + return; + } + _instance->smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), MessageEncoder().encode(RoutingChange(oldPhyAddr, newPhyAddr)), 500); + } + + void HdmiCecSinkImplementation::addDevice(const int logicalAddress) { + JsonObject params; + + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + if ( !HdmiCecSinkImplementation::_instance->deviceList[logicalAddress].m_isDevicePresent ) + { + HdmiCecSinkImplementation::_instance->deviceList[logicalAddress].m_isDevicePresent = true; + HdmiCecSinkImplementation::_instance->deviceList[logicalAddress].m_logicalAddress = LogicalAddress(logicalAddress); + HdmiCecSinkImplementation::_instance->m_numberOfDevices++; + HdmiCecSinkImplementation::_instance->m_pollNextState = POLL_THREAD_STATE_INFO; + + if(logicalAddress == 0x5) + { + LOGINFO(" logicalAddress =%d , Audio device detected, Notify Device Settings", logicalAddress ); + hdmiCecAudioDeviceConnected = true; + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ReportAudioDeviceConnectedStatus("success", "true"); + index++; + } + } + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->OnDeviceAdded(logicalAddress); + index++; + } + } + } + + void HdmiCecSinkImplementation::removeDevice(const int logicalAddress) { + JsonObject params; + + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED){ + LOGERR("Logical Address NOT Allocated"); + return; + } + + if (_instance->deviceList[logicalAddress].m_isDevicePresent) + { + _instance->m_numberOfDevices--; + + for (int i=0; i < m_numofHdmiInput; i++) + { + if (_instance->deviceList[logicalAddress].m_physicalAddr.getByteValue(0) == (hdmiInputs[i].m_portID + 1)) { + hdmiInputs[i].removeChild(_instance->deviceList[logicalAddress].m_physicalAddr); + hdmiInputs[i].update(LogicalAddress(LogicalAddress::UNREGISTERED)); + } + } + + if(logicalAddress == 0x5) + { + LOGINFO(" logicalAddress =%d , Audio device removed, Notify Device Settings", logicalAddress ); + + hdmiCecAudioDeviceConnected = false; + if (m_audioStatusDetectionTimer.isActive()){ + m_audioStatusDetectionTimer.stop(); + } + m_isAudioStatusInfoUpdated = false; + m_audioStatusReceived = false; + m_audioStatusTimerStarted = false; + LOGINFO("Audio device removed, reset the audio status info. m_isAudioStatusInfoUpdated :%d, m_audioStatusReceived :%d, m_audioStatusTimerStarted:%d ", m_isAudioStatusInfoUpdated,m_audioStatusReceived,m_audioStatusTimerStarted); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ReportAudioDeviceConnectedStatus("success", "false"); + index++; + } + } + + _instance->deviceList[logicalAddress].m_isRequestRetry = 0; + _instance->deviceList[logicalAddress].clear(); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->OnDeviceRemoved(logicalAddress); + index++; + } + } + } + + void HdmiCecSinkImplementation::request(const int logicalAddress) { + int requestType; + + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + if(!(_instance->smConnection)) + { + return; + } + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED || logicalAddress >= LogicalAddress::UNREGISTERED + TEST_ADD ){ + LOGERR("Logical Address NOT Allocated Or its not valid"); + return; + } + + requestType = _instance->requestType(logicalAddress); + _instance->deviceList[logicalAddress].m_isRequested = requestType; + + switch (requestType) + { + case CECDeviceParams::REQUEST_PHISICAL_ADDRESS : + { + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(GivePhysicalAddress()), 200); + } + break; + + case CECDeviceParams::REQUEST_CEC_VERSION : + { + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(GetCECVersion()), 100); + } + break; + + case CECDeviceParams::REQUEST_DEVICE_VENDOR_ID : + { + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(GiveDeviceVendorID()), 100); + } + break; + + case CECDeviceParams::REQUEST_OSD_NAME : + { + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(GiveOSDName()), 500); + } + break; + + case CECDeviceParams::REQUEST_POWER_STATUS : + { + _instance->smConnection->sendTo(LogicalAddress(logicalAddress), MessageEncoder().encode(GiveDevicePowerStatus()), 100); + } + break; + default: + { + _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; + } + break; + } + + _instance->deviceList[logicalAddress].m_requestTime = std::chrono::system_clock::now(); + LOGINFO("request type %d", _instance->deviceList[logicalAddress].m_isRequested); + } + + int HdmiCecSinkImplementation::requestStatus(const int logicalAddress) { + std::chrono::duration elapsed; + bool isElapsed = false; + + if(!HdmiCecSinkImplementation::_instance) + return -1; + + + if ( _instance->m_logicalAddressAllocated == LogicalAddress::UNREGISTERED || logicalAddress >= LogicalAddress::UNREGISTERED + TEST_ADD ) { + LOGERR("Logical Address NOT Allocated Or its not valid"); + return -1; + } + + switch ( _instance->deviceList[logicalAddress].m_isRequested ) { + case CECDeviceParams::REQUEST_PHISICAL_ADDRESS : + { + if( _instance->deviceList[logicalAddress].m_isPAUpdated && + _instance->deviceList[logicalAddress].m_isDeviceTypeUpdated ) + { + _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; + } + } + break; + + case CECDeviceParams::REQUEST_CEC_VERSION : + { + if( _instance->deviceList[logicalAddress].m_isVersionUpdated ) + { + _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; + } + } + break; + + case CECDeviceParams::REQUEST_DEVICE_VENDOR_ID : + { + if( _instance->deviceList[logicalAddress].m_isVendorIDUpdated ) + { + _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; + } + } + break; + + case CECDeviceParams::REQUEST_OSD_NAME : + { + if( _instance->deviceList[logicalAddress].m_isOSDNameUpdated ) + { + _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; + } + } + break; + + case CECDeviceParams::REQUEST_POWER_STATUS : + { + if( _instance->deviceList[logicalAddress].m_isPowerStatusUpdated ) + { + _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; + } + } + break; + default: + break; + } + + if ( _instance->deviceList[logicalAddress].m_isRequested != CECDeviceParams::REQUEST_NONE ) + { + elapsed = std::chrono::system_clock::now() - _instance->deviceList[logicalAddress].m_requestTime; + + if ( elapsed.count() > HDMICECSINK_REQUEST_MAX_WAIT_TIME_MS ) + { + LOGINFO("request elapsed "); + isElapsed = true; + } + } + + if (isElapsed) + { + /* For some request it should be retry, like report physical address etc for other we can have default values */ + switch( _instance->deviceList[logicalAddress].m_isRequested ) + { + case CECDeviceParams::REQUEST_PHISICAL_ADDRESS : + { + LOGINFO("Retry for REQUEST_PHISICAL_ADDRESS = %d", _instance->deviceList[logicalAddress].m_isRequestRetry); + /* Update with Invalid Physical Address */ + if ( _instance->deviceList[logicalAddress].m_isRequestRetry++ >= HDMICECSINK_REQUEST_MAX_RETRY ) + { + LOGINFO("Max retry for REQUEST_PHISICAL_ADDRESS = %d", _instance->deviceList[logicalAddress].m_isRequestRetry); + _instance->deviceList[logicalAddress].update(PhysicalAddress(0xF,0xF,0xF,0xF)); + _instance->deviceList[logicalAddress].update(DeviceType(DeviceType::RESERVED)); + _instance->deviceList[logicalAddress].m_isRequestRetry = 0; + } + } + break; + + case CECDeviceParams::REQUEST_CEC_VERSION : + { + /*Defaulting to 1.4*/ + _instance->deviceList[logicalAddress].update(Version(Version::V_1_4)); + } + break; + + case CECDeviceParams::REQUEST_DEVICE_VENDOR_ID : + { + _instance->deviceList[logicalAddress].update(VendorID(0,0,0)); + } + break; + + case CECDeviceParams::REQUEST_OSD_NAME : + { + if ( _instance->deviceList[logicalAddress].m_isRequestRetry++ >= HDMICECSINK_REQUEST_MAX_RETRY ) + { + LOGINFO("Max retry for REQUEST_OSD_NAME = %d", _instance->deviceList[logicalAddress].m_isRequestRetry); + _instance->deviceList[logicalAddress].update(OSDName("")); + _instance->deviceList[logicalAddress].m_isRequestRetry = 0; + } + } + break; + + case CECDeviceParams::REQUEST_POWER_STATUS : + { + _instance->deviceList[logicalAddress].update(PowerStatus(PowerStatus::POWER_STATUS_NOT_KNOWN)); + } + break; + default: + break; + } + + + _instance->deviceList[logicalAddress].m_isRequested = CECDeviceParams::REQUEST_NONE; + } + + if( _instance->deviceList[logicalAddress].m_isRequested == CECDeviceParams::REQUEST_NONE) + { + LOGINFO("Request Done"); + return CECDeviceParams::REQUEST_DONE; + } + + //LOGINFO("Request NOT Done"); + return CECDeviceParams::REQUEST_NOT_DONE; + } + + void HdmiCecSinkImplementation::threadRun() + { + std::vector connected; + std::vector disconnected; + int logicalAddressRequested = LogicalAddress::UNREGISTERED + TEST_ADD; + bool isExit = false; + + if(!HdmiCecSinkImplementation::_instance) + return; + + if(!(_instance->smConnection)) + return; + LOGINFO("Entering ThreadRun: _instance->m_pollThreadExit %d isExit %d _instance->m_pollThreadState %d _instance->m_pollNextState %d",_instance->m_pollThreadExit,isExit,_instance->m_pollThreadState,_instance->m_pollNextState ); + _instance->m_sleepTime = HDMICECSINK_PING_INTERVAL_MS; + + while(1) + { + + if (_instance->m_pollThreadExit || isExit ){ + LOGWARN("Thread Exits _instance->m_pollThreadExit %d isExit %d _instance->m_pollThreadState %d _instance->m_pollNextState %d",_instance->m_pollThreadExit,isExit,_instance->m_pollThreadState,_instance->m_pollNextState ); + break; + } + + if ( _instance->m_pollNextState != POLL_THREAD_STATE_NONE ) + { + _instance->m_pollThreadState = _instance->m_pollNextState; + _instance->m_pollNextState = POLL_THREAD_STATE_NONE; + } + + switch (_instance->m_pollThreadState) { + + case POLL_THREAD_STATE_POLL : + { + //LOGINFO("POLL_THREAD_STATE_POLL"); + _instance->allocateLogicalAddress(DeviceType::TV); + if ( _instance->m_logicalAddressAllocated != LogicalAddress::UNREGISTERED) + { + try{ + + logicalAddress = LogicalAddress(_instance->m_logicalAddressAllocated); + LibCCEC::getInstance().addLogicalAddress(logicalAddress); + _instance->smConnection->setSource(logicalAddress); + _instance->m_numberOfDevices = 0; + _instance->deviceList[_instance->m_logicalAddressAllocated].m_deviceType = DeviceType::TV; + _instance->deviceList[_instance->m_logicalAddressAllocated].m_isDevicePresent = true; + _instance->deviceList[_instance->m_logicalAddressAllocated].update(physical_addr); + _instance->deviceList[_instance->m_logicalAddressAllocated].m_cecVersion = Version::V_1_4; + _instance->deviceList[_instance->m_logicalAddressAllocated].m_vendorID = appVendorId; + _instance->deviceList[_instance->m_logicalAddressAllocated].m_powerStatus = PowerStatus(powerState); + _instance->deviceList[_instance->m_logicalAddressAllocated].m_currentLanguage = defaultLanguage; + _instance->deviceList[_instance->m_logicalAddressAllocated].m_osdName = osdName.toString().c_str(); + if(cecVersion == 2.0) { + _instance->deviceList[_instance->m_logicalAddressAllocated].m_cecVersion = Version::V_2_0; + _instance->smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), + MessageEncoder().encode(ReportFeatures(Version::V_2_0,allDevicetype,rcProfile,deviceFeatures)), 500); + } + _instance->smConnection->addFrameListener(_instance->msgFrameListener); + _instance->smConnection->sendTo(LogicalAddress(LogicalAddress::BROADCAST), + MessageEncoder().encode(ReportPhysicalAddress(physical_addr, _instance->deviceList[_instance->m_logicalAddressAllocated].m_deviceType)), 100); + + _instance->m_sleepTime = 0; + _instance->m_pollThreadState = POLL_THREAD_STATE_PING; + } + catch(InvalidStateException &e){ + LOGWARN("InvalidStateException caught while allocated logical address. %s", e.what()); + _instance->m_pollThreadState = POLL_THREAD_STATE_EXIT; + } + catch(IOException &e){ + LOGWARN("IOException caught while allocated logical address. %s", e.what()); + _instance->m_pollThreadState = POLL_THREAD_STATE_EXIT; + } + catch(...){ + LOGWARN("Exception caught while allocated logical address."); + _instance->m_pollThreadState = POLL_THREAD_STATE_EXIT; + } + } + else + { + LOGINFO("Not able allocate Logical Address for TV"); + _instance->m_pollThreadState = POLL_THREAD_STATE_EXIT; + } + } + break; + + case POLL_THREAD_STATE_PING : + { + //LOGINFO("POLL_THREAD_STATE_PING"); + _instance->m_pollThreadState = POLL_THREAD_STATE_INFO; + connected.clear(); + disconnected.clear(); + _instance->pingDevices(connected, disconnected); + + if ( disconnected.size() ){ + for( unsigned int i=0; i< disconnected.size(); i++ ) + { + LOGWARN("Disconnected Devices [%zu]", disconnected.size()); + _instance->removeDevice(disconnected[i]); + } + } + + if (connected.size()) { + LOGWARN("Connected Devices [%zu]", connected.size()); + for( unsigned int i=0; i< connected.size(); i++ ) + { + _instance->addDevice(connected[i]); + /* If new device is connected, then try to aquire the information */ + _instance->m_pollThreadState = POLL_THREAD_STATE_INFO; + _instance->m_sleepTime = 0; + } + } + else + { + for(int i=0;im_logicalAddressAllocated && + _instance->deviceList[i].m_isDevicePresent && + !_instance->deviceList[i].isAllUpdated() ) + { + _instance->m_pollNextState = POLL_THREAD_STATE_INFO; + _instance->m_sleepTime = 0; + } + } + /* Check for any update required */ + _instance->m_pollThreadState = POLL_THREAD_STATE_UPDATE; + _instance->m_sleepTime = 0; + } + } + break; + + case POLL_THREAD_STATE_INFO : + { + //LOGINFO("POLL_THREAD_STATE_INFO"); + + if ( logicalAddressRequested == LogicalAddress::UNREGISTERED + TEST_ADD ) + { + int i = 0; + for(;im_logicalAddressAllocated && + _instance->deviceList[i].m_isDevicePresent && + !_instance->deviceList[i].isAllUpdated() ) + { + //LOGINFO("POLL_THREAD_STATE_INFO -> request for %d", i); + logicalAddressRequested = i; + _instance->request(logicalAddressRequested); + _instance->m_sleepTime = HDMICECSINK_REQUEST_INTERVAL_TIME_MS; + break; + } + } + + if ( i == LogicalAddress::UNREGISTERED) + { + /*So there is no update required, try to ping after some seconds*/ + _instance->m_pollThreadState = POLL_THREAD_STATE_IDLE; + _instance->m_sleepTime = 0; + //LOGINFO("POLL_THREAD_STATE_INFO -> state change to Ping", i); + } + } + else + { + /*So there is request sent for logical address, so wait and check the status */ + if ( _instance->requestStatus(logicalAddressRequested) == CECDeviceParams::REQUEST_DONE ) + { + logicalAddressRequested = LogicalAddress::UNREGISTERED; + } + else + { + _instance->m_sleepTime = HDMICECSINK_REQUEST_INTERVAL_TIME_MS; + } + } + } + break; + + /* updating the power status and if required we can add other information later*/ + case POLL_THREAD_STATE_UPDATE : + { + //LOGINFO("POLL_THREAD_STATE_UPDATE"); + + for(int i=0;im_logicalAddressAllocated && + _instance->deviceList[i].m_isDevicePresent && + _instance->deviceList[i].m_isPowerStatusUpdated ) + { + std::chrono::duration elapsed = std::chrono::system_clock::now() - _instance->deviceList[i].m_lastPowerUpdateTime; + + if ( elapsed.count() > HDMICECSINK_UPDATE_POWER_STATUS_INTERVA_MS ) + { + _instance->deviceList[i].m_isPowerStatusUpdated = false; + _instance->m_pollNextState = POLL_THREAD_STATE_INFO; + _instance->m_sleepTime = 0; + } + } + } + + _instance->m_pollThreadState = POLL_THREAD_STATE_IDLE; + _instance->m_sleepTime = 0; + } + break; + + case POLL_THREAD_STATE_IDLE : + { + //LOGINFO("POLL_THREAD_STATE_IDLE"); + _instance->m_sleepTime = HDMICECSINK_PING_INTERVAL_MS; + _instance->m_pollThreadState = POLL_THREAD_STATE_PING; + } + break; + + case POLL_THREAD_STATE_WAIT : + { + /* Wait for Hdmi is connected, in case it disconnected */ + //LOGINFO("19Aug2020-[01] -> POLL_THREAD_STATE_WAIT"); + _instance->m_sleepTime = HDMICECSINK_WAIT_FOR_HDMI_IN_MS; + + if ( _instance->m_isHdmiInConnected == true ) + { + _instance->m_pollThreadState = POLL_THREAD_STATE_POLL; + } + } + break; + + case POLL_THREAD_STATE_EXIT : + { + isExit = true; + _instance->m_sleepTime = 0; + } + break; + } + + std::unique_lock lk(_instance->m_pollExitMutex); + if ( _instance->m_ThreadExitCV.wait_for(lk, std::chrono::milliseconds(_instance->m_sleepTime)) == std::cv_status::timeout ) + continue; + else + LOGINFO("Thread is going to Exit m_pollThreadExit %d\n", _instance->m_pollThreadExit ); + + } + } + + void HdmiCecSinkImplementation::allocateLAforTV() + { + bool gotLogicalAddress = false; + int addr = LogicalAddress::TV; + int i, j; + if (!(_instance->smConnection)) + return; + + for (i = 0; i< HDMICECSINK_NUMBER_TV_ADDR; i++) + { + /* poll for TV logical address - retry 5 times*/ + for (j = 0; j < 5; j++) + { + try { + smConnection->poll(LogicalAddress(addr), Throw_e()); + } + catch(CECNoAckException &e ) + { + LOGWARN("Poll caught %s \r\n",e.what()); + gotLogicalAddress = true; + break; + } + catch(Exception &e) + { + LOGWARN("Poll caught %s \r\n",e.what()); + usleep(250000); + } + } + if (gotLogicalAddress) + { + break; + } + addr = LogicalAddress::SPECIFIC_USE; + } + + if ( gotLogicalAddress ) + { + m_logicalAddressAllocated = addr; + } + else + { + m_logicalAddressAllocated = LogicalAddress::UNREGISTERED; + } + + LOGWARN("Logical Address for TV 0x%x \r\n",m_logicalAddressAllocated); + } + + void HdmiCecSinkImplementation::allocateLogicalAddress(int deviceType) + { + if( deviceType == DeviceType::TV ) + { + allocateLAforTV(); + } + } + + void HdmiCecSinkImplementation::CECEnable(void) + { + std::lock_guard lock(m_enableMutex); + JsonObject params; + LOGINFO("Entered CECEnable"); + if (cecEnableStatus) + { + LOGWARN("CEC Already Enabled"); + return; + } + + if(0 == libcecInitStatus) + { + try + { + LibCCEC::getInstance().init("HdmiCecSinkImplementation"); + } + catch(InvalidStateException &e){ + LOGWARN("InvalidStateException caught in LibCCEC::init %s", e.what()); + } + catch(IOException &e){ + LOGWARN("IOException caught in LibCCEC::init %s", e.what()); + } + catch(...){ + LOGWARN("Exception caught in LibCCEC::init"); + } + } + libcecInitStatus++; + + //Acquire CEC Addresses + _instance->getPhysicalAddress(); + + smConnection = new Connection(LogicalAddress::UNREGISTERED,false,"ServiceManager::Connection::"); + smConnection->open(); + allocateLogicalAddress(DeviceType::TV); + LOGINFO("logical address allocalted: %x \n",m_logicalAddressAllocated); + if ( m_logicalAddressAllocated != LogicalAddress::UNREGISTERED && smConnection) + { + logicalAddress = LogicalAddress(m_logicalAddressAllocated); + LOGINFO(" add logical address %x \n",m_logicalAddressAllocated); + LibCCEC::getInstance().addLogicalAddress(logicalAddress); + smConnection->setSource(logicalAddress); + } + msgProcessor = new HdmiCecSinkProcessor(*smConnection); + msgFrameListener = new HdmiCecSinkFrameListener(*msgProcessor); + if(smConnection) + { + LOGWARN("Start Thread %p", smConnection ); + m_pollThreadState = POLL_THREAD_STATE_POLL; + m_pollNextState = POLL_THREAD_STATE_NONE; + m_pollThreadExit = false; + m_pollThread = std::thread(threadRun); + } + cecEnableStatus = true; + + params["cecEnable"] = string("true"); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ReportCecEnabledEvent("true"); + index++; + } + + return; + } + + void HdmiCecSinkImplementation::CECDisable(void) + { + std::lock_guard lock(m_enableMutex); + JsonObject params; + LOGINFO("Entered CECDisable "); + if(!cecEnableStatus) + { + LOGWARN("CEC Already Disabled "); + return; + } + + if(m_currentArcRoutingState != ARC_STATE_ARC_TERMINATED) + { + stopArc(); + while(m_currentArcRoutingState != ARC_STATE_ARC_TERMINATED) + { + usleep(500000); + } + } + + LOGINFO(" CECDisable ARC stopped "); + cecEnableStatus = false; + if (smConnection != NULL) + { + LOGWARN("Stop Thread %p", smConnection ); + m_pollThreadExit = true; + m_ThreadExitCV.notify_one(); + + try + { + if (m_pollThread.joinable()) + { + LOGWARN("Join Thread %p", smConnection ); + m_pollThread.join(); + } + } + catch(const std::system_error& e) + { + LOGERR("system_error exception in thread join %s", e.what()); + } + catch(const std::exception& e) + { + LOGERR("exception in thread join %s", e.what()); + } + + m_pollThreadState = POLL_THREAD_STATE_NONE; + m_pollNextState = POLL_THREAD_STATE_NONE; + + LOGWARN("Deleted Thread %p", smConnection ); + + smConnection->close(); + delete smConnection; + smConnection = NULL; + } + + m_logicalAddressAllocated = LogicalAddress::UNREGISTERED; + m_currentArcRoutingState = ARC_STATE_ARC_TERMINATED; + if (m_audioStatusDetectionTimer.isActive()){ + m_audioStatusDetectionTimer.stop(); + } + m_isAudioStatusInfoUpdated = false; + m_audioStatusReceived = false; + m_audioStatusTimerStarted = false; + LOGINFO("CEC Disabled, reset the audio status info. m_isAudioStatusInfoUpdated :%d, m_audioStatusReceived :%d, m_audioStatusTimerStarted:%d ", m_isAudioStatusInfoUpdated,m_audioStatusReceived,m_audioStatusTimerStarted); + + for(int i=0; i< 16; i++) + { + if (_instance->deviceList[i].m_isDevicePresent) + { + _instance->deviceList[i].clear(); + } + } + + if(1 == libcecInitStatus) + { + try + { + LibCCEC::getInstance().term(); + } + catch(InvalidStateException &e){ + LOGWARN("InvalidStateException caught in LibCCEC::term %s", e.what()); + } + catch(IOException &e){ + LOGWARN("IOException caught in LibCCEC::term %s", e.what()); + } + catch(...){ + LOGWARN("Exception caught in LibCCEC::term"); + } + + libcecInitStatus--; + LOGWARN("CEC Disabled %d",libcecInitStatus); + + params["cecEnable"] = string("false"); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ReportCecEnabledEvent("false"); + index++; + } + } + return; + } + + + void HdmiCecSinkImplementation::getPhysicalAddress() + { + LOGINFO("Entered getPhysicalAddress "); + + uint32_t physAddress = 0x0F0F0F0F; + + try { + LibCCEC::getInstance().getPhysicalAddress(&physAddress); + physical_addr = {(uint8_t)((physAddress >> 24) & 0xFF),(uint8_t)((physAddress >> 16) & 0xFF),(uint8_t) ((physAddress >> 8) & 0xFF),(uint8_t)((physAddress) & 0xFF)}; + LOGINFO("getPhysicalAddress: physicalAddress: %s ", physical_addr.toString().c_str()); + } + catch (const std::exception& e) + { + LOGWARN("exception caught from getPhysicalAddress"); + } + return; + } + + bool HdmiCecSinkImplementation::getEnabled() + { + + + LOGINFO("getEnabled :%d ",cecEnableStatus); + if(true == cecEnableStatus) + return true; + else + return false; + } + + bool HdmiCecSinkImplementation::getAudioDeviceConnectedStatus() + { + LOGINFO("getAudioDeviceConnectedStatus :%d ", hdmiCecAudioDeviceConnected); + if(true == hdmiCecAudioDeviceConnected) + return true; + else + return false; + } + //Arc Routing related functions + void HdmiCecSinkImplementation::startArc() + { + if ( cecEnableStatus != true ) + { + LOGINFO("Initiate_Arc Cec is disabled-> EnableCEC first"); + return; + } + if(!HdmiCecSinkImplementation::_instance) + return; + + LOGINFO("Current ARC State : %d\n", m_currentArcRoutingState); + + _instance->requestArcInitiation(); + + // start initiate ARC timer 3 sec + if (m_arcStartStopTimer.isActive()) + { + m_arcStartStopTimer.stop(); + } + m_arcstarting = true; + m_arcStartStopTimer.start((HDMISINK_ARC_START_STOP_MAX_WAIT_MS)); + + } + void HdmiCecSinkImplementation::requestArcInitiation() + { + { + std::lock_guard lock(m_arcRoutingStateMutex); + m_currentArcRoutingState = ARC_STATE_REQUEST_ARC_INITIATION; + } + LOGINFO("requestArcInitiation release sem"); + _instance->m_semSignaltoArcRoutingThread.release(); + + } + void HdmiCecSinkImplementation::stopArc() + { + if ( cecEnableStatus != true ) + { + LOGINFO("Initiate_Arc Cec is disabled-> EnableCEC first"); + return; + } + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + if(m_currentArcRoutingState == ARC_STATE_REQUEST_ARC_TERMINATION || m_currentArcRoutingState == ARC_STATE_ARC_TERMINATED) + { + LOGINFO("ARC is either Termination in progress or already Terminated"); + return; + } + + _instance->requestArcTermination(); + /* start a timer for 3 sec to get the desired ARC_STATE_ARC_TERMINATED */ + if (m_arcStartStopTimer.isActive()) + { + m_arcStartStopTimer.stop(); + } + /* m_arcstarting = true means starting the ARC start timer ,false means ARC stopping timer*/ + m_arcstarting = false; + m_arcStartStopTimer.start((HDMISINK_ARC_START_STOP_MAX_WAIT_MS)); + + + } + void HdmiCecSinkImplementation::requestArcTermination() + { + { + std::lock_guard lock(m_arcRoutingStateMutex); + m_currentArcRoutingState = ARC_STATE_REQUEST_ARC_TERMINATION; + } + LOGINFO("requestArcTermination release sem"); + _instance->m_semSignaltoArcRoutingThread.release(); + + } + + void HdmiCecSinkImplementation::Process_InitiateArc() + { + JsonObject params; + + LOGINFO("Command: INITIATE_ARC \n"); + + if(!HdmiCecSinkImplementation::_instance) + return; + + //DD: Check cecSettingEnabled to prevent race conditions which gives immediate UI setting status + //Initiate ARC message may come from AVR/Soundbar while CEC disable is in-progress + if ( cecSettingEnabled != true ) + { + LOGINFO("Process InitiateArc from Audio device: Cec is disabled-> EnableCEC first"); + return; + } + + LOGINFO("Got : INITIATE_ARC and current Arcstate is %d\n",_instance->m_currentArcRoutingState); + + if (m_arcStartStopTimer.isActive()) + { + m_arcStartStopTimer.stop(); + } + if (powerState == DEVICE_POWER_STATE_ON ) { + LOGINFO("Notifying Arc Initiation event as power state is %s", powerState ? "Off" : "On"); + std::lock_guard lock(_instance->m_arcRoutingStateMutex); + _instance->m_currentArcRoutingState = ARC_STATE_ARC_INITIATED; + + _instance->m_semSignaltoArcRoutingThread.release(); + LOGINFO("Got : ARC_INITIATED and notify Device setting"); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ArcInitiationEvent("success"); + index++; + } + } else { + LOGINFO("Not notifying Arc Initiation event as power state is %s", powerState ? "Off" : "On"); + } + + } + void HdmiCecSinkImplementation::Process_TerminateArc() + { + JsonObject params; + + LOGINFO("Command: TERMINATE_ARC current arc state %d \n",HdmiCecSinkImplementation::_instance->m_currentArcRoutingState); + if (m_arcStartStopTimer.isActive()) + { + m_arcStartStopTimer.stop(); + } + std::lock_guard lock(m_arcRoutingStateMutex); + HdmiCecSinkImplementation::_instance->m_currentArcRoutingState = ARC_STATE_ARC_TERMINATED; + _instance->m_semSignaltoArcRoutingThread.release(); + + // trigger callback to Device setting informing to TERMINATE_ARC + LOGINFO("Got : ARC_TERMINATED and notify Device setting"); + std::list::const_iterator index(_hdmiCecSinkNotifications.begin()); + while (index != _hdmiCecSinkNotifications.end()) { + (*index)->ArcTerminationEvent("success"); + index++; + } + } + + void HdmiCecSinkImplementation::threadSendKeyEvent() + { + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + SendKeyInfo keyInfo = {-1,-1}; + + while(!_instance->m_sendKeyEventThreadExit) + { + keyInfo.logicalAddr = -1; + keyInfo.keyCode = -1; + { + // Wait for a message to be added to the queue + std::unique_lock lk(_instance->m_sendKeyEventMutex); + _instance->m_sendKeyCV.wait(lk, []{return (_instance->m_sendKeyEventThreadRun == true);}); + } + + if (_instance->m_sendKeyEventThreadExit == true) + { + LOGINFO(" threadSendKeyEvent Exiting"); + _instance->m_sendKeyEventThreadRun = false; + break; + } + + if (_instance->m_SendKeyQueue.empty()) { + _instance->m_sendKeyEventThreadRun = false; + continue; + } + + keyInfo = _instance->m_SendKeyQueue.front(); + _instance->m_SendKeyQueue.pop(); + + if(keyInfo.UserControl == "sendUserControlPressed" ) + { + LOGINFO("sendUserControlPressed : logical addr:0x%x keyCode: 0x%x queue size :%zu \n",keyInfo.logicalAddr,keyInfo.keyCode,_instance->m_SendKeyQueue.size()); + _instance->sendUserControlPressed(keyInfo.logicalAddr,keyInfo.keyCode); + } + else if(keyInfo.UserControl == "sendUserControlReleased") + { + LOGINFO("sendUserControlReleased : logical addr:0x%x queue size :%zu \n",keyInfo.logicalAddr,_instance->m_SendKeyQueue.size()); + _instance->sendUserControlReleased(keyInfo.logicalAddr); + } + else + { + LOGINFO("sendKeyPressEvent : logical addr:0x%x keyCode: 0x%x queue size :%zu \n",keyInfo.logicalAddr,keyInfo.keyCode,_instance->m_SendKeyQueue.size()); + _instance->sendKeyPressEvent(keyInfo.logicalAddr,keyInfo.keyCode); + _instance->sendKeyReleaseEvent(keyInfo.logicalAddr); + } + + if((_instance->m_SendKeyQueue.size()<=1 || (_instance->m_SendKeyQueue.size() % 2 == 0)) && ((keyInfo.keyCode == VOLUME_UP) || (keyInfo.keyCode == VOLUME_DOWN) || (keyInfo.keyCode == MUTE)) ) + { + if(keyInfo.keyCode == MUTE) + { + _instance->sendGiveAudioStatusMsg(); + } + else + { + LOGINFO("m_isAudioStatusInfoUpdated :%d, m_audioStatusReceived :%d, m_audioStatusTimerStarted:%d ",_instance->m_isAudioStatusInfoUpdated,_instance->m_audioStatusReceived,_instance->m_audioStatusTimerStarted); + if (!_instance->m_isAudioStatusInfoUpdated) + { + if ( !(_instance->m_audioStatusDetectionTimer.isActive())) + { + LOGINFO("Audio status info not updated. Starting the Timer!"); + _instance->m_audioStatusTimerStarted = true; + _instance->m_audioStatusDetectionTimer.start((HDMICECSINK_UPDATE_AUDIO_STATUS_INTERVAL_MS)); + } + LOGINFO("m_isAudioStatusInfoUpdated :%d, m_audioStatusReceived :%d, m_audioStatusTimerStarted:%d ", _instance->m_isAudioStatusInfoUpdated,_instance->m_audioStatusReceived,_instance->m_audioStatusTimerStarted); + } + else + { + if (!_instance->m_audioStatusReceived){ + _instance->sendGiveAudioStatusMsg(); + } + } + } + } + }//while(!_instance->m_sendKeyEventThreadExit) + }//threadSendKeyEvent + + void HdmiCecSinkImplementation::audioStatusTimerFunction() + { + m_audioStatusTimerStarted = false; + m_isAudioStatusInfoUpdated = true; + LOGINFO("Timer Expired. Requesting the AudioStatus since not received.\n"); + sendGiveAudioStatusMsg(); + LOGINFO("m_isAudioStatusInfoUpdated :%d, m_audioStatusReceived :%d, m_audioStatusTimerStarted:%d ", m_isAudioStatusInfoUpdated,m_audioStatusReceived,m_audioStatusTimerStarted); + } + + + void HdmiCecSinkImplementation::threadArcRouting() + { + bool isExit = false; + uint32_t currentArcRoutingState; + + if(!HdmiCecSinkImplementation::_instance) + { + return; + } + + LOGINFO("Running threadArcRouting"); + _instance->getHdmiArcPortID(); + + while(1) + { + + _instance->m_semSignaltoArcRoutingThread.acquire(); + + + + { + LOGINFO(" threadArcRouting Got semaphore"); + std::lock_guard lock(_instance->m_arcRoutingStateMutex); + + currentArcRoutingState = _instance->m_currentArcRoutingState; + + LOGINFO(" threadArcRouting Got Sem arc state %d",currentArcRoutingState); + } + + switch (currentArcRoutingState) + { + + case ARC_STATE_REQUEST_ARC_INITIATION : + { + + _instance->systemAudioModeRequest(); + _instance->Send_Request_Arc_Initiation_Message(); + + } + break; + case ARC_STATE_ARC_INITIATED : + { + _instance->Send_Report_Arc_Initiated_Message(); + } + break; + case ARC_STATE_REQUEST_ARC_TERMINATION : + { + + _instance->Send_Request_Arc_Termination_Message(); + + } + break; + case ARC_STATE_ARC_TERMINATED : + { + _instance->Send_Report_Arc_Terminated_Message(); + } + break; + case ARC_STATE_ARC_EXIT : + { + isExit = true; + } + break; + } + + if (isExit == true) + { + LOGINFO(" threadArcRouting EXITing"); + break; + } + }//while(1) + }//threadArcRouting + + void HdmiCecSinkImplementation::Send_Request_Arc_Initiation_Message() + { + if(!HdmiCecSinkImplementation::_instance) + return; + if(!(_instance->smConnection)) + return; + LOGINFO(" Send_Request_Arc_Initiation_Message "); + _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(RequestArcInitiation()), 1000); + + } + void HdmiCecSinkImplementation::Send_Report_Arc_Initiated_Message() + { + if(!HdmiCecSinkImplementation::_instance) + return; + if(!(_instance->smConnection)) + return; + _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(ReportArcInitiation()), 1000); + + } + void HdmiCecSinkImplementation::Send_Request_Arc_Termination_Message() + { + + if(!HdmiCecSinkImplementation::_instance) + return; + if(!(_instance->smConnection)) + return; + _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(RequestArcTermination()), 1000); + } + + void HdmiCecSinkImplementation::Send_Report_Arc_Terminated_Message() + { + if(!HdmiCecSinkImplementation::_instance) + return; + if(!(_instance->smConnection)) + return; + _instance->smConnection->sendTo(LogicalAddress::AUDIO_SYSTEM,MessageEncoder().encode(ReportArcTermination()), 1000); + + } + + void HdmiCecSinkImplementation::getHdmiArcPortID() + { + int err; + dsGetHDMIARCPortIdParam_t param; + err = IARM_Bus_Call(IARM_BUS_DSMGR_NAME, + (char *)IARM_BUS_DSMGR_API_dsGetHDMIARCPortId, + (void *)¶m, + sizeof(param)); + if (IARM_RESULT_SUCCESS == err) + { + LOGINFO("HDMI ARC port ID HdmiArcPortID=[%d] \n", param.portId); + HdmiArcPortID = param.portId; + } + } + + void HdmiCecSinkImplementation::getCecVersion() + { + RFC_ParamData_t param = {0}; + WDMP_STATUS status = getRFCParameter((char*)"thunderapi", TR181_HDMICECSINK_CEC_VERSION, ¶m); + if(WDMP_SUCCESS == status && param.type == WDMP_STRING) { + LOGINFO("CEC Version from RFC = [%s] \n", param.value); + cecVersion = atof(param.value); + } + else { + LOGINFO("Error while fetching CEC Version from RFC "); + } + } + + } // namespace Plugin +} // namespace WPEFrameworklk diff --git a/HdmiCecSink/HdmiCecSinkImplementation.h b/HdmiCecSink/HdmiCecSinkImplementation.h new file mode 100644 index 00000000..c9d91c11 --- /dev/null +++ b/HdmiCecSink/HdmiCecSinkImplementation.h @@ -0,0 +1,755 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2019 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 "ccec/FrameListener.hpp" +#include "ccec/Connection.hpp" + +#include "libIARM.h" +#include "ccec/Assert.hpp" +#include "ccec/Messages.hpp" +#include "ccec/MessageDecoder.hpp" +#include "ccec/MessageProcessor.hpp" + +#undef Assert // this define from Connection.hpp conflicts with WPEFramework + +#include "Module.h" +#include "tptimer.h" +#include +#include +#include +#include + +#include "UtilsLogging.h" +#include +#include "PowerManagerInterface.h" +#include + +using namespace WPEFramework; +using PowerState = WPEFramework::Exchange::IPowerManager::PowerState; +using ThermalTemperature = WPEFramework::Exchange::IPowerManager::ThermalTemperature; + + +namespace WPEFramework { + + namespace Plugin { + class HdmiCecSinkFrameListener : public FrameListener + { + public: + HdmiCecSinkFrameListener(MessageProcessor &processor) : processor(processor) {} + void notify(const CECFrame &in) const; + ~HdmiCecSinkFrameListener() {} + private: + MessageProcessor &processor; + }; + + class HdmiCecSinkProcessor : public MessageProcessor + { + public: + HdmiCecSinkProcessor(Connection &conn) : conn(conn) {} + void process (const ActiveSource &msg, const Header &header); + void process (const InActiveSource &msg, const Header &header); + void process (const ImageViewOn &msg, const Header &header); + void process (const TextViewOn &msg, const Header &header); + void process (const RequestActiveSourceMessage &msg, const Header &header); + void process (const Standby &msg, const Header &header); + void process (const GetCECVersion &msg, const Header &header); + void process (const CECVersion &msg, const Header &header); + void process (const SetMenuLanguageMessage &msg, const Header &header); + void process (const GiveOSDName &msg, const Header &header); + void process (const GivePhysicalAddress &msg, const Header &header); + void process (const GiveDeviceVendorID &msg, const Header &header); + void process (const SetOSDString &msg, const Header &header); + void process (const SetOSDName &msg, const Header &header); + void process (const RoutingChange &msg, const Header &header); + void process (const RoutingInformation &msg, const Header &header); + void process (const SetStreamPath &msg, const Header &header); + void process (const GetMenuLanguage &msg, const Header &header); + void process (const ReportPhysicalAddress &msg, const Header &header); + void process (const DeviceVendorID &msg, const Header &header); + void process (const GiveDevicePowerStatus &msg, const Header &header); + void process (const ReportPowerStatus &msg, const Header &header); + void process (const FeatureAbort &msg, const Header &header); + void process (const Abort &msg, const Header &header); + void process (const Polling &msg, const Header &header); + void process (const InitiateArc &msg, const Header &header); + void process (const TerminateArc &msg, const Header &header); + void process (const ReportShortAudioDescriptor &msg, const Header &header); + void process (const SetSystemAudioMode &msg, const Header &header); + void process (const ReportAudioStatus &msg, const Header &header); + void process (const GiveFeatures &msg, const Header &header); + void process (const RequestCurrentLatency &msg, const Header &header); + private: + Connection conn; + void printHeader(const Header &header) + { + printf("Header : From : %s \n", header.from.toString().c_str()); + printf("Header : to : %s \n", header.to.toString().c_str()); + } + + }; + + class CECDeviceParams { + public: + + enum { + REQUEST_NONE = 0, + REQUEST_PHISICAL_ADDRESS = 1, + REQUEST_CEC_VERSION, + REQUEST_DEVICE_VENDOR_ID, + REQUEST_POWER_STATUS, + REQUEST_OSD_NAME, + }; + + enum { + REQUEST_DONE = 0, + REQUEST_NOT_DONE, + REQUEST_TIME_ELAPSED, + }; + + DeviceType m_deviceType; + LogicalAddress m_logicalAddress; + PhysicalAddress m_physicalAddr; + Version m_cecVersion; + VendorID m_vendorID; + OSDName m_osdName; + PowerStatus m_powerStatus; + bool m_isDevicePresent; + bool m_isDeviceDisconnected; + Language m_currentLanguage; + bool m_isActiveSource; + bool m_isDeviceTypeUpdated; + bool m_isPAUpdated; + bool m_isVersionUpdated; + bool m_isOSDNameUpdated; + bool m_isVendorIDUpdated; + bool m_isPowerStatusUpdated; + int m_isRequested; + int m_isRequestRetry; + std::chrono::system_clock::time_point m_requestTime; + std::vector m_featureAborts; + std::chrono::system_clock::time_point m_lastPowerUpdateTime; + + CECDeviceParams() + : m_deviceType(0), m_logicalAddress(0),m_physicalAddr(0x0f,0x0f,0x0f,0x0f),m_cecVersion(0),m_vendorID(0,0,0),m_osdName(""),m_powerStatus(0),m_currentLanguage("") + { + m_isDevicePresent = false; + m_isActiveSource = false; + m_isPAUpdated = false; + m_isVersionUpdated = false; + m_isOSDNameUpdated = false; + m_isVendorIDUpdated = false; + m_isPowerStatusUpdated = false; + m_isDeviceDisconnected = false; + m_isDeviceTypeUpdated = false; + m_isRequestRetry = 0; + } + + void clear( ) + { + m_deviceType = 0; + m_logicalAddress = 0; + m_physicalAddr = PhysicalAddress(0x0f,0x0f,0x0f,0x0f); + m_cecVersion = 0; + m_vendorID = VendorID(0,0,0); + m_osdName = ""; + m_powerStatus = 0; + m_currentLanguage = ""; + m_isDevicePresent = false; + m_isActiveSource = false; + m_isPAUpdated = false; + m_isVersionUpdated = false; + m_isOSDNameUpdated = false; + m_isVendorIDUpdated = false; + m_isPowerStatusUpdated = false; + m_isDeviceDisconnected = false; + m_isDeviceTypeUpdated = false; + } + + void printVariable() + { + LOGWARN("Device LogicalAddress %s", m_logicalAddress.toString().c_str()); + LOGWARN("Device Type %s", m_deviceType.toString().c_str()); + LOGWARN("Device Present %d", m_isDevicePresent); + LOGWARN("Active Source %d", m_isActiveSource); + LOGWARN("PA Updated %d", m_isPAUpdated); + LOGWARN("Version Updated %d", m_isVersionUpdated); + LOGWARN("OSDName Updated %d", m_isOSDNameUpdated); + LOGWARN("PowerStatus Updated %d", m_isPowerStatusUpdated); + LOGWARN("VendorID Updated %d", m_isPowerStatusUpdated); + LOGWARN("CEC Version : %s", m_cecVersion.toString().c_str()); + LOGWARN("Vendor ID : %s", m_vendorID.toString().c_str()); + LOGWARN("PhisicalAddress : %s", m_physicalAddr.toString().c_str()); + LOGWARN("OSDName : %s", m_osdName.toString().c_str()); + LOGWARN("Power Status : %s", m_powerStatus.toString().c_str()); + LOGWARN("Language : %s", m_currentLanguage.toString().c_str()); + } + + bool isAllUpdated() { + if( !m_isPAUpdated + || !m_isVersionUpdated + || !m_isOSDNameUpdated + || !m_isVendorIDUpdated + || !m_isPowerStatusUpdated + || !m_isDeviceTypeUpdated ){ + return false; + } + return true; + } + + void update( const DeviceType &deviceType ) { + m_deviceType = deviceType; + m_isDeviceTypeUpdated = true; + } + + void update( const PhysicalAddress &physical_addr ) { + m_physicalAddr = physical_addr; + m_isPAUpdated = true; + } + + void update ( const VendorID &vendorId) { + m_vendorID = vendorId; + m_isVendorIDUpdated = true; + } + + void update ( const Version &version ) { + m_cecVersion = version; + m_isVersionUpdated = true; + } + + void update ( const OSDName &osdName ) { + m_osdName = osdName; + m_isOSDNameUpdated = true; + } + + void update ( const PowerStatus &status ) { + m_powerStatus = status; + m_isPowerStatusUpdated = true; + m_lastPowerUpdateTime = std::chrono::system_clock::now(); + } + }; + + class DeviceNode { + public: + uint8_t m_childsLogicalAddr[LogicalAddress::UNREGISTERED]; + + DeviceNode() { + int i; + for (i = 0; i < LogicalAddress::UNREGISTERED; i++ ) + { + m_childsLogicalAddr[i] = LogicalAddress::UNREGISTERED; + } + } + + } ; + typedef struct sendKeyInfo + { + int logicalAddr; + int keyCode; + string UserControl; + }SendKeyInfo; + + class HdmiPortMap { + public: + uint8_t m_portID; + bool m_isConnected; + LogicalAddress m_logicalAddr; + PhysicalAddress m_physicalAddr; + DeviceNode m_deviceChain[3]; + + HdmiPortMap(uint8_t portID) : m_portID(portID), + m_logicalAddr(LogicalAddress::UNREGISTERED), + m_physicalAddr(portID+1,0,0,0) + { + m_isConnected = false; + } + + void update(bool isConnected) + { + m_isConnected = isConnected; + } + + void update( const LogicalAddress &addr ) + { + m_logicalAddr = addr; + } + + void addChild( const LogicalAddress &logical_addr, const PhysicalAddress &physical_addr ) + { + LOGINFO(" logicalAddr = %d, phisicalAddr = %s", m_logicalAddr.toInt(), physical_addr.toString().c_str()); + + if ( m_logicalAddr.toInt() != LogicalAddress::UNREGISTERED && + m_logicalAddr.toInt() != logical_addr.toInt() ) + { + LOGINFO(" update own logicalAddr = %d, new devcie logicalAddress = %d", m_logicalAddr.toInt(), logical_addr.toInt() ); + /* check matching with this port's physical address */ + if( physical_addr.getByteValue(0) == m_physicalAddr.getByteValue(0) && + physical_addr.getByteValue(1) != 0 ) + { + if ( physical_addr.getByteValue(3) != 0 ) + { + m_deviceChain[2].m_childsLogicalAddr[physical_addr.getByteValue(3) - 1] = logical_addr.toInt(); + } + else if ( physical_addr.getByteValue(2) != 0 ) + { + m_deviceChain[1].m_childsLogicalAddr[physical_addr.getByteValue(2) - 1] = logical_addr.toInt(); + } + else if ( physical_addr.getByteValue(1) != 0 ) + { + m_deviceChain[0].m_childsLogicalAddr[physical_addr.getByteValue(1) - 1] = logical_addr.toInt(); + } + } + } + else if ( physical_addr == m_physicalAddr ) + { + update(logical_addr); + LOGINFO(" update own logicalAddr = %d", m_logicalAddr.toInt()); + } + } + + void removeChild( PhysicalAddress &physical_addr ) + { + if ( m_logicalAddr.toInt() != LogicalAddress::UNREGISTERED ) + { + /* check matching with this port's physical address */ + if( physical_addr.getByteValue(0) == m_physicalAddr.getByteValue(0) && + physical_addr.getByteValue(1) != 0 ) + { + if ( physical_addr.getByteValue(3) != 0 ) + { + m_deviceChain[2].m_childsLogicalAddr[physical_addr.getByteValue(3) - 1] = LogicalAddress::UNREGISTERED; + } + else if ( physical_addr.getByteValue(2) != 0 ) + { + m_deviceChain[1].m_childsLogicalAddr[physical_addr.getByteValue(2) - 1] = LogicalAddress::UNREGISTERED; + } + else if ( physical_addr.getByteValue(1) != 0 ) + { + m_deviceChain[0].m_childsLogicalAddr[physical_addr.getByteValue(1) - 1] = LogicalAddress::UNREGISTERED; + } + } + } + } + + void getRoute( PhysicalAddress &physical_addr, std::vector & route ) + { + LOGINFO(" logicalAddr = %d, phsical = %s", m_logicalAddr.toInt(), physical_addr.toString().c_str()); + + if ( m_logicalAddr.toInt() != LogicalAddress::UNREGISTERED ) + { + LOGINFO(" search for logicalAddr = %d", m_logicalAddr.toInt()); + /* check matching with this port's physical address */ + if( physical_addr.getByteValue(0) == m_physicalAddr.getByteValue(0) && + physical_addr.getByteValue(1) != 0 ) + { + if ( physical_addr.getByteValue(3) != 0 ) + { + route.push_back(m_deviceChain[2].m_childsLogicalAddr[physical_addr.getByteValue(3) - 1]); + } + + if ( physical_addr.getByteValue(2) != 0 ) + { + route.push_back(m_deviceChain[1].m_childsLogicalAddr[physical_addr.getByteValue(2) - 1]); + } + + if ( physical_addr.getByteValue(1) != 0 ) + { + route.push_back(m_deviceChain[0].m_childsLogicalAddr[physical_addr.getByteValue(1) - 1]); + } + + route.push_back(m_logicalAddr.toInt()); + } + else + { + route.push_back(m_logicalAddr.toInt()); + LOGINFO("logicalAddr = %d, physical = %s", m_logicalAddr.toInt(), m_physicalAddr.toString().c_str()); + } + } + } + }; + + class binary_semaphore { + + public: + + explicit binary_semaphore(int init_count = count_max) + + : count_(init_count) {} + + + + // P-operation / acquire + + void wait() + + { + + std::unique_lock lk(m_); + + cv_.wait(lk, [=]{ return 0 < count_; }); + + --count_; + + } + + bool try_wait() + + { + + std::lock_guard lk(m_); + + if (0 < count_) { + + --count_; + + return true; + + } else { + + return false; + + } + + } + + // V-operation / release + + void signal() + + { + + std::lock_guard lk(m_); + + if (count_ < count_max) { + + ++count_; + + cv_.notify_one(); + + } + + } + + + + // Lockable requirements + + void acquire() { wait(); } + + bool try_lock() { return try_wait(); } + + void release() { signal(); } + + + +private: + + static const int count_max = 1; + + int count_; + + std::mutex m_; + + std::condition_variable cv_; + +}; + // 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 HdmiCecSinkImplementation : public Exchange::IHdmiCecSink { + + enum { + POLL_THREAD_STATE_NONE, + POLL_THREAD_STATE_IDLE, + POLL_THREAD_STATE_POLL, + POLL_THREAD_STATE_PING, + POLL_THREAD_STATE_INFO, + POLL_THREAD_STATE_WAIT, + POLL_THREAD_STATE_CLEAN, + POLL_THREAD_STATE_UPDATE, + POLL_THREAD_STATE_EXIT, + }; + enum { + ARC_STATE_REQUEST_ARC_INITIATION, + ARC_STATE_ARC_INITIATED, + ARC_STATE_REQUEST_ARC_TERMINATION, + ARC_STATE_ARC_TERMINATED, + ARC_STATE_ARC_EXIT + }; + enum { + VOLUME_UP = 0x41, + VOLUME_DOWN = 0x42, + MUTE = 0x43, + UP = 0x01, + DOWN = 0x02, + LEFT = 0x03, + RIGHT = 0x04, + SELECT = 0x00, + HOME = 0x09, + BACK = 0x0D, + NUMBER_0 = 0x20, + NUMBER_1 = 0x21, + NUMBER_2 = 0x22, + NUMBER_3 = 0x23, + NUMBER_4 = 0x24, + NUMBER_5 = 0x25, + NUMBER_6 = 0x26, + NUMBER_7 = 0x27, + NUMBER_8 = 0x28, + NUMBER_9 = 0x29 + }; + public: + HdmiCecSinkImplementation(); + virtual ~HdmiCecSinkImplementation(); + static HdmiCecSinkImplementation* _instance; + CECDeviceParams deviceList[16]; + std::vector hdmiInputs; + int m_currentActiveSource; + void updateInActiveSource(const int logical_address, const InActiveSource &source ); + void updateActiveSource(const int logical_address, const ActiveSource &source ); + void updateTextViewOn(const int logicalAddress); + void updateImageViewOn(const int logicalAddress); + void updateDeviceChain(const LogicalAddress &logicalAddress, const PhysicalAddress &phy_addr); + void getActiveRoute(const LogicalAddress &logicalAddress, std::vector &route); + void removeDevice(const int logicalAddress); + void addDevice(const int logicalAddress); + void printDeviceList(); + void setStreamPath( const PhysicalAddress &physical_addr); + void setRoutingChange(const std::string &from, const std::string &to); + void sendStandbyMessage(); + void setCurrentLanguage(const Language &lang); + void sendMenuLanguage(); + void setActiveSource(bool isResponse); + void requestActiveSource(); + void startArc(); + void stopArc(); + void Process_InitiateArc(); + void Process_TerminateArc(); + void updateArcState(); + void requestShortaudioDescriptor(); + void Send_ShortAudioDescriptor_Event(JsonArray audiodescriptor); + void Process_ShortAudioDescriptor_msg(const ReportShortAudioDescriptor &msg); + void Process_SetSystemAudioMode_msg(const SetSystemAudioMode &msg); + void sendDeviceUpdateInfo(const int logicalAddress); + void sendFeatureAbort(const LogicalAddress logicalAddress, const OpCode feature, const AbortReason reason); + void reportFeatureAbortEvent(const LogicalAddress logicalAddress, const OpCode feature, const AbortReason reason); + void systemAudioModeRequest(); + void SendStandbyMsgEvent(const int logicalAddress); + void requestAudioDevicePowerStatus(); + void reportAudioDevicePowerStatusInfo(const int logicalAddress, const int powerStatus); + void updateCurrentLatency(int videoLatency, bool lowLatencyMode, int audioOutputCompensated, int audioOutputDelay); + void setLatencyInfo(); + void Process_ReportAudioStatus_msg(const ReportAudioStatus msg); + void sendKeyPressEvent(const int logicalAddress, int keyCode); + void sendKeyReleaseEvent(const int logicalAddress); + void sendUserControlPressed(const int logicalAddress, int keyCode); + void sendUserControlReleased(const int logicalAddress); + void sendGiveAudioStatusMsg(); + void onPowerModeChanged(const PowerState ¤tState, const PowerState &newState); + void registerEventHandlers(); + void getHdmiArcPortID(); + int m_numberOfDevices; /* Number of connected devices othethan own device */ + bool m_audioDevicePowerStatusRequested; + + BEGIN_INTERFACE_MAP(HdmiCecSinkImplementation) + INTERFACE_ENTRY(Exchange::IHdmiCecSink) + END_INTERFACE_MAP + + private: + class PowerManagerNotification : public Exchange::IPowerManager::IModeChangedNotification { + private: + PowerManagerNotification(const PowerManagerNotification&) = delete; + PowerManagerNotification& operator=(const PowerManagerNotification&) = delete; + + public: + explicit PowerManagerNotification(HdmiCecSinkImplementation& parent) + : _parent(parent) + { + } + ~PowerManagerNotification() override = default; + + public: + void OnPowerModeChanged(const PowerState currentState, const PowerState newState) override + { + _parent.onPowerModeChanged(currentState, newState); + } + + template + T* baseInterface() + { + static_assert(std::is_base_of(), "base type mismatch"); + return static_cast(this); + } + + BEGIN_INTERFACE_MAP(PowerManagerNotification) + INTERFACE_ENTRY(Exchange::IPowerManager::IModeChangedNotification) + END_INTERFACE_MAP + + private: + HdmiCecSinkImplementation& _parent; + + }; + // We do not allow this plugin to be copied !! + HdmiCecSinkImplementation(const HdmiCecSinkImplementation&) = delete; + HdmiCecSinkImplementation& operator=(const HdmiCecSinkImplementation&) = delete; + //Begin methods + void InitializePowerManager(PluginHost::IShell *service); + //End methods + std::string logicalAddressDeviceType; + bool cecSettingEnabled; + bool cecOTPSettingEnabled; + bool cecEnableStatus; + bool hdmiCecAudioDeviceConnected; + bool m_isHdmiInConnected; + int m_numofHdmiInput; + uint8_t m_deviceType; + int m_logicalAddressAllocated; + std::thread m_pollThread; + uint32_t m_pollThreadState; + uint32_t m_pollNextState; + bool m_pollThreadExit; + uint32_t m_sleepTime; + std::mutex m_pollExitMutex; + std::mutex m_enableMutex; + /* Send Key event related */ + bool m_sendKeyEventThreadExit; + bool m_sendKeyEventThreadRun; + bool m_isAudioStatusInfoUpdated; + bool m_audioStatusReceived; + bool m_audioStatusTimerStarted; + std::thread m_sendKeyEventThread; + std::mutex m_sendKeyEventMutex; + std::queue m_SendKeyQueue; + std::condition_variable m_sendKeyCV; + std::condition_variable m_ThreadExitCV; + + /* DALS - Latency Values */ + uint8_t m_video_latency; + uint8_t m_latency_flags; + uint8_t m_audio_output_delay; + + /* ARC related */ + std::thread m_arcRoutingThread; + uint32_t m_currentArcRoutingState; + std::mutex m_arcRoutingStateMutex; + binary_semaphore m_semSignaltoArcRoutingThread; + bool m_arcstarting; + TpTimer m_arcStartStopTimer; + TpTimer m_audioStatusDetectionTimer; + + Connection *smConnection; + std::vector m_connectedDevices; + HdmiCecSinkProcessor *msgProcessor; + HdmiCecSinkFrameListener *msgFrameListener; + PowerManagerInterfaceRef _powerManagerPlugin; + Core::Sink _pwrMgrNotification; + bool _registeredEventHandlers; + const void InitializeIARM(); + void DeinitializeIARM(); + void allocateLogicalAddress(int deviceType); + void allocateLAforTV(); + void pingDevices(std::vector &connected , std::vector &disconnected); + void CheckHdmiInState(); + void request(const int logicalAddress); + int requestType(const int logicalAddress); + int requestStatus(const int logicalAddress); + static void threadRun(); + void cecMonitoringThread(); + static void dsHdmiEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len); + void onHdmiHotPlug(int portId, int connectStatus); + bool loadSettings(); + void persistSettings(bool enableStatus); + void persistOTPSettings(bool enableStatus); + void persistOSDName(const char *name); + void persistVendorId(unsigned int vendorID); + void setEnabled(bool enabled); + bool getEnabled(); + bool getAudioDeviceConnectedStatus(); + void CECEnable(void); + void CECDisable(void); + void getPhysicalAddress(); + void getLogicalAddress(); + void cecAddressesChanged(int changeStatus); + + // Arc functions + + static void threadSendKeyEvent(); + static void threadArcRouting(); + void requestArcInitiation(); + void requestArcTermination(); + void Send_Request_Arc_Initiation_Message(); + void Send_Report_Arc_Initiated_Message(); + void Send_Request_Arc_Termination_Message(); + void Send_Report_Arc_Terminated_Message(); + void arcStartStopTimerFunction(); + void audioStatusTimerFunction(); + void getCecVersion(); + + + public: + Core::hresult GetActiveRoute(bool &available, uint8_t &length, IHdmiCecSinkActivePathIterator*& pathList, string &ActiveRoute, bool &success) override; + Core::hresult GetActiveSource(bool &available, uint8_t &logicalAddress, string &physicalAddress, string &deviceType, string &cecVersion, string &osdName, string &vendorID, string &powerStatus, string &port, bool &success) override; + Core::hresult GetAudioDeviceConnectedStatus(bool &connected, bool &success) override; + Core::hresult GetDeviceList(uint32_t &numberofdevices, IHdmiCecSinkDeviceListIterator*& deviceList, bool &success) override; + Core::hresult GetEnabled(bool &enabled, bool &success) override; + Core::hresult GetOSDName(string &name, bool &success) override; + Core::hresult GetVendorId(string &vendorid, bool &success) override; + Core::hresult PrintDeviceList(bool &printed, bool &success) override; + Core::hresult RequestActiveSource(HdmiCecSinkSuccess &success) override; + Core::hresult RequestShortAudioDescriptor(HdmiCecSinkSuccess &success) override; + Core::hresult SendAudioDevicePowerOnMessage(HdmiCecSinkSuccess &success) override; + Core::hresult SendGetAudioStatusMessage(HdmiCecSinkSuccess &success) override; + Core::hresult SendKeyPressEvent(const uint32_t &logicalAddress, const uint32_t &keyCode, HdmiCecSinkSuccess &success) override; + Core::hresult SendUserControlPressed(const uint32_t &logicalAddress, const uint32_t &keyCode, HdmiCecSinkSuccess &success) override; + Core::hresult SendUserControlReleased(const uint32_t &logicalAddress, HdmiCecSinkSuccess &success) override; + Core::hresult SendStandbyMessage(HdmiCecSinkSuccess &success) override; + Core::hresult SetActivePath(const string &activePath, HdmiCecSinkSuccess &success) override; + Core::hresult SetActiveSource(HdmiCecSinkSuccess &success) override; + Core::hresult SetEnabled(const bool &enabled, HdmiCecSinkSuccess &success) override; + Core::hresult SetOSDName(const string &name, HdmiCecSinkSuccess &success) override; + Core::hresult SetRoutingChange(const string &oldPort, const string &newPort, HdmiCecSinkSuccess &success) override; + Core::hresult SetupARCRouting(const bool &enabled, HdmiCecSinkSuccess &success) override; + Core::hresult SetVendorId(const string &vendorId, HdmiCecSinkSuccess &success) override; + Core::hresult SetLatencyInfo(const string &videoLatency, const string &lowLatencyMode, const string &audioOutputCompensated, const string &audioOutputDelay, HdmiCecSinkSuccess &success) override; + Core::hresult Configure(PluginHost::IShell* service) override; + Core::hresult Register(Exchange::IHdmiCecSink::INotification *notification) override; + Core::hresult Unregister(Exchange::IHdmiCecSink::INotification *notification) override; + Core::hresult SetMenuLanguage(const string &language, HdmiCecSinkSuccess &success) override; + + private: + std::list _hdmiCecSinkNotifications; + mutable Core::CriticalSection _adminLock; + }; + } // namespace Plugin +} // namespace WPEFramework + + + + diff --git a/HdmiCecSource/HdmiCecSourceImplementation.cpp b/HdmiCecSource/HdmiCecSourceImplementation.cpp index 4a4e3e64..1086f6ac 100644 --- a/HdmiCecSource/HdmiCecSourceImplementation.cpp +++ b/HdmiCecSource/HdmiCecSourceImplementation.cpp @@ -135,7 +135,7 @@ namespace WPEFramework LOGINFO("Command: TextViewOn\n"); HdmiCecSourceImplementation::_instance->addDevice(header.from.toInt()); } - void HdmiCecSourceProcessor::process (const RequestActiveSource &msg, const Header &header) + void HdmiCecSourceProcessor::process (const RequestActiveSourceMessage &msg, const Header &header) { printHeader(header); LOGINFO("Command: RequestActiveSource\n"); @@ -178,7 +178,7 @@ namespace WPEFramework LOGINFO("Command: CECVersion Version : %s \n",msg.version.toString().c_str()); HdmiCecSourceImplementation::_instance->addDevice(header.from.toInt()); } - void HdmiCecSourceProcessor::process (const SetMenuLanguage &msg, const Header &header) + void HdmiCecSourceProcessor::process (const SetMenuLanguageMessage &msg, const Header &header) { printHeader(header); LOGINFO("Command: SetMenuLanguage Language : %s \n",msg.language.toString().c_str()); @@ -1031,7 +1031,7 @@ namespace WPEFramework LOGINFO("Command: sending GiveDevicePowerStatus \r\n"); smConnection->sendTo(LogicalAddress::TV, MessageEncoder().encode(GiveDevicePowerStatus())); LOGINFO("Command: sending request active Source isDeviceActiveSource is set to false\r\n"); - smConnection->sendTo(LogicalAddress::BROADCAST, MessageEncoder().encode(RequestActiveSource())); + smConnection->sendTo(LogicalAddress::BROADCAST, MessageEncoder().encode(RequestActiveSourceMessage())); isDeviceActiveSource = false; LOGINFO("Command: GiveDeviceVendorID sending VendorID response :%s\n", \ (isLGTvConnected)?lgVendorId.toString().c_str():appVendorId.toString().c_str()); diff --git a/HdmiCecSource/HdmiCecSourceImplementation.h b/HdmiCecSource/HdmiCecSourceImplementation.h index 6239dab5..d0494a18 100644 --- a/HdmiCecSource/HdmiCecSourceImplementation.h +++ b/HdmiCecSource/HdmiCecSourceImplementation.h @@ -68,11 +68,11 @@ namespace WPEFramework { void process (const InActiveSource &msg, const Header &header); void process (const ImageViewOn &msg, const Header &header); void process (const TextViewOn &msg, const Header &header); - void process (const RequestActiveSource &msg, const Header &header); + void process (const RequestActiveSourceMessage &msg, const Header &header); void process (const Standby &msg, const Header &header); void process (const GetCECVersion &msg, const Header &header); void process (const CECVersion &msg, const Header &header); - void process (const SetMenuLanguage &msg, const Header &header); + void process (const SetMenuLanguageMessage &msg, const Header &header); void process (const GiveOSDName &msg, const Header &header); void process (const GivePhysicalAddress &msg, const Header &header); void process (const GiveDeviceVendorID &msg, const Header &header); diff --git a/HdmiInput/HdmiInput.cpp b/HdmiInput/HdmiInput.cpp index e45efa09..ef53a03a 100644 --- a/HdmiInput/HdmiInput.cpp +++ b/HdmiInput/HdmiInput.cpp @@ -718,7 +718,30 @@ namespace WPEFramework params["frameRateN"] = 60000; params["frameRateD"] = 1001; break; - + case dsVIDEO_FRAMERATE_100: + params["frameRateN"] = 100000; + params["frameRateD"] = 1000; + break; + case dsVIDEO_FRAMERATE_119dot88: + params["frameRateN"] = 120000; + params["frameRateD"] = 1001; + break; + case dsVIDEO_FRAMERATE_120: + params["frameRateN"] = 120000; + params["frameRateD"] = 1000; + break; + case dsVIDEO_FRAMERATE_200: + params["frameRateN"] = 200000; + params["frameRateD"] = 1000; + break; + case dsVIDEO_FRAMERATE_239dot76: + params["frameRateN"] = 240000; + params["frameRateD"] = 1001; + break; + case dsVIDEO_FRAMERATE_240: + params["frameRateN"] = 240000; + params["frameRateD"] = 100; + break; default: params["frameRateN"] = 60000; params["frameRateD"] = 1000; diff --git a/Tests/L1Tests/CMakeLists.txt b/Tests/L1Tests/CMakeLists.txt index 33773882..2550627b 100755 --- a/Tests/L1Tests/CMakeLists.txt +++ b/Tests/L1Tests/CMakeLists.txt @@ -19,7 +19,8 @@ cmake_minimum_required(VERSION 3.8) set(PLUGIN_NAME L1TestsIO) set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(${NAMESPACE}Plugins REQUIRED) @@ -27,16 +28,7 @@ set (TEST_SRC tests/test_UtilsFile.cpp ) -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/e39786088138f2749d64e9e90e0f9902daa77c40.zip -) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) -FetchContent_MakeAvailable(googletest) - set (TEST_LIB - gmock_main ${NAMESPACE}Plugins::${NAMESPACE}Plugins ) @@ -123,7 +115,8 @@ add_plugin_test_ex(PLUGIN_HDMICEC2 tests/test_HdmiCec2.cpp "../../HdmiCec_2" "${ # PLUGIN_HDMICECSINK set (HDMICECSINK_INC ${CMAKE_SOURCE_DIR}/../entservices-inputoutput/HdmiCecSink ${CMAKE_SOURCE_DIR}/../entservices-inputoutput/helpers) -add_plugin_test_ex(PLUGIN_HDMICECSINK tests/test_HdmiCecSink.cpp "${HDMICECSINK_INC}" "${NAMESPACE}HdmiCecSink") +set (HDMICECSINK_LIBS ${NAMESPACE}HdmiCecSink ${NAMESPACE}HdmiCecSinkImplementation) +add_plugin_test_ex(PLUGIN_HDMICECSINK tests/test_HdmiCecSink.cpp "${HDMICECSINK_INC}" "${HDMICECSINK_LIBS}") # PLUGIN_HDMICECSOURCE set (HDMICECSOURCE_INC ${CMAKE_SOURCE_DIR}/../entservices-inputoutput/HdmiCecSource ${CMAKE_SOURCE_DIR}/../entservices-inputoutput/helpers) @@ -136,6 +129,12 @@ add_plugin_test_ex(PLUGIN_AVINPUT tests/test_AVInput.cpp "${AVINPUT_INC}" "${NAM add_library(${MODULE_NAME} SHARED ${TEST_SRC}) +set_source_files_properties( + tests/test_HdmiCec2.cpp + tests/test_HdmiCecSource.cpp + tests/test_HdmiCecSink.cpp + PROPERTIES COMPILE_FLAGS "-fexceptions") + if (RDK_SERVICES_L1_TEST) find_library(TESTMOCKLIB_LIBRARIES NAMES L1TestMocklib) if (TESTMOCKLIB_LIBRARIES) @@ -148,7 +147,7 @@ endif (RDK_SERVICES_L1_TEST) include_directories(${TEST_INC}) -target_link_directories(${MODULE_NAME} PUBLIC ${CMAKE_INSTALL_PREFIX}/lib/wpeframework/plugins) +target_link_directories(${MODULE_NAME} PUBLIC ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/lib/wpeframework/plugins) target_link_libraries(${MODULE_NAME} ${TEST_LIB}) diff --git a/Tests/L1Tests/tests/test_AVInput.cpp b/Tests/L1Tests/tests/test_AVInput.cpp index fae90a90..a82e2d21 100644 --- a/Tests/L1Tests/tests/test_AVInput.cpp +++ b/Tests/L1Tests/tests/test_AVInput.cpp @@ -72,6 +72,9 @@ TEST_F(AVInputTest, RegisteredMethods) EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("contentProtected"))); EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setEdid2AllmSupport"))); EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getEdid2AllmSupport"))); + EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setVRRSupport"))); + EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getVRRSupport"))); + EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getVRRFrameRate"))); } TEST_F(AVInputTest, contentProtected) @@ -111,3 +114,21 @@ TEST_F(AVInputDsTest, setEdid2AllmSupport) EXPECT_EQ(response, string("{\"success\":true}")); } +TEST_F(AVInputDsTest, getVRRSupport) +{ + EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getVRRSupport"), _T("{\"portId\": \"0\",\"vrrSupport\":true}"), response)); + EXPECT_EQ(response, string("{\"vrrSupport\":true,\"success\":true}")); +} + +TEST_F(AVInputDsTest, setVRRSupport) +{ + EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setVRRSupport"), _T("{\"portId\": \"0\",\"vrrSupport\":true}"), response)); + EXPECT_EQ(response, string("{\"success\":true}")); +} + +TEST_F(AVInputDsTest, getVRRFrameRate) +{ + EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getVRRFrameRate"), _T("{\"portId\": \"0\"}"), response)); + EXPECT_EQ(response, string("{\"currentVRRVideoFrameRate\":0,\"success\":true}")); +} + diff --git a/Tests/L1Tests/tests/test_HdcpProfile.cpp b/Tests/L1Tests/tests/test_HdcpProfile.cpp index f0f6a06f..bec5f9b9 100755 --- a/Tests/L1Tests/tests/test_HdcpProfile.cpp +++ b/Tests/L1Tests/tests/test_HdcpProfile.cpp @@ -378,6 +378,8 @@ TEST_F(HDCPProfileDsTest, getSettopHDCPSupport_Hdcp_v2x) "\\}"))); } +#if 0 + TEST_F(HDCPProfileEventIarmTest, onDisplayConnectionChanged) { ASSERT_TRUE(dsHdmiEventHandler != nullptr); @@ -447,6 +449,7 @@ TEST_F(HDCPProfileEventIarmTest, onDisplayConnectionChanged) EVENT_UNSUBSCRIBE(0, _T("onDisplayConnectionChanged"), _T("client.events"), message); } +#endif TEST_F(HDCPProfileEventIarmTest, onHdmiOutputHDCPStatusEvent) { ASSERT_TRUE(dsHdmiEventHandler != nullptr); diff --git a/Tests/L1Tests/tests/test_HdmiCecSink.cpp b/Tests/L1Tests/tests/test_HdmiCecSink.cpp index 2f570df1..38631077 100755 --- a/Tests/L1Tests/tests/test_HdmiCecSink.cpp +++ b/Tests/L1Tests/tests/test_HdmiCecSink.cpp @@ -22,6 +22,9 @@ #include #include + +#include "HdmiCecSinkImplementation.h" +#include "HdmiCecSinkMock.h" #include "HdmiCecSink.h" #include "FactoriesImplementation.h" #include "IarmBusMock.h" diff --git a/Tests/L1Tests/tests/test_HdmiCecSource.cpp b/Tests/L1Tests/tests/test_HdmiCecSource.cpp index 3ae56adb..a298e038 100755 --- a/Tests/L1Tests/tests/test_HdmiCecSource.cpp +++ b/Tests/L1Tests/tests/test_HdmiCecSource.cpp @@ -989,7 +989,7 @@ TEST_F(HdmiCecSourceInitializedEventTest, requestActiveSourceProccess){ Header header; header.from = LogicalAddress(1); //specifies with logicalAddress in the deviceList we're using - RequestActiveSource requestActiveSource; + RequestActiveSourceMessage requestActiveSource; Plugin::HdmiCecSourceProcessor proc(Connection::getInstance()); diff --git a/Tests/L2Tests/CMakeLists.txt b/Tests/L2Tests/CMakeLists.txt index 7e852330..a142f79e 100755 --- a/Tests/L2Tests/CMakeLists.txt +++ b/Tests/L2Tests/CMakeLists.txt @@ -19,16 +19,10 @@ set(PLUGIN_NAME L2TestsIO) set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) set(THUNDER_PORT 9998) -#set(CMAKE_CXX_STANDARD 11) + find_package(${NAMESPACE}Plugins REQUIRED) -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/e39786088138f2749d64e9e90e0f9902daa77c40.zip -) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) -FetchContent_MakeAvailable(googletest) +set(SRC_FILES tests/test_foo_IN.cpp) if(PLUGIN_AVOUTPUT) set(SRC_FILES ${SRC_FILES} tests/AVOutputTV_L2Test.cpp) @@ -37,7 +31,7 @@ endif() add_library(${MODULE_NAME} SHARED ${SRC_FILES}) set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 + CXX_STANDARD 14 CXX_STANDARD_REQUIRED YES) target_compile_definitions(${MODULE_NAME} @@ -45,8 +39,8 @@ target_compile_definitions(${MODULE_NAME} MODULE_NAME=Plugin_${PLUGIN_NAME} THUNDER_PORT="${THUNDER_PORT}") -target_compile_options(${MODULE_NAME} PRIVATE -Wno-error) -target_link_libraries(${MODULE_NAME} PRIVATE gmock_main ${NAMESPACE}Plugins::${NAMESPACE}Plugins) +# target_compile_options(${MODULE_NAME} PRIVATE -Wno-error) +target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins) if (NOT L2_TEST_OOP_RPC) find_library(TESTMOCKLIB_LIBRARIES NAMES TestMocklib) @@ -78,8 +72,3 @@ target_include_directories( ) install(TARGETS ${MODULE_NAME} DESTINATION lib) - -write_config(${PLUGIN_NAME}) - - - diff --git a/Tests/L2Tests/tests/test_foo_IN.cpp b/Tests/L2Tests/tests/test_foo_IN.cpp new file mode 100755 index 00000000..9ce95a52 --- /dev/null +++ b/Tests/L2Tests/tests/test_foo_IN.cpp @@ -0,0 +1,10 @@ +#include +#include + +class PrintTestIO : public ::testing::Test { +}; + +// Single test with print statement +TEST_F(PrintTestIO, BasicOutputIO) { + std::cout << "this is a print statement from inputoutput" << std::endl; +} \ No newline at end of file diff --git a/build_dependencies.sh b/build_dependencies.sh index 92d10f7f..cbd25a7f 100644 --- a/build_dependencies.sh +++ b/build_dependencies.sh @@ -31,7 +31,7 @@ git clone --branch R4.4.3 https://github.com/rdkcentral/ThunderTools.git git clone --branch R4.4.1 https://github.com/rdkcentral/Thunder.git -git clone --branch main https://github.com/rdkcentral/entservices-apis.git +git clone --branch develop https://github.com/rdkcentral/entservices-apis.git git clone https://$GITHUB_TOKEN@github.com/rdkcentral/entservices-testframework.git