diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..29a6f601 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,5 @@ +# These owners will be the default owners for everything in +# the repo. Unless a later match takes precedence, +# @global-owner1 and @global-owner2 will be requested for +# review when someone opens a pull request. +* @rdkcentral/mw-player-int-maintainers diff --git a/CMakeLists.txt b/CMakeLists.txt index 59498af8..7902671f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ -# Middleware CMakeLists.txt +# LibPlayerGstInterface CMakeLists.txt cmake_minimum_required(VERSION 3.5) -project(Middleware) +project(Playergstinterface) find_package(PkgConfig REQUIRED) pkg_check_modules(GST REQUIRED gstreamer-plugins-base-1.0) pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0) @@ -10,11 +10,11 @@ pkg_check_modules(GSTREAMERBASE REQUIRED gstreamer-app-1.0) pkg_check_modules(GSTREAMERVIDEO REQUIRED gstreamer-video-1.0) include_directories(${GST_INCLUDE_DIRS} ${GSTREAMER_INCLUDE_DIRS} ${GSTREAMERBASE_INCLUDE_DIRS} ${GSTREAMERVIDEO_INCLUDE_DIRS}) -include_directories(${CMAKE_CURRENT_SOURCE_DIR} subtitle playerisobmff isobmff - closedcaptions - closedcaptions/subtec - drm drm/helper - drm/ocdm +include_directories(${CMAKE_CURRENT_SOURCE_DIR} subtitle playerisobmff isobmff + closedcaptions + closedcaptions/subtec + drm drm/helper + drm/ocdm externals/playersecmanager) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/externals) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/externals/playersecmanager) @@ -22,14 +22,19 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/externals/rdk) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/baseConversion) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/playerLogManager) -set(LIBMIDDLEWARE_DEPENDS ${OS_LD_FLAGS} ${UUID_LINK_LIBRARIES} ${LIBCJSON_LINK_LIBRARIES} ${GSTREAMERBASE_LINK_LIBRARIES} ${GSTREAMER_LINK_LIBRARIES} ${CURL_LINK_LIBRARIES} ${LibXml2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${OPENGL_LIBRARIES} ${GLEW_LIBRARIES} -ldl) +# pkg_check_modules(LIBDASH REQUIRED libdash) +# include_directories(${LIBDASH_INCLUDE_DIRS}) -#shoud be made part of middleware cmakelists +# set(LIBPLAYERGSTINTERFACE_DEPENDS ${OS_LD_FLAGS} ${UUID_LINK_LIBRARIES} ${LIBCJSON_LINK_LIBRARIES} ${GSTREAMERBASE_LINK_LIBRARIES} ${GSTREAMER_LINK_LIBRARIES} ${CURL_LINK_LIBRARIES} ${LIBDASH_LINK_LIBRARIES} ${LibXml2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${OPENGL_LIBRARIES} ${GLEW_LIBRARIES} -ldl) +set(LIBPLAYERGSTINTERFACE_DEPENDS ${OS_LD_FLAGS} ${UUID_LINK_LIBRARIES} ${LIBCJSON_LINK_LIBRARIES} ${GSTREAMERBASE_LINK_LIBRARIES} ${GSTREAMER_LINK_LIBRARIES} ${CURL_LINK_LIBRARIES} ${LibXml2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${OPENGL_LIBRARIES} ${GLEW_LIBRARIES} -ldl) + + +#shoud be made part of PLAYERGSTINTERFACE cmakelists add_subdirectory(baseConversion) add_subdirectory(playerLogManager) add_subdirectory(externals) -set(LIBMIDDLEWARE_SOURCES ${LIBMIDDLEWARE_SOURCES} closedcaptions/PlayerCCManager.cpp PlayerUtils.cpp) +set(LIBPLAYERGSTINTERFACE_SOURCES ${LIBPLAYERGSTINTERFACE_SOURCES} closedcaptions/PlayerCCManager.cpp PlayerUtils.cpp) set(SUBTEC_CLASS_SOURCES playerisobmff/playerisobmffbox.cpp playerisobmff/playerisobmffbuffer.cpp @@ -84,7 +89,7 @@ else() set(USE_MAC_FOR_RANDOM_GEN "-DUSE_MAC_FOR_RANDOM_GEN") endif(CMAKE_SYSTEM_NAME STREQUAL Darwin) -set(LIBMIDDLEWARE_HEADERS +set(LIBPLAYERGSTINTERFACE_HEADERS closedcaptions/CCTrackInfo.h GstUtils.h PlayerUtils.h @@ -106,7 +111,8 @@ set(LIBMIDDLEWARE_HEADERS vendor/brcm/BrcmSocInterface.h vendor/default/DefaultSocInterface.h subtitle/vttCue.h - ) + ProcessHandler.h +) install(FILES closedcaptions/CCTrackInfo.h PlayerScheduler.h @@ -117,8 +123,6 @@ install(FILES closedcaptions/CCTrackInfo.h drm/DrmUtils.h closedcaptions/PlayerCCManager.h PlayerUtils.h - GstUtils.h - PlayerMetadata.hpp drm/ocdm/opencdmsessionadapter.h drm/aes/Aes.h drm/DrmMemorySystem.h drm/DrmSessionManager.h drm/DrmSystems.h @@ -126,20 +130,22 @@ install(FILES closedcaptions/CCTrackInfo.h drm/DrmSession.h drm/ClearKeyDrmSession.h drm/DrmSessionFactory.h drm/ocdm/opencdmsessionadapter.h drm/helper/DrmHelper.h drm/HlsDrmBase.h drm/DrmConstants.h + subtitle/subtitleParser.h + subtec/subtecparser/WebVttSubtecParser.hpp + subtec/subtecparser/TtmlSubtecParser.hpp + playerisobmff/playerisobmffbuffer.h + playerisobmff/playerisobmffbox.h + GstUtils.h + PlayerMetadata.hpp drm/PlayerHlsDrmSessionInterface.h drm/PlayerHlsDrmSessionInterfaceBase.h drm/helper/VanillaDrmHelper.h drm/HlsOcdmBridgeInterface.h drm/HlsDrmSessionManager.h vendor/SocInterface.h - subtitle/subtitleParser.h - subtec/subtecparser/WebVttSubtecParser.hpp - subtec/subtecparser/TtmlSubtecParser.hpp subtec/subtecparser/WebvttSubtecDevInterface.hpp subtec/subtecparser/TextStyleAttributes.h subtec/libsubtec/SubtecPacket.hpp - playerisobmff/playerisobmffbuffer.h - playerisobmff/playerisobmffbox.h DESTINATION include) set(SOURCES @@ -156,8 +162,9 @@ set(SOURCES vendor/brcm/BrcmSocInterface.cpp vendor/default/DefaultSocInterface.cpp drm/processProtectionHls.cpp + ProcessHandler.cpp ) -set(LIBMIDDLEWARE_DRM_SOURCES drm/PlayerHlsDrmSessionInterface.cpp +set(LIBPLAYERGSTINTERFACE_DRM_SOURCES drm/PlayerHlsDrmSessionInterface.cpp drm/DrmSessionManager.cpp drm/DrmSession.cpp drm/DrmSessionFactory.cpp @@ -179,70 +186,70 @@ if (CMAKE_PLATFORM_UBUNTU OR CMAKE_SYSTEM_NAME STREQUAL Darwin ) # set(CMAKE_USE_SECCLIENT_MOCKS TRUE) endif() -set(LIBMIDDLEWARE_SOURCES ${LIBMIDDLEWARE_SOURCES} ${SOURCES} ${SUBTEC_CLASS_SOURCES}) +set(LIBPLAYERGSTINTERFACE_SOURCES ${LIBPLAYERGSTINTERFACE_SOURCES} ${SOURCES} ${SUBTEC_CLASS_SOURCES}) include_directories(${GSTVIDEO_INCLUDE_DIRS}) if(CMAKE_USE_THUNDER_OCDM_API_0_2) - set(LIBMIDDLEWARE_DEFINES "${LIBMIDDLEWARE_DEFINES} -DUSE_THUNDER_OCDM_API_0_2") + set(LIBPLAYERGSTINTERFACE_DEFINES "${LIBPLAYERGSTINTERFACE_DEFINES} -DUSE_THUNDER_OCDM_API_0_2") endif() if(CMAKE_USE_OPENCDM_ADAPTER) message("Using OPEN CDM support enabled") - set(LIBMIDDLEWARE_DEFINES "${LIBMIDDLEWARE_DEFINES} -DUSE_OPENCDM_ADAPTER") + set(LIBPLAYERGSTINTERFACE_DEFINES "${LIBPLAYERGSTINTERFACE_DEFINES} -DUSE_OPENCDM_ADAPTER") - set(LIBMIDDLEWARE_DRM_SOURCES "${LIBMIDDLEWARE_DRM_SOURCES}" drm/HlsDrmSessionManager.cpp + set(LIBPLAYERGSTINTERFACE_DRM_SOURCES "${LIBPLAYERGSTINTERFACE_DRM_SOURCES}" drm/HlsDrmSessionManager.cpp drm/HlsOcdmBridge.cpp drm/processProtectionHls.cpp ) # DRM Helpers if(CMAKE_USE_WIDEVINE) - set(LIBMIDDLEWARE_HELP_SOURCES "${LIBMIDDLEWARE_HELP_SOURCES}" drm/helper/WidevineDrmHelper.cpp) + set(LIBPLAYERGSTINTERFACE_HELP_SOURCES "${LIBPLAYERGSTINTERFACE_HELP_SOURCES}" drm/helper/WidevineDrmHelper.cpp) endif() if(CMAKE_USE_CLEARKEY) - set(LIBMIDDLEWARE_HELP_SOURCES "${LIBMIDDLEWARE_HELP_SOURCES}" drm/helper/ClearKeyHelper.cpp) + set(LIBPLAYERGSTINTERFACE_HELP_SOURCES "${LIBPLAYERGSTINTERFACE_HELP_SOURCES}" drm/helper/ClearKeyHelper.cpp) endif() if(CMAKE_USE_PLAYREADY) - set(LIBMIDDLEWARE_HELP_SOURCES "${LIBMIDDLEWARE_HELP_SOURCES}" drm/helper/PlayReadyHelper.cpp) + set(LIBPLAYERGSTINTERFACE_HELP_SOURCES "${LIBPLAYERGSTINTERFACE_HELP_SOURCES}" drm/helper/PlayReadyHelper.cpp) endif() if(CMAKE_USE_VERIMATRIX) message("CMAKE_USE_VERIMATRIX set") - set(LIBMIDDLEWARE_HELP_SOURCES "${LIBMIDDLEWARE_HELP_SOURCES}" drm/helper/VerimatrixHelper.cpp) + set(LIBPLAYERGSTINTERFACE_HELP_SOURCES "${LIBPLAYERGSTINTERFACE_HELP_SOURCES}" drm/helper/VerimatrixHelper.cpp) endif() else() message("No OpenCDM support enabled") endif() if(CMAKE_USE_CLEARKEY) - set(LIBMIDDLEWARE_DRM_SOURCES "${LIBMIDDLEWARE_DRM_SOURCES}" drm/ClearKeyDrmSession.cpp) - set(LIBMIDDLEWARE_HELP_SOURCES "${LIBMIDDLEWARE_HELP_SOURCES}" drm/helper/ClearKeyHelper.cpp) - set(LIBMIDDLEWARE_DEFINES "${LIBMIDDLEWARE_DEFINES} -DUSE_CLEARKEY") + set(LIBPLAYERGSTINTERFACE_DRM_SOURCES "${LIBPLAYERGSTINTERFACE_DRM_SOURCES}" drm/ClearKeyDrmSession.cpp) + set(LIBPLAYERGSTINTERFACE_HELP_SOURCES "${LIBPLAYERGSTINTERFACE_HELP_SOURCES}" drm/helper/ClearKeyHelper.cpp) + set(LIBPLAYERGSTINTERFACE_DEFINES "${LIBPLAYERGSTINTERFACE_DEFINES} -DUSE_CLEARKEY") endif() if(CMAKE_USE_OPENCDM_ADAPTER) message("Using OPEN CDM ADAPTER") # Include OpenCDM-related source files - set(LIBMIDDLEWARE_SOURCES ${LIBMIDDLEWARE_SOURCES} + set(LIBPLAYERGSTINTERFACE_SOURCES ${LIBPLAYERGSTINTERFACE_SOURCES} drm/ocdm/opencdmsessionadapter.cpp drm/ocdm/OcdmBasicSessionAdapter.cpp drm/ocdm/OcdmGstSessionAdapter.cpp ) # Add GStreamer video dependency - set(LIBMIDDLEWARE_DEPENDS "${LIBMIDDLEWARE_DEPENDS} -lgstvideo-1.0") + set(LIBPLAYERGSTINTERFACE_DEPENDS "${LIBPLAYERGSTINTERFACE_DEPENDS} -lgstvideo-1.0") if(CMAKE_USE_OPENCDM_ADAPTER_MOCKS) # Add mock headers and sources if mock is enabled - set(LIBMIDDLEWARE_HEADERS ${LIBMIDDLEWARE_HEADERS} open_cdm.h open_cdm_adapter.h) - set(LIBMIDDLEWARE_MOCK_SOURCES ${LIBMIDDLEWARE_MOCK_SOURCES} test/mocks/opencdmMocks.cpp) - set(LIBMIDDLEWARE_MOCK_DEPENDS -lgmock -lgtest) + set(LIBPLAYERGSTINTERFACE_HEADERS ${LIBPLAYERGSTINTERFACE_HEADERS} open_cdm.h open_cdm_adapter.h) + set(LIBPLAYERGSTINTERFACE_MOCK_SOURCES ${LIBPLAYERGSTINTERFACE_MOCK_SOURCES} test/mocks/opencdmMocks.cpp) + set(LIBPLAYERGSTINTERFACE_MOCK_DEPENDS -lgmock -lgtest) else() # Link with actual OpenCDM library - set(LIBMIDDLEWARE_DEPENDS ${LIBMIDDLEWARE_DEPENDS} "-locdm") + set(LIBPLAYERGSTINTERFACE_DEPENDS ${LIBPLAYERGSTINTERFACE_DEPENDS} "-locdm") endif() # Find OpenCDM headers and include them @@ -253,7 +260,7 @@ if(CMAKE_USE_OPENCDM_ADAPTER) find_path(STAGING_INCDIR gstreamer-1.0) include_directories(${STAGING_INCDIR}/gstreamer-1.0) endif() -set(LIBMIDDLEWARE_SOURCES ${LIBMIDDLEWARE_SOURCES} ${LIBMIDDLEWARE_DRM_SOURCES} ${LIBMIDDLEWARE_HELP_SOURCES} ) +set(LIBPLAYERGSTINTERFACE_SOURCES ${LIBPLAYERGSTINTERFACE_SOURCES} ${LIBPLAYERGSTINTERFACE_DRM_SOURCES} ${LIBPLAYERGSTINTERFACE_HELP_SOURCES} ) add_library(subtec SHARED subtec/libsubtec/PacketSender.cpp subtec/libsubtec/SubtecChannel.cpp) set(SUBTEC_PUBLIC_HEADERS subtec/libsubtec/SubtecChannel.hpp subtec/libsubtec/SubtecAttribute.hpp) @@ -261,7 +268,7 @@ set_target_properties(subtec PROPERTIES PUBLIC_HEADER "${SUBTEC_PUBLIC_HEADERS}" set(SUBTEC_COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -DSUBTEC_PACKET_DEBUG=1") if(CMAKE_PLATFORM_UBUNTU) message("CMAKE_PLATFORM_UBUNTU set") - set(LIBMIDDLEWARE_DEFINES "${LIBMIDDLEWARE_DEFINES} -DUBUNTU=1 -DNO_NATIVE_AV=1") + set(LIBPLAYERGSTINTERFACE_DEFINES "${LIBPLAYERGSTINTERFACE_DEFINES} -DUBUNTU=1 -DNO_NATIVE_AV=1") set(SUBTEC_COMPILE_FLAGS "${SUBTEC_COMPILE_FLAGS} -DUBUNTU=1") endif() @@ -282,16 +289,16 @@ install (TARGETS subtec if (CMAKE_GST_SUBTEC_ENABLED) set(CMAKE_SUBTITLE_SUPPORT TRUE) message("CMAKE_GST_SUBTEC_ENABLED set") - set(LIBMIDDLEWARE_DEFINES "${LIBMIDDLEWARE_DEFINES} -DGST_SUBTEC_ENABLED") + set(LIBPLAYERGSTINTERFACE_DEFINES "${LIBPLAYERGSTINTERFACE_DEFINES} -DGST_SUBTEC_ENABLED") endif() if (CMAKE_SUBTITLE_SUPPORT) message("CMAKE_SUBTITLE_SUPPORT set") - set(LIBMIDDLEWARE_DEFINES "${LIBMIDDLEWARE_DEFINES} -DSUBTITLE_SUPPORTED") + set(LIBPLAYERGSTINTERFACE_DEFINES "${LIBPLAYERGSTINTERFACE_DEFINES} -DSUBTITLE_SUPPORTED") find_path(STAGING_INCDIR closedcaption/ccDataReader.h) include_directories(${STAGING_INCDIR}/closedcaption) if (CMAKE_USE_CC_MANAGER_MOCKS) - set(LIBMIDDLEWARE_MOCK_SOURCES ${LIBMIDDLEWARE_MOCK_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../test/fakes/ccManagerFakes.cpp) + set(LIBPLAYERGSTINTERFACE_MOCK_SOURCES ${LIBPLAYERGSTINTERFACE_MOCK_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../test/fakes/ccManagerFakes.cpp) else() set(LIBSUBTECCONNECTOR_DEPENDS pthread rdkCCReader subtec) endif() @@ -302,14 +309,14 @@ if (CMAKE_SUBTITLE_SUPPORT) add_library(subtec_connector SHARED ${LIBSUBTECCONNECTOR_SOURCES}) target_link_libraries(subtec_connector ${LIBSUBTECCONNECTOR_DEPENDS}) - target_link_libraries(subtec_connector PlayerLogManager) + target_link_libraries(subtec_connector playerlogmanager) install(TARGETS subtec_connector DESTINATION lib) - set(LIBMIDDLEWARE_SOURCES ${LIBMIDDLEWARE_SOURCES} closedcaptions/subtec/PlayerSubtecCCManager.cpp) + set(LIBPLAYERGSTINTERFACE_SOURCES ${LIBPLAYERGSTINTERFACE_SOURCES} closedcaptions/subtec/PlayerSubtecCCManager.cpp) endif() -add_library(middleware SHARED ${SOURCES} ${LIBMIDDLEWARE_HEADERS} ${LIBMIDDLEWARE_SOURCES} ${LIBMIDDLEWARE_DRM_SOURCES} ${LIBMIDDLEWARE_HELP_SOURCES}) +add_library(playergstinterface SHARED ${SOURCES} ${LIBPLAYERGSTINTERFACE_HEADERS} ${LIBPLAYERGSTINTERFACE_SOURCES} ${LIBPLAYERGSTINTERFACE_DRM_SOURCES} ${LIBPLAYERGSTINTERFACE_HELP_SOURCES}) -target_include_directories(middleware PUBLIC +target_include_directories(playergstinterface PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/externals ${CMAKE_CURRENT_SOURCE_DIR}/subtec/subtecparser @@ -322,29 +329,26 @@ target_include_directories(middleware PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/vendor) if (CMAKE_SUBTITLE_SUPPORT) - target_link_libraries(middleware subtec_connector) + target_link_libraries(playergstinterface subtec_connector) endif() -if (CMAKE_INBUILT_AAMP_DEPENDENCIES) - message("Building middleware support libraries") - add_subdirectory(gst-plugins) -endif() +string(STRIP "${LIBPLAYERGSTINTERFACE_DEPENDS}" LIBPLAYERGSTINTERFACE_DEPENDS) -target_link_libraries(middleware ${LIBMIDDLEWARE_DEPENDS}) +target_link_libraries(playergstinterface ${LIBPLAYERGSTINTERFACE_DEPENDS}) -target_link_libraries(middleware ${GST_LIBRARIES} ${GSTREAMER_LIBRARIES} ${GSTREAMERBASE_LIBRARIES} ${GSTREAMERBASE_LINK_LIBRARIES}) +target_link_libraries(playergstinterface ${GST_LIBRARIES} ${GSTREAMER_LIBRARIES} ${GSTREAMERBASE_LIBRARIES} ${GSTREAMERBASE_LINK_LIBRARIES}) -target_link_libraries(middleware ${GSTVIDEO_LIBRARIES} ${LIBMIDDLEWARE_DEPENDS}) +target_link_libraries(playergstinterface ${GSTVIDEO_LIBRARIES} ${LIBPLAYERGSTINTERFACE_DEPENDS}) -set_target_properties(middleware PROPERTIES COMPILE_FLAGS "${LIBMIDDLEWARE_DEFINES} ${OS_CXX_FLAGS}") +set_target_properties(playergstinterface PROPERTIES COMPILE_FLAGS "${LIBPLAYERGSTINTERFACE_DEFINES} ${OS_CXX_FLAGS}") -install(TARGETS middleware +install(TARGETS playergstinterface LIBRARY DESTINATION lib - PUBLIC_HEADER DESTINATION lib/include + PUBLIC_HEADER DESTINATION include ) -target_link_libraries(subtec PlayerLogManager) -target_link_libraries(middleware ${GSTVIDEO_LIBRARIES} ${LIBMIDDLEWARE_DEPENDS}) -target_link_libraries(middleware subtec) -target_link_libraries(middleware BaseConversion) -target_link_libraries(middleware playerfbinterface) -set(LIBMIDDLEWARE_SOURCES ${LIBMIDDLEWARE_SOURCES} {LIBMIDDLEWARE_MOCK_SOURCES}) +target_link_libraries(subtec playerlogmanager) +target_link_libraries(playergstinterface ${GSTVIDEO_LIBRARIES} ${LIBPLAYERGSTINTERFACE_DEPENDS}) +target_link_libraries(playergstinterface subtec) +target_link_libraries(playergstinterface baseconversion) +target_link_libraries(playergstinterface playerfbinterface) +set(LIBPLAYERGSTINTERFACE_SOURCES ${LIBPLAYERGSTINTERFACE_SOURCES} {LIBPLAYERGSTINTERFACE_MOCK_SOURCES}) diff --git a/GstUtils.h b/GstUtils.h index cffd05f0..f4a2eda6 100644 --- a/GstUtils.h +++ b/GstUtils.h @@ -115,7 +115,7 @@ GstCaps* GetCaps(GstStreamOutputFormat format); /** * @fn GetCurrentTimeMS * @brief Get the current time in milliseconds - * + * * @return The current time in milliseconds */ long long GetCurrentTimeMS(void); diff --git a/InterfacePlayerRDK.cpp b/InterfacePlayerRDK.cpp index e79c3310..debffd5f 100644 --- a/InterfacePlayerRDK.cpp +++ b/InterfacePlayerRDK.cpp @@ -33,12 +33,7 @@ #include #ifdef USE_EXTERNAL_STATS -// narrowly define MediaType for backwards compatibility -#define MediaType GstMediaType -#define eMEDIATYPE_VIDEO 0 -#include "aamp-xternal-stats.h" -#undef eMEDIATYPE_VIDEO -#undef MediaType +#include "player-xternal-stats.h" #endif #include "PlayerUtils.h" @@ -63,20 +58,19 @@ // for now name is being kept as aamp should be changed when gst-plugins are migrated -static const char* GstPluginNamePR = "playreadydecryptor"; -static const char* GstPluginNameWV = "widevinedecryptor"; -static const char* GstPluginNameCK = "clearkeydecryptor"; -static const char* GstPluginNameVMX = "verimatrixdecryptor"; +static const char* GstPluginNamePR = "aampplayreadydecryptor"; +static const char* GstPluginNameWV = "aampwidevinedecryptor"; +static const char* GstPluginNameCK = "aampclearkeydecryptor"; +static const char* GstPluginNameVMX = "aampverimatrixdecryptor"; #define GST_MIN_PTS_UPDATE_INTERVAL 4000 /**< Time duration in milliseconds if exceeded and pts has not changed; it is concluded pts is not changing */ #include -#define NO_PLAYBIN 1 #define GST_NORMAL_PLAY_RATE 1 /*InterfacePlayerRDK constructor*/ -InterfacePlayerRDK::InterfacePlayerRDK() : +InterfacePlayerRDK::InterfacePlayerRDK() : mProtectionLock(), mPauseInjector(false), mSourceSetupMutex(), stopCallback(NULL), tearDownCb(NULL), notifyFirstFrameCallback(NULL), -mSourceSetupCV(), mScheduler(), callbackMap(), setupStreamCallbackMap(), mDrmSystem(NULL), mEncrypt(NULL), mDRMSessionManager(NULL) +mSourceSetupCV(), mScheduler(), callbackMap(), setupStreamCallbackMap(), mDrmSystem(NULL), mEncrypt(NULL) { interfacePlayerPriv = new InterfacePlayerPriv(); m_gstConfigParam = new Configs(); @@ -197,7 +191,7 @@ bool InterfacePlayerRDK::IsPipelinePaused() { return interfacePlayerPriv->gstPrivateContext->paused; } - + /** * @brief Sets a flag indicating that pipeline transition to PLAYING state is pending */ @@ -608,8 +602,9 @@ gboolean InterfacePlayerRDK::IdleCallbackOnEOS(gpointer user_data) void MonitorAV( InterfacePlayerRDK *pInterfacePlayerRDK ) { - const int AVSYNC_THRESHOLD_MS = pInterfacePlayerRDK->m_gstConfigParam->monitorAvsyncThresholdMs; - const int JUMP_THRESHOLD_MS = pInterfacePlayerRDK->m_gstConfigParam->monitorJumpThresholdMs; + const int AVSYNC_POSITIVE_THRESHOLD_MS = pInterfacePlayerRDK->m_gstConfigParam->monitorAvsyncThresholdPositiveMs; + const int AVSYNC_NEGATIVE_THRESHOLD_MS = pInterfacePlayerRDK->m_gstConfigParam->monitorAvsyncThresholdNegativeMs; + const int JUMP_THRESHOLD_MS = pInterfacePlayerRDK->m_gstConfigParam->monitorAvJumpThresholdMs; GstState state = GST_STATE_VOID_PENDING; @@ -635,7 +630,7 @@ void MonitorAV( InterfacePlayerRDK *pInterfacePlayerRDK ) int maxTracks = (privatePlayer->gstPrivateContext->rate == GST_NORMAL_PLAY_RATE) ? 2 : 1; for( int i=0; igstPrivateContext->stream[i].sinkbin; + auto sinkbin = privatePlayer->gstPrivateContext->stream[i].sinkbin; if( sinkbin && (privatePlayer->gstPrivateContext->stream[i].format != GST_FORMAT_INVALID)) { gint64 position = GST_CLOCK_TIME_NONE; @@ -677,7 +672,9 @@ void MonitorAV( InterfacePlayerRDK *pInterfacePlayerRDK ) description = "trickplay"; break; case 2: - if( abs(av_position[0] - av_position[1]) > AVSYNC_THRESHOLD_MS ) + { + int delta = av_position[eGST_MEDIATYPE_VIDEO] - av_position[eGST_MEDIATYPE_AUDIO]; + if( delta > AVSYNC_POSITIVE_THRESHOLD_MS || delta < AVSYNC_NEGATIVE_THRESHOLD_MS ) { if( !description ) { // both moving, but diverged @@ -688,6 +685,7 @@ void MonitorAV( InterfacePlayerRDK *pInterfacePlayerRDK ) { // workaround to detect decoders that jump over AV gaps without delay description = "jump"; } + } break; default: break; @@ -798,10 +796,9 @@ bool gst_StartsWith( const char *inputStr, const char *prefix ); /** *@brief set the encrypted content, should be used by playready plugin */ -void InterfacePlayerRDK::setEncryption(void *Encrypt, void *DRMSessionManager) +void InterfacePlayerRDK::setEncryption(void *Encrypt) { mEncrypt = Encrypt; - mDRMSessionManager = DRMSessionManager; } /** @@ -1300,7 +1297,7 @@ void InterfacePlayerRDK::TearDownStream(int type) stream->bufferUnderrun = false; stream->eosReached = false; GstMediaType mediaType = static_cast(type); - + if (stream->format != GST_FORMAT_INVALID) { pthread_mutex_lock(&stream->sourceLock); @@ -1672,9 +1669,7 @@ static gboolean gstappsrc_seek(void *src, guint64 offset, void* _this) InterfacePlayerRDK *pInterfacePlayerRDK = (InterfacePlayerRDK*)_this; InterfacePlayerPriv* privatePlayer = pInterfacePlayerRDK->GetPrivatePlayer(); HANDLER_CONTROL_HELPER(privatePlayer->gstPrivateContext->callbackControl, TRUE); -#ifdef TRACE - MW_LOG_MIL("appsrc %p seek-signal - offset %" G_GUINT64_FORMAT, src, offset); -#endif + MW_LOG_TRACE("appsrc %p seek-signal - offset %" G_GUINT64_FORMAT, src, offset); return TRUE; } static GstMediaType gstGetMediaTypeForSource(const void *source, const void *_this) @@ -2120,7 +2115,6 @@ int InterfacePlayerRDK::SetupStream(int streamId, void *playerInstance, std::st } else { -#ifdef NO_PLAYBIN MW_LOG_INFO("subs using subtecbin"); stream->sinkbin = gst_element_factory_make("subtecbin", NULL); /* Creates a new element of "subtecbin" type and returns a new GstElement */ if (!stream->sinkbin) /* When a new element can not be created a NULL is returned */ @@ -2145,18 +2139,6 @@ int InterfacePlayerRDK::SetupStream(int streamId, void *playerInstance, std::st interfacePlayerPriv->gstPrivateContext->subtitle_sink = GST_ELEMENT(gst_object_ref(stream->sinkbin)); g_object_set(stream->sinkbin, "mute", interfacePlayerPriv->gstPrivateContext->subtitleMuted ? TRUE : FALSE, NULL); return 0; -#else - MW_LOG_INFO("subs using playbin"); - stream->sinkbin = GST_ELEMENT(gst_object_ref_sink(gst_element_factory_make("playbin", NULL))); - auto vipertransform = gst_element_factory_make("vipertransform", NULL); - auto textsink = gst_element_factory_make("subtecsink", NULL); - auto subtitlebin = gst_bin_new("subtitlebin"); - gst_bin_add_many(GST_BIN(subtitlebin), vipertransform, textsink, NULL); - gst_element_link(vipertransform, textsink); - gst_element_add_pad(subtitlebin, gst_ghost_pad_new("sink", gst_element_get_static_pad(vipertransform, "sink"))); - - g_object_set(stream->sinkbin, "text-sink", subtitlebin, NULL); -#endif } } } @@ -3197,6 +3179,7 @@ bool InterfacePlayerRDK::Pause(bool pause , bool forceStopGstreamerPreBuffering) if (interfacePlayerPriv->gstPrivateContext->pipeline != NULL) { GstState nextState = pause ? GST_STATE_PAUSED : GST_STATE_PLAYING; + interfacePlayerPriv->gstPrivateContext->buffering_target_state = nextState; if (GST_STATE_PAUSED == nextState && forceStopGstreamerPreBuffering) { @@ -3224,7 +3207,6 @@ bool InterfacePlayerRDK::Pause(bool pause , bool forceStopGstreamerPreBuffering) { MW_LOG_ERR("InterfacePlayerRDK_Pause - gst_element_set_state - FAILED rc %d", rc); } - interfacePlayerPriv->gstPrivateContext->buffering_target_state = nextState; interfacePlayerPriv->gstPrivateContext->paused = pause; interfacePlayerPriv->gstPrivateContext->pendingPlayState = false; } @@ -3669,7 +3651,7 @@ bool gst_StartsWith( const char *inputStr, const char *prefix ) bool GstPlayer_isVideoOrAudioDecoder(const char *name, InterfacePlayerRDK *pInterfacePlayerRDK) { // The idea is to identify video or audio decoder plugin created at runtime by playbin and register to its first-frame/pts-error callbacks - // This support is available in BCOM plugins in RDK builds and hence checking only for such plugin instances here + // This support is available in plugins in RDK builds and hence checking only for such plugin instances here // For platforms that doesnt support callback, we use GST_STATE_PLAYING state change of playbin to notify first frame to app bool isAudioOrVideoDecoder = false; InterfacePlayerPriv* privatePlayer = pInterfacePlayerRDK->GetPrivatePlayer(); @@ -4368,7 +4350,7 @@ void InterfacePlayerRDK::SetVolumeOrMuteUnMute(void) else { - interfacePlayerPriv->socInterface->SetAudioProperty(&volumePropertyName, &mutePropertyName, isSinkBinVolume); + interfacePlayerPriv->socInterface->SetAudioProperty(volumePropertyName, mutePropertyName, isSinkBinVolume); if(isSinkBinVolume) { //some platforms sets volume/mute property on sinkbin rather then audio sink @@ -4449,7 +4431,6 @@ static gboolean buffering_timeout (gpointer data) MW_LOG_WARN("numberOfVideoBuffersSent %d frames %i", privatePlayer->gstPrivateContext->numberOfVideoBuffersSent, frames); isBufferingTimeoutConditionMet = true; privatePlayer->gstPrivateContext->buffering_in_progress = false; - pInterfacePlayerRDK->DumpDiagnostics(); // application can schedule a retune based on isBufferingTimeoutConditionMet } else if (frames == -1 || frames >= pInterfacePlayerRDK->m_gstConfigParam->framesToQueue || privatePlayer->gstPrivateContext->buffering_timeout_cnt-- == 0) @@ -4718,18 +4699,11 @@ static GstBusSyncReply bus_sync_handler(GstBus * bus, GstMessage * msg, Interfac gst_StartsWith(GST_OBJECT_NAME(msg->src), GstPluginNameCK) == true || gst_StartsWith(GST_OBJECT_NAME(msg->src), GstPluginNameVMX) == true)) { - privatePlayer->mPlayerName = "player"; - MW_LOG_MIL("InterfacePlayerRDK setting encrypted player (%p) instance for %s decryptor", pInterfacePlayerRDK->mEncrypt, GST_OBJECT_NAME(msg->src)); - GValue val = { 0, }; - g_value_init(&val, G_TYPE_POINTER); - - g_value_set_pointer(&val, (gpointer) pInterfacePlayerRDK->mDRMSessionManager); // encryption is being passed by player - - g_object_set_property(G_OBJECT(msg->src), privatePlayer->mPlayerName.c_str(), &val); - GValue val_drm = { 0, }; - g_value_init(&val_drm, G_TYPE_POINTER); - g_value_set_pointer(&val_drm, (gpointer) pInterfacePlayerRDK->mEncrypt); - g_object_set_property(G_OBJECT(msg->src), "drm-session-manager", &val_drm); + MW_LOG_MIL("InterfacePlayerRDK setting encrypted player (%p) instance for %s decryptor", pInterfacePlayerRDK->mEncrypt, GST_OBJECT_NAME(msg->src)); + GValue val = { 0, }; + g_value_init(&val, G_TYPE_POINTER); + g_value_set_pointer(&val, (gpointer) pInterfacePlayerRDK->mEncrypt); // encryption is being passed by player + g_object_set_property(G_OBJECT(msg->src), privatePlayer->mPlayerName.c_str(), &val); } } break; @@ -4847,6 +4821,7 @@ void InterfacePlayerRDK::NotifyFragmentCachingComplete() if(interfacePlayerPriv->gstPrivateContext->pendingPlayState) { MW_LOG_MIL("InterfacePlayer: Setting pipeline to PLAYING state "); + interfacePlayerPriv->gstPrivateContext->buffering_target_state = GST_STATE_PLAYING; if (SetStateWithWarnings(interfacePlayerPriv->gstPrivateContext->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { MW_LOG_ERR("InterfacePlayer_Configure GST_STATE_PLAYING failed"); @@ -4904,7 +4879,6 @@ void InterfacePlayerRDK::EndOfStreamReached(int mediaType, bool &shouldHaltBuffe } } -#define NO_PLAYBIN 1 /** * @brief Setup pipeline for a particular stream type * @param[in] pInterfacePlayerRDK pointer to InterfacePlayerRDK instance @@ -4920,13 +4894,13 @@ int InterfacePlayerRDK::InterfacePlayer_SetupStream(int streamId, std::string ma return retvalue; } + /* * @brief Check whether Gstreamer platform has support of the given codec or not. * codec to component mapping done in gstreamer side. * @param codecName - Name of codec to be checked * @return True if platform has the support else false */ - bool InterfacePlayerRDK::IsCodecSupported(const std::string &codecName) { bool retValue = false; @@ -5050,7 +5024,7 @@ void InterfacePlayerRDK::InitializePlayerGstreamerPlugins() if (pluginFeature == NULL) { MW_LOG_ERR("InterfacePlayerRDK: %s plugin feature not available; reloading player's plugin", GstPluginNamePR); - GstPlugin * plugin = gst_plugin_load_by_name ("plugin"); + GstPlugin * plugin = gst_plugin_load_by_name ("aamp"); if(plugin) { gst_object_unref(plugin); @@ -5161,15 +5135,3 @@ double InterfacePlayerRDK::FlushTrack(int mediaType, double pos, double audioDel return rate; } - -/** - * @brief Dump diagnostic information - * - */ -void InterfacePlayerRDK::DumpDiagnostics() -{ - MW_LOG_MIL("video_dec %p audio_dec %p video_sink %p audio_sink %p numberOfVideoBuffersSent %d", - interfacePlayerPriv->gstPrivateContext->video_dec, interfacePlayerPriv->gstPrivateContext->audio_dec, interfacePlayerPriv->gstPrivateContext->video_sink, - interfacePlayerPriv->gstPrivateContext->audio_sink, interfacePlayerPriv->gstPrivateContext->numberOfVideoBuffersSent); - interfacePlayerPriv->socInterface->DumpDiagnosis(); -} diff --git a/InterfacePlayerRDK.h b/InterfacePlayerRDK.h index cde23816..dcfba178 100644 --- a/InterfacePlayerRDK.h +++ b/InterfacePlayerRDK.h @@ -107,8 +107,9 @@ struct Configs bool progressLogging; bool monitorAV; bool disableUnderflow; - int monitorAvsyncThresholdMs; - int monitorJumpThresholdMs; + int monitorAvsyncThresholdPositiveMs; + int monitorAvsyncThresholdNegativeMs; + int monitorAvJumpThresholdMs; }; typedef struct GstPlaybackQualityData @@ -139,7 +140,6 @@ class InterfacePlayerRDK Configs *m_gstConfigParam; char *mDrmSystem; void *mEncrypt; - void *mDRMSessionManager; std::map> callbackMap; std::map> setupStreamCallbackMap; PlayerScheduler mScheduler; @@ -232,7 +232,7 @@ class InterfacePlayerRDK */ void EnablePendingPlayState(); /* - *@brief Registers need data callback from application + *@brief Registers need data callback from application */ void RegisterNeedDataCb(const HandleNeedDataCb &callback) { @@ -240,7 +240,7 @@ class InterfacePlayerRDK } /* - *@brief Registers enough data callback from application + *@brief Registers enough data callback from application */ void RegisterEnoughDataCb(const HandleEnoughDataCb &callback) { @@ -713,7 +713,7 @@ class InterfacePlayerRDK /** * @brief get the encryption from application to share it with PlayReadyDecryptor Plugin */ - void setEncryption(void *mEncrypt, void *mDRMSessionManager); + void setEncryption(void *mEncrypt); /** * @brief Removes all active GStreamer probes. diff --git a/OSX/patches/0009-qtdemux-tm_gst-1.16.patch b/OSX/patches/0009-qtdemux-tm_gst-1.16.patch index f1e75ba5..7c51e8ad 100644 --- a/OSX/patches/0009-qtdemux-tm_gst-1.16.patch +++ b/OSX/patches/0009-qtdemux-tm_gst-1.16.patch @@ -23,7 +23,7 @@ index a99fcaa..1fee819 100644 +++ b/gst/isomp4/qtdemux.c @@ -678,6 +678,11 @@ gst_qtdemux_init (GstQTDemux * qtdemux) GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE); - + gst_qtdemux_reset (qtdemux, TRUE); + + qtdemux->aamp_base_pts = GST_CLOCK_TIME_NONE; @@ -31,11 +31,11 @@ index a99fcaa..1fee819 100644 + qtdemux->aamp_override_enabled = FALSE; + qtdemux->aamp_rate = 1.0; } - + static void @@ -2382,10 +2387,13 @@ gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent, GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment); - + /* map segment to internal qt segments and push on each stream */ - if (QTDEMUX_N_STREAMS (demux)) { + if (QTDEMUX_N_STREAMS (demux) && !demux->aamp_override_enabled) { @@ -45,11 +45,11 @@ index a99fcaa..1fee819 100644 + else if(demux->aamp_override_enabled) { + GST_WARNING_OBJECT (demux, "ignore newsegment %" GST_SEGMENT_FORMAT, &segment); + } - + /* clear leftover in current segment, if any */ gst_adapter_clear (demux->adapter); @@ -2502,6 +2510,37 @@ gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent, - + goto drop; } + case GST_EVENT_CUSTOM_DOWNSTREAM: @@ -89,7 +89,7 @@ index a99fcaa..1fee819 100644 @@ -6226,8 +6265,58 @@ gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux, goto exit; } - + - GST_BUFFER_DTS (buf) = dts; - GST_BUFFER_PTS (buf) = pts; + if (G_LIKELY (!qtdemux->aamp_override_enabled)) @@ -162,7 +162,8 @@ index 83a050a..66d79d1 100644 + gdouble aamp_rate; + gboolean aamp_override_enabled; }; - + struct _GstQTDemuxClass { --- +-- 2.14.2 + diff --git a/OSX/patches/0013-qtdemux-remove-override-segment-event_gst-1.16.patch b/OSX/patches/0013-qtdemux-remove-override-segment-event_gst-1.16.patch index a2e7cbbf..56fd88e3 100644 --- a/OSX/patches/0013-qtdemux-remove-override-segment-event_gst-1.16.patch +++ b/OSX/patches/0013-qtdemux-remove-override-segment-event_gst-1.16.patch @@ -30,5 +30,6 @@ index e1a6ebf..5750031 100644 segment.duration = demux->segment.duration; segment.base = gst_segment_to_running_time (&demux->segment, GST_FORMAT_TIME, demux->segment.position); --- +-- 2.14.2 + diff --git a/OSX/patches/0014-qtdemux-clear-crypto-info-on-trak-switch_gst-1.16.patch b/OSX/patches/0014-qtdemux-clear-crypto-info-on-trak-switch_gst-1.16.patch index d7f5af82..2f225110 100644 --- a/OSX/patches/0014-qtdemux-clear-crypto-info-on-trak-switch_gst-1.16.patch +++ b/OSX/patches/0014-qtdemux-clear-crypto-info-on-trak-switch_gst-1.16.patch @@ -22,7 +22,7 @@ index 5750031..e3d6b36 100644 @@ -2680,6 +2680,17 @@ gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream) stream->duration_last_moof = 0; } - + +static void gst_qtdemux_stream_flush_crypto_info (QtDemuxStream * stream) +{ + QtDemuxCencSampleSetInfo *info = @@ -43,7 +43,8 @@ index 5750031..e3d6b36 100644 gst_qtdemux_stream_flush_samples_data (stream); + gst_qtdemux_stream_flush_crypto_info (stream); } - + static void --- +-- 2.14.2 + diff --git a/OSX/patches/0021-qtdemux-tm-multiperiod_gst-1.16.patch b/OSX/patches/0021-qtdemux-tm-multiperiod_gst-1.16.patch index 0a58a3c7..54cab2d6 100644 --- a/OSX/patches/0021-qtdemux-tm-multiperiod_gst-1.16.patch +++ b/OSX/patches/0021-qtdemux-tm-multiperiod_gst-1.16.patch @@ -28,7 +28,7 @@ index 70ba6fa..e0528f8 100644 + qtdemux->aamp_last_pts = GST_CLOCK_TIME_NONE; + qtdemux->aamp_pts_offset = 0; } - + static void @@ -2517,6 +2519,8 @@ gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent, if (gst_structure_has_name(structure, "aamp_override")) @@ -118,7 +118,8 @@ index ed37c52..906d442 100644 + GstClockTime aamp_last_pts; + GstClockTime aamp_pts_offset; }; - + struct _GstQTDemuxClass { --- +-- 2.14.2 + diff --git a/OSX/patches/JsonHelper.patch b/OSX/patches/JsonHelper.patch index 46794d01..9a3fbc82 100644 --- a/OSX/patches/JsonHelper.patch +++ b/OSX/patches/JsonHelper.patch @@ -4,7 +4,7 @@ Notice: Code in patch files takes the license of the source which is being patch --- a/JsonHelper.cpp 2024-03-07 16:33:38.158962188 +0000 +++ b/JsonHelper.cpp 2024-03-07 17:03:08.693947151 +0000 @@ -400,17 +400,17 @@ - + template void JsonHelper::put(std::string const&, std::string const&); template void JsonHelper::put(std::string const&, std::uint32_t const&); -template void JsonHelper::put(std::string const&, std::uint64_t const&); @@ -14,7 +14,7 @@ Notice: Code in patch files takes the license of the source which is being patch +template <> void JsonHelper::put(std::string const&, std::int64_t const&); template void JsonHelper::put(std::string const&, double const&); template void JsonHelper::put(std::string const&, bool const&); - + template void JsonHelper::appendArrayElem(std::string const&); template void JsonHelper::appendArrayElem(std::uint32_t const&); -template void JsonHelper::appendArrayElem(std::uint64_t const&); @@ -24,10 +24,10 @@ Notice: Code in patch files takes the license of the source which is being patch +template <> void JsonHelper::appendArrayElem(std::int64_t const&); template void JsonHelper::appendArrayElem(double const&); template void JsonHelper::appendArrayElem(bool const&); - + @@ -431,8 +431,8 @@ template bool JsonHelper::getArrayElem(JsonPath const&, int) const; - + template void JsonHelper::putArray(std::string const&, std::vector const&); -template void JsonHelper::putArray(std::string const&, std::vector const&); -template void JsonHelper::putArray(std::string const&, std::vector const&); diff --git a/OSX/patches/subttxrend-app-packet.patch b/OSX/patches/subttxrend-app-packet.patch index f2a07475..a8f57b2a 100644 --- a/OSX/patches/subttxrend-app-packet.patch +++ b/OSX/patches/subttxrend-app-packet.patch @@ -19,7 +19,7 @@ index cc5d9ad..a1ff731 100644 + SET_CC_ATTRIBUTES = 18, FLUSH = 19, + TTML_INFO = 20, - + MAX, INVALID = 0xFFFFFFFF, @@ -252,11 +253,12 @@ const std::array(Packet::Type::MAX)> packetTypeStr @@ -35,5 +35,5 @@ index cc5d9ad..a1ff731 100644 + "FLUSH", + "TTML_INFO" }; - + inline std::ostream& operator<<(std::ostream& out, Packet::Type packetType) diff --git a/OSX/patches/subttxrend-app-ubuntu_24_04_build.patch b/OSX/patches/subttxrend-app-ubuntu_24_04_build.patch index 09076e79..4851e6d9 100644 --- a/OSX/patches/subttxrend-app-ubuntu_24_04_build.patch +++ b/OSX/patches/subttxrend-app-ubuntu_24_04_build.patch @@ -12,29 +12,29 @@ index 7fcdba3..f0218da 100644 +++ b/dvbsubdecoder/include/dvbsubdecoder/BasicAllocator.hpp @@ -27,6 +27,7 @@ #define DVBSUBDECODER_BASICALLOCATOR_HPP_ - + #include +#include - + #include "Allocator.hpp" - + diff --git a/subttxrend-common/src/StringUtils.cpp b/subttxrend-common/src/StringUtils.cpp index b295150..4e8aa02 100644 --- a/subttxrend-common/src/StringUtils.cpp +++ b/subttxrend-common/src/StringUtils.cpp @@ -47,11 +47,11 @@ std::string StringUtils::trim(const std::string& value) - + trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), - std::not1(std::ptr_fun(isSpace)))); + [](unsigned char c){ return !std::isspace(c); })); - + trimmed.erase( std::find_if(trimmed.rbegin(), trimmed.rend(), - std::not1(std::ptr_fun(isSpace))).base(), + [](unsigned char c){ return !std::isspace(c); }).base(), trimmed.end()); - + return trimmed; diff --git a/subttxrend-gfx/src/PrerenderedFontImpl.hpp b/subttxrend-gfx/src/PrerenderedFontImpl.hpp index 63500f4..74618cc 100644 @@ -45,7 +45,7 @@ index 63500f4..74618cc 100644 #include #include +#include - + #include #include FT_FREETYPE_H diff --git a/subttxrend-gfx/waylandcpp/src/waylandcpp-client/File.cpp b/subttxrend-gfx/waylandcpp/src/waylandcpp-client/File.cpp @@ -57,7 +57,7 @@ index 27c6ae6..a41415d 100644 #include #include +#include - + namespace waylandcpp { diff --git a/subttxrend-ttml/src/DataDumper.h b/subttxrend-ttml/src/DataDumper.h @@ -65,11 +65,11 @@ index c643eeb..207d7ab 100644 --- a/subttxrend-ttml/src/DataDumper.h +++ b/subttxrend-ttml/src/DataDumper.h @@ -26,6 +26,7 @@ - + #include #include +#include - + namespace subttxrend { diff --git a/subttxrend-ttml/src/Parser/StyleSet.cpp b/subttxrend-ttml/src/Parser/StyleSet.cpp @@ -81,6 +81,6 @@ index 92fd2f3..8d41db0 100644 #include #include +#include - + namespace subttxrend { diff --git a/OSX/patches/subttxrend-app-xkbcommon.patch b/OSX/patches/subttxrend-app-xkbcommon.patch index a4996926..0e334baa 100644 --- a/OSX/patches/subttxrend-app-xkbcommon.patch +++ b/OSX/patches/subttxrend-app-xkbcommon.patch @@ -12,7 +12,7 @@ index 5ef5616..b6180d8 100644 +find_package(PkgConfig REQUIRED) + +pkg_check_modules(XKBCOMMON REQUIRED xkbcommon) - + # # Include directories @@ -80,6 +83,7 @@ include_directories(${LIBSUBTTXRENDCC_INCLUDE_DIRS}) @@ -20,7 +20,7 @@ index 5ef5616..b6180d8 100644 include_directories(${LIBSUBTTXRENDTTML_INCLUDE_DIRS}) include_directories(${LIBSUBTTXRENDWEBVTT_INCLUDE_DIRS}) +include_directories(${XKBCOMMON_INCLUDE_DIRS}) - + # # Definitions (flags etc.) diff --git a/subttxrend-cc/CMakeLists.txt b/subttxrend-cc/CMakeLists.txt @@ -34,7 +34,7 @@ index 949921f..33f6cf8 100644 +find_package(PkgConfig REQUIRED) + +pkg_check_modules(XKBCOMMON REQUIRED xkbcommon) - + # # Include directories @@ -57,6 +60,7 @@ find_package(Ipp2Utils REQUIRED CONFIG) @@ -42,7 +42,7 @@ index 949921f..33f6cf8 100644 include_directories(${LIBSUBTTXRENDGFX_INCLUDE_DIRS}) include_directories(${LIBSUBTTXRENDPROTOCOL_INCLUDE_DIRS}) +include_directories(${XKBCOMMON_INCLUDE_DIRS}) - + # # Public headers diff --git a/subttxrend-dvbsub/CMakeLists.txt b/subttxrend-dvbsub/CMakeLists.txt @@ -57,7 +57,7 @@ index a405d1b..8234a5d 100644 + +pkg_check_modules(XKBCOMMON REQUIRED xkbcommon) + - + # # Include directories @@ -57,6 +61,7 @@ find_package(Ipp2Utils REQUIRED CONFIG) @@ -65,7 +65,7 @@ index a405d1b..8234a5d 100644 include_directories(${LIBSUBTTXRENDGFX_INCLUDE_DIRS}) include_directories(${LIBDVBSUBDECODER_INCLUDE_DIRS}) +include_directories(${XKBCOMMON_INCLUDE_DIRS}) - + # # Documentation diff --git a/subttxrend-scte/CMakeLists.txt b/subttxrend-scte/CMakeLists.txt @@ -80,7 +80,7 @@ index 958bc5d..89f182b 100644 + +pkg_check_modules(XKBCOMMON REQUIRED xkbcommon) + - + # # Include directories @@ -61,6 +65,7 @@ include_directories(${LIBSUBTTXRENDCOMMON_INCLUDE_DIRS}) @@ -88,7 +88,7 @@ index 958bc5d..89f182b 100644 include_directories(${LIBSUBTTXRENDPROTOCOL_INCLUDE_DIRS}) include_directories(${ZLIB_INCLUDE_DIRS}) +include_directories(${XKBCOMMON_INCLUDE_DIRS}) - + # # Public headers diff --git a/subttxrend-ttml/CMakeLists.txt b/subttxrend-ttml/CMakeLists.txt @@ -103,7 +103,7 @@ index 6ecc66b..db7ff8a 100644 + +pkg_check_modules(XKBCOMMON REQUIRED xkbcommon) + - + # # Include directories @@ -60,6 +64,7 @@ include_directories(${LIBSUBTTXRENDCOMMON_INCLUDE_DIRS}) @@ -111,7 +111,7 @@ index 6ecc66b..db7ff8a 100644 include_directories(${LIBXML2_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) +include_directories(${XKBCOMMON_INCLUDE_DIRS}) - + # # Documentation diff --git a/subttxrend-ttxt/CMakeLists.txt b/subttxrend-ttxt/CMakeLists.txt @@ -125,7 +125,7 @@ index 7873230..9370671 100644 +find_package(PkgConfig REQUIRED) + +pkg_check_modules(XKBCOMMON REQUIRED xkbcommon) - + # # Include directories @@ -59,6 +62,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) @@ -133,7 +133,7 @@ index 7873230..9370671 100644 include_directories(${LIBSUBTTXRENDGFX_INCLUDE_DIRS}) include_directories(${LIBTTXDECODER_INCLUDE_DIRS}) +include_directories(${XKBCOMMON_INCLUDE_DIRS}) - + # # Documentation diff --git a/subttxrend-webvtt/CMakeLists.txt b/subttxrend-webvtt/CMakeLists.txt @@ -148,7 +148,7 @@ index 407c4c3..09ccd60 100644 + +pkg_check_modules(XKBCOMMON REQUIRED xkbcommon) + - + # # Include directories @@ -45,6 +49,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) @@ -156,6 +156,6 @@ index 407c4c3..09ccd60 100644 include_directories(${LIBSUBTTXRENDCOMMON_INCLUDE_DIRS}) include_directories(${LIBSUBTTXRENDGFX_INCLUDE_DIRS}) +include_directories(${XKBCOMMON_INCLUDE_DIRS}) - + # # Documentation diff --git a/OSX/patches/websocket-ipplayer2-link.patch b/OSX/patches/websocket-ipplayer2-link.patch index 4fe66248..b6fd0157 100644 --- a/OSX/patches/websocket-ipplayer2-link.patch +++ b/OSX/patches/websocket-ipplayer2-link.patch @@ -7,7 +7,7 @@ index 05cc1a9..bf25e95 100644 +++ b/src/ipp2/CMakeLists.txt @@ -183,10 +183,10 @@ else(ASIO_PATH) endif(ASIO_PATH) - + target_link_libraries(${IPP2_UTILS_LIBNAME} PUBLIC pthread) -target_link_libraries(${IPP2_UTILS_LIBNAME} PUBLIC ${CURL_LIBRARIES}) -target_link_libraries(${IPP2_UTILS_LIBNAME} PUBLIC ${JSONCPP_LIBRARIES}) @@ -17,6 +17,6 @@ index 05cc1a9..bf25e95 100644 +target_link_libraries(${IPP2_UTILS_LIBNAME} PUBLIC ${JSONCPP_LINK_LIBRARIES}) +target_link_libraries(${IPP2_UTILS_LIBNAME} PUBLIC ${LIBGIO_LINK_LIBRARIES}) +target_link_libraries(${IPP2_UTILS_LIBNAME} PUBLIC ${TINYXML2_LINK_LIBRARIES}) - + if (NOT BUILD_PC) target_link_libraries(${IPP2_UTILS_LIBNAME} PUBLIC ${LIBRDKLOGGER_LIBRARIES}) diff --git a/OSX/patches/websocket-ipplayer2-typescpp.patch b/OSX/patches/websocket-ipplayer2-typescpp.patch index a0dd90f6..cb468f42 100644 --- a/OSX/patches/websocket-ipplayer2-typescpp.patch +++ b/OSX/patches/websocket-ipplayer2-typescpp.patch @@ -10,5 +10,7 @@ index 05ff8e2..8aa2db5 100644 #include "Serializer.h" #include "Utils.h" +#include - + namespace ipp2 { + + diff --git a/OSX/patches/websocket-ipplayer2-ubuntu_24_04_build.patch b/OSX/patches/websocket-ipplayer2-ubuntu_24_04_build.patch index e6180e89..22b696b8 100644 --- a/OSX/patches/websocket-ipplayer2-ubuntu_24_04_build.patch +++ b/OSX/patches/websocket-ipplayer2-ubuntu_24_04_build.patch @@ -15,5 +15,6 @@ index 3ff9a2f..4e0b925 100644 #include #include +#include - + struct sockaddr_storage; + diff --git a/PlayerUtils.cpp b/PlayerUtils.cpp index 00502b79..79b097dc 100644 --- a/PlayerUtils.cpp +++ b/PlayerUtils.cpp @@ -250,3 +250,17 @@ void ResolveURL(std::string& dst, std::string base, const char *uri , bool bProp } } } + +/** + * @brief Trim a string + */ +void trim(std::string& src) +{ + size_t first = src.find_first_not_of(" \n\r\t\f\v"); + if (first != std::string::npos) + { + size_t last = src.find_last_not_of(" \n\r\t\f\v"); + std::string dst = src.substr(first, (last - first + 1)); + src = dst; + } +} diff --git a/PlayerUtils.h b/PlayerUtils.h index 40db3523..8879b127 100644 --- a/PlayerUtils.h +++ b/PlayerUtils.h @@ -104,5 +104,11 @@ void player_ResolveURL(std::string& dst, std::string base, const char *uri , boo */ static const char * ParseUriProtocol(const char *uri); +/** + * @fn trim + * @param[in][out] src Buffer containing string + */ +void trim(std::string& src); + #endif /* __PLAYER_UTILS_H__ */ diff --git a/ProcessHandler.cpp b/ProcessHandler.cpp new file mode 100644 index 00000000..021b8a04 --- /dev/null +++ b/ProcessHandler.cpp @@ -0,0 +1,159 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2023 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. + */ + +/** + * @file ProcessHandler.cpp + * @brief Process utility functions + */ + + +#include "ProcessHandler.h" +#include "PlayerUtils.h" +#include "PlayerLogManager.h" +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Parse the process info line and get the name of process + * + * @param proc status line + * @retval - process name + */ +std::string ProcessHandler::splitName(std::string& line ) +{ + std::string delimiter = ":"; + std::string token = line.substr(line.find(delimiter) + delimiter.length()); + trim(token); + return token; +} + +/** + * @brief convert the string pid value to long + * + * @param process pid as string + * @retval - pid ; if failed -1 + */ +long ProcessHandler::convertPid(std::string& name) +{ + char* p; + long pid = -1; + pid = strtol(name.c_str(), &p, BASE_NUMBER); + if( *p != 0) + pid = -1; + return pid; +} + +/** + * @brief Get the process name from Pid + * + * @param process pid as string + * @retval - true or false + */ +std::string ProcessHandler::GetProcessName(std::string& pid) +{ + std::fstream newFile; + std::string procPath = PROCESS_PROC_DIR+pid+PROCESS_PROC_STATUS; + std::string line; + std::string output = ""; + newFile.open(procPath, std::ios::in); + if (newFile.is_open()) + { + while(getline(newFile, line)) + { + if (line.find("Name:") != std::string::npos) + { + output = splitName(line); + break; + } + } + newFile.close(); + } + return output; +} + + +/** + * @brief kill the process by name + * + * @param process name to kill + * @retval - true or false + */ +bool ProcessHandler::KillProcess(std::string processName) +{ + bool status = false; + struct dirent *entry; + DIR *dir = opendir(PROCESS_PROC_DIR.c_str()); + if (dir == NULL) { + return status; + } + + while ((entry = readdir(dir)) != NULL) + { + std::string strPid = std::string(entry->d_name); + long lPid = convertPid(strPid); + if (lPid > 0) + { + std::string name = GetProcessName(strPid); + if (name == processName) + { + MW_LOG_INFO("Killing the process %s PID %ld", name.c_str(), lPid); + status = KillProcess(lPid); + break; /**< No need to move further*/ + } + } + } + closedir(dir); + return status; +} + +/** + * @brief self kill the process + * + * @retval - true or false + */ +bool ProcessHandler::SelfKill() +{ + return KillProcess(getpid()); +} + +/** + * @brief kill the process by pid number + * + * @param pid + * @retval - true or false + */ +bool ProcessHandler::KillProcess(long pid) +{ + bool ret = true; + if(kill(pid, SIGKILL) < 0) + { + MW_LOG_WARN("Kill Failed = %d", errno); + ret = false; + } + return ret; +} + +/** + * EOF + */ diff --git a/ProcessHandler.h b/ProcessHandler.h new file mode 100644 index 00000000..a9b552e7 --- /dev/null +++ b/ProcessHandler.h @@ -0,0 +1,99 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2023 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. +*/ + + +/** +* @file ProcessHandler.h +* @brief Context-free process utility functions. +*/ + +#ifndef __PROCESS_HANDLER_H__ +#define __PROCESS_HANDLER_H__ + +#include + +/** + * @class ProcessHandler + * @brief Class for controlling process from AAMP + */ +class ProcessHandler +{ + const std::string PROCESS_PROC_DIR = "/proc/"; + const std::string PROCESS_PROC_STATUS = "/status"; + const unsigned int BASE_NUMBER = 10; + + /** + * @fn splitName + */ + std::string splitName(std::string& line ); + + /** + * @fn convertPid + */ + long convertPid(std::string& name); + + public: + + /** + * @fn constructor - ProcessHandler + */ + ProcessHandler() + { + } + + /** + * @brief ProcessHandler Destructor function + */ + ~ProcessHandler(){}; + + /** + * @brief Copy constructor + */ + ProcessHandler(const ProcessHandler&) = delete; + + /** + * @brief ProcessHandler assignment operator overloading + */ + ProcessHandler& operator=(const ProcessHandler&) = delete; + + /** + * @fn GetProcessName + */ + std::string GetProcessName(std::string& pid); + + /** + * @fn KillProcess + */ + bool KillProcess(std::string processName); + + /** + * @fn SelfKill + */ + bool SelfKill(void); + + /** + * @fn KillProcess + */ + bool KillProcess(long pid); +}; + +#endif +/** + * EOF + */ diff --git a/SocUtils.cpp b/SocUtils.cpp index 501c33a8..e59173d6 100644 --- a/SocUtils.cpp +++ b/SocUtils.cpp @@ -139,5 +139,16 @@ namespace SocUtils { return socInterface->ResetNewSegmentEvent(); } + /** + * @brief Check if GST Subtec is enabled + */ + bool isGstSubtecEnabled() + { +#ifdef GST_SUBTEC_ENABLED + return true; +#else + return false; +#endif + } } diff --git a/SocUtils.h b/SocUtils.h index 509a164a..3064808d 100644 --- a/SocUtils.h +++ b/SocUtils.h @@ -109,5 +109,10 @@ namespace SocUtils * Manages segment event tracking for trickplay scenarios without disrupting seekplay or advertisements. */ bool ResetNewSegmentEvent(); + + /** + * @brief Check if GST Subtec is enabled + */ + bool isGstSubtecEnabled(); } #endif // SOC_UTILS_H diff --git a/baseConversion/CMakeLists.txt b/baseConversion/CMakeLists.txt index 9b6c4527..f17cb90a 100644 --- a/baseConversion/CMakeLists.txt +++ b/baseConversion/CMakeLists.txt @@ -1,15 +1,15 @@ cmake_minimum_required(VERSION 3.5) -project(BaseConversion) +project(baseconversion) include_directories(..) set(BaseConversion_SRC _base64.cpp base16.cpp) -add_library(BaseConversion SHARED ${BaseConversion_SRC}) +add_library(baseconversion SHARED ${BaseConversion_SRC}) -set_target_properties(BaseConversion PROPERTIES PUBLIC_HEADER "_base64.h;base16.h") +set_target_properties(baseconversion PROPERTIES PUBLIC_HEADER "_base64.h;base16.h") # Install the library and its headers -install(TARGETS BaseConversion +install(TARGETS baseconversion DESTINATION lib PUBLIC_HEADER DESTINATION include) diff --git a/cmake/FindWPEFramework.cmake b/cmake/FindWPEFramework.cmake index 813d6d1f..746e7610 100644 --- a/cmake/FindWPEFramework.cmake +++ b/cmake/FindWPEFramework.cmake @@ -47,10 +47,16 @@ if(PC_WPEFRAMEWORK_FOUND) HINTS ${PC_WPEFRAMEWORK_INCLUDEDIR} ${PC_WPEFRAMEWORK_INCLUDE_DIRS}) if (USE_THUNDER_R4) - set(WPEFRAMEWORK_LIBS WPEFrameworkPlugins WPEFrameworkCore WPEFrameworkCOM WPEFrameworkSecurityUtil WPEFrameworkWebSocket) + set(WPEFRAMEWORK_LIBS WPEFrameworkPlugins WPEFrameworkCore WPEFrameworkCOM WPEFrameworkWebSocket) else() - set(WPEFRAMEWORK_LIBS WPEFrameworkPlugins WPEFrameworkCore WPEFrameworkTracing WPEFrameworkProtocols WPEFrameworkSecurityUtil) + set(WPEFRAMEWORK_LIBS WPEFrameworkPlugins WPEFrameworkCore WPEFrameworkTracing WPEFrameworkProtocols) endif() + +# Add WPEFrameworkSecurityUtil if DISABLE_SECURITY_TOKEN is not enabled +if (NOT DISABLE_SECURITY_TOKEN) + list(APPEND WPEFRAMEWORK_LIBS WPEFrameworkSecurityUtil) +endif() + set(WPEFRAMEWORK_LIBRARY ) foreach(LIB ${WPEFRAMEWORK_LIBS}) find_library(WPEFRAMEWORK_LIBRARY_${LIB} NAMES ${LIB} diff --git a/drm/ClearKeyDrmSession.cpp b/drm/ClearKeyDrmSession.cpp index 173c84d9..bcab100e 100644 --- a/drm/ClearKeyDrmSession.cpp +++ b/drm/ClearKeyDrmSession.cpp @@ -22,6 +22,7 @@ * @brief Source file for ClearKey DRM Session. */ +// #include "config.h" #include "ClearKeyDrmSession.h" #include "PlayerUtils.h" #include diff --git a/drm/DrmSessionManager.cpp b/drm/DrmSessionManager.cpp index 4fbf8345..a2e6d67a 100755 --- a/drm/DrmSessionManager.cpp +++ b/drm/DrmSessionManager.cpp @@ -82,14 +82,12 @@ void DrmSessionManager::UpdateDRMConfig( bool useSecManager, bool enablePROutputProtection, bool propagateURIParam, - bool isFakeTune, - bool wideVineKIDWorkaround) + bool isFakeTune) { m_drmConfigParam->mUseSecManager = useSecManager; m_drmConfigParam->mEnablePROutputProtection = enablePROutputProtection; m_drmConfigParam->mPropagateURIParam = propagateURIParam; m_drmConfigParam->mIsFakeTune = isFakeTune; - m_drmConfigParam->mIsWVKIDWorkaround = wideVineKIDWorkaround; } /** diff --git a/drm/DrmSessionManager.h b/drm/DrmSessionManager.h index 9235bb0f..634f90d4 100644 --- a/drm/DrmSessionManager.h +++ b/drm/DrmSessionManager.h @@ -113,9 +113,8 @@ struct configs{ bool mRuntimeDRMConfig; int mContentProtectionDataUpdateTimeout; bool mEnablePROutputProtection; - bool mPropagateURIParam; + bool mPropagateURIParam; bool mIsFakeTune; - bool mIsWVKIDWorkaround; }; /** * @class DrmSessionManager @@ -407,63 +406,6 @@ class DrmSessionManager { ProfileUpdateCb = callback; }; - - using ProfileBeginCallback = std::function; - ProfileBeginCallback profileBeginCb; - void RegisterProfBegin(const ProfileBeginCallback callback) - { - profileBeginCb = callback; - }; - - using ProfileEndCallback = std::function; - ProfileEndCallback profileEndCb; - void RegisterProfEnd(const ProfileEndCallback callback) - { - profileEndCb = callback; - }; - - using ProfileErrorCallback = std::function; - ProfileErrorCallback profileErrorCb; - void RegisterProfError(const ProfileErrorCallback callback) - { - profileErrorCb = callback; - }; - - using LAProfileBeginCallback = std::function; - LAProfileBeginCallback laprofileBeginCb; - void RegisterLAProfBegin(const LAProfileBeginCallback callback) - { - laprofileBeginCb = callback; - }; - - using LAProfileEndCallback = std::function; - LAProfileEndCallback laprofileEndCb; - void RegisterLAProfEnd(const LAProfileEndCallback callback) - { - laprofileEndCb = callback; - }; - - using LAProfileErrorCallback = std::function; - LAProfileErrorCallback laprofileErrorCb; - void RegisterLAProfError(const LAProfileErrorCallback callback) - { - laprofileErrorCb = callback; - }; - - using SetFailureCallback = std::function; - SetFailureCallback setfailureCb; - void RegisterSetFailure(const SetFailureCallback callback) - { - setfailureCb = callback; - }; - - //using DrmMetaDataCallback = std::function; - using DrmMetaDataCallback = std::function()>; - DrmMetaDataCallback DrmMetaDataCb; - void RegisterMetaDataCb(const DrmMetaDataCallback callback) - { - DrmMetaDataCb = callback; - }; /* * @brief Register Content Protection Update callback to application */ @@ -483,10 +425,15 @@ class DrmSessionManager */ void UpdateDRMConfig( bool useSecManager, + // int licenseRetryWaitTime, + // int drmNetworkTimeout, + // int curlConnectTimeout, + // bool curlLicenseLogging, + // bool runtimeDRMConfig, + // int contentProtectionDataUpdateTimeout, bool enablePROutputProtection, bool propagateURIParam, - bool isFakeTune, - bool wideVineKIDWorkaround); + bool isFakeTune); }; diff --git a/drm/helper/ClearKeyHelper.cpp b/drm/helper/ClearKeyHelper.cpp index a3f80875..c466433b 100644 --- a/drm/helper/ClearKeyHelper.cpp +++ b/drm/helper/ClearKeyHelper.cpp @@ -245,14 +245,10 @@ bool ClearKeyHelperFactory::isDRM(const struct DrmInfo& drmInfo) const DrmHelperPtr ClearKeyHelperFactory::createHelper(const struct DrmInfo& drmInfo) const { - MW_LOG_ERR("tanuj creating helper"); if (isDRM(drmInfo)) { return std::make_shared(drmInfo); } - else{ - MW_LOG_ERR("tanuj creating helper failed"); - } return NULL; } diff --git a/drm/helper/WidevineDrmHelper.cpp b/drm/helper/WidevineDrmHelper.cpp index fd63aa8e..23a55636 100755 --- a/drm/helper/WidevineDrmHelper.cpp +++ b/drm/helper/WidevineDrmHelper.cpp @@ -247,14 +247,10 @@ bool WidevineDrmHelperFactory::isDRM(const struct DrmInfo& drmInfo) const DrmHelperPtr WidevineDrmHelperFactory::createHelper(const struct DrmInfo& drmInfo) const { - if (isDRM(drmInfo)) { - MW_LOG_ERR("tanuj creating helper"); return std::make_shared(drmInfo); } - else - MW_LOG_ERR("tanuj failed to create helper"); return NULL; } diff --git a/drm/ocdm/opencdmsessionadapter.cpp b/drm/ocdm/opencdmsessionadapter.cpp index 6f2d5d9a..1e25b222 100644 --- a/drm/ocdm/opencdmsessionadapter.cpp +++ b/drm/ocdm/opencdmsessionadapter.cpp @@ -22,9 +22,13 @@ * @brief Handles operation with OCDM session to handle DRM License data */ #include "opencdmsessionadapter.h" + #include "DrmHelper.h" #include "PlayerUtils.h" +#include "ProcessHandler.h" +#include "PlayerExternalsInterface.h" + #include #include #include @@ -313,39 +317,25 @@ int OCDMSessionAdapter::processDRMKey(DrmData* key, uint32_t timeout) { // SAGE Hang .. Need to restart the wpecdmi process and then self kill player to recover MW_LOG_WARN("processKey: Update() returned HWError.Restarting process..."); - int systemResult = -1; + ProcessHandler processHandler; // In Release another process handles opencdm which needs to be restarts .In Sprint this process is not available. // So check if process exists before killing it . - systemResult = system("pgrep WPEcdmi"); - if(systemResult == 0) + if (processHandler.KillProcess("WPEFramework")) /** Current OCDM process **/ { - systemResult = system("pkill -9 WPEcdmi"); - if(systemResult != 0) - { - MW_LOG_WARN("Unable to shutdown WPEcdmi process.%d", systemResult); - } + MW_LOG_WARN("OCDM HWError reported.. Killed the process WPEFramework for recovery.."); } - else + else { - // check for WPEFramework process - systemResult = system("pgrep WPEFramework"); - if(systemResult == 0) + if(processHandler.KillProcess("WPEcdmi")) /** Backword compatibility **/ { - systemResult = system("pkill -9 WPEFramework"); - if(systemResult != 0) - { - MW_LOG_WARN("Unable to shutdown WPEFramework process.%d", systemResult); - } + MW_LOG_WARN("OCDM HWError reported.. Killed the process WPEcdmi for recovery.."); } - } + } // wait for 5sec for all the logs to be flushed sleep(5); // Now kill self - if(kill(getpid(), SIGKILL) < 0) - { - MW_LOG_WARN("Kill Failed = %d", errno); //CID:88415 - checked return - } + processHandler.SelfKill(); } else { #ifdef USE_THUNDER_OCDM_API_0_2 diff --git a/drm/processProtectionHls.cpp b/drm/processProtectionHls.cpp index 645e516b..aa8a7c77 100755 --- a/drm/processProtectionHls.cpp +++ b/drm/processProtectionHls.cpp @@ -183,7 +183,7 @@ shared_ptr ProcessContentProtection( std::string attrName, bool propa int status = DRM_API_FAILED; string psshDataStr = ""; char* psshData = NULL; - + do { shared_ptr drmHelper = getDrmHelper(attrName, propagateURIParam, isSamplesRequired); diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index e31edfe5..ada306a6 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -102,8 +102,8 @@ string(STRIP "${LIB_EXT_DEPENDS}" LIB_EXT_DEPENDS) target_link_libraries(playerfbinterface ${LIB_EXT_DEPENDS}) -target_link_libraries(playerfbinterface PlayerLogManager) -target_link_libraries(playerfbinterface BaseConversion) +target_link_libraries(playerfbinterface playerlogmanager) +target_link_libraries(playerfbinterface baseconversion) # Install the library and its headers install(TARGETS playerfbinterface diff --git a/externals/Module.h b/externals/Module.h index 6e32f0aa..63af6544 100644 --- a/externals/Module.h +++ b/externals/Module.h @@ -14,7 +14,7 @@ * 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. + * limitations under the License. */ /** @@ -26,7 +26,7 @@ #ifndef MODULE_NAME -#define MODULE_NAME playerfbinterface +#define MODULE_NAME EntosPlayerFireboltInterface #endif diff --git a/externals/PlayerExternalsInterface.cpp b/externals/PlayerExternalsInterface.cpp index 504c6c56..f96e4624 100644 --- a/externals/PlayerExternalsInterface.cpp +++ b/externals/PlayerExternalsInterface.cpp @@ -45,7 +45,7 @@ PlayerExternalsInterface::PlayerExternalsInterface() { m_pIarmInterface = new FakePlayerIarmInterface(); } - + #else m_pIarmInterface = new FakePlayerIarmInterface(); #endif @@ -72,20 +72,6 @@ bool PlayerExternalsInterface::IsSourceUHD() return m_pIarmInterface->IsSourceUHD(); } -/** - * @brief check if Live Latency COrrection is supported - */ -bool PlayerExternalsInterface::IsLiveLatencyCorrectionSupported() -{ - bool bRet = false;; - if(!IsContainerEnvironment()) - { - bRet = m_pIarmInterface->IsLiveLatencyCorrectionSupported(); - } - - return bRet; -} - /** * @brief gets display resolution */ @@ -132,7 +118,7 @@ char * PlayerExternalsInterface::GetTR181PlayerConfig(const char * paramName, si { sRet = m_pIarmInterface->GetTR181Config(paramName, iConfigLen); } - + return sRet; } @@ -200,3 +186,4 @@ bool PlayerExternalsInterface::IsConfigWifiCurlHeader() #endif return bRet; } + diff --git a/externals/PlayerExternalsInterface.h b/externals/PlayerExternalsInterface.h index 4d373f28..f0bd4d13 100644 --- a/externals/PlayerExternalsInterface.h +++ b/externals/PlayerExternalsInterface.h @@ -86,20 +86,13 @@ class FakePlayerIarmInterface : public PlayerExternalsInterfaceBase m_isHDCPEnabled = true; } - /** - * @fn IsLiveLatencyCorrectionSupported - * @brief Checks if Live Latency Correction is supported - * @return True if supported. False if not. - */ - bool IsLiveLatencyCorrectionSupported() override {return false;} - /** * @fn IsActiveStreamingInterfaceWifi * @brief Checks if current active interface is wifi and also sets up NET_SRV_MGR event to handles active interface change * @return True if current active is wifi. False if not. */ static bool IsActiveStreamingInterfaceWifi(){return false;} - + /** * @fn GetTR181Config * @brief Gets appropriate TR181 Config @@ -108,7 +101,7 @@ class FakePlayerIarmInterface : public PlayerExternalsInterfaceBase * @return Parameter config retrieved */ char * GetTR181Config(const char * paramName, size_t & iConfigLen) override{return nullptr;} - + /** * @fn isHDCPConnection2_2 * @brief Is current HDCP protocol 2_2 @@ -118,11 +111,11 @@ class FakePlayerIarmInterface : public PlayerExternalsInterfaceBase /** * @fn GetActiveInterface - * @brief Is current active interface wifi? + * @brief Is current active interface wifi? * @return True if wifi. False, if not. */ bool GetActiveInterface()override{return false;} - + ~FakePlayerIarmInterface(){} }; @@ -140,7 +133,7 @@ class PlayerExternalsInterface static std::shared_ptr s_pPlayerOP; - + public: /** @@ -151,7 +144,7 @@ class PlayerExternalsInterface * @fn ~PlayerExternalsInterface */ virtual ~PlayerExternalsInterface(); - /** + /** * @brief Copy constructor disabled * */ @@ -161,16 +154,16 @@ class PlayerExternalsInterface * */ PlayerExternalsInterface& operator=(const PlayerExternalsInterface&) = delete; - + /** * @brief Routine to check ActiveStreamingInterface * */ static bool IsActiveStreamingInterfaceWifi(void); + + - - - char * GetTR181PlayerConfig(const char * paramName, size_t & iConfigLen); + char * GetTR181PlayerConfig(const char * paramName, size_t & iConfigLen); // State functions @@ -179,7 +172,7 @@ class PlayerExternalsInterface * @retval true if 2.2 false otherwise */ bool isHDCPConnection2_2() { return m_pIarmInterface->isHDCPConnection2_2(); } - /** + /** * @fn IsSourceUHD * @retval true, if source is UHD, otherwise false */ @@ -199,27 +192,21 @@ class PlayerExternalsInterface void setGstElement(GstElement *element) { m_pIarmInterface->setGstElement(element); } // Singleton for object creation - + /** * @fn GetPlayerExternalsInterfaceInstance * @retval PlayerExternalsInterface object - */ + */ static std::shared_ptr GetPlayerExternalsInterfaceInstance(); /** * @fn IsPlayerExternalsInterfaceInstanceActive * @retval true or false */ static bool IsPlayerExternalsInterfaceInstanceActive(); - - /** - * @fn IsLiveLatencyCorrectionSupported - * @retval true or false - */ - bool IsLiveLatencyCorrectionSupported(); - + /** * @fn GetActiveInterface - * @brief Is current active interface wifi? + * @brief Is current active interface wifi? * @return True if wifi. False, if not. */ bool GetActiveInterface(); diff --git a/externals/PlayerExternalsInterfaceBase.h b/externals/PlayerExternalsInterfaceBase.h index d158cc2b..ad8999f1 100644 --- a/externals/PlayerExternalsInterfaceBase.h +++ b/externals/PlayerExternalsInterfaceBase.h @@ -49,15 +49,15 @@ class PlayerExternalsInterfaceBase GstElement* m_gstElement; - - + + public: PlayerExternalsInterfaceBase():m_sourceWidth(0),m_sourceHeight(0),m_gstElement(nullptr){} /** * @fn IsSourceUHD - * @brief Finds out if source is of UHD resolution + * @brief Finds out if source is of UHD resolution * @return True if UHD. False if not UHD. */ bool IsSourceUHD() @@ -90,7 +90,7 @@ class PlayerExternalsInterfaceBase } return retVal; } - + /** * @fn setGstElement * @brief Set Video decoder Gst Element for UHD identification @@ -130,20 +130,13 @@ class PlayerExternalsInterfaceBase */ virtual void SetHDMIStatus(){} - /** - * @fn IsLiveLatencyCorrectionSupported - * @brief Checks if Live Latency Correction is supported - * @return True if supported. False if not. - */ - virtual bool IsLiveLatencyCorrectionSupported() {return false;} - /** * @fn IsActiveStreamingInterfaceWifi * @brief Checks if current active interface is wifi and also sets up NET_SRV_MGR event to handles active interface change * @return True if current active is wifi. False if not. */ bool IsActiveStreamingInterfaceWifi(){return false;} - + /** * @fn GetTR181Config * @brief Gets appropriate TR181 Config @@ -152,7 +145,7 @@ class PlayerExternalsInterfaceBase * @return Parameter config retrieved */ virtual char * GetTR181Config(const char * paramName, size_t & iConfigLen){return nullptr;} - + /** * @fn isHDCPConnection2_2 * @brief Is current HDCP protocol 2_2 @@ -162,7 +155,7 @@ class PlayerExternalsInterfaceBase /** * @fn GetActiveInterface - * @brief Is current active interface wifi? + * @brief Is current active interface wifi? * @return True if wifi. False, if not. */ virtual bool GetActiveInterface(){return false;} diff --git a/externals/PlayerRfc.cpp b/externals/PlayerRfc.cpp index 5f73058a..3fd8a2cd 100644 --- a/externals/PlayerRfc.cpp +++ b/externals/PlayerRfc.cpp @@ -63,8 +63,8 @@ namespace RFCSettings else { MW_LOG_ERR("get RFC Parameter for %s Failed : %s type = %d", parameter.c_str(), getTR181ErrorString(status), param.type); - } - } + } + } #endif return strhost; } diff --git a/externals/PlayerRfc.h b/externals/PlayerRfc.h index 8aaa0621..54534fc3 100644 --- a/externals/PlayerRfc.h +++ b/externals/PlayerRfc.h @@ -24,7 +24,7 @@ #ifndef _PLAYER_RFC_H #define _PLAYER_RFC_H -namespace RFCSettings{ +namespace RFCSettings{ /** * @fn getRFCValue * @brief Fetch data from RFC diff --git a/externals/PlayerThunderAccessBase.h b/externals/PlayerThunderAccessBase.h index 8916f1de..6b1706c9 100644 --- a/externals/PlayerThunderAccessBase.h +++ b/externals/PlayerThunderAccessBase.h @@ -109,7 +109,7 @@ struct PlayerAudioData{ int pk; std::string mixType; - PlayerAudioData(std::string lang, std::string content_Type, std::string nm, std::string t, int pk_int, std::string mix_Type) + PlayerAudioData(std::string lang, std::string content_Type, std::string nm, std::string t, int pk_int, std::string mix_Type) : language(lang), contentType(content_Type), name(nm), @@ -170,13 +170,13 @@ class PlayerThunderAccessBase * @param callsign plugin callsign */ PlayerThunderAccessBase(PlayerThunderAccessPlugin callsign) {} - + /** * @fn ~PlayerThunderAccessBase * @note clean up */ virtual ~PlayerThunderAccessBase(){} - + /** * @brief PlayerThunderAccessBase copy constructor disabled */ @@ -195,7 +195,7 @@ class PlayerThunderAccessBase * @retval false on failure */ virtual bool ActivatePlugin() = 0; - + /** * @fn UnSubscribeEvent * @note unSubscribe event data for the specific plugin diff --git a/externals/playersecmanager/PlayerMemoryUtils.cpp b/externals/playersecmanager/PlayerMemoryUtils.cpp index 094c3af4..5aa90d52 100644 --- a/externals/playersecmanager/PlayerMemoryUtils.cpp +++ b/externals/playersecmanager/PlayerMemoryUtils.cpp @@ -40,7 +40,7 @@ void * player_CreateSharedMem( size_t shmLen, key_t & shmKey) { // generate pseudo-random value to use as a unique key shmKey = rand() + 1; // must be non-zero to allow access to non-child processes - + // allocate memory segment and identifier int shmId = shmget(shmKey, shmLen, IPC_CREAT | // create new segment @@ -104,3 +104,4 @@ void player_CleanUpSharedMem(void* shmPointer, key_t shmKey, size_t shmLen) MW_LOG_ERR("bad shmPointer=%p", shmPointer ); } } + diff --git a/externals/playersecmanager/PlayerSecInterface.h b/externals/playersecmanager/PlayerSecInterface.h index 85b01240..18ba7078 100644 --- a/externals/playersecmanager/PlayerSecInterface.h +++ b/externals/playersecmanager/PlayerSecInterface.h @@ -96,7 +96,7 @@ struct PlayerSecExtendedStatus /** * @fn isSecFeatureEnabled * @brief check if sec feature is enabled - * + * * @return bool */ bool isSecFeatureEnabled(); @@ -104,7 +104,7 @@ bool isSecFeatureEnabled(); /** * @fn isSecManagerEnabled * @brief check if sec manager is enabled - * + * * @return bool */ bool isSecManagerEnabled(); @@ -112,25 +112,25 @@ bool isSecManagerEnabled(); /** * @fn DrmMetaDataEvent::getAsVerboseErrorCode * @brief get as verbose error code - * + * * @param httpCode - http code * @param secManagerClass - sec manager class * @param secManagerReasonCode - sec manager reason code - * + * * @return bool */ bool getAsVerboseErrorCode(int32_t httpCode, int32_t &secManagerClass, int32_t &secManagerReasonCode ); /** - * @class PlayerSecInterface + * @class PlayerSecInterface * @brief PlayerSecInterface Class */ -class PlayerSecInterface +class PlayerSecInterface { public : /** * @fn PlayerSecInterface - * + * * @brief acquire license via sec client * @param[in] serviceHostUrl - service host url * @param[in] numberOfRequestMetadataKeys - number of request metadata keys @@ -148,10 +148,10 @@ public : * @param[out] licenseResponseLength - license response length * @param[out] refreshDurationSeconds - refresh duration seconds * @param[out] statusInfo - status info - * + * * @return int32_t */ - + int32_t PlayerSec_AcquireLicense( const char *serviceHostUrl, uint8_t numberOfRequestMetadataKeys, const char *requestMetadata[][2], uint8_t numberOfAccessAttributes, const char *accessAttributes[][2], const char *contentMetadata, @@ -168,20 +168,20 @@ public : * @return int32_t */ int32_t PlayerSec_FreeResource( const char *resource ); - + /** * @fn isSecRequestFailed * @brief check if sec request failed - * + * * @param requestResult - request result - * + * * @return bool */ bool isSecRequestFailed( int32_t requestResult ); /** * @fn isSecResultInRange - * + * * @brief check if sec result is in range * @param requestResult - request result * diff --git a/externals/playersecmanager/PlayerSecManager.cpp b/externals/playersecmanager/PlayerSecManager.cpp index 697b8009..5a336a4e 100755 --- a/externals/playersecmanager/PlayerSecManager.cpp +++ b/externals/playersecmanager/PlayerSecManager.cpp @@ -230,7 +230,7 @@ PlayerSecManager::PlayerSecManager() : mSecManagerObj(SECMANAGER_CALL_SIGN), mSe mRegisteredEvents(), mWatermarkPluginObj(WATERMARK_PLUGIN_CALLSIGN), mWatMutex(), mSpeedStateMutex() { std::lock_guard lock(mSecMutex); - mSecManagerObj.ActivatePlugin(); + mSecManagerObj.ActivatePlugin(); { std::lock_guard lock(mWatMutex); mWatermarkPluginObj.ActivatePlugin(); @@ -239,7 +239,7 @@ PlayerSecManager::PlayerSecManager() : mSecManagerObj(SECMANAGER_CALL_SIGN), mSe /* hide watermarking at startup */ ShowWatermark(false); - /*Start Scheduler for handling RDKShell API invocation*/ + /*Start Scheduler for handling RDKShell API invocation*/ if(false == mSchedulerStarted) { StartScheduler(); // pass dummy required playerId parameter; note that we don't yet have a valid player instance to derive it from @@ -285,7 +285,7 @@ PlayerSecManager::~PlayerSecManager() { std::lock_guard lock(mSecMutex); - /*Stop Scheduler used for handling RDKShell API invocation*/ + /*Stop Scheduler used for handling RDKShell API invocation*/ if(true == mSchedulerStarted) { StopScheduler(); @@ -300,7 +300,7 @@ static std::size_t getInputSummaryHash(const char* moneyTraceMetadata[][2], cons { std::stringstream ss; ss<< moneyTraceMetadata[0][1]< lock(mSecMutex); if(accTokenLen > 0 && contMetaLen > 0 && licReqLen > 0) @@ -430,20 +430,20 @@ bool PlayerSecManager::AcquireLicenseOpenOrUpdate( const char* licenseUrl, const shmPt_contMeta = player_CreateSharedMem(contMetaLen, shmKey_contMeta); shmPt_licReq = player_CreateSharedMem(licReqLen, shmKey_licReq); } - + //Set shared memory with the buffer //Set shared memory with the buffer if(nullptr != shmPt_accToken && nullptr != accessToken && nullptr != shmPt_contMeta && nullptr != contentMetadata && nullptr != shmPt_licReq && nullptr != licenseRequest) - { + { //copy buffer to shm memcpy(shmPt_accToken, accessToken, accTokenLen); memcpy(shmPt_contMeta, contentMetadata, contMetaLen); memcpy(shmPt_licReq, licenseRequest, licReqLen); MW_LOG_INFO("Access token, Content metadata and license request are copied successfully, passing details with SecManager"); - + //Set json params to be used by sec manager param["accessTokenBufferKey"] = shmKey_accToken; param["accessTokenLength"] = accTokenLen; @@ -474,7 +474,7 @@ bool PlayerSecManager::AcquireLicenseOpenOrUpdate( const char* licenseUrl, const * multiple object creation is OK as an existing instance should be returned * where input data changes e.g. following a call to updatePlaybackSession * the input data to the shared session is updated here*/ - newSession = PlayerSecManagerSession(response["sessionId"].Number(), + newSession = PlayerSecManagerSession(response["sessionId"].Number(), getInputSummaryHash(moneyTraceMetadata, contentMetadata, contMetaLen, licenseRequest, keySystemId, mediaUsage, accessToken, isVideoMuted)); @@ -517,13 +517,13 @@ bool PlayerSecManager::AcquireLicenseOpenOrUpdate( const char* licenseUrl, const { session = newSession; } - + } // TODO: Sort these values out for backward compatibility if(response.HasLabel("secManagerResultContext")) { JsonObject resultContext = response["secManagerResultContext"].Object(); - + if(resultContext.HasLabel("class")) *statusCode = resultContext["class"].Number(); if(resultContext.HasLabel("reason")) @@ -531,7 +531,7 @@ bool PlayerSecManager::AcquireLicenseOpenOrUpdate( const char* licenseUrl, const if(resultContext.HasLabel("businessStatus")) *businessStatus = resultContext["businessStatus"].Number(); } - + if(!ret) { //As per Secmanager retry is meaningful only for @@ -548,7 +548,7 @@ bool PlayerSecManager::AcquireLicenseOpenOrUpdate( const char* licenseUrl, const { ++retryCount; MW_LOG_WARN("SecManager license request failed, response for %s : statusCode: %d, reasonCode: %d, so retrying with delay %d, retry count : %u", apiName, *statusCode, *reasonCode, sleepTime, retryCount ); - ms_sleep(sleepTime); + ms_sleep(sleepTime); } else { @@ -722,7 +722,7 @@ bool PlayerSecManager::setPlaybackSpeedState(int64_t sessionId, int64_t playback std::lock_guard lock(mSecMutex); rpcResult = mSecManagerObj.InvokeJSONRPC("setPlaybackSpeedState", param, result); } - + if (rpcResult) { if (!result["success"].Boolean()) @@ -871,7 +871,7 @@ void watermarkSessionHandler(const JsonObject& parameters) std::string param; parameters.ToString(param); MW_LOG_WARN("PlayerSecManager::%s:%d i/p params: %s", __FUNCTION__, __LINE__, param.c_str()); - std::function sendWatermarkEvent_CB = PlayerSecManager::getWatermarkSessionEvent_CB(); + std::function sendWatermarkEvent_CB = PlayerSecManager::getWatermarkSessionEvent_CB(); if (nullptr != sendWatermarkEvent_CB) { sendWatermarkEvent_CB( parameters["sessionId"].Number(),parameters["conditionContext"].Number(),parameters["watermarkingSystem"].String()); @@ -908,7 +908,7 @@ void addWatermarkHandler(const JsonObject& parameters) PlayerSecManager *instance = static_cast(data); instance->UpdateWatermark(graphicId, smKey, smSize); }, (void *)PlayerSecManager::GetInstance())); - + if (parameters["adjustVisibilityRequired"].Boolean()) { int sessionId = parameters["sessionId"].Number(); diff --git a/externals/playersecmanager/PlayerSecManager.h b/externals/playersecmanager/PlayerSecManager.h index 57e8495e..e38305a8 100755 --- a/externals/playersecmanager/PlayerSecManager.h +++ b/externals/playersecmanager/PlayerSecManager.h @@ -113,22 +113,22 @@ class PlayerSecManager : public PlayerScheduler * @fn setVideoWindowSize * * @param[in] sessionId - session id - * @param[in] video_width - video width - * @param[in] video_height - video height + * @param[in] video_width - video width + * @param[in] video_height - video height */ bool setVideoWindowSize(int64_t sessionId, int64_t video_width, int64_t video_height); /** * @fn setPlaybackSpeedState * * @param[in] sessionId - session id - * @param[in] playback_speed - playback speed - * @param[in] playback_position - playback position + * @param[in] playback_speed - playback speed + * @param[in] playback_position - playback position */ bool setPlaybackSpeedState(int64_t sessionId, int64_t playback_speed, int64_t playback_position); /** * @fn loadClutWatermark * @param[in] sessionId - session id - * + * */ bool loadClutWatermark(int64_t sessionId, int64_t graphicId, int64_t watermarkClutBufferKey, int64_t watermarkImageBufferKey, int64_t clutPaletteSize, const char* clutPaletteFormat, int64_t watermarkWidth, int64_t watermarkHeight, float aspectRatio); /** @@ -214,13 +214,13 @@ class PlayerSecManager : public PlayerScheduler * @fn ~PlayerSecManager */ ~PlayerSecManager(); - /** - * @brief Copy constructor disabled - * - */ + /** + * @brief Copy constructor disabled + * + */ PlayerSecManager(const PlayerSecManager&) = delete; /** - * @brief assignment operator disabled + * @brief assignment operator disabled * */ PlayerSecManager* operator=(const PlayerSecManager&) = delete; diff --git a/externals/playersecmanager/PlayerSecManagerSession.h b/externals/playersecmanager/PlayerSecManagerSession.h index 550e8663..4c0a4226 100755 --- a/externals/playersecmanager/PlayerSecManagerSession.h +++ b/externals/playersecmanager/PlayerSecManagerSession.h @@ -36,7 +36,7 @@ class PlayerSecManager; /** - * @brief Represents an player sec manager session, + * @brief Represents an player sec manager session, * Sessions are automatically closed there are no PlayerSecManagerSession objects that reference it*/ class PlayerSecManagerSession { @@ -76,7 +76,7 @@ class PlayerSecManagerSession mutable std::mutex sessionIdMutex; /** - * @brief constructor for valid objects + * @brief constructor for valid objects * this will cause PlayerSecManager::ReleaseSession() to be called on sessionID * when the last PlayerSecManagerSession, referencing is destroyed * this is only intended to be used in PlayerSecManager::acquireLicence() @@ -85,7 +85,7 @@ class PlayerSecManagerSession PlayerSecManagerSession(int64_t sessionID, std::size_t inputSummaryHash); public: /** - * @brief constructor for an invalid object*/ + * @brief constructor for an invalid object*/ PlayerSecManagerSession(): mpSessionManager(), sessionIdMutex() {}; //allow copying, the secManager session will only be closed when all copies have gone out of scope diff --git a/externals/playersecmanager/ThunderAccessPlayer.h b/externals/playersecmanager/ThunderAccessPlayer.h index 71194071..e9b4717f 100755 --- a/externals/playersecmanager/ThunderAccessPlayer.h +++ b/externals/playersecmanager/ThunderAccessPlayer.h @@ -68,13 +68,13 @@ class ThunderAccessPlayer * @note Security token acquisition, controller object creation */ ThunderAccessPlayer(std::string callsign); - + /** * @fn ~ThunderAccessPlayer * @note clean up */ ~ThunderAccessPlayer(); - + /** * @brief ThunderAccessPlayer copy constructor disabled */ @@ -93,7 +93,7 @@ class ThunderAccessPlayer * @retval false on failure */ bool ActivatePlugin(); -#ifdef USE_CPP_THUNDER_PLUGIN_ACCESS +#ifdef USE_CPP_THUNDER_PLUGIN_ACCESS /** * @fn InvokeJSONRPC * @note Invoke JSONRPC call for the plugin @@ -102,7 +102,7 @@ class ThunderAccessPlayer * @retval false on failure */ bool InvokeJSONRPC(std::string method, const JsonObject ¶m, JsonObject &result, const uint32_t waitTime = THUNDER_RPC_TIMEOUT); - + /** * @fn SubscribeEvent * @note Subscribe event data for the specific plugin @@ -111,7 +111,7 @@ class ThunderAccessPlayer * @retval false on failure */ bool SubscribeEvent (std::string eventName, std::function functionHandler); -#endif +#endif /** * @fn UnSubscribeEvent * @note unSubscribe event data for the specific plugin diff --git a/externals/rdk/PlayerExternalsRdkInterface.cpp b/externals/rdk/PlayerExternalsRdkInterface.cpp index e3458331..29208734 100644 --- a/externals/rdk/PlayerExternalsRdkInterface.cpp +++ b/externals/rdk/PlayerExternalsRdkInterface.cpp @@ -126,7 +126,7 @@ void PlayerExternalsRdkInterface::SetHDMIStatus() dsHdcpProtocolVersion_t hdcpReceiverProtocol = dsHDCP_VERSION_MAX; dsHdcpProtocolVersion_t hdcpCurrentProtocol = dsHDCP_VERSION_MAX; - + try { @@ -327,33 +327,10 @@ bool PlayerExternalsRdkInterface::GetActiveInterface() return isInterfaceWifi; } -bool PlayerExternalsRdkInterface::IsLiveLatencyCorrectionSupported() -{ - bool IsMS12V2 = true; - try { - //Get the HDMI port - device::Manager::Initialize(); - std::string strVideoPort = device::Host::getInstance().getDefaultVideoPortName(); - ::device::VideoOutputPort &vPort = ::device::Host::getInstance().getVideoOutputPort(strVideoPort); - int caps; - vPort.getAudioOutputPort().getAudioCapabilities(&caps); - if(((caps & dsAUDIOSUPPORT_MS12V2) != dsAUDIOSUPPORT_MS12V2)) - { - IsMS12V2 = false; - MW_LOG_INFO("MS12V2 Audio not supported in this device\n"); - } - device::Manager::DeInitialize(); - } - catch (...) { - MW_LOG_WARN("DeviceSettings exception caught\n"); - } - return IsMS12V2 ; -} - static void getActiveInterfaceEventHandler (const char *owner, IARM_EventId_t eventId, void *data, size_t len) { static char previousInterface[20] = {'\0'}; - + if (strcmp (owner, "NET_SRV_MGR") != 0) return; @@ -375,13 +352,13 @@ static void getActiveInterfaceEventHandler (const char *owner, IARM_EventId_t ev { isInterfaceWifi = false; } - - + + } char * PlayerExternalsRdkInterface::GetTR181Config(const char * paramName, size_t & iConfigLen) { - + char * strConfig = NULL; IARM_Result_t result; HOSTIF_MsgData_t param; diff --git a/externals/rdk/PlayerExternalsRdkInterface.h b/externals/rdk/PlayerExternalsRdkInterface.h index 6a68d5a1..50b3611a 100644 --- a/externals/rdk/PlayerExternalsRdkInterface.h +++ b/externals/rdk/PlayerExternalsRdkInterface.h @@ -43,7 +43,7 @@ //class representing IARM interface in rdk class PlayerExternalsRdkInterface : public PlayerExternalsInterfaceBase { - + dsHdcpProtocolVersion_t m_hdcpCurrentProtocol; public: @@ -95,19 +95,12 @@ class PlayerExternalsRdkInterface : public PlayerExternalsInterfaceBase */ static bool IsActiveStreamingInterfaceWifi(); - /** - * @fn IsLiveLatencyCorrectionSupported - * @brief Checks if Live Latency Correction is supported - * @return True if supported. False if not. - */ - bool IsLiveLatencyCorrectionSupported() override; - // Singleton for object creation - + /** * @fn GetPlayerExternalsRdkInterfaceInstance * @retval PlayerExternalsRdkInterface object - */ + */ static PlayerExternalsRdkInterface * GetPlayerExternalsRdkInterfaceInstance(); /** @@ -128,7 +121,7 @@ class PlayerExternalsRdkInterface : public PlayerExternalsInterfaceBase /** * @fn GetActiveInterface - * @brief Is current active interface wifi? + * @brief Is current active interface wifi? * @return True if wifi. False, if not. */ bool GetActiveInterface(); diff --git a/externals/rdk/PlayerThunderAccess.cpp b/externals/rdk/PlayerThunderAccess.cpp index 37a01a7e..a8b83d33 100644 --- a/externals/rdk/PlayerThunderAccess.cpp +++ b/externals/rdk/PlayerThunderAccess.cpp @@ -337,7 +337,7 @@ bool PlayerThunderAccess::GetResolutionFromDS_VIDEOIN(int & widthFromDS, int & h bool bRetVal = false; JsonObject param; - JsonObject result; + JsonObject result; PlayerThunderAccess* thunderDsObj = new PlayerThunderAccess(PlayerThunderAccessPlugin::DS); @@ -356,7 +356,7 @@ bool PlayerThunderAccess::GetScreenResolution(int & screenWidth, int & screenHei bool bRetVal = false; JsonObject param; - JsonObject result; + JsonObject result; PlayerThunderAccess* thunderRDKShellObj = new PlayerThunderAccess(PlayerThunderAccessPlugin::RDKSHELL); @@ -426,7 +426,7 @@ void PlayerThunderAccess::OnInputStatusChanged(const JsonObject& parameters) mOnInputStatusChangedCb(strStatus); } -/** +/** * @brief Gets onSignalChanged and translates into player events */ void PlayerThunderAccess::OnSignalChanged (const JsonObject& parameters) @@ -485,7 +485,7 @@ void PlayerThunderAccess::RegisterEventOnVideoStreamInfoUpdateHdmiin(std::functi */ void PlayerThunderAccess::OnVideoStreamInfoUpdate(const JsonObject& parameters) { - + std::string message; parameters.ToString(message); MW_LOG_WARN("%s",message.c_str()); @@ -498,7 +498,7 @@ void PlayerThunderAccess::OnVideoStreamInfoUpdate(const JsonObject& parameters) data.width = (int)videoInfoObj["width"].Number(); data.height = (int)videoInfoObj["height"].Number(); mVideoInfoUpdatedMethodCb(data); - + } void PlayerThunderAccess::RegisterOnPlayerStatusOta(std::function onPlayerStatusCb) @@ -539,7 +539,7 @@ void PlayerThunderAccess::onPlayerStatusHandler_OTA(const JsonObject& parameters data.vid_codec = videoInfoObj["codec"].String(); data.vid_hdrType = videoInfoObj["hdrType"].String(); data.vid_bitrate = videoInfoObj["bitrate"].Number(); - + JsonObject audioInfoObj = playerData["audioInfo"].Object(); data.aud_codec = audioInfoObj["codec"].String(); @@ -649,7 +649,7 @@ void PlayerThunderAccess::SetPreferredAudioLanguages_OTA(std::string preferredLa JsonObject properties; bool modifiedLang = false; bool modifiedRend = false; - + if((0 != preferredLanguagesString.length()) && (preferredLanguagesString != atsc_preferredLanguagesString)){ properties["preferredAudioLanguage"] = preferredLanguagesString.c_str(); modifiedLang = true; @@ -685,7 +685,7 @@ void PlayerThunderAccess::SetPreferredAudioLanguages_OTA(std::string preferredLa std::string paramStr; param.ToString(paramStr); MW_LOG_WARN( "[OTA_SHIM] setProperties success with param:%s", paramStr.c_str()); - + } } } @@ -837,7 +837,7 @@ bool PlayerThunderAccess::GetTextTracksOta(std::vector txtData) txtData.push_back(temp); // txtTracks.push_back(TextTrackInfo(index, languageCode, true, empty, textData["name"].String(), serviceNo, empty, (int)textData["pk"].Number())); - + } if(!txtData.empty()) @@ -875,7 +875,7 @@ void PlayerThunderAccess::DisableContentRestrictionsOta(long grace, long time, b } InvokeJSONRPC("disableContentRestrictionsUntil", param, result); - + } /** diff --git a/externals/rdk/PlayerThunderAccess.h b/externals/rdk/PlayerThunderAccess.h index 427d2f5c..a2a24f61 100644 --- a/externals/rdk/PlayerThunderAccess.h +++ b/externals/rdk/PlayerThunderAccess.h @@ -53,13 +53,13 @@ class PlayerThunderAccess : public PlayerThunderAccessBase * @param callsign plugin callsign */ PlayerThunderAccess(PlayerThunderAccessPlugin callsign); - + /** * @fn ~PlayerThunderAccess * @note clean up */ ~PlayerThunderAccess(); - + /** * @brief PlayerThunderAccess copy constructor disabled */ @@ -78,7 +78,7 @@ class PlayerThunderAccess : public PlayerThunderAccessBase * @retval false on failure */ bool ActivatePlugin() override; - + /** * @fn UnSubscribeEvent * @note unSubscribe event data for the specific plugin @@ -110,7 +110,7 @@ class PlayerThunderAccess : public PlayerThunderAccessBase * @retval false if failure */ bool SetVideoRectangle(int x, int y, int w, int h, std::string videoInputType, PlayerThunderAccessShim shim) override; - + /** * @fn SetPreferredAudioLanguages_OTA * @param data player's input on preferred languages @@ -319,7 +319,7 @@ class PlayerThunderAccess : public PlayerThunderAccessBase std::function mOnPlayerStatusCb; //callback to player on player status update std::function mOnPlayerStatusHandlerCb; //callback to player on status change, rmf std::function mOnPlayerErrorHandlerCb; //callback to player on error, rmf - + /** * @fn RegisterEvent * @param[in] eventName : Event name @@ -396,7 +396,7 @@ class PlayerThunderAccess : public PlayerThunderAccessBase * @return true if success, false if failure */ bool GetResolutionFromDS_VIDEOIN(int & widthFromDS, int & heightFromDS); - + /** * @fn SubscribeEvent * @note Subscribe event data for the specific plugin diff --git a/gst-plugins/CMakeLists.txt b/gst-plugins/CMakeLists.txt deleted file mode 100755 index aefcafd5..00000000 --- a/gst-plugins/CMakeLists.txt +++ /dev/null @@ -1,117 +0,0 @@ -########################################################################## -# Copyright 2025 RDK Management -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation, version 2.1 -# of the license. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -# Boston, MA 02110-1301, USA. -######################################################################### - -cmake_minimum_required (VERSION 2.6) -project (GST-PLUGINS) -#find_package(GStreamer 1.4 REQUIRED) -#add_subdirectory(jsbindings) -find_package(PkgConfig REQUIRED) - -message("using gstreamer-1.0") -pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0) -pkg_check_modules(GSTREAMERBASE REQUIRED gstreamer-app-1.0) - -pkg_check_modules(CURL REQUIRED libcurl) - -# Mac OS X -if(CMAKE_SYSTEM_NAME STREQUAL Darwin) - set(OS_CXX_FLAGS "${OS_CXX_FLAGS} -g -x objective-c++") - set(OS_LD_FLAGS "${OS_LD_FLAGS} -framework Cocoa") - string(STRIP ${OS_LD_FLAGS} OS_LD_FLAGS) - set(CLI_LD_FLAGS "${CLI_LD_FLAGS} -lgstvideo-1.0") - string(STRIP ${CLI_LD_FLAGS} CLI_LD_FLAGS) - #set(AAMP_OS_SOURCES cocoa_window.mm) #to be decided -endif(CMAKE_SYSTEM_NAME STREQUAL Darwin) - -find_package (Threads REQUIRED) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories(${GSTREAMER_INCLUDE_DIRS}) -include_directories(${CURL_INCLUDE_DIRS}) -include_directories(${GSTREAMERBASE_INCLUDE_DIRS}) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../middleware/closedcaptions) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../middleware) - -set(GST_COMMON_DEPENDENCIES ${OS_LD_FLAGS} ${GSTREAMERBASE_LIBRARIES} ${GSTREAMER_LIBRARIES} ${CURL_LIBRARIES} ${CLI_LD_FLAGS} -ldl -luuid ${SEC_CLIENT_LIB}) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-multichar -std=c++11") - -if(CMAKE_IARM_MGR) - message("CMAKE_IARM_MGR set") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIARM_MGR") -endif() - -set(GST_MIDDLEWARE_SOURCES gstinit.cpp - ../../middleware/playerLogManager/PlayerLogManager.cpp) - -if(CMAKE_CDM_DRM) - message("CMAKE_CDM_DRM set") - set(GST_MIDDLEWARE_SOURCES "${GST_MIDDLEWARE_SOURCES}" drm/gst/gstcdmidecryptor.cpp drm/gst/gstplayreadydecryptor.cpp drm/gst/gstwidevinedecryptor.cpp drm/gst/gstclearkeydecryptor.cpp drm/gst/gstverimatrixdecryptor.cpp) -endif() - -message("AAMP consolidated build, enabling gst_subtec") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGST_SUBTEC_ENABLED") -add_subdirectory(gst_subtec) - -add_library(gstplugin SHARED ${GST_MIDDLEWARE_SOURCES}) - -if(CMAKE_CDM_DRM) - target_include_directories (gstplugin PRIVATE drm/gst) - if(CMAKE_USE_OPENCDM_ADAPTER) - message("CMAKE_USE_OPENCDM_ADAPTER set") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_OPENCDM_ADAPTER") - set(GST_COMMON_DEPENDENCIES "${GST_COMMON_DEPENDENCIES} -locdm") - find_path (STAGING_INCDIR opencdm) - include_directories(${STAGING_INCDIR}/opencdm) - else() - message("CMAKE_USE_OPENCDM_ADAPTER not set") - endif() - set(PLUGIN_DEFINES "${PLUGIN_DEFINES} -DDRM_BUILD_PROFILE=DRM_BUILD_PROFILE_OEM -DTARGET_LITTLE_ENDIAN=1 -DTARGET_SUPPORTS_UNALIGNED_DWORD_POINTERS=0 ${SEC_CONTENT_METADATA_ENABLED}") -else() - message("CMAKE_CDM_DRM not set") -endif() - -target_link_libraries (gstplugin aamp ${GST_COMMON_DEPENDENCIES}) -target_include_directories (gstplugin PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../ ${CMAKE_CURRENT_SOURCE_DIR}/../../drm ${CMAKE_CURRENT_SOURCE_DIR}/../../drm/helper ${CMAKE_CURRENT_SOURCE_DIR}/../../tsb/api ${CMAKE_CURRENT_SOURCE_DIR}/../../downloader ${CMAKE_CURRENT_SOURCE_DIR}/../../middleware ${CMAKE_CURRENT_SOURCE_DIR}/../../middleware/gst-plugins ${CMAKE_CURRENT_SOURCE_DIR}/../../middleware/vendor ${CMAKE_CURRENT_SOURCE_DIR}/../../middleware/drm ${CMAKE_CURRENT_SOURCE_DIR}/../../middleware/drm/ocdm ${CMAKE_CURRENT_SOURCE_DIR}/../../middleware/drm/helper ${CMAKE_CURRENT_SOURCE_DIR}/../../middleware/externals/playersecmanager) - -set(LIBPLUGIN_DEFINES "${PLUGIN_DEFINES}") - -if (CMAKE_AMLOGIC_SOC) - message("CMAKE_AMLOGIC_SOC set") - target_link_libraries (gstplugin gstsvpext) -endif() - -#TODO Remove once PrivateInstance_Player is compilation flag independent. -#if(CMAKE_USE_SECCLIENT) -# message("CMAKE_USE_SECCLIENT set") -# set(LIBPLUGIN_DEFINES "${LIBPLUGIN_DEFINES} -DUSE_SECCLIENT") -#elseif(CMAKE_USE_SECMANAGER) -# message("CMAKE_USE_SECMANAGER set") -# set(LIBPLUGIN_DEFINES "${LIBPLUGIN_DEFINES} -DUSE_SECMANAGER") -#endif() - -install(TARGETS gstplugin DESTINATION lib/gstreamer-1.0) - -if(CMAKE_WPEWEBKIT_JSBINDINGS) - message("CMAKE_WPEWEBKIT_JSBINDINGS set") - #target_link_libraries (gstplugin aampjsbindings) - #set(LIBPLUGIN_DEFINES "${LIBPLUGIN_DEFINES} -DAAMP_JSCONTROLLER_ENABLED") -endif() - -set_target_properties(gstplugin PROPERTIES COMPILE_FLAGS "${LIBPLUGIN_DEFINES}") diff --git a/gst-plugins/COPYING b/gst-plugins/COPYING deleted file mode 100644 index 5836b722..00000000 --- a/gst-plugins/COPYING +++ /dev/null @@ -1,22 +0,0 @@ -This software is licensed by RDK Management under the GNU Lesser General -Public License version 2.1 only, as per COPYING.LGPL and subject to any -additional licenses included in this file. - -Please use the following copyright for source within this repository: - - Copyright RDK Management - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, version 2.1 - of the license. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the - Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - Boston, MA 02110-1301, USA. diff --git a/gst-plugins/COPYING.LGPL b/gst-plugins/COPYING.LGPL deleted file mode 100644 index 27805856..00000000 --- a/gst-plugins/COPYING.LGPL +++ /dev/null @@ -1,176 +0,0 @@ - -GNU LESSER GENERAL PUBLIC LICENSE - -Version 2.1, February 1999 - -Copyright (C) 1991, 1999 Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the Public License, version 2, hence - the version number 2.1.] -Preamble - -The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. - -This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. - -When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. - -To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. - -For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. - -We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. - -To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author`s reputation will not be affected by problems that might be introduced by others. - -Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. - -Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. - -When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. - -We call this license the "Lesser" General Public License because it does Less to protect the user`s freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. - -For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. - -In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. - -Although the Lesser General Public License is Less protective of the users` freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. - -The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". - -A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. - -The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) - -"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. - -Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. - -1. You may copy and distribute verbatim copies of the Library`s complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. - -You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: - -a) The modified work must itself be a software library. -b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. -c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. -d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. -(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. - -3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. - -Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. - -This option is useful when you wish to copy part of the code of the Library into a program that is not a library. - -4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. - -If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. - -5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. - -However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. - -When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. - -If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) - -Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. - -6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer`s own use and reverse engineering for debugging such modifications. - -You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: - -a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) -b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user`s computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. -c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. -d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. -e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. -For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. - -It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. - -7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: - -a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. -b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. -8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. - -9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. - -10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients` exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. - -11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. - -This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - -12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. - -13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. - -14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - -NO WARRANTY - -15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Libraries - -If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). - -To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - -one line to give the library`s name and an idea of what it does. -Copyright (C) year name of author - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: - -Yoyodyne, Inc., hereby disclaims all copyright interest in -the library `Frob` (a library for tweaking knobs) written -by James Random Hacker. - -signature of Ty Coon, 1 April 1990 -Ty Coon, President of Vice -That`s all there is to it! - diff --git a/gst-plugins/drm/gst/gstcdmidecryptor.cpp b/gst-plugins/drm/gst/gstcdmidecryptor.cpp deleted file mode 100755 index ced2a132..00000000 --- a/gst-plugins/drm/gst/gstcdmidecryptor.cpp +++ /dev/null @@ -1,1073 +0,0 @@ -/* -* Copyright 2018 RDK Management -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, version 2.1 -* of the license. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -* Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include "gstcdmidecryptor.h" -#include -#include -#if defined(AMLOGIC) -#include -#endif -#include -#include -#include "DrmConstants.h" - -GST_DEBUG_CATEGORY_STATIC ( gst_cdmidecryptor_debug_category); -#define GST_CAT_DEFAULT gst_cdmidecryptor_debug_category -#define DECRYPT_FAILURE_THRESHOLD 5 - -enum -{ - PROP_0, PROP_PLAYER, PROP_DRM_SESSION_MANAGER -}; - -//#define FUNCTION_DEBUG 1 -#ifdef FUNCTION_DEBUG -#define DEBUG_FUNC() g_warning("####### %s : %d ####\n", __FUNCTION__, __LINE__); -#else -#define DEBUG_FUNC() -#endif - -/** - * @brief Replaces the Key ID in Widevine PSSH data with the Key ID from Clear Key PSSH data. - * - * This function modifies the Widevine PSSH data by replacing its Key ID with the Key ID - * from the Clear Key PSSH data. It allocates memory for the modified PSSH data and returns it. - * - * @param[in] InputData Pointer to the input PSSH data. - * @param[in] InputDataLength Length of the input PSSH data. - * @param[out] OutputDataLength Reference to store the length of the modified PSSH data. - * @return Pointer to the modified PSSH data. Returns NULL if the input data is invalid - * or memory allocation fails. - * - * @note The caller is responsible for freeing the memory allocated for the modified PSSH data. - */ -static unsigned char* ReplaceKIDPsshData(const unsigned char *InputData, const size_t InputDataLength, size_t & OutputDataLength) -{ - unsigned char *outputData = NULL; - unsigned int WIDEVINE_PSSH_KEYID_OFFSET = 36u; - unsigned int CK_PSSH_KEYID_OFFSET = 32u; - unsigned int COMMON_KEYID_SIZE = 16u; - unsigned char WVSamplePSSH[] = { - 0x00, 0x00, 0x00, 0x3c, - 0x70, 0x73, 0x73, 0x68, - 0x00, 0x00, 0x00, 0x00, - 0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce, - 0xa3, 0xc8, 0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed, - 0x00, 0x00, 0x00, 0x1c, 0x08, 0x01, 0x12, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //dummy KeyId (16 byte) - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //dummy KeyId (16 byte) - 0x22, 0x06, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x37 - }; - if (InputData) - { - MW_LOG_INFO("Converting system UUID of PSSH data size (%zu)", InputDataLength); -#ifdef ENABLE_DUMP - MW_LOG_INFO("PSSH Data (%d) Before Modification : ", InputDataLength); - DumpBlob(InputData, InputDataLength); -#endif - /** Replace KeyID of WV PSSH Data with Key ID of CK PSSH Data **/ - int iWVpssh = WIDEVINE_PSSH_KEYID_OFFSET; - int CKPssh = CK_PSSH_KEYID_OFFSET; - int size = 0; - if (CK_PSSH_KEYID_OFFSET+COMMON_KEYID_SIZE <= InputDataLength) - { - for (; size < COMMON_KEYID_SIZE; ++size, ++iWVpssh, ++CKPssh ) - { - /** Transfer KeyID from CK PSSH data to WV PSSH Data **/ - WVSamplePSSH[iWVpssh] = InputData[CKPssh]; - } - /** Allocate WV PSSH Data memory and transfer local data **/ - outputData = (unsigned char *)malloc(sizeof(WVSamplePSSH)); - if (outputData) - { - memcpy(outputData, WVSamplePSSH, sizeof(WVSamplePSSH)); - OutputDataLength = sizeof(WVSamplePSSH); -#ifdef ENABLE_DUMP - MW_LOG_INFO("PSSH Data (%d) after Modification : ", OutputDataLength); DumpBlob(outputData, OutputDataLength); -#endif - return outputData; - } - else - { - MW_LOG_ERR("PSSH Data Memory allocation failed "); - } - } - else - { - //Invalid PSSH data - MW_LOG_ERR("Invalid Clear Key PSSH data "); } - } - else - { //Invalid argument - PSSH Data - MW_LOG_ERR("Invalid Argument of PSSH data "); - } - return NULL; -} - -static const gchar *srcMimeTypes[] = { "video/x-h264", "video/x-h264(memory:SecMem)", "audio/mpeg", "video/x-h265", "video/x-h265(memory:SecMem)", "audio/x-eac3", "audio/x-gst-fourcc-ec_3", "audio/x-ac3","audio/x-opus", nullptr }; - -/* class initialization */ -G_DEFINE_TYPE_WITH_CODE (GstCDMIDecryptor, gst_cdmidecryptor, GST_TYPE_BASE_TRANSFORM, - GST_DEBUG_CATEGORY_INIT (gst_cdmidecryptor_debug_category, "cdmidecryptor", 0, - "debug category for cdmidecryptor element")); - -#if defined(UBUNTU) -// stubs to avoid strange ubuntu-specific SegFault while running L2 Plugin tests -static void gst_cdmidecryptor_class_init( GstCDMIDecryptorClass * klass) -{ - printf( "gst_aampcdmidecryptor_class_init\n" ); -} -static void gst_cdmidecryptor_init( GstCDMIDecryptor *cdmidecryptor) -{ - printf( "gst_aampcdmidecryptor_init\n" ); -} -#else -/* prototypes */ -static void gst_cdmidecryptor_dispose(GObject*); -static GstCaps *gst_cdmidecryptor_transform_caps( - GstBaseTransform * trans, GstPadDirection direction, GstCaps * caps, - GstCaps * filter); -static gboolean gst_cdmidecryptor_sink_event(GstBaseTransform * trans, - GstEvent * event); -static GstFlowReturn gst_cdmidecryptor_transform_ip( - GstBaseTransform * trans, GstBuffer * buf); -static GstStateChangeReturn gst_cdmidecryptor_changestate( - GstElement* element, GstStateChange transition); -static void gst_cdmidecryptor_set_property(GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static gboolean gst_cdmidecryptor_accept_caps(GstBaseTransform * trans, - GstPadDirection direction, GstCaps * caps); -static OpenCDMError(*OCDMGstTransformCaps)(GstCaps **); - -static void gst_cdmidecryptor_class_init( - GstCDMIDecryptorClass *klass) -{ - DEBUG_FUNC(); - GObjectClass *gobject_class = G_OBJECT_CLASS(klass); - GstBaseTransformClass *base_transform_class = GST_BASE_TRANSFORM_CLASS(klass); - - gobject_class->set_property = gst_cdmidecryptor_set_property; - gobject_class->dispose = gst_cdmidecryptor_dispose; - - g_object_class_install_property(gobject_class, PROP_PLAYER, - g_param_spec_pointer("player", "PLAYER", - "DrmSessionManager instance for DrmCallback", G_PARAM_WRITABLE)); - - g_object_class_install_property(gobject_class, PROP_DRM_SESSION_MANAGER, - g_param_spec_pointer("drm-session-manager", "DRM Session Manager", - "Pointer to DRM session manager", G_PARAM_WRITABLE)); - - GST_ELEMENT_CLASS(klass)->change_state = - gst_cdmidecryptor_changestate; - - base_transform_class->transform_caps = GST_DEBUG_FUNCPTR( - gst_cdmidecryptor_transform_caps); - base_transform_class->sink_event = GST_DEBUG_FUNCPTR( - gst_cdmidecryptor_sink_event); - base_transform_class->transform_ip = GST_DEBUG_FUNCPTR( - gst_cdmidecryptor_transform_ip); - -#if !defined(AMLOGIC) - base_transform_class->accept_caps = GST_DEBUG_FUNCPTR( - gst_cdmidecryptor_accept_caps); -#endif - base_transform_class->transform_ip_on_passthrough = FALSE; - - gst_element_class_set_static_metadata(GST_ELEMENT_CLASS(klass), - "Decrypt encrypted content with CDMi", - GST_ELEMENT_FACTORY_KLASS_DECRYPTOR, - "Decrypts streams encrypted using Encryption.", - "comcast"); - //GST_DEBUG_OBJECT(cdmidecryptor, "Inside custom plugin init\n"); -} - -static void gst_cdmidecryptor_init( - GstCDMIDecryptor *cdmidecryptor) -{ - DEBUG_FUNC(); - const char* ocdmgsttransformcaps = "opencdm_gstreamer_transform_caps"; - GstBaseTransform* base = GST_BASE_TRANSFORM(cdmidecryptor); - - gst_base_transform_set_in_place(base, TRUE); - gst_base_transform_set_passthrough(base, FALSE); - gst_base_transform_set_gap_aware(base, FALSE); - - g_mutex_init(&cdmidecryptor->mutex); - //GST_DEBUG_OBJECT(cdmidecryptor, "\n Initialized plugin mutex\n"); - g_cond_init(&cdmidecryptor->condition); - cdmidecryptor->streamReceived = false; - // Lock access to canWait to keep Coverity happy - g_mutex_lock(&cdmidecryptor->mutex); - cdmidecryptor->canWait = false; - g_mutex_unlock(&cdmidecryptor->mutex); - cdmidecryptor->protectionEvent = NULL; - cdmidecryptor->sessionManager = NULL; - cdmidecryptor->drmSession = NULL; - cdmidecryptor->player = NULL; - cdmidecryptor->mediaType = eGST_MEDIATYPE_MANIFEST; - cdmidecryptor->firstsegprocessed = false; - cdmidecryptor->selectedProtection = NULL; - cdmidecryptor->decryptFailCount = 0; - cdmidecryptor->hdcpOpProtectionFailCount = 0; - cdmidecryptor->notifyDecryptError = true; - cdmidecryptor->streamEncrypted = false; - cdmidecryptor->ignoreSVP = false; - cdmidecryptor->sinkCaps = NULL; - cdmidecryptor->svpCtx = NULL; - - OCDMGstTransformCaps = (OpenCDMError(*)(GstCaps**))dlsym(RTLD_DEFAULT, ocdmgsttransformcaps); - if (OCDMGstTransformCaps) - GST_INFO_OBJECT(cdmidecryptor, "Has opencdm_gstreamer_transform_caps support \n"); - else - GST_INFO_OBJECT(cdmidecryptor, "No opencdm_gstreamer_transform_caps support \n"); - //GST_DEBUG_OBJECT(cdmidecryptor, "******************Init called**********************\n"); -} - -void gst_cdmidecryptor_dispose(GObject * object) -{ - DEBUG_FUNC(); - - GstCDMIDecryptor *cdmidecryptor = - GST_CDMI_DECRYPTOR(object); - - GST_DEBUG_OBJECT(cdmidecryptor, "dispose"); - - if (cdmidecryptor->protectionEvent) - { - gst_event_unref(cdmidecryptor->protectionEvent); - cdmidecryptor->protectionEvent = NULL; - } - if (cdmidecryptor->sinkCaps) - { - gst_caps_unref(cdmidecryptor->sinkCaps); - cdmidecryptor->sinkCaps = NULL; - } - - g_mutex_clear(&cdmidecryptor->mutex); - g_cond_clear(&cdmidecryptor->condition); - - G_OBJECT_CLASS(gst_cdmidecryptor_parent_class)->dispose(object); -} - -/* - Append modified caps to dest, but only if it does not already exist in updated caps. - */ -static void gst_cdmicapsappendifnotduplicate(GstCaps* destCaps, - GstStructure* cap) -{ - DEBUG_FUNC(); - - bool duplicate = false; - unsigned size = gst_caps_get_size(destCaps); - for (unsigned index = 0; !duplicate && index < size; ++index) - { - GstStructure* tempCap = gst_caps_get_structure(destCaps, index); - if (gst_structure_is_equal(tempCap, cap)) - duplicate = true; - } - - if (!duplicate) - gst_caps_append_structure(destCaps, cap); - else - gst_structure_free(cap); -} - -static GstCaps * -gst_cdmidecryptor_transform_caps(GstBaseTransform * trans, - GstPadDirection direction, GstCaps * caps, GstCaps * filter) -{ - DEBUG_FUNC(); - GstCDMIDecryptor *cdmidecryptor = GST_CDMI_DECRYPTOR(trans); - g_return_val_if_fail(direction != GST_PAD_UNKNOWN, NULL); - unsigned size = gst_caps_get_size(caps); - GstCaps* transformedCaps = gst_caps_new_empty(); - - GST_DEBUG_OBJECT(trans, "direction: %s, caps: %" GST_PTR_FORMAT " filter:" - " %" GST_PTR_FORMAT, (direction == GST_PAD_SRC) ? "src" : "sink", caps, filter); - - if(!cdmidecryptor->selectedProtection) - { - GstStructure *capstruct = gst_caps_get_structure(caps, 0); - const gchar* capsinfo = gst_structure_get_string(capstruct, "protection-system"); - if(capsinfo != NULL) - { - if(!g_strcmp0(capsinfo, PLAYREADY_UUID)) - { - cdmidecryptor->selectedProtection = PLAYREADY_UUID; - } - else if(!g_strcmp0(capsinfo, WIDEVINE_UUID)) - { - cdmidecryptor->selectedProtection = WIDEVINE_UUID; - } - else if(!g_strcmp0(capsinfo, CLEARKEY_UUID)) - { - cdmidecryptor->selectedProtection = CLEARKEY_UUID; - cdmidecryptor->ignoreSVP = true; - } - else if(!g_strcmp0(capsinfo, VERIMATRIX_UUID)) - { - cdmidecryptor->selectedProtection = VERIMATRIX_UUID; - } - } - else - { - GST_DEBUG_OBJECT(trans, "can't find protection-system field from caps: %" GST_PTR_FORMAT, caps); - } - } - - for (unsigned i = 0; i < size; ++i) - { - GstStructure* in = gst_caps_get_structure(caps, i); - GstStructure* out = NULL; - - if (direction == GST_PAD_SRC) - { - - out = gst_structure_copy(in); - /* filter out the video related fields from the up-stream caps, - because they are not relevant to the input caps of this element and - can cause caps negotiation failures with adaptive bitrate streams */ - for (int index = gst_structure_n_fields(out) - 1; index >= 0; - --index) - { - const gchar* fieldName = gst_structure_nth_field_name(out, - index); - - if (g_strcmp0(fieldName, "base-profile") - && g_strcmp0(fieldName, "codec_data") - && g_strcmp0(fieldName, "height") - && g_strcmp0(fieldName, "framerate") - && g_strcmp0(fieldName, "level") - && g_strcmp0(fieldName, "pixel-aspect-ratio") - && g_strcmp0(fieldName, "profile") - && g_strcmp0(fieldName, "rate") - && g_strcmp0(fieldName, "width")) - { - continue; - } - else - { - gst_structure_remove_field(out, fieldName); - GST_TRACE_OBJECT(cdmidecryptor, "Removing field %s", fieldName); - } - } - - gst_structure_set(out, "protection-system", G_TYPE_STRING, - cdmidecryptor->selectedProtection, "original-media-type", - G_TYPE_STRING, gst_structure_get_name(in), NULL); - - gst_structure_set_name(out, "application/x-cenc"); - - } - else - { - if (!gst_structure_has_field(in, "original-media-type")) - { - GST_DEBUG_OBJECT(trans, "No original-media-type field in caps: %" GST_PTR_FORMAT, out); - - // Check if these caps are present in supported src pad caps in case direction is GST_PAD_SINK, - // we can allow caps in this case, since plugin will let the data passthrough - gboolean found = false; - for (int j = 0; srcMimeTypes[j]; j++) - { - if (gst_structure_has_name(in, srcMimeTypes[j])) - { - found = true; - break; - } - } - if (found) - { - //From supported src type format - out = gst_structure_copy(in); - } - else - { - continue; - } - } - else - { - - out = gst_structure_copy(in); - gst_structure_set_name(out, - gst_structure_get_string(out, "original-media-type")); - - /* filter out the DRM related fields from the down-stream caps */ - for (int j = 0; j < gst_structure_n_fields(in); ++j) - { - const gchar* fieldName = gst_structure_nth_field_name(in, j); - - if (g_str_has_prefix(fieldName, "protection-system") - || g_str_has_prefix(fieldName, "original-media-type")) - { - gst_structure_remove_field(out, fieldName); - } - } - } - } - - gst_cdmicapsappendifnotduplicate(transformedCaps, out); - -#if defined(AMLOGIC) - if (direction == GST_PAD_SINK && !gst_caps_is_empty(transformedCaps) && OCDMGstTransformCaps) - OCDMGstTransformCaps(&transformedCaps); -#endif - } - - if (filter) - { - GstCaps* intersection; - - GST_LOG_OBJECT(trans, "Using filter caps %" GST_PTR_FORMAT, filter); - intersection = gst_caps_intersect_full(transformedCaps, filter, - GST_CAPS_INTERSECT_FIRST); - gst_caps_unref(transformedCaps); - transformedCaps = intersection; - } - - GST_LOG_OBJECT(trans, "returning %" GST_PTR_FORMAT, transformedCaps); - if (direction == GST_PAD_SINK && !gst_caps_is_empty(transformedCaps)) - { - g_mutex_lock(&cdmidecryptor->mutex); - // clean up previous caps - if (cdmidecryptor->sinkCaps) - { - gst_caps_unref(cdmidecryptor->sinkCaps); - cdmidecryptor->sinkCaps = NULL; - } - cdmidecryptor->sinkCaps = gst_caps_copy(transformedCaps); - g_mutex_unlock(&cdmidecryptor->mutex); - GST_DEBUG_OBJECT(trans, "Set sinkCaps to %" GST_PTR_FORMAT, cdmidecryptor->sinkCaps); - } - return transformedCaps; -} - -#ifdef USE_OPENCDM_ADAPTER - -static GstFlowReturn gst_cdmidecryptor_transform_ip( - GstBaseTransform * trans, GstBuffer * buffer) -{ - DEBUG_FUNC(); - - GstCDMIDecryptor *cdmidecryptor = - GST_CDMI_DECRYPTOR(trans); - - GstFlowReturn result = GST_FLOW_OK; - - guint subSampleCount = 0; - guint ivSize; - gboolean encrypted; - const GValue* value; - GstBuffer* ivBuffer = NULL; - GstBuffer* keyIDBuffer = NULL; - GstBuffer* subsamplesBuffer = NULL; - GstMapInfo subSamplesMap; - GstProtectionMeta* protectionMeta = NULL; - gboolean mutexLocked = FALSE; - int errorCode; - - GST_DEBUG_OBJECT(cdmidecryptor, "Processing buffer"); - - if (!buffer) - { - GST_ERROR_OBJECT(cdmidecryptor,"Failed to get writable buffer"); - result = GST_FLOW_NOT_SUPPORTED; - goto free_resources; - } - - protectionMeta = - reinterpret_cast(gst_buffer_get_protection_meta(buffer)); - - g_mutex_lock(&cdmidecryptor->mutex); - mutexLocked = TRUE; - if (!protectionMeta) - { - GST_DEBUG_OBJECT(cdmidecryptor, - "Failed to get GstProtection metadata from buffer %p, could be clear buffer",buffer); -#if defined(AMLOGIC) - // call decrypt even for clear samples in order to copy it to a secure buffer. If secure buffers are not supported - // decrypt() call will return without doing anything - if (cdmidecryptor->drmSession != NULL) - errorCode = cdmidecryptor->drmSession->decrypt(keyIDBuffer, ivBuffer, buffer, subSampleCount, subsamplesBuffer, cdmidecryptor->sinkCaps); - else - { /* If drmSession creation failed, then the call will be aborted here */ - result = GST_FLOW_NOT_SUPPORTED; - GST_ERROR_OBJECT(cdmidecryptor, "drmSession is **** NULL ****, returning GST_FLOW_NOT_SUPPORTED"); - } -#endif - goto free_resources; - } - - GST_TRACE_OBJECT(cdmidecryptor, - "Mutex acquired, stream received: %s canWait: %d", - cdmidecryptor->streamReceived ? "yes" : "no", cdmidecryptor->canWait); - - if (!cdmidecryptor->canWait - && !cdmidecryptor->streamReceived) - { - result = GST_FLOW_NOT_SUPPORTED; - goto free_resources; - } - - if (!cdmidecryptor->firstsegprocessed) - { - GST_DEBUG_OBJECT(cdmidecryptor, "\n\nWaiting for key\n"); - } - // The key might not have been received yet. Wait for it. - if (!cdmidecryptor->streamReceived) - g_cond_wait(&cdmidecryptor->condition, - &cdmidecryptor->mutex); - - if (!cdmidecryptor->streamReceived) - { - GST_ERROR_OBJECT(cdmidecryptor, - "Condition signaled from state change transition. Aborting."); - result = GST_FLOW_NOT_SUPPORTED; - goto free_resources; - } - - /* If drmSession creation failed, then the call will be aborted here */ - if (cdmidecryptor->drmSession == NULL) - { - GST_ERROR_OBJECT(cdmidecryptor, "drmSession is invalid **** NULL ****. Aborting."); - result = GST_FLOW_NOT_SUPPORTED; - goto free_resources; - } - - GST_TRACE_OBJECT(cdmidecryptor, "Got key event ; Proceeding with decryption"); - - if (!gst_structure_get_uint(protectionMeta->info, "iv_size", &ivSize)) - { - GST_ERROR_OBJECT(cdmidecryptor, "failed to get iv_size"); - result = GST_FLOW_NOT_SUPPORTED; - goto free_resources; - } - - if (!gst_structure_get_boolean(protectionMeta->info, "encrypted", - &encrypted)) - { - GST_ERROR_OBJECT(cdmidecryptor, - "failed to get encrypted flag"); - result = GST_FLOW_NOT_SUPPORTED; - goto free_resources; - } - - // Unencrypted sample. - if (!ivSize || !encrypted) - goto free_resources; - - GST_TRACE_OBJECT(trans, "protection meta: %" GST_PTR_FORMAT, protectionMeta->info); - if (!gst_structure_get_uint(protectionMeta->info, "subsample_count", - &subSampleCount)) - { - GST_ERROR_OBJECT(cdmidecryptor, - "failed to get subsample_count"); - result = GST_FLOW_NOT_SUPPORTED; - goto free_resources; - } - - value = gst_structure_get_value(protectionMeta->info, "iv"); - if (!value) - { - GST_ERROR_OBJECT(cdmidecryptor, "Failed to get IV for sample"); - result = GST_FLOW_NOT_SUPPORTED; - goto free_resources; - } - - ivBuffer = gst_value_get_buffer(value); - - value = gst_structure_get_value(protectionMeta->info, "kid"); - if (!value) { - GST_ERROR_OBJECT(cdmidecryptor, "Failed to get kid for sample"); - result = GST_FLOW_NOT_SUPPORTED; - goto free_resources; - } - - keyIDBuffer = gst_value_get_buffer(value); - - if (subSampleCount) - { - value = gst_structure_get_value(protectionMeta->info, "subsamples"); - if (!value) - { - GST_ERROR_OBJECT(cdmidecryptor, - "Failed to get subsamples"); - result = GST_FLOW_NOT_SUPPORTED; - goto free_resources; - } - subsamplesBuffer = gst_value_get_buffer(value); - if (!gst_buffer_map(subsamplesBuffer, &subSamplesMap, GST_MAP_READ)) - { - GST_ERROR_OBJECT(cdmidecryptor, - "Failed to map subsample buffer"); - result = GST_FLOW_NOT_SUPPORTED; - goto free_resources; - } - } - - errorCode = cdmidecryptor->drmSession->decrypt(keyIDBuffer, ivBuffer, buffer, subSampleCount, subsamplesBuffer, cdmidecryptor->sinkCaps); - - cdmidecryptor->streamEncrypted = true; - if (errorCode != 0 || cdmidecryptor->hdcpOpProtectionFailCount) - { - if(errorCode == HDCP_OUTPUT_PROTECTION_FAILURE) - { - cdmidecryptor->hdcpOpProtectionFailCount++; - } - else if(cdmidecryptor->hdcpOpProtectionFailCount) - { - if(cdmidecryptor->hdcpOpProtectionFailCount >= DECRYPT_FAILURE_THRESHOLD) { - GstStructure *newmsg = gst_structure_new("HDCPProtectionFailure", "message", G_TYPE_STRING,"HDCP Output Protection Error", NULL); - gst_element_post_message(reinterpret_cast(cdmidecryptor),gst_message_new_application (GST_OBJECT (cdmidecryptor), newmsg)); - } - cdmidecryptor->hdcpOpProtectionFailCount = 0; - } - else - { - GST_ERROR_OBJECT(cdmidecryptor, "decryption failed; error code %d\n",errorCode); - cdmidecryptor->decryptFailCount++; - if(cdmidecryptor->decryptFailCount >= DECRYPT_FAILURE_THRESHOLD && cdmidecryptor->notifyDecryptError ) - { - cdmidecryptor->notifyDecryptError = false; - GError *error; - if(errorCode == HDCP_COMPLIANCE_CHECK_FAILURE) - { - // Failure - 2.2 vs 1.4 HDCP - error = g_error_new(GST_STREAM_ERROR , GST_STREAM_ERROR_FAILED, "HDCP Compliance Check Failure"); - } - else - { - error = g_error_new(GST_STREAM_ERROR , GST_STREAM_ERROR_FAILED, "Decrypt Error: code %d", errorCode); - } - gst_element_post_message(reinterpret_cast(cdmidecryptor), gst_message_new_error (GST_OBJECT (cdmidecryptor), error, "Decrypt Failed")); - g_error_free(error); - result = GST_FLOW_ERROR; - } - goto free_resources; - } - } - else - { - cdmidecryptor->decryptFailCount = 0; - cdmidecryptor->hdcpOpProtectionFailCount = 0; - if (cdmidecryptor->mediaType == eGST_MEDIATYPE_AUDIO) - { - GST_DEBUG_OBJECT(cdmidecryptor, "Decryption successful for Audio packets"); - } - else - { - GST_DEBUG_OBJECT(cdmidecryptor, "Decryption successful for Video packets"); - } - } - - if (!cdmidecryptor->firstsegprocessed - && cdmidecryptor->sessionManager) - { - cdmidecryptor->sessionManager->profileBeginCb(cdmidecryptor->mediaType); - cdmidecryptor->firstsegprocessed = true; - } - - free_resources: - - if (!cdmidecryptor->firstsegprocessed - && cdmidecryptor->sessionManager) - { - if(!cdmidecryptor->streamEncrypted) - { - cdmidecryptor->sessionManager->profileEndCb(cdmidecryptor->mediaType); - } - else - { - cdmidecryptor->sessionManager->profileErrorCb(cdmidecryptor->mediaType, result); - } - cdmidecryptor->firstsegprocessed = true; - } - - if (subsamplesBuffer) - gst_buffer_unmap(subsamplesBuffer, &subSamplesMap); - - if (protectionMeta) - gst_buffer_remove_meta(buffer, - reinterpret_cast(protectionMeta)); - - if (mutexLocked) - g_mutex_unlock(&cdmidecryptor->mutex); - return result; -} -#endif - - -/* sink event handlers */ -static gboolean gst_cdmidecryptor_sink_event(GstBaseTransform * trans, - GstEvent * event) -{ - DEBUG_FUNC(); - - GstCDMIDecryptor *cdmidecryptor = - GST_CDMI_DECRYPTOR(trans); - gboolean result = FALSE; - - switch (GST_EVENT_TYPE(event)) - { - - //GST_EVENT_PROTECTION has information about encryption and contains initData for DRM library - //This is the starting point of DRM activities. - case GST_EVENT_PROTECTION: - { - const gchar* systemId; - const gchar* origin; - unsigned char *outData = NULL; - size_t outDataLen = 0; - GstBuffer* initdatabuffer; - - if(NULL == cdmidecryptor) - { - GST_ERROR_OBJECT(cdmidecryptor, - "Invalid CDMI Decryptor Instance\n"); - result = FALSE; - break; - } - - //We need to get the sinkpad for sending upstream queries and - //getting the current pad capability ie, VIDEO or AUDIO - //in order to support tune time profiling - GstPad * sinkpad = gst_element_get_static_pad( - reinterpret_cast(cdmidecryptor), "sink"); - - //if (cdmidecryptor->player == NULL) //cdmidecryptor->sessionManager - if(cdmidecryptor->sessionManager == NULL) - { - const GValue *val; - GstStructure * structure = gst_structure_new("get_aamp_instance", - "aamp_instance", G_TYPE_POINTER, 0, NULL); - GstQuery *query = gst_query_new_custom(GST_QUERY_CUSTOM, structure); - gboolean res = gst_pad_peer_query(sinkpad, query); - if (res) - { - structure = (GstStructure *) gst_query_get_structure(query); - val = (gst_structure_get_value(structure, "aamp_instance")); - cdmidecryptor->sessionManager = - (DrmSessionManager*) g_value_get_pointer(val); - } - gst_query_unref(query); - } - //if(cdmidecryptor->player == NULL) - if(cdmidecryptor->sessionManager == NULL) - { - GST_ERROR_OBJECT(cdmidecryptor, - "cdmidecryptor unable to retrieve player instance\n"); - result = FALSE; - break; - } - - - GST_DEBUG_OBJECT(cdmidecryptor, - "Received encrypted event: Proceeding to parse initData\n"); - gst_event_parse_protection(event, &systemId, &initdatabuffer, &origin); - GST_DEBUG_OBJECT(cdmidecryptor, "systemId: %s", systemId); - GST_DEBUG_OBJECT(cdmidecryptor, "origin: %s", origin); - /** If WideVine KeyID workaround is present check the systemId is clearKey **/ - if (cdmidecryptor->sessionManager->m_drmConfigParam->mIsWVKIDWorkaround){ - if(!g_str_equal(systemId, CLEARKEY_UUID) ){ - gst_event_unref(event); - result = TRUE; - break; - } - GST_DEBUG_OBJECT(cdmidecryptor, "\nWideVine KeyID workaround is present, Select KeyID from Clear Key\n"); - systemId = WIDEVINE_UUID ; - - }else{ /* else check the selected protection system */ - if (!g_str_equal(systemId, cdmidecryptor->selectedProtection)) - { - gst_event_unref(event); - result = TRUE; - break; - } - } - - GstMapInfo mapInfo; - if (!gst_buffer_map(initdatabuffer, &mapInfo, GST_MAP_READ)) - break; - GST_DEBUG_OBJECT(cdmidecryptor, "scheduling keyNeeded event"); - - if (eGST_MEDIATYPE_MANIFEST == cdmidecryptor->mediaType) - { - GstCaps* caps = gst_pad_get_current_caps(sinkpad); - GstStructure *capstruct = gst_caps_get_structure(caps, 0); - const gchar* capsinfo = gst_structure_get_string(capstruct, - "original-media-type"); - - if (!g_strcmp0(capsinfo, "audio/mpeg")) - { - cdmidecryptor->mediaType = eGST_MEDIATYPE_AUDIO; - } - else if (!g_strcmp0(capsinfo, "audio/x-opus")) - { - cdmidecryptor->mediaType = eGST_MEDIATYPE_AUDIO; - } - else if (!g_strcmp0(capsinfo, "audio/x-eac3") || !g_strcmp0(capsinfo, "audio/x-ac3")) - { - cdmidecryptor->mediaType = eGST_MEDIATYPE_AUDIO; - } - else if (!g_strcmp0(capsinfo, "audio/x-gst-fourcc-ec_3")) - { - cdmidecryptor->mediaType = eGST_MEDIATYPE_AUDIO; - } - else if (!g_strcmp0(capsinfo, "video/x-h264")) - { - cdmidecryptor->mediaType = eGST_MEDIATYPE_VIDEO; - } - else if (!g_strcmp0(capsinfo, "video/x-h265")) - { - cdmidecryptor->mediaType = eGST_MEDIATYPE_VIDEO; - } - else - { - gst_caps_unref(caps); - result = false; - break; - } - gst_caps_unref(caps); - } - - if (cdmidecryptor->sessionManager->m_drmConfigParam->mIsWVKIDWorkaround){ - GST_DEBUG_OBJECT(cdmidecryptor, "\nWideVine KeyID workaround is present, Applying WideVine KID workaround\n"); - outData = ReplaceKIDPsshData(reinterpret_cast(mapInfo.data), mapInfo.size, outDataLen); - if (NULL == outData){ - GST_ERROR_OBJECT(cdmidecryptor, "\nFailed to Apply WideVine KID workaround!\n"); - break; - } - } - - cdmidecryptor->sessionManager->laprofileBeginCb(cdmidecryptor->mediaType); - g_mutex_lock(&cdmidecryptor->mutex); - GST_DEBUG_OBJECT(cdmidecryptor, "\n acquired lock for mutex\n"); - //cdmidecryptor->sessionManager = cdmidecryptor->mDRMLicenseManager; - //void *e = cdmidecryptor->sessionManager->DrmMetaDataCb(); - std::shared_ptr e = cdmidecryptor->sessionManager->DrmMetaDataCb(); - int err = -1; - if (cdmidecryptor->sessionManager->m_drmConfigParam->mIsWVKIDWorkaround){ - cdmidecryptor->drmSession = cdmidecryptor->sessionManager->createDrmSession(err, - reinterpret_cast(systemId), eMEDIAFORMAT_DASH, - outData, outDataLen, (int)cdmidecryptor->mediaType, cdmidecryptor->player, e.get(), nullptr, false); - }else{ - cdmidecryptor->drmSession = - cdmidecryptor->sessionManager->createDrmSession(err, - reinterpret_cast(systemId), eMEDIAFORMAT_DASH, - reinterpret_cast(mapInfo.data), - mapInfo.size, (int)cdmidecryptor->mediaType, cdmidecryptor->player, e.get(), nullptr, false); - } - if(err != -1) - { - cdmidecryptor->sessionManager->setfailureCb(e.get(),err); - } - if (NULL == cdmidecryptor->drmSession) - { -/* For Avoided setting 'streamReceived' as FALSE if createDrmSession() failed after a successful case. - * Set to FALSE is already handled on gst_cdmidecryptor_init() as part of initialization. - */ -#if 0 - cdmidecryptor->streamReceived = FALSE; -#endif /* 0 */ - - /* Need to reset canWait to skip conditional wait in "gst_cdmidecryptor_transform_ip to avoid deadlock - * scenario on drm session failure - */ - cdmidecryptor->canWait = false; - /* session manager fails to create session when state is inactive. Skip sending error event - * in this scenario. Later player will change it to active after processing SetLanguage(), or for the next Tune. - */ - if(SessionMgrState::eSESSIONMGR_ACTIVE == cdmidecryptor->sessionManager->getSessionMgrState()) - { - cdmidecryptor->sessionManager->laprofileErrorCb(e.get()); - GST_ERROR_OBJECT(cdmidecryptor,"Failed to create DRM Session\n"); - } - result = TRUE; - } - else - { - cdmidecryptor->streamReceived = TRUE; - cdmidecryptor->sessionManager->laprofileEndCb(cdmidecryptor->mediaType); - if (!cdmidecryptor->firstsegprocessed) - { - cdmidecryptor->sessionManager->profileBeginCb(cdmidecryptor->mediaType); - } - - result = TRUE; - } - g_cond_signal(&cdmidecryptor->condition); - g_mutex_unlock(&cdmidecryptor->mutex); - GST_DEBUG_OBJECT(cdmidecryptor, "\n releasing ...................... mutex\n"); - - gst_object_unref(sinkpad); - gst_buffer_unmap(initdatabuffer, &mapInfo); - gst_event_unref(event); - if(outData){ - free(outData); - outData = NULL; - } - - break; - } - default: - result = GST_BASE_TRANSFORM_CLASS( - gst_cdmidecryptor_parent_class)->sink_event(trans, - event); - break; - } - - return result; -} - -static GstStateChangeReturn gst_cdmidecryptor_changestate( - GstElement* element, GstStateChange transition) -{ - DEBUG_FUNC(); - - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstCDMIDecryptor* cdmidecryptor = - GST_CDMI_DECRYPTOR(element); - - switch (transition) - { - case GST_STATE_CHANGE_READY_TO_PAUSED: - GST_DEBUG_OBJECT(cdmidecryptor, "READY->PAUSED"); - g_mutex_lock(&cdmidecryptor->mutex); - cdmidecryptor->canWait = true; - g_mutex_unlock(&cdmidecryptor->mutex); - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_DEBUG_OBJECT(cdmidecryptor, "PAUSED->READY"); - g_mutex_lock(&cdmidecryptor->mutex); - cdmidecryptor->canWait = false; - g_cond_signal(&cdmidecryptor->condition); - g_mutex_unlock(&cdmidecryptor->mutex); - break; -#if defined(AMLOGIC) - case GST_STATE_CHANGE_NULL_TO_READY: - GST_DEBUG_OBJECT(cdmidecryptor, "NULL->READY"); - if (cdmidecryptor->svpCtx == NULL) - gst_svp_ext_get_context(&cdmidecryptor->svpCtx, (int)Server, 0); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - GST_DEBUG_OBJECT(cdmidecryptor, "READY->NULL"); - if (cdmidecryptor->svpCtx) { - gst_svp_ext_free_context(cdmidecryptor->svpCtx); - cdmidecryptor->svpCtx = NULL; - } - break; -} -#endif - default: - break; - } - - ret = - GST_ELEMENT_CLASS(gst_cdmidecryptor_parent_class)->change_state( - element, transition); - return ret; -} - -static void gst_cdmidecryptor_set_property(GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - DEBUG_FUNC(); - - GstCDMIDecryptor* cdmidecryptor = - GST_CDMI_DECRYPTOR(object); - switch (prop_id) - { - case PROP_DRM_SESSION_MANAGER: - GST_OBJECT_LOCK(cdmidecryptor); - cdmidecryptor->player = - (DrmCallbacks*) g_value_get_pointer(value); - GST_DEBUG_OBJECT(cdmidecryptor, - "Received player instance from appsrc\n"); - GST_OBJECT_UNLOCK(cdmidecryptor); - break; - case PROP_PLAYER: - GST_OBJECT_LOCK(cdmidecryptor); - cdmidecryptor->sessionManager = - (DrmSessionManager*)g_value_get_pointer(value); - GST_DEBUG_OBJECT(cdmidecryptor, - "Received DRM session manager"); - GST_OBJECT_UNLOCK(cdmidecryptor); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static gboolean gst_cdmidecryptor_accept_caps(GstBaseTransform * trans, - GstPadDirection direction, GstCaps * caps) -{ - gboolean ret = TRUE; - GST_DEBUG_OBJECT (trans, "received accept caps with direction: %s caps: %" GST_PTR_FORMAT, (direction == GST_PAD_SRC) ? "src" : "sink", caps); - - GstCaps *allowedCaps = NULL; - - if (direction == GST_PAD_SINK) - { - allowedCaps = gst_pad_query_caps(trans->sinkpad, caps); - } - else - { - allowedCaps = gst_pad_query_caps(trans->srcpad, caps); - } - - if (!allowedCaps) - { - GST_ERROR_OBJECT(trans, "Error while query caps on %s pad of plugin with filter caps: %" GST_PTR_FORMAT, (direction == GST_PAD_SRC) ? "src" : "sink", caps); - ret = FALSE; - } - else - { - GST_DEBUG_OBJECT(trans, "Allowed caps: %" GST_PTR_FORMAT, allowedCaps); - ret = gst_caps_is_subset(caps, allowedCaps); - gst_caps_unref(allowedCaps); - } - - // Check if these are same as src pad caps in case direction is GST_PAD_SINK, - // we can let it through in this case - if (ret == FALSE && direction == GST_PAD_SINK) - { - guint size = gst_caps_get_size(caps); - for (guint i = 0; i < size; i++) - { - GstStructure* inCaps = gst_caps_get_structure(caps, i); - for (int j = 0; srcMimeTypes[j]; j++) - { - if (gst_structure_has_name(inCaps, srcMimeTypes[j])) - { - GST_DEBUG_OBJECT(trans, "found the requested caps in supported src mime types (type:%s), respond as supported!", srcMimeTypes[j]); - ret = TRUE; - break; - } - } - } - } - GST_DEBUG_OBJECT(trans, "Return from accept_caps: %d", ret); - return ret; -} -#endif diff --git a/gst-plugins/drm/gst/gstcdmidecryptor.h b/gst-plugins/drm/gst/gstcdmidecryptor.h deleted file mode 100644 index 87241bec..00000000 --- a/gst-plugins/drm/gst/gstcdmidecryptor.h +++ /dev/null @@ -1,88 +0,0 @@ -/* -* Copyright 2018 RDK Management -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, version 2.1 -* of the license. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -* Boston, MA 02110-1301, USA. -*/ - - -#ifndef _GST_CDMIDECRYPTOR_H_ -#define _GST_CDMIDECRYPTOR_H_ - - -#include -#include -#include "DrmSessionManager.h" -#include "DrmCallbacks.h" - -G_BEGIN_DECLS - -#define GST_TYPE_CDMI_DECRYPTOR (gst_cdmidecryptor_get_type()) -#define GST_CDMI_DECRYPTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CDMI_DECRYPTOR, GstCDMIDecryptor)) -#define GST_CDMI_DECRYPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CDMI_DECRYPTOR, GstCDMIDecryptorClass)) -#define GST_IS_CDMI_DECRYPTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_CDMI_DECRYPTOR)) -#define GST_IS_CDMI_DECRYPTOR_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_CDMI_DECRYPTOR)) - -typedef struct _GstCDMIDecryptor GstCDMIDecryptor; -typedef struct _GstCDMIDecryptorClass GstCDMIDecryptorClass; - -/** - * @struct _GstCDMIDecryptor - * @brief GstElement structure override for CDMI decryptor - */ -struct _GstCDMIDecryptor -{ - GstBaseTransform base_cdmidecryptor; - class DrmSessionManager* sessionManager; - class DrmSession* drmSession; - class DrmCallbacks * player; - gboolean streamReceived; - gboolean canWait; - gboolean firstsegprocessed; - GstMediaType mediaType; - - GMutex mutex; - GCond condition; - - GstEvent* protectionEvent; - const gchar* selectedProtection; - gushort decryptFailCount; - gushort hdcpOpProtectionFailCount; - gboolean notifyDecryptError; - gboolean streamEncrypted; - gboolean ignoreSVP; //No need for svp for clearKey streams - GstCaps* sinkCaps; - //GstBuffer* initDataBuffer; - void** svpCtx; -}; - -/** - * @struct _GstCDMIDecryptorClass - * @brief GstElementClass structure override for CDMI decryptor - */ -struct _GstCDMIDecryptorClass -{ - GstBaseTransformClass base_cdmidecryptor_class; -}; - -/** - * @brief Get type of CDMI decryptor - * @retval Type of CDMI decryptor - */ -GType gst_cdmidecryptor_get_type (void); - -G_END_DECLS - -#endif diff --git a/gst-plugins/drm/gst/gstclearkeydecryptor.cpp b/gst-plugins/drm/gst/gstclearkeydecryptor.cpp deleted file mode 100644 index 5895a0b1..00000000 --- a/gst-plugins/drm/gst/gstclearkeydecryptor.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* -* Copyright 2018 RDK Management -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, version 2.1 -* of the license. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -* Boston, MA 02110-1301, USA. -*/ - -/** - * @file gstclearkeydecryptor.cpp - * @brief player clearkey decryptor plugin definitions - */ - -#include -#include -#include -#include "gstclearkeydecryptor.h" -//#define FUNCTION_DEBUG 1 -#ifdef FUNCTION_DEBUG -#define DEBUG_FUNC() g_warning("####### %s : %d ####\n", __FUNCTION__, __LINE__); -#else -#define DEBUG_FUNC() -#endif - -/* prototypes */ -static void gst_clearkeydecryptor_finalize(GObject*); - -/* class initialization */ -#define gst_clearkeydecryptor_parent_class parent_class -G_DEFINE_TYPE(Gstclearkeydecryptor, gst_clearkeydecryptor, GST_TYPE_CDMI_DECRYPTOR); - -GST_DEBUG_CATEGORY(gst_clearkeydecryptor_debug_category); -#define GST_CAT_DEFAULT gst_clearkeydecryptor_debug_category - - -/* pad templates */ - -static GstStaticPadTemplate gst_clearkeydecryptor_src_template = -GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS("video/x-h264;audio/mpeg;video/x-h265;audio/x-eac3;audio/x-gst-fourcc-ec_3;audio/x-ac3")); - -static GstStaticPadTemplate gst_clearkeydecryptor_sink_template = -GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS( - "application/x-cenc, original-media-type=(string)video/x-h264, protection-system=(string)" CLEARKEY_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)video/x-h265, protection-system=(string)" CLEARKEY_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-eac3, protection-system=(string)" CLEARKEY_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-ac3, protection-system=(string)" CLEARKEY_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-gst-fourcc-ec_3, protection-system=(string)" CLEARKEY_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/mpeg, protection-system=(string)" CLEARKEY_PROTECTION_SYSTEM_ID)); - -static GstStaticPadTemplate gst_clearkeydecryptor_dummy_sink_template = -GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS("clearkey/x-unused")); - -/** - * @brief clearkey decryptor class initialization - * @param klass Gstreamer Class - */ -static void gst_clearkeydecryptor_class_init( - GstclearkeydecryptorClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS(klass); - GstElementClass* elementClass = GST_ELEMENT_CLASS(klass); - - DEBUG_FUNC(); - - gobject_class->finalize = gst_clearkeydecryptor_finalize; - - /* Setting up pads and setting metadata should be moved to - base_class_init if you intend to subclass this class. */ - gst_element_class_add_static_pad_template(elementClass, &gst_clearkeydecryptor_src_template); - gst_element_class_add_static_pad_template(elementClass, &gst_clearkeydecryptor_sink_template); - - gst_element_class_set_static_metadata(elementClass, - "Decrypt ClearKey encrypted contents", - GST_ELEMENT_FACTORY_KLASS_DECRYPTOR, - "Decrypts streams encrypted using ClearKey Encryption.", - "comcast"); -} - -/** - * @brief ClearKey decryptor element initialization - * @param clearkeydecryptor clearkey decryptor element pointer - */ -static void gst_clearkeydecryptor_init(Gstclearkeydecryptor *clearkeydecryptor) -{ - DEBUG_FUNC(); -} - - -/** - * @brief clearkey decryptor element termination - * @param object clearkey decryptor element pointer - */ -static void gst_clearkeydecryptor_finalize(GObject * object) -{ - DEBUG_FUNC(); - GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object)); -} - - diff --git a/gst-plugins/drm/gst/gstclearkeydecryptor.h b/gst-plugins/drm/gst/gstclearkeydecryptor.h deleted file mode 100644 index 559913d5..00000000 --- a/gst-plugins/drm/gst/gstclearkeydecryptor.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -* Copyright 2018 RDK Management -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, version 2.1 -* of the license. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -* Boston, MA 02110-1301, USA. -*/ - -/** - * @file gstclearkeydecryptor.h - * @brief clear key decryptor plugin declarations - */ - - -#ifndef GSTCLEARKEYDECRYPTOR_H_ -#define GSTCLEARKEYDECRYPTOR_H_ - - -#include -#include -#include "DrmSessionManager.h" - -#include "gstcdmidecryptor.h" // For base gobject - -// Declared static here because this string exists in player and gstplugin .so -// library files This string needs to match the start -// of the gsteamer plugin name as created by the macros. -static const char* GstPluginNameCK = "clearkeydecryptor"; - -G_BEGIN_DECLS - -#define CLEARKEY_PROTECTION_SYSTEM_ID "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" - -#define GST_TYPE_CLEARKEYDECRYPTOR (gst_clearkeydecryptor_get_type()) -#define GST_CLEARKEYDECRYPTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CLEARKEYDECRYPTOR, Gstclearkeydecryptor)) -#define GST_CLEARKEYDECRYPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CLEARKEYDECRYPTOR, GstclearkeydecryptorClass)) -#define GST_IS_CLEARKEYDECRYPTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_CLEARKEYDECRYPTOR)) -#define GST_IS_CLEARKEYDECRYPTOR_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_CLEARKEYDECRYPTOR)) - -typedef struct _Gstclearkeydecryptor Gstclearkeydecryptor; -typedef struct _GstclearkeydecryptorClass GstclearkeydecryptorClass; - -/** - * @struct _Gstclearkeydecryptor - * @brief GstElement structure override for clearkey decryptor - */ -struct _Gstclearkeydecryptor -{ - GstCDMIDecryptor parent; -}; - -/** - * @struct _GstclearkeydecryptorClass - * @brief GstElementClass structure override for clearkey decryptor - */ -struct _GstclearkeydecryptorClass -{ - GstCDMIDecryptorClass parentClass; -}; - - -/** - * @brief Get type of clearkey decryptor - * @retval Type of clearkey decryptor - */ -GType gst_clearkeydecryptor_get_type (void); - -G_END_DECLS - - -#endif /* GSTCLEARKEYDECRYPTOR_H_ */ diff --git a/gst-plugins/drm/gst/gstplayreadydecryptor.cpp b/gst-plugins/drm/gst/gstplayreadydecryptor.cpp deleted file mode 100644 index 9b63fe9c..00000000 --- a/gst-plugins/drm/gst/gstplayreadydecryptor.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* -* Copyright 2018 RDK Management -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, version 2.1 -* of the license. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -* Boston, MA 02110-1301, USA. -*/ - -/** - * @file gstplayreadydecryptor.cpp - * @brief Playready decryptor plugin definitions - */ - -#include -#include -#include -#include "gstplayreadydecryptor.h" -//#define FUNCTION_DEBUG 1 -#ifdef FUNCTION_DEBUG -#define DEBUG_FUNC() g_warning("####### %s : %d ####\n", __FUNCTION__, __LINE__); -#else -#define DEBUG_FUNC() -#endif - -/* prototypes */ -static void gst_playreadydecryptor_finalize(GObject*); - -/* class initialization */ -#define gst_playreadydecryptor_parent_class parent_class -G_DEFINE_TYPE(Gstplayreadydecryptor, gst_playreadydecryptor, GST_TYPE_CDMI_DECRYPTOR); - -GST_DEBUG_CATEGORY(gst_playreadydecryptor_debug_category); -#define GST_CAT_DEFAULT gst_playreadydecryptor_debug_category - - -/* pad templates */ - -static GstStaticPadTemplate gst_playreadydecryptor_src_template = - GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS("video/x-h264;video/x-h264(memory:SecMem);audio/mpeg;video/x-h265;video/x-h265(memory:SecMem);audio/x-eac3;audio/x-gst-fourcc-ec_3;audio/x-ac3")); - -static GstStaticPadTemplate gst_playreadydecryptor_sink_template = - GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS( - "application/x-cenc, original-media-type=(string)video/x-h264, protection-system=(string)" PLAYREADY_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)video/x-h265, protection-system=(string)" PLAYREADY_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-eac3, protection-system=(string)" PLAYREADY_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-ac3, protection-system=(string)" PLAYREADY_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-gst-fourcc-ec_3, protection-system=(string)" PLAYREADY_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/mpeg, protection-system=(string)" PLAYREADY_PROTECTION_SYSTEM_ID)); - -static GstStaticPadTemplate gst_playreadydecryptor_dummy_sink_template = - GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS("playready/x-unused")); - -/** - * @brief Playready decryptor class initialization - * @param klass Gstreamer Class - */ -static void gst_playreadydecryptor_class_init( - GstplayreadydecryptorClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS(klass); - GstElementClass* elementClass = GST_ELEMENT_CLASS(klass); - - DEBUG_FUNC(); - - gobject_class->finalize = gst_playreadydecryptor_finalize; - - /* Setting up pads and setting metadata should be moved to - base_class_init if you intend to subclass this class. */ - gst_element_class_add_static_pad_template(elementClass, &gst_playreadydecryptor_src_template); - gst_element_class_add_static_pad_template(elementClass, &gst_playreadydecryptor_sink_template); - - gst_element_class_set_static_metadata(elementClass, - "Decrypt PlayReady encrypted contents", - GST_ELEMENT_FACTORY_KLASS_DECRYPTOR, - "Decrypts streams encrypted using PlayReady Encryption.", - "Comcast"); -} - -/** - * @brief Playready decryptor element initialization - * @param playreadydecryptor playready decryptor element pointer - */ -static void gst_playreadydecryptor_init(Gstplayreadydecryptor *playreadydecryptor) -{ - DEBUG_FUNC(); -} - - -/** - * @brief Playready decryptor element termination - * @param object playready decryptor element pointer - */ -static void gst_playreadydecryptor_finalize(GObject * object) -{ - DEBUG_FUNC(); - GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object)); -} - - - diff --git a/gst-plugins/drm/gst/gstplayreadydecryptor.h b/gst-plugins/drm/gst/gstplayreadydecryptor.h deleted file mode 100644 index d49db76e..00000000 --- a/gst-plugins/drm/gst/gstplayreadydecryptor.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -* Copyright 2018 RDK Management -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, version 2.1 -* of the license. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -* Boston, MA 02110-1301, USA. -*/ - -/** - * @file gstplayreadydecryptor.h - * @brief Playready decryptor plugin declarations - */ - -#ifndef _GST_PLAYREADYDECRYPTOR_H_ -#define _GST_PLAYREADYDECRYPTOR_H_ - -#include -#include -#include "DrmSessionManager.h" - -#include "gstcdmidecryptor.h" // For base gobject - -// Declared static here because this string exists in player and gstplugin .so -// libraries This string needs to match the start -// of the gsteamer plugin name as created by the macros. -static const char* GstPluginNamePR = "playreadydecryptor"; - -G_BEGIN_DECLS - -#define PLAYREADY_PROTECTION_SYSTEM_ID "9a04f079-9840-4286-ab92-e65be0885f95" - -#define GST_TYPE_PLAYREADYDECRYPTOR (gst_playreadydecryptor_get_type()) -#define GST_PLAYREADYDECRYPTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_PLAYREADYDECRYPTOR, Gstplayreadydecryptor)) -#define GST_PLAYREADYDECRYPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_PLAYREADYDECRYPTOR, GstplayreadydecryptorClass)) -#define GST_IS_PLAYREADYDECRYPTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_PLAYREADYDECRYPTOR)) -#define GST_IS_PLAYREADYDECRYPTOR_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_PLAYREADYDECRYPTOR)) - -typedef struct _Gstplayreadydecryptor Gstplayreadydecryptor; -typedef struct _GstplayreadydecryptorClass GstplayreadydecryptorClass; - -/** - * @struct _Gstplayreadydecryptor - * @brief GstElement structure override for playready decryptor - */ -struct _Gstplayreadydecryptor -{ - GstCDMIDecryptor parent; -}; - -/** - * @struct _GstplayreadydecryptorClass - * @brief GstElementClass structure override for playready decryptor - */ -struct _GstplayreadydecryptorClass -{ - GstCDMIDecryptorClass parentClass; -}; - - -/** - * @brief Get type of playready decryptor - * @retval Type of playready decryptor - */ -GType gst_playreadydecryptor_get_type (void); - -G_END_DECLS - - -#endif diff --git a/gst-plugins/drm/gst/gstverimatrixdecryptor.cpp b/gst-plugins/drm/gst/gstverimatrixdecryptor.cpp deleted file mode 100755 index 4b4fef38..00000000 --- a/gst-plugins/drm/gst/gstverimatrixdecryptor.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* -* Copyright 2018 RDK Management -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, version 2.1 -* of the license. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -* Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include "gstverimatrixdecryptor.h" - -#define FUNCTION_DEBUG 1 -#ifdef FUNCTION_DEBUG -#define DEBUG_FUNC() g_warning("####### %s : %d ####\n", __FUNCTION__, __LINE__); -#else -#define DEBUG_FUNC() -#endif - -/* prototypes */ -static void gst_verimatrixdecryptor_finalize(GObject*); - -/* class initialization */ -#define gst_verimatrixdecryptor_parent_class parent_class -G_DEFINE_TYPE(Gstverimatrixdecryptor, gst_verimatrixdecryptor, GST_TYPE_CDMI_DECRYPTOR); - -GST_DEBUG_CATEGORY(gst_verimatrixdecryptor_debug_category); -#define GST_CAT_DEFAULT gst_verimatrixdecryptor_debug_category - - -/* pad templates */ - -static GstStaticPadTemplate gst_verimatrixdecryptor_src_template = - GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS("video/x-h264;audio/mpeg;video/x-h265;audio/x-eac3;audio/x-gst-fourcc-ec_3;audio/x-ac3")); - -static GstStaticPadTemplate gst_verimatrixdecryptor_sink_template = - GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS( - "application/x-cenc, original-media-type=(string)video/x-h264, protection-system=(string)" VERIMATRIX_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)video/x-h265, protection-system=(string)" VERIMATRIX_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-eac3, protection-system=(string)" VERIMATRIX_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-ac3, protection-system=(string)" VERIMATRIX_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-gst-fourcc-ec_3, protection-system=(string)" VERIMATRIX_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/mpeg, protection-system=(string)" VERIMATRIX_PROTECTION_SYSTEM_ID)); - -static GstStaticPadTemplate gst_verimatrixdecryptor_dummy_sink_template = - GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS("verimatrix/x-unused")); - - -static void gst_verimatrixdecryptor_class_init(GstverimatrixdecryptorClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS(klass); - GstElementClass* elementClass = GST_ELEMENT_CLASS(klass); - - DEBUG_FUNC(); - - gobject_class->finalize = gst_verimatrixdecryptor_finalize; - - gst_element_class_add_static_pad_template(elementClass, &gst_verimatrixdecryptor_src_template); - gst_element_class_add_static_pad_template(elementClass, &gst_verimatrixdecryptor_sink_template); - - gst_element_class_set_static_metadata(elementClass, - "Decrypt Verimatrix encrypted contents", - GST_ELEMENT_FACTORY_KLASS_DECRYPTOR, - "Decrypts streams encrypted using Verimatrix Encryption.", - "Comcast"); -} - -static void gst_verimatrixdecryptor_init(Gstverimatrixdecryptor *verimatrixdecryptor) -{ - DEBUG_FUNC(); -} - -static void gst_verimatrixdecryptor_finalize(GObject * object) -{ - DEBUG_FUNC(); - GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object)); -} - - - diff --git a/gst-plugins/drm/gst/gstverimatrixdecryptor.h b/gst-plugins/drm/gst/gstverimatrixdecryptor.h deleted file mode 100755 index 8ca472e6..00000000 --- a/gst-plugins/drm/gst/gstverimatrixdecryptor.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -* Copyright 2018 RDK Management -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, version 2.1 -* of the license. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -* Boston, MA 02110-1301, USA. -*/ - -/** - * @file gstverimatrixdecryptor.h - * @brief Widevine decryptor plugin declarations - */ - - -#ifndef _GST_VERIMATRIXDECRYPTOR_H_ -#define _GST_VERIMATRIXDECRYPTOR_H_ - -#include -#include -#include "DrmSessionManager.h" - -#include "gstcdmidecryptor.h" // For base gobject - -// Declared static here because this string exists in player and gstplugin .so -// library files This string needs to match the start -// of the gsteamer plugin name as created by the macros. -static const char* GstPluginNameVMX = "verimatrixdecryptor"; - -G_BEGIN_DECLS - -#define VERIMATRIX_PROTECTION_SYSTEM_ID "9a27dd82-fde2-4725-8cbc-4234aa06ec09" - -#define GST_TYPE_VERIMATRIXDECRYPTOR (gst_verimatrixdecryptor_get_type()) -#define GST_VERIMATRIXDECRYPTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_VERIMATRIXDECRYPTOR, Gstverimatrixdecryptor)) -#define GST_VERIMATRIXDECRYPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_VERIMATRIXDECRYPTOR, GstverimatrixdecryptorClass)) -#define GST_IS_VERIMATRIXDECRYPTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VERIMATRIXDECRYPTOR)) -#define GST_IS_VERIMATRIXDECRYPTOR_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VERIMATRIXDECRYPTOR)) - -typedef struct _Gstverimatrixdecryptor Gstverimatrixdecryptor; -typedef struct _GstverimatrixdecryptorClass GstverimatrixdecryptorClass; -//typedef struct _GstverimatrixdecryptorPrivate GstverimatrixdecryptorPrivate; - -/** - * @struct _Gstverimatrixdecryptor - * @brief GstElement structure override for Widevine decryptor - */ -struct _Gstverimatrixdecryptor -{ - GstCDMIDecryptor parent; -// GstverimatrixdecryptorPrivate priv; -}; - -/** - * @struct _GstverimatrixdecryptorClass - * @brief GstElementClass structure override for Widevine decryptor - */ -struct _GstverimatrixdecryptorClass -{ - GstCDMIDecryptorClass parentClass; -}; - -/** - * @brief Get type of Verimatrix decryptor - * @retval Type of Verimatrix decryptor - */ -GType gst_verimatrixdecryptor_get_type (void); - -G_END_DECLS - - -#endif diff --git a/gst-plugins/drm/gst/gstwidevinedecryptor.cpp b/gst-plugins/drm/gst/gstwidevinedecryptor.cpp deleted file mode 100644 index a3d70292..00000000 --- a/gst-plugins/drm/gst/gstwidevinedecryptor.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -* Copyright 2018 RDK Management -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, version 2.1 -* of the license. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -* Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include "gstwidevinedecryptor.h" - -#define FUNCTION_DEBUG 1 -#ifdef FUNCTION_DEBUG -#define DEBUG_FUNC() g_warning("####### %s : %d ####\n", __FUNCTION__, __LINE__); -#else -#define DEBUG_FUNC() -#endif - -/* prototypes */ -static void gst_widevinedecryptor_finalize(GObject*); - -/* class initialization */ -#define gst_widevinedecryptor_parent_class parent_class -G_DEFINE_TYPE(Gstwidevinedecryptor, gst_widevinedecryptor, GST_TYPE_CDMI_DECRYPTOR); - -GST_DEBUG_CATEGORY(gst_widevinedecryptor_debug_category); -#define GST_CAT_DEFAULT gst_widevinedecryptor_debug_category - - -/* pad templates */ - -static GstStaticPadTemplate gst_widevinedecryptor_src_template = - GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS("video/x-h264;video/x-h264(memory:SecMem);audio/mpeg;video/x-h265;video/x-h265(memory:SecMem);audio/x-eac3;audio/x-gst-fourcc-ec_3;audio/x-ac3;audio/x-opus")); - -static GstStaticPadTemplate gst_widevinedecryptor_sink_template = - GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS( - "application/x-cenc, original-media-type=(string)video/x-h264, protection-system=(string)" WIDEVINE_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)video/x-h265, protection-system=(string)" WIDEVINE_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-eac3, protection-system=(string)" WIDEVINE_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-ac3, protection-system=(string)" WIDEVINE_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-opus, protection-system=(string)" WIDEVINE_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/x-gst-fourcc-ec_3, protection-system=(string)" WIDEVINE_PROTECTION_SYSTEM_ID "; " - "application/x-cenc, original-media-type=(string)audio/mpeg, protection-system=(string)" WIDEVINE_PROTECTION_SYSTEM_ID)); - -static GstStaticPadTemplate gst_widevinedecryptor_dummy_sink_template = - GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS("widevine/x-unused")); - - -static void gst_widevinedecryptor_class_init(GstwidevinedecryptorClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS(klass); - GstElementClass* elementClass = GST_ELEMENT_CLASS(klass); - - DEBUG_FUNC(); - - gobject_class->finalize = gst_widevinedecryptor_finalize; - - /* Setting up pads and setting metadata should be moved to - base_class_init if you intend to subclass this class. */ - gst_element_class_add_static_pad_template(elementClass, &gst_widevinedecryptor_src_template); - gst_element_class_add_static_pad_template(elementClass, &gst_widevinedecryptor_sink_template); - - gst_element_class_set_static_metadata(elementClass, - "Decrypt Widevine encrypted contents", - GST_ELEMENT_FACTORY_KLASS_DECRYPTOR, - "Decrypts streams encrypted using Widevine Encryption.", - "Comcast"); -} - -static void gst_widevinedecryptor_init(Gstwidevinedecryptor *widevinedecryptor) -{ - DEBUG_FUNC(); -} - -static void gst_widevinedecryptor_finalize(GObject * object) -{ - DEBUG_FUNC(); - GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object)); -} - - - diff --git a/gst-plugins/drm/gst/gstwidevinedecryptor.h b/gst-plugins/drm/gst/gstwidevinedecryptor.h deleted file mode 100644 index 961f4eee..00000000 --- a/gst-plugins/drm/gst/gstwidevinedecryptor.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -* Copyright 2018 RDK Management -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, version 2.1 -* of the license. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -* Boston, MA 02110-1301, USA. -*/ - -/** - * @file gstwidevinedecryptor.h - * @brief Widevine decryptor plugin declarations - */ - - -#ifndef _GST_WIDEVINEDECRYPTOR_H_ -#define _GST_WIDEVINEDECRYPTOR_H_ - -#include -#include -#include "DrmSessionManager.h" - -#include "gstcdmidecryptor.h" // For base gobject - -// Declared static here because this string exists in player and gstplugin .so -// library files This string needs to match the start -// of the gsteamer plugin name as created by the macros. -static const char* GstPluginNameWV = "widevinedecryptor"; - -G_BEGIN_DECLS - -#define WIDEVINE_PROTECTION_SYSTEM_ID "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed" - -#define GST_TYPE_WIDEVINEDECRYPTOR (gst_widevinedecryptor_get_type()) -#define GST_WIDEVINEDECRYPTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_WIDEVINEDECRYPTOR, Gstwidevinedecryptor)) -#define GST_WIDEVINEDECRYPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_WIDEVINEDECRYPTOR, GstwidevinedecryptorClass)) -#define GST_IS_WIDEVINEDECRYPTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_WIDEVINEDECRYPTOR)) -#define GST_IS_WIDEVINEDECRYPTOR_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_WIDEVINEDECRYPTOR)) - -typedef struct _Gstwidevinedecryptor Gstwidevinedecryptor; -typedef struct _GstwidevinedecryptorClass GstwidevinedecryptorClass; -//typedef struct _GstwidevinedecryptorPrivate GstwidevinedecryptorPrivate; - -/** - * @struct _Gstwidevinedecryptor - * @brief GstElement structure override for Widevine decryptor - */ -struct _Gstwidevinedecryptor -{ - GstCDMIDecryptor parent; -// GstwidevinedecryptorPrivate priv; -}; - -/** - * @struct _GstwidevinedecryptorClass - * @brief GstElementClass structure override for Widevine decryptor - */ -struct _GstwidevinedecryptorClass -{ - GstCDMIDecryptorClass parentClass; -}; - -/** - * @brief Get type of Widevine decryptor - * @retval Type of Widevine decryptor - */ -GType gst_widevinedecryptor_get_type (void); - -G_END_DECLS - - -#endif diff --git a/gst-plugins/gst_subtec/CMakeLists.txt b/gst-plugins/gst_subtec/CMakeLists.txt deleted file mode 100644 index 5370721d..00000000 --- a/gst-plugins/gst_subtec/CMakeLists.txt +++ /dev/null @@ -1,81 +0,0 @@ -# -# Copyright (C) 2022 RDK Management -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# - -cmake_minimum_required (VERSION 2.6) -project (gst_subtec) -find_package(PkgConfig REQUIRED) - -pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0) -pkg_check_modules(GSTREAMERBASE REQUIRED gstreamer-app-1.0) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories(${GSTREAMER_INCLUDE_DIRS}) -include_directories(${GSTREAMERBASE_INCLUDE_DIRS}) - -if(CMAKE_SYSTEM_NAME STREQUAL Darwin) - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../middleware/subtec/libsubtec) - link_directories(${GSTREAMERBASE_LIBRARY_DIRS} ${GSTREAMER_LIBRARY_DIRS}) - link_directories(${CMAKE_INSTALL_PREFIX}) -endif(CMAKE_SYSTEM_NAME STREQUAL Darwin) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-multichar -std=c++11 -DSUBTEC_PACKET_DEBUG") - -set(GSTSUBTEC_DEPENDENCIES ${GSTREAMERBASE_LIBRARIES} ${GSTREAMER_LIBRARIES}) - -add_library(gstsubtecsink SHARED gstsubtecsink.cpp) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../subtec/libsubtec) -target_link_libraries(gstsubtecsink PRIVATE subtec) -target_link_libraries(gstsubtecsink ${GSTSUBTEC_DEPENDENCIES}) -#target_link_libraries(gstsubtecsink ${GSTSUBTEC_DEPENDENCIES} "-lsubtec") - -add_library(gstsubtecbin SHARED gstsubtecbin.cpp) - -target_link_libraries(gstsubtecbin ${GSTSUBTEC_DEPENDENCIES}) - -add_library(gstsubtecmp4transform SHARED gstsubtecmp4transform.cpp) - -target_link_libraries(gstsubtecmp4transform ${GSTSUBTEC_DEPENDENCIES}) - -add_library(gstvipertransform SHARED gstvipertransform.cpp) - -target_link_libraries(gstvipertransform ${GSTSUBTEC_DEPENDENCIES}) - -install (TARGETS gstsubtecsink - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib/gstreamer-1.0 - ARCHIVE DESTINATION lib/gstreamer-1.0 -) - -install (TARGETS gstsubtecbin - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib/gstreamer-1.0 - ARCHIVE DESTINATION lib/gstreamer-1.0 -) - -install (TARGETS gstsubtecmp4transform - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib/gstreamer-1.0 - ARCHIVE DESTINATION lib/gstreamer-1.0 -) - -install (TARGETS gstvipertransform - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib/gstreamer-1.0 - ARCHIVE DESTINATION lib/gstreamer-1.0 -) diff --git a/gst-plugins/gst_subtec/Readme.md b/gst-plugins/gst_subtec/Readme.md deleted file mode 100644 index 2cfb01a6..00000000 --- a/gst-plugins/gst_subtec/Readme.md +++ /dev/null @@ -1,23 +0,0 @@ -# Subtec GStreamer Plugin for sending subtitles to Subtec - -Subtitles can be sent from PLAYER directly to the Subtec Application or via this GStreamer plugin. -Sending via the GStreamer plugin is enabled in PLAYER through config "gstSubtecEnabled", which is -disabled by default in the PLAYER simulator builds. - -## Building and installing the Subtec Gstreamer Plugin for PLAYER Simulator - -### For Ubuntu - -From the player(a_mp) folder run: - -cmake -Bbuild/gst_subtec -H./Linux/gst-plugins/gst_subtec -DCMAKE_INSTALL_PREFIX=./Linux -DCMAKE_PLATFORM_UBUNTU=1 -make -C build/gst_subtec -make -C build/gst_subtec install - -### For macOS - -From the player(a_mp) folder run: - -PKG_CONFIG_PATH=/Library/Frameworks/GStreamer.framework/Versions/1.0/lib/pkgconfig/ cmake -Bgst_subtec -H./.libs/gst-plugins/gst_subtec -DCMAKE_INSTALL_PREFIX=./Debug -make -C build/gst_subtec -make -C build/gst_subtec install diff --git a/gst-plugins/gst_subtec/gstsubtecbin.cpp b/gst-plugins/gst_subtec/gstsubtecbin.cpp deleted file mode 100644 index 683b219e..00000000 --- a/gst-plugins/gst_subtec/gstsubtecbin.cpp +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright (C) 2022 RDK Management - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * SECTION:element-gstsubtecbin - * - * Plugs the subtec pipeline - adding mp4transform and/or vipertransform - * elements as required - */ - -#include -#include "gstsubtecbin.h" - -GST_DEBUG_CATEGORY_STATIC (gst_subtecbin_debug_category); -#define GST_CAT_DEFAULT gst_subtecbin_debug_category - -static void gst_subtecbin_dispose (GObject * object); -static void gst_subtecbin_finalize (GObject * object); -static void gst_subtecbin_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * spec); -static void gst_subtecbin_get_property (GObject * object, - guint property_id, GValue * value, GParamSpec * pspec); - - -static GstStaticPadTemplate gst_subtecbin_sink_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/ttml+xml; text/vtt; application/mp4;") - ); - -/* class initialization */ -G_DEFINE_TYPE_WITH_CODE (GstSubtecBin, gst_subtecbin, GST_TYPE_BIN, - GST_DEBUG_CATEGORY_INIT (gst_subtecbin_debug_category, "subtecbin", 0, - "debug category for subtecbin element")); - -enum -{ - PROP_0, - PROP_MUTE, - PROP_NO_EOS, - PROP_ASYNC, - PROP_SYNC, - PROP_SUBTEC_SOCKET, - PROP_PTS_OFFSET, - PROP_ATTRIBUTE_VALUES -}; - -static void -gst_subtecbin_class_init (GstSubtecBinClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstBinClass *base_sink_class = GST_BIN_CLASS (klass); - GstElementClass *element_class = GST_ELEMENT_CLASS(klass); - - GST_LOG("gst_subtecbin_class_init"); - - gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS(klass), - &gst_subtecbin_sink_template); - - gst_element_class_set_static_metadata (GST_ELEMENT_CLASS(klass), - "OOB Subtec data sink", "Sink/Parser/Subtitle", "Packs TTML or WebVTT data into SubTtxRend APP suitable packets", "Comcast"); - - gobject_class->set_property = gst_subtecbin_set_property; - gobject_class->get_property = gst_subtecbin_get_property; - - g_object_class_install_property(gobject_class, - PROP_MUTE, - g_param_spec_boolean("mute", "Mute", "Mutes the subtitles", - FALSE, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_class, - PROP_NO_EOS, - g_param_spec_boolean("no-eos", "No EOS", "Eats the EOS and stops the stream exiting", - FALSE, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_class, - PROP_ASYNC, - g_param_spec_boolean("async", "Async", "Sets async on children (require preroll before returning async_done)", - TRUE, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_class, - PROP_SYNC, - g_param_spec_boolean("sync", "Sync", "Sets sync on children (synchronize render on clock)", - TRUE, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_class, - PROP_SUBTEC_SOCKET, - g_param_spec_string("subtec-socket", "Subtec socket", "Alternative subtec socket (default /var/run/subttx/pes_data_main)", - NULL, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_class, - PROP_PTS_OFFSET, - g_param_spec_uint64("pts-offset", "PTS offset", "PTS offset for mpeg-2 ts HLS streams", - 0, G_MAXUINT64, 0, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_class, - PROP_ATTRIBUTE_VALUES, - g_param_spec_boxed("attribute-values", "Attribute values", "GstStructure specifying attributes", - GST_TYPE_STRUCTURE, - (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS))); - - gobject_class->dispose = gst_subtecbin_dispose; - gobject_class->finalize = gst_subtecbin_finalize; -} - -static void gst_subtecbin_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstSubtecBin *subtecbin = GST_SUBTECBIN (object); - - GST_DEBUG_OBJECT (subtecbin, "set_property %d", prop_id); - - switch (prop_id) { - case PROP_MUTE: - if (subtecbin->sink) - g_object_set_property(G_OBJECT(subtecbin->sink), "mute", value); - subtecbin->mute = g_value_get_boolean(value); - break; - case PROP_NO_EOS: - if (subtecbin->sink) - g_object_set_property(G_OBJECT(subtecbin->sink), "no-eos", value); - subtecbin->no_eos = g_value_get_boolean(value); - break; - case PROP_ASYNC: - if (subtecbin->sink) - g_object_set_property(G_OBJECT(subtecbin->sink), "async", value); - subtecbin->async = g_value_get_boolean(value); - break; - case PROP_SYNC: - if (subtecbin->sink) - g_object_set_property(G_OBJECT(subtecbin->sink), "sync", value); - subtecbin->sync = g_value_get_boolean(value); - break; - case PROP_SUBTEC_SOCKET: - if (subtecbin->sink) - g_object_set_property(G_OBJECT(subtecbin->sink), "subtec-socket", value); - subtecbin->subtec_socket = g_value_get_string(value); - break; - case PROP_PTS_OFFSET: - { - if (subtecbin->sink) - g_object_set_property(G_OBJECT(subtecbin->sink), "pts-offset", value); - subtecbin->pts_offset = g_value_get_uint64(value); - } - break; - case PROP_ATTRIBUTE_VALUES: - if (subtecbin->sink) - g_object_set_property(G_OBJECT(subtecbin->sink), "attribute-values", value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -void -gst_subtecbin_get_property (GObject * object, guint property_id, - GValue * value, GParamSpec * pspec) -{ - GstSubtecBin *subtecbin = GST_SUBTECBIN (object); - - GST_DEBUG_OBJECT (subtecbin, "get_property %d", property_id); - - switch (property_id) { - case PROP_MUTE: - g_value_set_boolean(value, subtecbin->mute); - break; - case PROP_NO_EOS: - g_value_set_boolean(value, subtecbin->no_eos); - break; - case PROP_ASYNC: - g_value_set_boolean(value, subtecbin->async); - break; - case PROP_SYNC: - g_value_set_boolean(value, subtecbin->sync); - break; - case PROP_SUBTEC_SOCKET: - g_value_set_string(value, subtecbin->subtec_socket.c_str()); - break; - case PROP_PTS_OFFSET: - g_value_set_uint64(value, subtecbin->pts_offset); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -type_found (GstElement * typefind, guint probability, - GstCaps * caps, GstSubtecBin * subtecbin) -{ - GST_DEBUG_OBJECT (subtecbin, "subs_typefind found caps %" GST_PTR_FORMAT, caps); - subtecbin->sink = gst_element_factory_make("subtecsink", NULL); - - g_return_if_fail (subtecbin->sink != NULL); - - g_object_set(G_OBJECT(subtecbin->sink), "mute", subtecbin->mute, NULL); - g_object_set(G_OBJECT(subtecbin->sink), "no-eos", subtecbin->no_eos, NULL); - g_object_set(G_OBJECT(subtecbin->sink), "async", subtecbin->async, NULL); - g_object_set(G_OBJECT(subtecbin->sink), "sync", subtecbin->sync, NULL); - g_object_set(G_OBJECT(subtecbin->sink), "pts-offset", subtecbin->pts_offset, NULL); - - GstElementFactory *ttml_transform_factory = NULL; - GList *sub_parser_factories = gst_element_factory_list_filter (gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_MEDIA_SUBTITLE, - GST_RANK_PRIMARY), - caps, - GST_PAD_SINK, - TRUE); - GList *tmp = sub_parser_factories; - - for (; tmp; tmp = tmp->next) { - GstElementFactory *factory = (GstElementFactory *) tmp->data; - GST_DEBUG_OBJECT(subtecbin, "factory name %s can sink caps %d", gst_plugin_feature_get_name ((GstPluginFeature *) factory), gst_element_factory_can_sink_all_caps(factory, caps)); - if (gst_element_factory_can_sink_all_caps(factory, caps)) - { - if (gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_DEMUXER)) - { - subtecbin->demux = gst_element_factory_create(factory, NULL); - - GstPad *demux_pad = gst_element_get_static_pad(subtecbin->demux, "src"); - GstCaps *demux_caps = gst_pad_get_pad_template_caps(demux_pad); - - GST_DEBUG_OBJECT(subtecbin, "seek allowed caps %" GST_PTR_FORMAT, demux_caps); - auto ttml_formatter_factory = gst_element_factory_find("vipertransform"); - if (gst_element_factory_can_sink_all_caps(ttml_formatter_factory, demux_caps)) - { - subtecbin->formatter = gst_element_factory_make("vipertransform", NULL); - } - } - } - } - gst_plugin_feature_list_free(sub_parser_factories); - - GList *chain = NULL; - - if (subtecbin->demux) - { - GST_DEBUG_OBJECT(subtecbin, "demuxer"); - chain = g_list_append(chain, gst_object_ref(subtecbin->demux)); - } - if (subtecbin->formatter) - { - GST_DEBUG_OBJECT(subtecbin, "formatter"); - chain = g_list_append(chain, gst_object_ref(subtecbin->formatter)); - } - if (subtecbin->sink) - { - GST_DEBUG_OBJECT(subtecbin, "sink"); - chain = g_list_append(chain, gst_object_ref(subtecbin->sink)); - } - - tmp = chain; - - gst_element_sync_state_with_parent(GST_ELEMENT(subtecbin)); - for(; tmp; tmp = tmp->next) - { - GstElement *current = GST_ELEMENT(tmp->data); - GST_DEBUG_OBJECT(subtecbin, "element %s", gst_element_get_name(current)); - gst_bin_add(GST_BIN(subtecbin), current); - if (tmp->prev) - gst_element_link(GST_ELEMENT(tmp->prev->data), current); - else - gst_element_link(typefind, current); - gst_object_unref(current); - } - - tmp = chain; - for(; tmp; tmp = tmp->next) - { - gst_element_sync_state_with_parent(GST_ELEMENT(tmp->data)); - } - if (chain) - { - g_list_free(chain); - } -} - -static void -gst_subtecbin_init (GstSubtecBin *subtecbin) -{ - GST_DEBUG_OBJECT(subtecbin, "init1"); - - subtecbin->typefind = gst_element_factory_make("typefind", "subs_typefind"); - gst_bin_add(GST_BIN(subtecbin), subtecbin->typefind); - gst_element_add_pad (GST_ELEMENT (subtecbin), gst_ghost_pad_new("sink", gst_element_get_static_pad(subtecbin->typefind, "sink"))); - gst_element_sync_state_with_parent(GST_ELEMENT(subtecbin)); - - g_signal_connect(subtecbin->typefind, "have-type", G_CALLBACK(type_found), subtecbin); -} - -void -gst_subtecbin_dispose (GObject * object) -{ - GstSubtecBin *subtecbin = GST_SUBTECBIN (object); - - GST_DEBUG_OBJECT (subtecbin, "dispose"); - - /* clean up as possible. may be called multiple times */ -} - -void -gst_subtecbin_finalize (GObject * object) -{ - GstSubtecBin *subtecbin = GST_SUBTECBIN (object); - - GST_DEBUG_OBJECT (subtecbin, "finalize"); - - /* clean up object here */ -} - - -static gboolean -plugin_init (GstPlugin * plugin) -{ - return gst_element_register (plugin, "subtecbin", GST_RANK_PRIMARY, - GST_TYPE_SUBTECBIN); -} - -#ifndef VERSION -#define VERSION "0.1.0" -#endif -#ifndef PACKAGE -#define PACKAGE "GstreamerPlugins" -#endif -#ifndef PACKAGE_NAME -#define PACKAGE_NAME "GstreamerPlugins" -#endif -#ifndef GST_PACKAGE_ORIGIN -#define GST_PACKAGE_ORIGIN "http://comcast.com/" -#endif - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - subtecbin, - "SubTtxRend autoplug bin", - plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst-plugins/gst_subtec/gstsubtecbin.h b/gst-plugins/gst_subtec/gstsubtecbin.h deleted file mode 100644 index 36ce349f..00000000 --- a/gst-plugins/gst_subtec/gstsubtecbin.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2022 RDK Management - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _GST_SUBTECBIN_H_ -#define _GST_SUBTECBIN_H_ - -#include -#include - -// Declared static here because this string exists in player and gstplugin .so -// library files This string needs to match the start -// of the gsteamer plugin name as created by the macros. -static const char* GstPluginNameSubtecBin = "subtecbin"; - -G_BEGIN_DECLS - -#define GST_TYPE_SUBTECBIN (gst_subtecbin_get_type()) -#define GST_SUBTECBIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SUBTECBIN,GstSubtecBin)) -#define GST_SUBTECBIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SUBTECBIN,GstSubtecBinClass)) -#define GST_IS_SUBTECBIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SUBTECBIN)) -#define GST_IS_SUBTECBIN_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SUBTECBIN)) - -typedef struct _GstSubtecBin GstSubtecBin; -typedef struct _GstSubtecBinClass GstSubtecBinClass; - -struct _GstSubtecBin -{ - GstBin parent; - GstPad *sinkpad; - GstElement *typefind; - GstElement *demux; - GstElement *formatter; - GstElement *sink; - bool no_eos = false; - bool mute = false; - bool async = true; - bool sync = true; - std::string subtec_socket{}; - guint64 pts_offset{0}; -}; - -struct _GstSubtecBinClass -{ - GstBinClass parent_class; -}; - -GType gst_subtecbin_get_type (void); - -G_END_DECLS - -#endif diff --git a/gst-plugins/gst_subtec/gstsubtecmp4transform.cpp b/gst-plugins/gst_subtec/gstsubtecmp4transform.cpp deleted file mode 100644 index cc8618d2..00000000 --- a/gst-plugins/gst_subtec/gstsubtecmp4transform.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (C) 2022 RDK Management - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include "gstsubtecmp4transform.h" - -#include -#include - -#include -#include -#include - -GST_DEBUG_CATEGORY_STATIC (gst_subtecmp4transform_debug_category); -#define GST_CAT_DEFAULT gst_subtecmp4transform_debug_category - -/* prototypes */ - - -static void gst_subtecmp4transform_dispose (GObject * object); -static void gst_subtecmp4transform_finalize (GObject * object); - -static GstCaps *gst_subtecmp4transform_transform_caps (GstBaseTransform * trans, - GstPadDirection direction, GstCaps * caps, GstCaps * filter); -static GstCaps *gst_subtecmp4transform_fixate_caps (GstBaseTransform * trans, - GstPadDirection direction, GstCaps * caps, GstCaps * othercaps); -static gboolean gst_subtecmp4transform_accept_caps (GstBaseTransform * trans, - GstPadDirection direction, GstCaps * caps); -static gboolean gst_subtecmp4transform_set_caps (GstBaseTransform * trans, - GstCaps * incaps, GstCaps * outcaps); -static gboolean gst_subtecmp4transform_query (GstBaseTransform * trans, - GstPadDirection direction, GstQuery * query); -static gboolean gst_subtecmp4transform_decide_allocation (GstBaseTransform * trans, - GstQuery * query); -static gboolean gst_subtecmp4transform_filter_meta (GstBaseTransform * trans, - GstQuery * query, GType api, const GstStructure * params); -static gboolean gst_subtecmp4transform_propose_allocation (GstBaseTransform * trans, - GstQuery * decide_query, GstQuery * query); -static gboolean gst_subtecmp4transform_transform_size (GstBaseTransform * trans, - GstPadDirection direction, GstCaps * caps, gsize size, GstCaps * othercaps, - gsize * othersize); -static gboolean gst_subtecmp4transform_get_unit_size (GstBaseTransform * trans, - GstCaps * caps, gsize * size); -static gboolean gst_subtecmp4transform_start (GstBaseTransform * trans); -static gboolean gst_subtecmp4transform_stop (GstBaseTransform * trans); -static gboolean gst_subtecmp4transform_sink_event (GstBaseTransform * trans, - GstEvent * event); -static gboolean gst_subtecmp4transform_src_event (GstBaseTransform * trans, - GstEvent * event); -static GstFlowReturn gst_subtecmp4transform_prepare_output_buffer (GstBaseTransform * - trans, GstBuffer * input, GstBuffer ** outbuf); -static gboolean gst_subtecmp4transform_copy_metadata (GstBaseTransform * trans, - GstBuffer * input, GstBuffer * outbuf); -static gboolean gst_subtecmp4transform_transform_meta (GstBaseTransform * trans, - GstBuffer * outbuf, GstMeta * meta, GstBuffer * inbuf); -static void gst_subtecmp4transform_before_transform (GstBaseTransform * trans, - GstBuffer * buffer); -static GstFlowReturn gst_subtecmp4transform_transform (GstBaseTransform * trans, - GstBuffer * inbuf, GstBuffer * outbuf); -static GstFlowReturn gst_subtecmp4transform_transform_ip (GstBaseTransform * trans, - GstBuffer * buf); - -enum -{ - PROP_0 -}; - -/* pad templates */ - -static GstStaticPadTemplate gst_subtecmp4transform_src_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/ttml+xml") - ); - -static GstStaticPadTemplate gst_subtecmp4transform_sink_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/mp4") - ); - - -/* class initialization */ - -G_DEFINE_TYPE_WITH_CODE (GstSubtecMp4Transform, gst_subtecmp4transform, GST_TYPE_BASE_TRANSFORM, - GST_DEBUG_CATEGORY_INIT (gst_subtecmp4transform_debug_category, "subtecmp4transform", 0, - "debug category for subtecmp4transform element")); - -static void -gst_subtecmp4transform_class_init (GstSubtecMp4TransformClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstBaseTransformClass *base_transform_class = GST_BASE_TRANSFORM_CLASS (klass); - - gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS(klass), - &gst_subtecmp4transform_src_template); - gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS(klass), - &gst_subtecmp4transform_sink_template); - - gst_element_class_set_static_metadata (GST_ELEMENT_CLASS(klass), - "Subtec ISO MP4 demuxer", "Demuxer/Subtitle", "Pulls subtitle data from stpp box", "Comcast"); - - base_transform_class->transform_caps = GST_DEBUG_FUNCPTR (gst_subtecmp4transform_transform_caps); - base_transform_class->transform_ip = GST_DEBUG_FUNCPTR (gst_subtecmp4transform_transform_ip); -} - -static void -gst_subtecmp4transform_init (GstSubtecMp4Transform *subtecmp4transform) -{ -} - -static GstCaps * -gst_subtecmp4transform_transform_caps (GstBaseTransform * trans, GstPadDirection direction, - GstCaps * caps, GstCaps * filter) -{ - GstSubtecMp4Transform *subtecmp4transform = GST_SUBTECMP4TRANSFORM (trans); - GstCaps *othercaps; - - static GstStaticCaps ttml_caps = - GST_STATIC_CAPS ("application/ttml+xml"); - static GstStaticCaps vtt_caps = - GST_STATIC_CAPS ("text/vtt"); - static GstStaticCaps mp4_caps = - GST_STATIC_CAPS ("application/mp4"); - - GST_DEBUG_OBJECT (subtecmp4transform, "transform_caps caps"); - GST_DEBUG_OBJECT (subtecmp4transform, "direction %s from caps %" GST_PTR_FORMAT, - direction == GST_PAD_SRC ? "src" : "sink", caps); - GST_DEBUG_OBJECT (subtecmp4transform, "filter %s NULL", filter == NULL ? "is" : "is not"); - - /* Copy other caps and modify as appropriate */ - /* This works for the simplest cases, where the transform modifies one - * or more fields in the caps structure. It does not work correctly - * if passthrough caps are preferred. */ - const GstStructure *s = gst_caps_get_structure (caps, 0); - - if (direction == GST_PAD_SRC) - { - /* transform caps going upstream */ - if (gst_structure_has_name (s, "application/ttml+xml")) - { - othercaps = gst_caps_new_empty(); - othercaps = gst_caps_merge(othercaps, gst_static_caps_get(&mp4_caps)); - /* transform caps going downstream */ - } - else - { - othercaps = gst_caps_copy(caps); - } - } - else - { - if (gst_structure_has_name (s, "application/mp4")) - { - othercaps = gst_caps_new_empty(); - othercaps = gst_caps_merge(othercaps, gst_static_caps_get(&ttml_caps)); - const GValue* viper_hd = gst_structure_get_value(s, "viper_ttml_format"); - if (NULL != viper_hd) - gst_caps_set_value(othercaps, "viper_ttml_format", viper_hd); - - /* transform caps going downstream */ - } - else if (gst_structure_has_name (s, "text/vtt")) - { - othercaps = gst_caps_new_empty(); - othercaps = gst_caps_merge(othercaps, gst_static_caps_get(&vtt_caps)); - /* transform caps going downstream */ - } - else - { - othercaps = gst_caps_copy(caps); - } - } - - GST_DEBUG_OBJECT (subtecmp4transform, "othercaps %" GST_PTR_FORMAT, othercaps); - - if (filter) { - GstCaps *intersect; - - intersect = gst_caps_intersect (othercaps, filter); - gst_caps_unref (othercaps); - - return intersect; - } else { - return othercaps; - } -} - -static std::uint32_t parse32(std::uint8_t *ptr, std::size_t len, std::size_t offset) -{ - if (offset + 4 > len) throw std::out_of_range("len too short"); - - std::uint32_t value = 0; - - const std::uint32_t byte0 = static_cast(ptr[offset]) & 0xFF; - const std::uint32_t byte1 = static_cast(ptr[offset + 1]) & 0xFF; - const std::uint32_t byte2 = static_cast(ptr[offset + 2]) & 0xFF; - const std::uint32_t byte3 = static_cast(ptr[offset + 3]) & 0xFF; - - value |= byte3; - value |= byte2 << 8; - value |= byte1 << 16; - value |= byte0 << 24; - - return value; -} - -static bool parseName(std::uint8_t *ptr, std::size_t len, std::size_t offset, std::string &value) -{ - if (offset + 4 > len) return false; - - const char byte0 = static_cast(ptr[offset]) & 0xFF; - const char byte1 = static_cast(ptr[offset + 1]) & 0xFF; - const char byte2 = static_cast(ptr[offset + 2]) & 0xFF; - const char byte3 = static_cast(ptr[offset + 3]) & 0xFF; - - value += byte0; - value += byte1; - value += byte2; - value += byte3; - - return true; -} - -static bool isContainer(const std::string &name) -{ - static const std::vector containerNames{"moov", "trak", "mdia", "minf", "dinf", "stbl", "mvex"}; - - for (const auto &container : containerNames) - { - if (!container.compare(name)) return true; - } - - return false; -} - -static bool printBoxes(GstSubtecMp4Transform *subtecmp4transform, uint8_t *boxes, size_t len) -{ - size_t offset = 0; - - GST_DEBUG_OBJECT (subtecmp4transform, "printBoxes: len %zu", len); - - while (offset < len) - { - std::size_t boxSize; - std::string boxName; - - try - { - boxSize = parse32(boxes, len, offset); - offset += 4; - parseName(boxes, len, offset, boxName); - } - catch (const std::out_of_range &e) - { - GST_WARNING_OBJECT (subtecmp4transform, "parse error:%s", e.what()); - return false; - } - - if (isContainer(boxName)) - { - offset += 4; - } - else - offset += boxSize - 4; - - GST_DEBUG_OBJECT (subtecmp4transform, "box name: %s size %zu offset %zu", boxName.c_str(), boxSize, offset); - } - - return true; -} - -static bool findBoxOffsetAndLength(GstSubtecMp4Transform *subtecmp4transform, uint8_t *buf, size_t len, const std::string &name, size_t &boxOffset, size_t &boxLength) -{ - size_t offset = 0; - - while (offset < len) - { - std::size_t boxSize; - std::string boxName; - - try - { - boxSize = parse32(buf, len, offset); - offset += 4; - parseName(buf, len, offset, boxName); - } - catch (const std::out_of_range &e) - { - GST_WARNING_OBJECT (subtecmp4transform, "parse error:%s", e.what()); - return false; - } - - GST_DEBUG_OBJECT (subtecmp4transform, "boxName %s name %s len %zu", boxName.c_str(), name.c_str(), boxSize); - - if (!boxName.compare(name)) - { - boxOffset = offset + 4; - boxLength = boxSize; - - return true; - } - - if (isContainer(boxName)) - { - offset += 4; - } - else - offset += boxSize - 4; - } - - return false; -} - -static GstFlowReturn -gst_subtecmp4transform_transform_ip (GstBaseTransform * trans, GstBuffer * buf) -{ - GstSubtecMp4Transform *subtecmp4transform = GST_SUBTECMP4TRANSFORM (trans); - - GST_DEBUG_OBJECT (subtecmp4transform, "transform_ip"); - - GstMapInfo map; - - gst_buffer_map(buf, &map, (GstMapFlags)GST_MAP_READWRITE); - - size_t offset = 0, length = 0; - - if (!findBoxOffsetAndLength(subtecmp4transform, reinterpret_cast(map.data), map.size, "ftyp", offset, length)) - { - if (findBoxOffsetAndLength(subtecmp4transform, reinterpret_cast(map.data), map.size, "mdat", offset, length)) - { - GST_DEBUG_OBJECT (subtecmp4transform, "offset %zu length %zu", offset, length); - memcpy(map.data, map.data + offset, length); - gst_buffer_resize(buf, 0, length); - } - } - else - { - GST_DEBUG_OBJECT (subtecmp4transform, "DROPPING FRAME"); - gst_buffer_unmap(buf, &map); - return GST_BASE_TRANSFORM_FLOW_DROPPED; - } - - gst_buffer_unmap(buf, &map); - - return GST_FLOW_OK; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - - return gst_element_register (plugin, "subtecmp4transform", GST_RANK_PRIMARY, - GST_TYPE_SUBTECMP4TRANSFORM); -} - -#ifndef VERSION -#define VERSION "0.1.0" -#endif -#ifndef PACKAGE -#define PACKAGE "GstreamerPlugins" -#endif -#ifndef PACKAGE_NAME -#define PACKAGE_NAME "GstreamerPlugins" -#endif -#ifndef GST_PACKAGE_ORIGIN -#define GST_PACKAGE_ORIGIN "http://comcast.com/" -#endif - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - subtecmp4transform, - "MP4 demuxer for subtitle packets", - plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN) - diff --git a/gst-plugins/gst_subtec/gstsubtecmp4transform.h b/gst-plugins/gst_subtec/gstsubtecmp4transform.h deleted file mode 100644 index 15359b5a..00000000 --- a/gst-plugins/gst_subtec/gstsubtecmp4transform.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2022 RDK Management - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _GST_SUBTECMP4TRANSFORM_H_ -#define _GST_SUBTECMP4TRANSFORM_H_ - -#include - -// Declared static here because this string exists in player and gstplugin .so -// library files This string needs to match the start -// of the gsteamer plugin name as created by the macros. -static const char* GstPluginNameSubtecMp4Transform = "subtecmp4transform"; - -G_BEGIN_DECLS - -#define GST_TYPE_SUBTECMP4TRANSFORM (gst_subtecmp4transform_get_type()) -#define GST_SUBTECMP4TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SUBTECMP4TRANSFORM,GstSubtecMp4Transform)) -#define GST_SUBTECMP4TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SUBTECMP4TRANSFORM,GstSubtecMp4TransformClass)) -#define GST_IS_SUBTECMP4TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SUBTECMP4TRANSFORM)) -#define GST_IS_SUBTECMP4TRANSFORM_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SUBTECMP4TRANSFORM)) - -typedef struct _GstSubtecMp4Transform GstSubtecMp4Transform; -typedef struct _GstSubtecMp4TransformClass GstSubtecMp4TransformClass; - -struct _GstSubtecMp4Transform -{ - GstBaseTransform base_subtecmp4transform; - -}; - -struct _GstSubtecMp4TransformClass -{ - GstBaseTransformClass base_subtecmp4transform_class; -}; - -GType gst_subtecmp4transform_get_type (void); - -G_END_DECLS - -#endif diff --git a/gst-plugins/gst_subtec/gstsubtecsink.cpp b/gst-plugins/gst_subtec/gstsubtecsink.cpp deleted file mode 100644 index 522dafcb..00000000 --- a/gst-plugins/gst_subtec/gstsubtecsink.cpp +++ /dev/null @@ -1,656 +0,0 @@ -/* - * Copyright (C) 2022 RDK Management - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#include -#include -#include "gstsubtecsink.h" -#include -#include - -GST_DEBUG_CATEGORY_STATIC (gst_subtecsink_debug_category); -#define GST_CAT_DEFAULT gst_subtecsink_debug_category - -static GstBaseSinkClass* parentClass = nullptr; - -/* prototypes */ -static void gst_subtecsink_set_property (GObject * object, - guint property_id, const GValue * value, GParamSpec * pspec); -static void gst_subtecsink_get_property (GObject * object, - guint property_id, GValue * value, GParamSpec * pspec); -static void gst_subtecsink_dispose (GObject * object); -static void gst_subtecsink_finalize (GObject * object); - -static void set_mute(GstSubtecSink *subtecsink); -static void set_attribute(GstSubtecSink *subtecsink); - -static gboolean gst_subtecsink_set_caps (GstBaseSink * sink, GstCaps * caps); -static gboolean gst_subtecsink_start (GstBaseSink * sink); -static gboolean gst_subtecsink_stop (GstBaseSink * sink); -static gboolean gst_subtecsink_query (GstBaseSink * sink, GstQuery * query); -static gboolean gst_subtecsink_event (GstBaseSink * sink, GstEvent * event); -static GstFlowReturn gst_subtecsink_render (GstBaseSink * sink, - GstBuffer * buffer); -static GstStateChangeReturn gst_subtecsink_change_state(GstElement *element, - GstStateChange transition); -static GstFlowReturn gst_subtecsink_prepare (GstBaseSink * sink, - GstBuffer * buffer); -static GstFlowReturn gst_subtecsink_preroll (GstBaseSink * sink, - GstBuffer * buffer); - -enum -{ - PROP_0, - PROP_MUTE, - PROP_NO_EOS, - PROP_SUBTEC_SOCKET, - PROP_PTS_OFFSET, - PROP_ATTRIBUTE_VALUES -}; - -enum -{ - FONT_COLOR_INDEX = 0, - BACKGROUND_COLOR_INDEX, - FONT_OPACITY_INDEX, - BACKGROUND_OPACITY_INDEX, - FONT_STYLE_INDEX, - FONT_SIZE_INDEX, - FONT_ITALIC_INDEX, - FONT_UNDERLINE_INDEX, - BORDER_TYPE_INDEX, - BORDER_COLOR_INDEX, - WIN_COLOR_INDEX, - WIN_OPACITY_INDEX, - EDGE_TYPE_INDEX, - EDGE_COLOR_INDEX -}; - -static GstStaticPadTemplate gst_subtecsink_sink_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/ttml+xml; text/vtt") - ); - - -G_DEFINE_TYPE_WITH_CODE (GstSubtecSink, gst_subtecsink, GST_TYPE_BASE_SINK, - GST_DEBUG_CATEGORY_INIT (gst_subtecsink_debug_category, "subtecsink", 0, - "debug category for subtecsink element")); - -static void -gst_subtecsink_class_init (GstSubtecSinkClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstBaseSinkClass *base_sink_class = GST_BASE_SINK_CLASS (klass); - GstElementClass *element_class = GST_ELEMENT_CLASS(klass); - - parentClass = GST_BASE_SINK_CLASS(g_type_class_peek_parent(klass)); - - GST_LOG("gst_subtecsink_class_init"); - - gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS(klass), - &gst_subtecsink_sink_template); - - gst_element_class_set_static_metadata (GST_ELEMENT_CLASS(klass), - "OOB Subtec data sink", "Sink/Parser/Subtitle", "Packs TTML or WebVTT data into SubTtxRend APP suitable packets", "Comcast"); - - - gobject_class->set_property = gst_subtecsink_set_property; - gobject_class->get_property = gst_subtecsink_get_property; - gobject_class->dispose = gst_subtecsink_dispose; - gobject_class->finalize = gst_subtecsink_finalize; - - g_object_class_install_property(gobject_class, - PROP_MUTE, - g_param_spec_boolean("mute", "Mute", "Mutes the subtitles", - FALSE, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_class, - PROP_NO_EOS, - g_param_spec_boolean("no-eos", "No EOS", "Eats the EOS and stops the stream exiting", - FALSE, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_class, - PROP_SUBTEC_SOCKET, - g_param_spec_string("subtec-socket", "Subtec socket", "Alternative subtec socket (default /var/run/subttx/pes_data_main)", - NULL, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_class, - PROP_PTS_OFFSET, - g_param_spec_uint64("pts-offset", "PTS offset", "PTS offset for mpeg-2 ts HLS streams", - 0, G_MAXUINT64, 0, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property(gobject_class, - PROP_ATTRIBUTE_VALUES, - g_param_spec_boxed("attribute-values", "Attribute values", "GstStructure specifying attributes", - GST_TYPE_STRUCTURE, - (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS))); - - - base_sink_class->set_caps = GST_DEBUG_FUNCPTR (gst_subtecsink_set_caps); - base_sink_class->start = GST_DEBUG_FUNCPTR (gst_subtecsink_start); - base_sink_class->stop = GST_DEBUG_FUNCPTR (gst_subtecsink_stop); - base_sink_class->query = GST_DEBUG_FUNCPTR (gst_subtecsink_query); - base_sink_class->event = GST_DEBUG_FUNCPTR (gst_subtecsink_event); - base_sink_class->render = GST_DEBUG_FUNCPTR (gst_subtecsink_render); - base_sink_class->prepare = GST_DEBUG_FUNCPTR (gst_subtecsink_prepare); - base_sink_class->preroll = GST_DEBUG_FUNCPTR (gst_subtecsink_preroll); - - element_class->change_state = GST_DEBUG_FUNCPTR (gst_subtecsink_change_state); -} - -static GstFlowReturn -gst_subtecsink_prepare (GstBaseSink * sink, GstBuffer * buffer) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (sink); - - GST_DEBUG_OBJECT (subtecsink, "prepare PTS %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_PTS(buffer))); - - return GST_FLOW_OK; -} - -static GstFlowReturn -gst_subtecsink_preroll (GstBaseSink * sink, GstBuffer * buffer) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (sink); - - GST_DEBUG_OBJECT (subtecsink, "preroll PTS %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_PTS(buffer))); - - return GST_FLOW_OK; -} - - -GstStateChangeReturn gst_subtecsink_change_state(GstElement *element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstSubtecSink *subtecsink = GST_SUBTECSINK(element); - - GST_DEBUG_OBJECT(subtecsink, "change_state 0x%X", transition); - - switch (transition) - { - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - { - GST_DEBUG_OBJECT(subtecsink, "changing state to playing"); - if (subtecsink->m_channel) - { - subtecsink->m_channel->SendResumePacket(); - - if (subtecsink->m_mute) - subtecsink->m_channel->SendMutePacket(); - else - subtecsink->m_channel->SendUnmutePacket(); - - set_attribute(subtecsink); - } - break; - } - default: - break; - } - ret = GST_ELEMENT_CLASS (parentClass)->change_state(element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - { - return ret; - } - - switch (transition) - { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - { - GST_DEBUG_OBJECT(subtecsink, "changing state to paused"); - if (subtecsink->m_channel) - { - subtecsink->m_channel->SendMutePacket(); - subtecsink->m_channel->SendPausePacket(); - } - break; - } - default: - break; - } - - return ret; -} - -static void -gst_subtecsink_init (GstSubtecSink *subtecsink) -{ - GST_DEBUG_OBJECT(subtecsink, "init"); - - gst_base_sink_set_async_enabled(GST_BASE_SINK(subtecsink), FALSE); - - subtecsink->m_attribute_mask = 0; - subtecsink->m_attribute_values = {0}; - subtecsink->m_pts_offset = 0; -} - -void -set_mute(GstSubtecSink *subtecsink) -{ - if (subtecsink->m_mute) - if (subtecsink->m_channel) subtecsink->m_channel->SendMutePacket(); else GST_WARNING_OBJECT (subtecsink, "Mute failed due to NULL channel"); - else - if (subtecsink->m_channel) subtecsink->m_channel->SendUnmutePacket(); else GST_WARNING_OBJECT (subtecsink, "Unmute failed due to NULL channel"); -} - -void -set_attribute(GstSubtecSink *subtecsink) -{ - if (subtecsink->m_channel) - { - subtecsink->m_channel->SendCCSetAttributePacket(0, subtecsink->m_attribute_mask, subtecsink->m_attribute_values); - } - else - { - GST_WARNING_OBJECT (subtecsink, "SetAttribute failed due to NULL channel"); - } -} - -void -gst_subtecsink_set_property (GObject * object, guint property_id, - const GValue * value, GParamSpec * pspec) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (object); - - GST_DEBUG_OBJECT (subtecsink, "set_property"); - - switch (property_id) { - case PROP_MUTE: - { - auto mute = g_value_get_boolean (value); - GST_TRACE_OBJECT(subtecsink, "%s current mute %s setting mute to %s", __func__, subtecsink->m_mute ? "true" : "false", mute ? "true" : "false"); - - //Pause senderthread - subtecsink->m_mute = mute; - set_mute(subtecsink); - } - break; - case PROP_NO_EOS: - { - auto no_eos = g_value_get_boolean(value); - GST_TRACE_OBJECT(subtecsink, "%s setting no_eos to %s", __func__, no_eos ? "true" : "false"); - subtecsink->m_no_eos = no_eos; - } - break; - case PROP_SUBTEC_SOCKET: - { - auto subtec_socket = g_value_get_string(value); - GST_TRACE_OBJECT(subtecsink, "%s setting subtec_socket to %s", __func__, subtec_socket); - subtecsink->m_subtec_socket = subtec_socket; - } - break; - case PROP_PTS_OFFSET: - { - auto pts_offset = g_value_get_uint64(value); - GST_TRACE_OBJECT(subtecsink, "%s setting pts_offset to %lu", __func__, pts_offset); - subtecsink->m_pts_offset = pts_offset; - subtecsink->m_send_timestamp = true; - } - break; - case PROP_ATTRIBUTE_VALUES: - { - const GstStructure *attributevalues = gst_value_get_structure(value); - if (attributevalues != NULL) - { - gst_structure_get_uint(attributevalues, "font_color", &subtecsink->m_attribute_values[FONT_COLOR_INDEX]); - gst_structure_get_uint(attributevalues, "background_color", &subtecsink->m_attribute_values[BACKGROUND_COLOR_INDEX]); - gst_structure_get_uint(attributevalues, "font_opacity", &subtecsink->m_attribute_values[FONT_OPACITY_INDEX]); - gst_structure_get_uint(attributevalues, "background_opacity", &subtecsink->m_attribute_values[BACKGROUND_OPACITY_INDEX]); - gst_structure_get_uint(attributevalues, "font_style", &subtecsink->m_attribute_values[FONT_STYLE_INDEX]); - gst_structure_get_uint(attributevalues, "font_size", &subtecsink->m_attribute_values[FONT_SIZE_INDEX]); - gst_structure_get_uint(attributevalues, "window_color", &subtecsink->m_attribute_values[WIN_COLOR_INDEX]); - gst_structure_get_uint(attributevalues, "window_opacity", &subtecsink->m_attribute_values[WIN_OPACITY_INDEX]); - gst_structure_get_uint(attributevalues, "edge_type", &subtecsink->m_attribute_values[EDGE_TYPE_INDEX]); - gst_structure_get_uint(attributevalues, "edge_color", &subtecsink->m_attribute_values[EDGE_COLOR_INDEX]); - gst_structure_get_uint(attributevalues, "attribute_mask", &subtecsink->m_attribute_mask); - - set_attribute(subtecsink); - } - else - { - GST_ERROR_OBJECT(subtecsink, "%s attribute value NULL", __func__); - } - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -void -gst_subtecsink_get_property (GObject * object, guint property_id, - GValue * value, GParamSpec * pspec) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (object); - - GST_DEBUG_OBJECT (subtecsink, "get_property %d", property_id); - - switch (property_id) { - case PROP_MUTE: - g_value_set_boolean (value, subtecsink->m_mute); - break; - case PROP_NO_EOS: - g_value_set_boolean (value, subtecsink->m_no_eos); - break; - case PROP_SUBTEC_SOCKET: - g_value_set_string (value, subtecsink->m_subtec_socket.c_str()); - break; - case PROP_PTS_OFFSET: - g_value_set_uint64 (value, subtecsink->m_pts_offset); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -void -gst_subtecsink_dispose (GObject * object) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (object); - - GST_DEBUG_OBJECT (subtecsink, "dispose"); - - if (subtecsink->m_channel) subtecsink->m_channel->SendResetAllPacket(); - - G_OBJECT_CLASS (gst_subtecsink_parent_class)->dispose (object); -} - -void -gst_subtecsink_finalize (GObject * object) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (object); - - GST_DEBUG_OBJECT (subtecsink, "finalize"); - - G_OBJECT_CLASS (gst_subtecsink_parent_class)->finalize (object); -} - -/* notify subclass of new caps */ -static gboolean -gst_subtecsink_set_caps (GstBaseSink * sink, GstCaps * caps) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (sink); - - GST_DEBUG_OBJECT (subtecsink, "set_caps"); - - const GstStructure *s = gst_caps_get_structure (caps, 0); - const gchar* caps_name = gst_structure_get_name(s); - - GST_DEBUG_OBJECT (subtecsink, "set_caps name %s", caps_name); - - if (!strcmp("text/vtt", caps_name) || !strcmp("application/x-subtitle-vtt", caps_name)) - subtecsink->m_channel = SubtecChannel::SubtecChannelFactory(SubtecChannel::ChannelType::WEBVTT); - else if (!strcmp("application/ttml+xml", caps_name)) - subtecsink->m_channel = SubtecChannel::SubtecChannelFactory(SubtecChannel::ChannelType::TTML); - else - { - GST_ERROR_OBJECT(subtecsink, "Unknown caps - cannot create subtec channel"); - return FALSE; - } - - subtecsink->m_channel->SendResetAllPacket(); - subtecsink->m_channel->SendSelectionPacket(1920, 1080); - set_mute(subtecsink); - set_attribute(subtecsink); - - return TRUE; -} - - -static gboolean -gst_subtecsink_start (GstBaseSink * sink) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (sink); - - GST_DEBUG_OBJECT (subtecsink, "start"); - bool ret = false; - - if (subtecsink->m_subtec_socket.empty()) - ret = SubtecChannel::InitComms(); - else - ret = SubtecChannel::InitComms(subtecsink->m_subtec_socket.c_str()); - - if (!ret) - { - GST_WARNING_OBJECT (subtecsink, "Init failed - subtitle parsing disabled"); - } - - subtecsink->m_send_timestamp = true; - - return ret; -} - -static gboolean -gst_subtecsink_stop (GstBaseSink * sink) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (sink); - if (subtecsink->m_channel) - { - subtecsink->m_channel->SendResetChannelPacket(); - subtecsink->m_channel->SendResetAllPacket(); - } - - GST_DEBUG_OBJECT (subtecsink, "stop"); - - return TRUE; -} - -static gboolean -gst_subtecsink_query (GstBaseSink * sink, GstQuery * query) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (sink); - - GST_DEBUG_OBJECT (subtecsink, "query %s", GST_QUERY_TYPE_NAME(query)); - - return GST_BASE_SINK_CLASS(G_OBJECT_CLASS (gst_subtecsink_parent_class))->query(sink, query); -} - -/** - * @brief Get the subtec timestamp in ms - applies the offset sent from upstream if applicable - * - * @param sink - * @param pts - * @param offset - * @return std::uint64_t - */ -static std::uint64_t get_timestamp_ms(GstBaseSink * sink, GstClockTime pts, GstClockTime offset) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (sink); - - //Get timestamp - if segment time > pts, this means we have skipped into the middle of the segment - auto timestampMs = static_cast(std::max(pts, sink->segment.time) / GST_MSECOND); - - GST_DEBUG_OBJECT (subtecsink, "offset %" G_GINT64_FORMAT " pts %" GST_TIME_FORMAT , offset, GST_TIME_ARGS(pts)); - - // Offset -1 means no offset - if (static_cast(offset) > 0) - { - GST_DEBUG_OBJECT (subtecsink, "add %" GST_TIME_FORMAT " offset to %" GST_TIME_FORMAT " to give %" GST_TIME_FORMAT, - GST_TIME_ARGS(offset), GST_TIME_ARGS(timestampMs*GST_MSECOND), GST_TIME_ARGS((timestampMs+offset)*GST_MSECOND)); - timestampMs += offset; - } - //For debug - this is what you get from filesrc when debugging using gst-launch1.0 - else if (static_cast(pts) < 0) - { - GST_DEBUG_OBJECT (subtecsink, "offset is -1 and pts is -1 - setting time to 0"); - timestampMs = 0; - } - - return timestampMs; -} - -static gboolean -gst_subtecsink_event (GstBaseSink * sink, GstEvent * event) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (sink); - gboolean res = TRUE; - GST_TRACE_OBJECT(subtecsink, "%s eventType %s", __func__, gst_event_type_get_name(GST_EVENT_TYPE(event))); - - switch(GST_EVENT_TYPE(event)) - { - case GST_EVENT_FLUSH_START: - if (subtecsink->m_channel) subtecsink->m_channel->SendResetChannelPacket(); - break; - case GST_EVENT_FLUSH_STOP: - if (subtecsink->m_channel) subtecsink->m_channel->SendSelectionPacket(1920, 1080); - subtecsink->m_send_timestamp = true; - set_mute(subtecsink); - set_attribute(subtecsink); - break; - case GST_EVENT_SEGMENT: - { - const GstSegment *segment; - gst_event_parse_segment(event, &segment); - subtecsink->m_segmentstart = segment->start; - GST_DEBUG_OBJECT(subtecsink, "segment.start: %" G_GUINT64_FORMAT, segment->start); - } - break; - case GST_EVENT_EOS: - //Useful for debug with fakesrc - if (subtecsink->m_no_eos) - { - GST_DEBUG_OBJECT(subtecsink, "Eating EOS (nomnom)"); - return TRUE; - } - else - { - GST_DEBUG_OBJECT(subtecsink, "Received EOS"); - } - break; - case GST_EVENT_CUSTOM_DOWNSTREAM: - { - const GstStructure *structure = gst_event_get_structure(event); - if (gst_structure_has_name(structure, "sub_clock_sync")) - { - GstClockTime pts = g_value_get_uint64(gst_structure_get_value(structure, "current-pts")); - auto timestampMs = get_timestamp_ms(sink, pts, subtecsink->m_pts_offset); - GST_DEBUG_OBJECT(subtecsink, - "%s generating timestamp %u", - __func__, - static_cast(timestampMs)); - subtecsink->m_channel->SendTimestampPacket((timestampMs)); - subtecsink->m_send_timestamp = false; - } - gst_event_unref(event); - res = TRUE; - goto drop; - } - break; - default: - break; - } - - GST_DEBUG_OBJECT (subtecsink, "event"); - - res = GST_BASE_SINK_CLASS(G_OBJECT_CLASS (gst_subtecsink_parent_class))->event(sink, event); -drop: - return res; -} - -static GstFlowReturn -gst_subtecsink_render (GstBaseSink * sink, GstBuffer * buffer) -{ - GstSubtecSink *subtecsink = GST_SUBTECSINK (sink); - - GST_DEBUG_OBJECT (subtecsink, "render PTS %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_PTS(buffer))); - - GstMapInfo map; - std::vector dataBuffer; - - if (gst_buffer_map(buffer, &map, GST_MAP_READ)) - { - auto inputData = static_cast(map.data); - auto inputSize = static_cast(map.size); - std::string instr(const_cast(reinterpret_cast(map.data)), map.size); - - GST_TRACE("%s unpacking GstBuffer size: %d\n", __func__, inputSize); - - for (std::uint32_t i = 0; i < inputSize; i++) - { - dataBuffer.push_back(inputData[i]); - } - - gst_buffer_unmap(buffer, &map); - } - else - { - GST_WARNING("%s error unpacking GstBuffer!", __func__); - } - - if (!dataBuffer.empty()) - { - if (subtecsink->m_send_timestamp) - { - //On seek, segment "time" will be ahead of buffer PTS - otherwise just use PTS - auto timestampMs = get_timestamp_ms(sink, subtecsink->m_segmentstart, subtecsink->m_pts_offset); - - GST_DEBUG_OBJECT(subtecsink, - "%s generating timestamp %u", - __func__, - static_cast(timestampMs)); - - subtecsink->m_channel->SendTimestampPacket((timestampMs)); - subtecsink->m_send_timestamp = false; - } - - auto offset = static_cast(GST_BUFFER_OFFSET(buffer)); - if (offset == -1) - offset = 0; - - GST_DEBUG_OBJECT (subtecsink, "sending data packet with offset %" G_GINT64_FORMAT " buffer %" G_GUINT64_FORMAT, offset, GST_BUFFER_OFFSET(buffer)); - subtecsink->m_channel->SendDataPacket(std::move(dataBuffer), 0 - offset); - } - - return GST_FLOW_OK; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - - return gst_element_register (plugin, "subtecsink", GST_RANK_PRIMARY, - GST_TYPE_SUBTECSINK); -} - -#ifndef VERSION -#define VERSION "0.1.0" -#endif -#ifndef PACKAGE -#define PACKAGE "GstreamerPlugins" -#endif -#ifndef PACKAGE_NAME -#define PACKAGE_NAME "GstreamerPlugins" -#endif -#ifndef GST_PACKAGE_ORIGIN -#define GST_PACKAGE_ORIGIN "http://comcast.com/" -#endif - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - subtecsink, - "SubTtxRend text/ttml sink", - plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN) - diff --git a/gst-plugins/gst_subtec/gstsubtecsink.h b/gst-plugins/gst_subtec/gstsubtecsink.h deleted file mode 100644 index 56f3b085..00000000 --- a/gst-plugins/gst_subtec/gstsubtecsink.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2022 RDK Management - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _GST_SUBTECSINK_H_ -#define _GST_SUBTECSINK_H_ - -#include -#include -#include -#include -#include "SubtecChannel.hpp" - -G_BEGIN_DECLS - -#define GST_TYPE_SUBTECSINK (gst_subtecsink_get_type()) -#define GST_SUBTECSINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SUBTECSINK,GstSubtecSink)) -#define GST_SUBTECSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SUBTECSINK,GstSubtecSinkClass)) -#define GST_IS_SUBTECSINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SUBTECSINK)) -#define GST_IS_SUBTECSINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SUBTECSINK)) - -typedef struct _GstSubtecSink GstSubtecSink; -typedef struct _GstSubtecSinkClass GstSubtecSinkClass; - -struct _GstSubtecSink -{ - GstBaseSink base_subtecsink; - - std::unique_ptr m_channel; - gboolean m_mute; - gboolean m_no_eos; - gboolean m_send_timestamp{true}; - guint64 m_segmentstart{0}; - guint64 m_pts_offset{0}; - std::string m_subtec_socket{}; - attributesType m_attribute_values{0}; - guint m_attribute_mask{0}; -}; - -struct _GstSubtecSinkClass -{ - GstBaseSinkClass base_subtecsink_class; -}; - -GType gst_subtecsink_get_type (void); - -G_END_DECLS - -#endif diff --git a/gst-plugins/gst_subtec/gstvipertransform.cpp b/gst-plugins/gst_subtec/gstvipertransform.cpp deleted file mode 100644 index e3ba85e8..00000000 --- a/gst-plugins/gst_subtec/gstvipertransform.cpp +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright (C) 2022 RDK Management - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * SECTION:element-gstvipertransform - * - * The vipertransform element performs the necessary transforms for legacy linear content. - * These are needed to overcome limitations in the TTML delivery - * - */ - -#include -#include -#include "gstvipertransform.h" - -#include -#include -#include -#include -#include - -namespace { constexpr auto XmlStart = "dispose = gst_vipertransform_dispose; - gobject_class->finalize = gst_vipertransform_finalize; - - base_transform_class->set_caps = GST_DEBUG_FUNCPTR (gst_vipertransform_set_caps); - base_transform_class->transform = GST_DEBUG_FUNCPTR (gst_vipertransform_transform); - base_transform_class->before_transform = GST_DEBUG_FUNCPTR (gst_vipertransform_before_transform); - base_transform_class->sink_event = GST_DEBUG_FUNCPTR (gst_vipertransform_event); -} - - -static gboolean gst_vipertransform_event (GstBaseTransform * trans, GstEvent * event) -{ - GstViperTransform *vipertransform = GST_VIPERTRANSFORM (trans); - - GST_TRACE_OBJECT(vipertransform, "%s eventType %s", __func__, gst_event_type_get_name(GST_EVENT_TYPE(event))); - - switch(GST_EVENT_TYPE(event)) - { - case GST_EVENT_FLUSH_START: - vipertransform->m_content_type = ViperContentType::UNKNOWN; - vipertransform->m_linear_begin_offset = 0; - break; - case GST_EVENT_FLUSH_STOP: - vipertransform->m_content_type = ViperContentType::UNKNOWN; - vipertransform->m_linear_begin_offset = 0; - break; - } - - GST_DEBUG_OBJECT (vipertransform, "event"); - - return GST_BASE_TRANSFORM_CLASS(G_OBJECT_CLASS (gst_vipertransform_parent_class))->sink_event(trans, event); -} - -static void -gst_vipertransform_init (GstViperTransform *vipertransform) -{ - GST_DEBUG_OBJECT (vipertransform, "init"); - vipertransform->m_content_type = ViperContentType::UNKNOWN; -} - -static gboolean gst_vipertransform_set_caps (GstBaseTransform * trans, - GstCaps * incaps, GstCaps * outcaps) -{ - GstViperTransform *vipertransform = GST_VIPERTRANSFORM (trans); - - GST_DEBUG_OBJECT (vipertransform, "set_caps"); - - const GstStructure *s = gst_caps_get_structure (incaps, 0); - const gchar* caps_name = gst_structure_get_name(s); - - GST_DEBUG_OBJECT (vipertransform, "caps %s", caps_name); - - // If not TTML set to passthrough mode - if (strcmp("application/ttml+xml", caps_name)) - { - gst_base_transform_set_passthrough(trans, TRUE); - GST_DEBUG_OBJECT (vipertransform, "Setting passthrough"); - } - - vipertransform->m_search_first_begin = true; - vipertransform->m_linear_begin_offset = 0; - - return TRUE; -} - -void -gst_vipertransform_dispose (GObject * object) -{ - GstViperTransform *vipertransform = GST_VIPERTRANSFORM (object); - - GST_DEBUG_OBJECT (vipertransform, "dispose"); - - G_OBJECT_CLASS (gst_vipertransform_parent_class)->dispose (object); -} - -void -gst_vipertransform_finalize (GObject * object) -{ - GstViperTransform *vipertransform = GST_VIPERTRANSFORM (object); - - GST_DEBUG_OBJECT (vipertransform, "finalize"); - - G_OBJECT_CLASS (gst_vipertransform_parent_class)->finalize (object); -} - -/** - * @brief Convert a time string (HHHH:MM:SS.000) to milliseconds - * - * @param timeString - * @return gint64 - */ -gint64 convertTime(const std::string &timeString) -{ - gint64 retMs = 0; - int hours, mins; - float secs; - - if (std::sscanf(timeString.c_str(), "%d:%d:%f", &hours, &mins, &secs)) - { - retMs += static_cast(hours) * 3600; - retMs += mins * 60; - retMs *= 1000; - retMs += static_cast(secs * 1000.0); - } - - return retMs; -} - -/** - * @brief Find a specific tag and return the contents, position and contents length - * - * @param instring - * @param tag - * @param start_pos - * @return std::tuple - */ -std::tuple findTag(const std::string &instring, const std::string &tag, std::size_t start_pos) -{ - std::string tag_start{tag+"=\""}; - std::size_t pos = start_pos; - - pos = instring.find(tag_start, pos); - - if (pos == std::string::npos) - return {"", std::string::npos, 0}; - - pos += tag_start.length(); // Takes us to contents - std::size_t endpos = instring.find_first_of('"', pos); // following " - std::size_t len = endpos - pos; - std::string tag_contents = instring.substr(pos, len); - - return {tag_contents, pos, len}; -} - - -/** - * @brief Search the TTML for the first begin="" tag. We will use this to calculate a timestamp offset - * eg if the first begin tag is begin="458:34:12:123" then we take this and subtract the - * buffer PTS ms to get an offset for the start of the stream - * PTS 0 2 4 - * time|----------|--b----b--|-b------b-etc - * ttml empty 1st b=2:40 - * - * 2:40 - 2s = 2:38 offset at the start of the stream - * - * We can then use this offset to sync the subtitles and audio PTS - * - * @param ss - * @param firstBeginMs - * @return true - * @return false - */ -static bool findFirstBegin(const std::string &ttml, gint64 &firstBeginMs) -{ - std::size_t pos; - std::string tag_contents; - - std::tie(tag_contents, pos, std::ignore) = findTag(ttml, "begin", 0); - - if (pos != std::string::npos) - { - firstBeginMs = convertTime(tag_contents); - return true; - } - - return false; -} - -/** - * @brief Find the offset in ms between the buffer PTS and the first "begin" tag in the TTML - * - * @param ttml - * @param buf - * @param offset_ms - * @return true - * @return false - */ -static bool find_offset_ms_from_pts(const std::string &ttml, GstBuffer *buf, gint64 &offset_ms) -{ - gint64 first_begin_ms = 0; - - if (findFirstBegin(ttml, first_begin_ms)) - { - guint64 pts_ms = GST_BUFFER_PTS(buf) / GST_MSECOND; - auto duration_ms = GST_BUFFER_DURATION(buf) / GST_MSECOND; - offset_ms = first_begin_ms - pts_ms; - } - else - return false; - - return true; -} - -/** - * @brief Get the restamp pts offset from the buffer - * - * @param buf - * @return gint64 - */ -static gint64 GetRestampPTSOffsetMS(GstBuffer * buf) -{ - return GST_BUFFER_OFFSET(buf); -} - -/** - * @brief Check if there are more than one xml docs in the current segment - * - * @param vipertransform - * @param ttml - * @return true - * @return false - */ -static bool is_harmonic_uhd(GstViperTransform *vipertransform, const std::string &ttml) -{ - // Check for more than one element (Harmonic UHD case) - const char *xml_marker = XmlStart; - auto first_marker = ttml.find(xml_marker); - auto second_marker = ttml.find(xml_marker, first_marker+1); - - return (second_marker != std::string::npos); -} - -/** - * @brief Split Harmonic muxed buffers into a string vector - * In the case of Harmonic linear content, the TTML docs are concatenated in a single segment - * The timestamps are referenced to the start of the TTML doc, so the structure will be as follows: - * <------First TTML doc - * - * ... - * - *

- * Text from 0s - 1s - *

- * - *
- * <------Second TTML doc - * - * ... - * - *

- * Text from 1s - 2s - *

- * - *
- * - * @param vipertransform - * @param ttml - * @return true - * @return false - */ -static std::vector split_buffer(const std::string &ttml) -{ - std::vector ttml_vec; - std::size_t pos=0, start_pos=0, end_pos = 0; - - while ((start_pos = ttml.find(XmlStart, pos)) != std::string::npos) - { - end_pos = ttml.find(XmlStart, start_pos+1); - auto sub = ttml.substr(start_pos, end_pos); - - ttml_vec.emplace_back(std::move(sub)); - pos = end_pos; - } - - return ttml_vec; -} - -/** - * @brief Check if the incoming content needs an offset. If so, parse it from the TTML - * - * @param GstBaseTransform *trans - * @param GstBuffer *buf - */ -static void gst_vipertransform_before_transform (GstBaseTransform * trans, - GstBuffer * buf) -{ - GstViperTransform *vipertransform = GST_VIPERTRANSFORM (trans); - - GST_DEBUG_OBJECT (vipertransform, "before_transform PTS %" GST_TIME_FORMAT " mode %d", GST_TIME_ARGS(GST_BUFFER_PTS(buf)), (int)vipertransform->m_content_type); - - if (gst_base_transform_is_passthrough(trans)) - { - GST_DEBUG_OBJECT (vipertransform, "Passthrough set"); - return; - } - - //Parse TTML string from buffer - std::string ttml; - { - GstMapInfo inmap; - if (gst_buffer_map(buf, &inmap, (GstMapFlags)GST_MAP_READ)) - { - GST_DEBUG_OBJECT (vipertransform, "map.size %lu", inmap.size); - ttml.assign(reinterpret_cast(inmap.data), inmap.size); - gst_buffer_unmap(buf, &inmap); - } - else - { - GST_ERROR_OBJECT (vipertransform, "Could not open for reading"); - return; - } - } - - //If there is more than one segment in the buffer, just take the first one - if (is_harmonic_uhd(vipertransform, ttml)) - { - auto ttml_vec = split_buffer(ttml); - if (!ttml_vec.empty()) - { - ttml = ttml_vec.front(); - GST_DEBUG_OBJECT (vipertransform, "uhd[0] %s", ttml.c_str()); - } - } - - gint64 first_begin_ms = 0; - //Find the gap between the PTS and the first "begin" tag - - if (findFirstBegin(ttml, first_begin_ms)) - { - gint64 restamp_pts_offset_ms = GetRestampPTSOffsetMS(buf); - gint64 offset_from_pts_ms = first_begin_ms - (GST_BUFFER_PTS(buf) / GST_MSECOND); - - GST_DEBUG_OBJECT(vipertransform, "first_begin_ms %" G_GINT64_FORMAT " offset_from_pts_ms %" G_GINT64_FORMAT " restamp_pts_offset_ms %" G_GINT64_FORMAT " buf duration %" G_GUINT64_FORMAT " lbo %" G_GINT64_FORMAT " ", - first_begin_ms, offset_from_pts_ms, restamp_pts_offset_ms, GST_BUFFER_DURATION(buf) / GST_MSECOND, vipertransform->m_linear_begin_offset); - - if (ViperContentType::UNKNOWN == vipertransform->m_content_type) - { - //If first cue time does not line up with PTS, this is linear content and needs an offset - // If the offset is greater than the buffer duration, we need to set the offset - // to the first cue time - // If the offset is less than the buffer duration, we need to set the offset - // to the restamp offset - if (std::abs(offset_from_pts_ms - restamp_pts_offset_ms) > GST_BUFFER_DURATION(buf) / GST_MSECOND) - { - vipertransform->m_content_type = ViperContentType::LINEAR_OFFSET; - if (vipertransform->m_linear_begin_offset == 0 || abs(offset_from_pts_ms) < vipertransform->m_linear_begin_offset) - { - vipertransform->m_linear_begin_offset = offset_from_pts_ms; - } - } - // If no misalignment was found, correct for any PTS re-stamping offset applied by Player for linear content - else if (restamp_pts_offset_ms != 0) - { - vipertransform->m_linear_begin_offset = restamp_pts_offset_ms; - vipertransform->m_content_type = ViperContentType::LINEAR_OFFSET; - } - else - { - //First cue time lines up with PTS so no offset needed - vipertransform->m_content_type = ViperContentType::PASSTHROUGH; - gst_base_transform_set_passthrough(trans, TRUE); - } - } - //See if we can get the offset a bit closer - //If the new offset is less, go for that - //If it's equal to the last, we're probably at the beginning of the segment so stick with this - else if (ViperContentType::LINEAR_OFFSET == vipertransform->m_content_type) - { - if ((std::abs(offset_from_pts_ms - restamp_pts_offset_ms) > GST_BUFFER_DURATION(buf) / GST_MSECOND)) - { - vipertransform->m_linear_begin_offset = offset_from_pts_ms; - } - else - { - vipertransform->m_linear_begin_offset = restamp_pts_offset_ms; - } - } - else - { - GST_DEBUG_OBJECT (vipertransform, "Empty segment - no cue found"); - } - } - return; -} - -/** - * @brief Add the offset to the GstBuffer if required. Also split the incoming buffer - * if needed for Harmonic content - * - * @param trans - * @param inbuf - * @param outbuf - * @return GstFlowReturn - */ -static GstFlowReturn -gst_vipertransform_transform (GstBaseTransform * trans, GstBuffer * inbuf, - GstBuffer * outbuf) -{ - GstViperTransform *vipertransform = GST_VIPERTRANSFORM (trans); - - GST_DEBUG_OBJECT (vipertransform, "transform"); - - std::string ttml; - - { - GstMapInfo inmap, outmap; - if (gst_buffer_map(inbuf, &inmap, (GstMapFlags)GST_MAP_READ) && gst_buffer_map(outbuf, &outmap, (GstMapFlags)GST_MAP_WRITE)) - { - ttml.assign(reinterpret_cast(inmap.data), inmap.size); - memcpy(outmap.data, inmap.data, inmap.size); - gst_buffer_unmap(outbuf, &outmap); - gst_buffer_unmap(inbuf, &inmap); - } - else - { - GST_ERROR_OBJECT (vipertransform, "Could not map buffers"); - return GST_FLOW_ERROR; - } - } - - - if (is_harmonic_uhd(vipertransform, ttml)) - { - std::vector ttml_vec; - - GST_DEBUG_OBJECT (vipertransform, "Harmonic transform"); - - //Split inbuf into a vector of xml docs - ttml_vec = split_buffer(ttml); - - if (ttml_vec.empty()) - { - GST_DEBUG_OBJECT (vipertransform, "vector empty - passing data straight through"); - return GST_FLOW_OK; - } - - int segment_duration; - GstClockTime pts = GST_BUFFER_PTS(inbuf); - - //Useful for debugging via filesrc (filesrc sets pts/dts/duration to -1) - if (static_cast(GST_BUFFER_DURATION(inbuf)) == -1) - { - segment_duration = ttml_vec.size() * GST_SECOND; - pts = 0; - } - else - segment_duration = GST_BUFFER_DURATION(inbuf) / ttml_vec.size(); - - auto segment_count = 0; - - //Split single, concatenated buffer into separate buffers - //Add an offset to the buffer object for use by the sink - //Then push them as new, separate buffers to the pipeline - for (const auto &item : ttml_vec) - { - GstBuffer *buf; - GstMemory *mem; - - guint64 pts_ms = pts / GST_MSECOND; - guint64 duration_ms = segment_duration / GST_MSECOND; - - gchar *data = (gchar *)g_malloc(item.size()); - memcpy(data, item.c_str(), item.size()); - - buf = gst_buffer_new_wrapped(data, item.size()); - //Retimestamp new buffer if required - GST_BUFFER_PTS(buf) = pts + ((segment_count * segment_duration)); - GST_BUFFER_DTS(buf) = pts + ((segment_count * segment_duration)); - GST_BUFFER_DURATION(buf) = segment_duration; - - //Incoming Harmonic content might be either - // a. TTML timestamped relative to the start of the fragment or - // b. MediaKind-style with TTML timestamp being absolute from some fairly arbitrary zero point - if (vipertransform->m_linear_begin_offset != 0) - GST_BUFFER_OFFSET(buf) = vipertransform->m_linear_begin_offset; - else - GST_BUFFER_OFFSET(buf) = 0 - (pts_ms + (duration_ms * segment_count)); - - GST_DEBUG_OBJECT (vipertransform, "pts_ms: %" G_GUINT64_FORMAT " duration_ms %" G_GUINT64_FORMAT " offset ms %" G_GUINT64_FORMAT " segment_count %d", pts_ms, duration_ms, GST_BUFFER_OFFSET(buf), segment_count); - - //Push fragment as a separate GstBuffer - gst_pad_push(gst_element_get_static_pad(&trans->element, "src"), buf); - segment_count++; - } - - return GST_BASE_TRANSFORM_FLOW_DROPPED; - } - else if (vipertransform->m_linear_begin_offset != 0) - { - GST_BUFFER_OFFSET(outbuf) = vipertransform->m_linear_begin_offset; - } - - return GST_FLOW_OK; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - return gst_element_register (plugin, "vipertransform", GST_RANK_PRIMARY + 1, - GST_TYPE_VIPERTRANSFORM); -} - -#ifndef VERSION -#define VERSION "0.1.0" -#endif -#ifndef PACKAGE -#define PACKAGE "GstreamerPlugins" -#endif -#ifndef PACKAGE_NAME -#define PACKAGE_NAME "GstreamerPlugins" -#endif -#ifndef GST_PACKAGE_ORIGIN -#define GST_PACKAGE_ORIGIN "http://comcast.com/" -#endif - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - vipertransform, - "Applies any necessary transforms for TTML content", - plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst-plugins/gst_subtec/gstvipertransform.h b/gst-plugins/gst_subtec/gstvipertransform.h deleted file mode 100644 index e2e8f4f0..00000000 --- a/gst-plugins/gst_subtec/gstvipertransform.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2022 RDK Management - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _GST_VIPERTRANSFORM_H_ -#define _GST_VIPERTRANSFORM_H_ - -#include - -#include - -// Declared static here because this string exists in player and gstplugin .so -// library files This string needs to match the start -// of the gsteamer plugin name as created by the macros. -static const char* GstPluginNameViperTransform = "vipertransform"; - -G_BEGIN_DECLS - -#define GST_TYPE_VIPERTRANSFORM (gst_vipertransform_get_type()) -#define GST_VIPERTRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIPERTRANSFORM,GstViperTransform)) -#define GST_VIPERTRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIPERTRANSFORM,GstViperTransformClass)) -#define GST_IS_VIPERTRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIPERTRANSFORM)) -#define GST_IS_VIPERTRANSFORM_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIPERTRANSFORM)) - -typedef struct _GstViperTransform GstViperTransform; -typedef struct _GstViperTransformClass GstViperTransformClass; - -enum class ViperContentType -{ - UNKNOWN, - PASSTHROUGH, - LINEAR_OFFSET, - LINEAR_OFFSET_PRELIM, - HARMONIC_UHD -}; - -struct _GstViperTransform -{ - GstBaseTransform base_vipertransform; - ViperContentType m_content_type {ViperContentType::UNKNOWN}; - gint64 m_linear_begin_offset {0}; - gboolean m_search_first_begin {true}; -}; - -struct _GstViperTransformClass -{ - GstBaseTransformClass base_vipertransform_class; -}; - -GType gst_vipertransform_get_type (void); - -G_END_DECLS - -#endif diff --git a/gst-plugins/gstinit.cpp b/gst-plugins/gstinit.cpp deleted file mode 100755 index 569bad20..00000000 --- a/gst-plugins/gstinit.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* -* Copyright 2018 RDK Management -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, version 2.1 -* of the license. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -* Boston, MA 02110-1301, USA. -*/ - -/** - * @file gstinit.cpp - * @brief gstreamer plugin initialization - */ - -#include -#include -#ifdef DRM_BUILD_PROFILE -#include "gstplayreadydecryptor.h" -#include "gstwidevinedecryptor.h" -#include "gstclearkeydecryptor.h" -#include "gstverimatrixdecryptor.h" -#endif - - -/** - * @brief plugin_init , invoked by gstreamer core on load. Registers player gstreamer elements. - * @param plugin GstPlugin to which elements should be registered - * @retval status of operation - */ -static gboolean plugin_init(GstPlugin * plugin) -{ - gboolean ret = false; -#ifdef DRM_BUILD_PROFILE - ret = gst_element_register(plugin, GstPluginNamePR, - GST_RANK_PRIMARY, GST_TYPE_PLAYREADYDECRYPTOR ); - if(ret) - { - printf("player plugin_init registered %s element\n", GstPluginNamePR); - } - else - { - printf("player plugin_init FAILED to register %s element\n", GstPluginNamePR); - } - ret = gst_element_register(plugin, GstPluginNameWV, - GST_RANK_PRIMARY, GST_TYPE_WIDEVINEDECRYPTOR ); - if(ret) - { - printf("player plugin_init registered %s element\n", GstPluginNameWV); - } - else - { - printf("player plugin_init FAILED to register %s element\n", GstPluginNameWV); - } - ret = gst_element_register(plugin, GstPluginNameCK, - GST_RANK_PRIMARY, GST_TYPE_CLEARKEYDECRYPTOR ); - if(ret) - { - printf("player plugin_init registered %s element\n", GstPluginNameCK); - } - else - { - printf("player plugin_init FAILED to register %s element\n", GstPluginNameCK); - } - ret = gst_element_register(plugin, GstPluginNameVMX, - GST_RANK_PRIMARY, GST_TYPE_VERIMATRIXDECRYPTOR ); - if(ret) - { - printf("player plugin_init registered %s element\n", GstPluginNameVMX); - } - else - { - printf("player plugin_init FAILED to register %s element\n", GstPluginNameVMX); - } -#else -#endif - return ret; -} - -#ifndef VERSION -#define VERSION "0.0.1" -#endif -#ifndef PACKAGE -#define PACKAGE "RDK" -#endif -#ifndef PACKAGE_NAME -#define PACKAGE_NAME "plugin" -#endif -#ifndef GST_PACKAGE_ORIGIN -#define GST_PACKAGE_ORIGIN "https://rdkcentral.com/" -#endif - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - plugin, - "Interface Player", - plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/install-middleware.sh b/install-middleware.sh index 7182990c..4c4a51d0 100755 --- a/install-middleware.sh +++ b/install-middleware.sh @@ -72,7 +72,7 @@ PLAYER_DIR=$PWD # MAIN execution starts # Get and process install options -install_options_fn "$@" +install_options_fn "$@" INSTALL_STATUS_ARR+=("install_options_fn check passed.") tools_banner_fn @@ -101,7 +101,7 @@ fi if [ ${OPTION_QUICK} = false ] ; then echo "" echo "*** Check/Install dependency packages" - install_pkgs_fn + install_pkgs_fn INSTALL_STATUS_ARR+=("install_pkgs_fn check passed.") else INSTALL_STATUS_ARR+=("install_pkgs_fn check SKIPPED.") @@ -114,7 +114,7 @@ echo "*** Check/Install source packages" # Install gstreamer # -install_gstreamer_fn +install_gstreamer_fn INSTALL_STATUS_ARR+=("install_gstreamer_fn check passed.") # Build gst-plugins-good. install_gstreamer_fn must have been called first @@ -123,29 +123,29 @@ INSTALL_STATUS_ARR+=("install_gstplugingood_fn check passed.") # Build googletest # -install_build_googletest_fn "${OPTION_CLEAN}" +install_build_googletest_fn "${OPTION_CLEAN}" INSTALL_STATUS_ARR+=("install_build_googletest check passed.") # Build glib # -install_build_glib_fn "${OPTION_CLEAN}" +install_build_glib_fn "${OPTION_CLEAN}" INSTALL_STATUS_ARR+=("install_build_glib check passed.") # Build libcjson -install_build_libcjson_fn "${OPTION_CLEAN}" +install_build_libcjson_fn "${OPTION_CLEAN}" INSTALL_STATUS_ARR+=("install_build_libcjson check passed.") # Build subtec # CLEAN=false -if [ ${OPTION_CLEAN} = true ] ; then +if [ ${OPTION_CLEAN} = true ] ; then CLEAN=true fi if [ ${OPTION_SUBTEC_CLEAN} = true ] ; then CLEAN=true fi -if [ ${OPTION_SUBTEC_SKIP} = false ] ; then +if [ ${OPTION_SUBTEC_SKIP} = false ] ; then subtec_install_build_fn "${CLEAN}" INSTALL_STATUS_ARR+=("subtec_install_build check passed.") else diff --git a/playerLogManager/CMakeLists.txt b/playerLogManager/CMakeLists.txt index 4bffc7c3..81d4ad87 100644 --- a/playerLogManager/CMakeLists.txt +++ b/playerLogManager/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.5) -project(PlayerLogManager) +project(playerlogmanager) include_directories(..) @@ -22,17 +22,17 @@ endif() set(PlayerLogManager_SRC PlayerLogManager.cpp) -add_library(PlayerLogManager SHARED ${PlayerLogManager_SRC}) +add_library(playerlogmanager SHARED ${PlayerLogManager_SRC}) -set_target_properties(PlayerLogManager PROPERTIES PUBLIC_HEADER "PlayerLogManager.h") +set_target_properties(playerlogmanager PROPERTIES PUBLIC_HEADER "PlayerLogManager.h") -set_target_properties(PlayerLogManager PROPERTIES COMPILE_FLAGS "${LIBPLAYERLOGMANAGER_DEFINES}") +set_target_properties(playerlogmanager PROPERTIES COMPILE_FLAGS "${LIBPLAYERLOGMANAGER_DEFINES}") string(STRIP "${LIBPLAYERLOGMANAGER_DEPENDS}" LIBPLAYERLOGMANAGER_DEPENDS) -target_link_libraries(PlayerLogManager ${LIBPLAYERLOGMANAGER_DEPENDS}) +target_link_libraries(playerlogmanager ${LIBPLAYERLOGMANAGER_DEPENDS}) # Install the library and its headers -install(TARGETS PlayerLogManager +install(TARGETS playerlogmanager DESTINATION lib PUBLIC_HEADER DESTINATION include) diff --git a/playerLogManager/PlayerLogManager.h b/playerLogManager/PlayerLogManager.h index 4e9a7f4e..16149f8c 100644 --- a/playerLogManager/PlayerLogManager.h +++ b/playerLogManager/PlayerLogManager.h @@ -45,10 +45,10 @@ enum MW_LogLevel }; /** - * @class PlayerLogManager + * @class PlayerLogManager * @brief PlayerLogManager Class */ -class PlayerLogManager +class PlayerLogManager { public : static MW_LogLevel mwLoglevel; @@ -82,7 +82,7 @@ public : { return (chkLevel>=mwLoglevel); } - + /** * @fn setLogLevel * @@ -96,21 +96,21 @@ public : mwLoglevel = newLevel; } } - + /** * @brief lock or unlock log level. This allows (for example) logging to be locked to info or trace, so that "more verbose while tuning, less verbose after tune complete" behavior doesn't override desired log level used for debugging. This is also used as part of aampcli "noisy" and "quiet" command handling. - * + * * @param lock if true, subsequent calls to setLogLevel will be ignored */ static void lockLogLevel( bool lock ) { locked = lock; } -/** +/** * @fn getHexDebugStr - */ + */ static std::string getHexDebugStr(const std::vector& data) - { + { std::ostringstream hexSs; hexSs << "0x"; hexSs << std::hex << std::uppercase << std::setfill('0'); diff --git a/scripts/install_dependencies.sh b/scripts/install_dependencies.sh index c228028c..d4c6ceb6 100644 --- a/scripts/install_dependencies.sh +++ b/scripts/install_dependencies.sh @@ -20,12 +20,12 @@ declare DEFAULT_OPENSSL_VERSION="openssl@3.4" -function install_pkgs_pkgconfig_darwin_fn() +function install_pkgs_pkgconfig_darwin_fn() { echo "`brew --prefix ${1}`/lib/pkgconfig" } -function install_pkgs_darwin_fn() +function install_pkgs_darwin_fn() { # Check if brew package $1 is installed # http://stackoverflow.com/a/20802425/1573477 @@ -55,7 +55,7 @@ function install_pkgs_darwin_fn() if [ "$OPENSSL_CUR_PATH" != "{$OPENSSL_PATH}" ] ; then sudo rm -f /usr/local/ssl || true sudo ln -s $OPENSSL_PATH /usr/local/ssl - fi + fi fi PKGDIR="`brew --prefix ${PKG}`/lib/pkgconfig:" INSTALLED_PKGCONFIG=$PKGDIR$INSTALLED_PKGCONFIG @@ -203,7 +203,7 @@ function install_pkgs_fn() # ORC causes compile errors on x86_64 Mac, but not on ARM64 if [[ $ARCH == "x86_64" ]]; then - + # Workaround for making boost compatible with websocketpp (used for subtec) export BOOST_ROOT="/usr/local/opt/boost@1.85" @@ -226,7 +226,7 @@ function install_pkgs_fn() esac fi elif [[ $ARCH == "arm64" ]]; then - + # Workaround for making boost compatible with websocketpp (used for subtec) export BOOST_ROOT="/opt/homebrew/opt/boost@1.85" export CMAKE_PREFIX_PATH="/opt/homebrew/opt/boost@1.85" @@ -247,7 +247,7 @@ function install_pkgs_fn() fi - elif [[ "$OSTYPE" == "linux"* ]]; then + elif [[ "$OSTYPE" == "linux"* ]]; then install_pkgs_linux_fn fi } diff --git a/scripts/install_glib.sh b/scripts/install_glib.sh index 43d76af6..15e2dd0c 100644 --- a/scripts/install_glib.sh +++ b/scripts/install_glib.sh @@ -10,8 +10,8 @@ function install_build_glib_fn() if [ -d glib ] ; then rm -rf glib # uninstall? - #rm $LOCAL_DEPS_BUILD_DIR/lib/libgmock.a - #rm $LOCAL_DEPS_BUILD_DIR/lib/libgmock_main.a + #rm $LOCAL_DEPS_BUILD_DIR/lib/libgmock.a + #rm $LOCAL_DEPS_BUILD_DIR/lib/libgmock_main.a #rm $LOCAL_DEPS_BUILD_DIR/lib/libgtest.a fi fi diff --git a/scripts/install_gstreamer.sh b/scripts/install_gstreamer.sh index fd7d5f1d..65fd6634 100644 --- a/scripts/install_gstreamer.sh +++ b/scripts/install_gstreamer.sh @@ -7,13 +7,13 @@ function install_gstreamer_fn() { # There is no CLEAN function - if [[ "$OSTYPE" == "darwin"* ]]; then + if [[ "$OSTYPE" == "darwin"* ]]; then # homebrew versions are not equivalent to the install package so we don't use it. In the future that may change. if [[ $ARCH == "x86_64" ]]; then DEFAULT_GSTVERSION="1.18.6" elif [[ $ARCH == "arm64" ]]; then - DEFAULT_GSTVERSION="1.24.9" + DEFAULT_GSTVERSION="1.24.9" else echo "Architecture $ARCH is unsupported" return 1 @@ -50,7 +50,7 @@ function install_gstreamer_fn() echo "Fixing Gstreamer.framework .pc files." sudo sed -i '.bak' 's#prefix=.*#prefix=/Library/Frameworks/GStreamer.framework/Versions/1.0#' /Library/Frameworks/GStreamer.framework/Libraries/pkgconfig/* fi - + fi INSTALL_STATUS_ARR+=("gstreamer $DEFAULT_GSTVERSION was successfully installed.") @@ -65,7 +65,7 @@ function install_gstpluginsgoodfn() { cd $LOCAL_DEPS_BUILD_DIR - if [[ "$OSTYPE" == "darwin"* ]]; then + if [[ "$OSTYPE" == "darwin"* ]]; then # homebrew versions are not equivalent to the install package so we don't use it. In the future that may change. # $OPTION_CLEAN == true @@ -84,7 +84,7 @@ function install_gstpluginsgoodfn() curl -o gst-plugins-good-$DEFAULT_GSTVERSION.tar.xz https://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-$DEFAULT_GSTVERSION.tar.xz tar -xvzf gst-plugins-good-$DEFAULT_GSTVERSION.tar.xz cd gst-plugins-good-$DEFAULT_GSTVERSION - + patch -p1 < ../../OSx/patches/0009-qtdemux-tm_gst-1.16.patch patch -p1 < ../../OSx/patches/0013-qtdemux-remove-override-segment-event_gst-1.16.patch patch -p1 < ../../OSx/patches/0014-qtdemux-clear-crypto-info-on-trak-switch_gst-1.16.patch diff --git a/scripts/install_gtest.sh b/scripts/install_gtest.sh index 89c72368..5fb4f786 100644 --- a/scripts/install_gtest.sh +++ b/scripts/install_gtest.sh @@ -13,8 +13,8 @@ function install_build_googletest_fn() if [ -d googletest ] ; then rm -rf googletest # uninstall? - #rm $LOCAL_DEPS_BUILD_DIR/lib/libgmock.a - #rm $LOCAL_DEPS_BUILD_DIR/lib/libgmock_main.a + #rm $LOCAL_DEPS_BUILD_DIR/lib/libgmock.a + #rm $LOCAL_DEPS_BUILD_DIR/lib/libgmock_main.a #rm $LOCAL_DEPS_BUILD_DIR/lib/libgtest.a fi fi @@ -33,7 +33,7 @@ function install_build_googletest_fn() echo "Building googletest" mkdir -p build cd build - if [[ "$OSTYPE" == "darwin"* ]]; then + if [[ "$OSTYPE" == "darwin"* ]]; then env PKG_CONFIG_PATH=${LOCAL_DEPS_BUILD_DIR}/lib/pkgconfig cmake .. -DCMAKE_INSTALL_PREFIX=${LOCAL_DEPS_BUILD_DIR} elif [[ "$OSTYPE" == "linux"* ]]; then env PKG_CONFIG_PATH=${LOCAL_DEPS_BUILD_DIR}/lib/pkgconfig cmake .. -DCMAKE_PLATFORM_UBUNTU=1 -DCMAKE_INSTALL_PREFIX=${LOCAL_DEPS_BUILD_DIR} @@ -44,3 +44,4 @@ function install_build_googletest_fn() popd fi } + diff --git a/scripts/install_libcjson.sh b/scripts/install_libcjson.sh index 560d5965..5f48b555 100755 --- a/scripts/install_libcjson.sh +++ b/scripts/install_libcjson.sh @@ -6,7 +6,7 @@ function install_build_libcjson_fn() if [[ "$OSTYPE" == "darwin"* ]]; then # Should not be built or installed, but aampmetrics needs it in /usr/local - # which is a problem on MacOS ARM64 as brew installs to /opt/homebrew now and + # which is a problem on MacOS ARM64 as brew installs to /opt/homebrew now and # aampmetrics assumes/hardcodes -L/usr/local/lib # Once fixed by using ${LIBCJSON_LINK_LIBRARIES} instead of -lcjson this # script can be removed @@ -35,7 +35,7 @@ function install_build_libcjson_fn() cmake .. -DCMAKE_INSTALL_PREFIX=${LOCAL_DEPS_BUILD_DIR} make make install - + INSTALL_STATUS_ARR+=("cjson was successfully installed.") fi @@ -53,7 +53,7 @@ function install_build_libcjson_fn() echo "Required symlink $TARGET for arm64 already exists." else - + echo "Creating required symlink for arm64: $TARGET -> $SOURCE" sudo ln -s "$SOURCE" "$TARGET" fi diff --git a/scripts/install_libdash.sh b/scripts/install_libdash.sh index 78612f43..6f2266e4 100755 --- a/scripts/install_libdash.sh +++ b/scripts/install_libdash.sh @@ -26,8 +26,8 @@ function install_build_libdash_fn() git checkout stable_3_0 do_clone_fn -b rdk-next "https://code.rdkcentral.com/r/rdk/components/generic/rdk-oe/meta-rdk-ext" patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0001-libdash-build.patch - patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0002-libdash-starttime-uint64.patch - patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0003-libdash-presentationTimeOffset-uint64.patch + patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0002-libdash-starttime-uint64.patch + patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0003-libdash-presentationTimeOffset-uint64.patch patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0004-Support-of-EventStream.patch patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0005-DELIA-39460-libdash-memleak.patch patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0006-RDK-32003-LLD-Support.patch @@ -35,7 +35,7 @@ function install_build_libdash_fn() patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0008-DELIA-53263-Use-Label-TAG.patch patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0009-RDK-35134-Support-for-FailoverContent.patch patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0010-RDKAAMP-121-Failover-Tag-on-SegmentTemplate.patch - patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0011-RDKAAMP-61-AAMP-low-latency-dash-stream-evaluation.patch + patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0011-RDKAAMP-61-AAMP-low-latency-dash-stream-evaluation.patch patch -p1 < meta-rdk-ext/recipes-multimedia/libdash/libdash/0012-To-retrieves-the-text-content-of-CDATA-section.patch mkdir -p build cd build diff --git a/scripts/install_options.sh b/scripts/install_options.sh index 6d85b158..59f07375 100755 --- a/scripts/install_options.sh +++ b/scripts/install_options.sh @@ -46,19 +46,19 @@ function install_options_fn() OPTION_QUICK=true echo "Skip : ${QUICK}" ;; - r ) + r ) OPTION_RIALTO_REFERENCE=${OPTARG} echo "rialto tag : ${RIALTO_REFERENCE}" ;; - s ) + s ) OPTION_SUBTEC_SKIP=true # overrides any subtec or subtec clean setting echo "Skip subtec: ${OPTION_SKIP_SUBTEC}" ;; - p ) + p ) OPTION_PROTOBUF_REFERENCE=${OPTARG} echo "protobuf branch : ${PROTOBUF_REFERENCE}" - ;; + ;; * ) echo "Usage: $0 [-b branch name] [-d local setup directory name] [-c] [-f compiler flags] [-g google release tag] [-n] [-q] [-s] [subtec [clean]]" echo " [-r rialto tag] [-p protobuf branch name] [rialto] (Linux only)" @@ -82,7 +82,7 @@ function install_options_fn() # Parse subtec options if [[ ${@:$OPTIND:1} = "subtec" ]]; then - OPTION_SUBTEC_BUILD=true + OPTION_SUBTEC_BUILD=true shift if [[ ${@:$OPTIND:1} = "clean" ]]; then OPTION_SUBTEC_CLEAN=true @@ -96,3 +96,4 @@ function install_options_fn() fi } + diff --git a/scripts/install_rialto.sh b/scripts/install_rialto.sh index e63daf8a..6d3428e3 100644 --- a/scripts/install_rialto.sh +++ b/scripts/install_rialto.sh @@ -45,9 +45,9 @@ function rialto_build_repo_fn() make make install popd -} +} -function rialto_build_fn() +function rialto_build_fn() { echo "Building protobuf" pushd protobuf @@ -55,8 +55,8 @@ function rialto_build_fn() ./configure --prefix="${1}" make make install - popd - + popd + rialto_build_repo_fn rialto -DNATIVE_BUILD=ON -DRIALTO_BUILD_TYPE=Debug INSTALL_STATUS_ARR+=("rialto was successfully installed.") diff --git a/scripts/install_subtec.sh b/scripts/install_subtec.sh index 97bbbbae..963ec9b3 100755 --- a/scripts/install_subtec.sh +++ b/scripts/install_subtec.sh @@ -7,12 +7,12 @@ function subtec_install_fn() { if [ -z "${1}" ] ; then echo "Middleware directory parameter is empty, can not find patch files." return 1 - fi + fi # Need LOCAL_DEPS_BUILD_DIR passed in so we can patch the location of glib if [ -z "${2}" ] ; then echo "Dependency directory parameter is empty, can not patch subtec-app CMakeLists.txt" return 1 - fi + fi echo "Cloning subtec-app..." do_clone_fn "https://code.rdkcentral.com/r/components/generic/subtec-app" @@ -40,9 +40,9 @@ function subtec_install_fn() { SED_ARG="''" # MacOS -i has different -i argument fi sed -i ${SED_ARG} 's:COMMAND gdbus-codegen --interface-prefix com.libertyglobal.rdk --generate-c-code SubtitleDbusInterface ${CMAKE_CURRENT_SOURCE_DIR}/api/dbus/SubtitleDbusInterface.xml:COMMAND '"${2}"'/glib/build/gio/gdbus-2.0/codegen/gdbus-codegen --interface-prefix com.libertyglobal.rdk --generate-c-code SubtitleDbusInterface ${CMAKE_CURRENT_SOURCE_DIR}/api/dbus/SubtitleDbusInterface.xml:g' subttxrend-dbus/CMakeLists.txt - + sed -i ${SED_ARG} 's:COMMAND gdbus-codegen --interface-prefix com.libertyglobal.rdk --generate-c-code TeletextDbusInterface ${CMAKE_CURRENT_SOURCE_DIR}/api/dbus/TeletextDbusInterface.xml:COMMAND '"${2}"'/glib/build/gio/gdbus-2.0/codegen/gdbus-codegen --interface-prefix com.libertyglobal.rdk --generate-c-code TeletextDbusInterface ${CMAKE_CURRENT_SOURCE_DIR}/api/dbus/TeletextDbusInterface.xml:g' subttxrend-dbus/CMakeLists.txt - + echo "subtec-app source prepared" popd } @@ -66,7 +66,7 @@ function subtec_install_build_fn() { # Tell installer where DEPs are so cmake can be patched subtec_install_fn ${PLAYER_DIR} ${LOCAL_DEPS_BUILD_DIR} fi - + # Build cd subtec-app/subttxrend-app/x86_builder/ @@ -82,3 +82,4 @@ function subtec_install_build_fn() { fi fi } + diff --git a/scripts/tools.sh b/scripts/tools.sh index b91106a7..6094d10a 100755 --- a/scripts/tools.sh +++ b/scripts/tools.sh @@ -2,7 +2,7 @@ function tools_banner_fn () { - + echo "" echo " ###### #### # #### #### ###### ### # #### #### " echo " ## ## ## ### ### ### ## ## # ## ## ## " @@ -17,7 +17,7 @@ function tools_banner_fn () function tools_arch_fn () { - if [[ "${OSTYPE}" == "darwin"* ]]; then + if [[ "${OSTYPE}" == "darwin"* ]]; then ARCH=$(uname -m) if [[ ${ARCH} == "x86_64" ]]; then export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH @@ -40,7 +40,7 @@ function tools_arch_fn () function tools_install_fn () { - if [[ "${OSTYPE}" == "darwin"* ]]; then + if [[ "${OSTYPE}" == "darwin"* ]]; then echo "Checking Xcode..." @@ -65,12 +65,12 @@ function tools_install_fn () if [[ -z ${CUR_XTOOLS_VER} || -z ${CUR_XCODE_VER} ]] ; then echo "Xcode or Xcode CLI tools installation not found." echo -e " - XCode and Xcode Command Line Tools can be found here. + XCode and Xcode Command Line Tools can be found here. https://developer.apple.com/download/all/?q=xcode%20${CUR_MACOS_VER} - - Download the required XIP file(s). Double-click the XIP file(s) to make its content available - (the name will show up in the Finder sidebar), and a window generally opens also showing the - content. Drag the application from the dialog into the Applications directory to install (you + + Download the required XIP file(s). Double-click the XIP file(s) to make its content available + (the name will show up in the Finder sidebar), and a window generally opens also showing the + content. Drag the application from the dialog into the Applications directory to install (you may need an administrator password). Wait for the copy process to finish. Then run the following: @@ -85,11 +85,11 @@ function tools_install_fn () if XPATH=$( xcode-select --print-path ) && test -d "${XPATH}" && test -x "${XPATH}" ; then echo "Xcode tools installed in '${XPATH}'" - else + else #... isn't correctly installed echo "Xcode tools installation not found." return 1 - fi + fi # Check if homebrew is installed if [[ -z $(which brew) ]] ; then @@ -127,7 +127,7 @@ echo "" echo "********PLAYER install summary end*************" echo -n "build completed $(date) elapsed time " -if [[ "${OSTYPE}" == "darwin"* ]]; then +if [[ "${OSTYPE}" == "darwin"* ]]; then date -ju -f "%s" ${SECONDS} +%T else date -u -d "@$SECONDS" +%T diff --git a/subtitle/vttCue.h b/subtitle/vttCue.h index cae71519..8d5b1912 100644 --- a/subtitle/vttCue.h +++ b/subtitle/vttCue.h @@ -19,7 +19,7 @@ /** * @file vttCue.h - * + * * @brief Provides data structure to hold a WebVTT cue data * */ diff --git a/test/utests/CMakeLists.txt b/test/utests/CMakeLists.txt new file mode 100644 index 00000000..aa428e6a --- /dev/null +++ b/test/utests/CMakeLists.txt @@ -0,0 +1,89 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2022 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. + +cmake_minimum_required(VERSION 3.10.3) + +project(UnitTests) + +# Don't include CTestDashboardTargets in GUI projects +set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED 1) +include(CTest) + +set(PLAYER_ROOT "../../") + +find_package(PkgConfig REQUIRED) + +pkg_check_modules(GTEST REQUIRED gtest) +pkg_check_modules(GMOCK REQUIRED gmock) +pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0) +pkg_check_modules(GSTREAMERBASE REQUIRED gstreamer-app-1.0) +pkg_check_modules(GLIB REQUIRED glib-2.0) +pkg_check_modules(LibXml2 REQUIRED libxml-2.0) +pkg_check_modules(LIBCJSON REQUIRED libcjson) + +if (NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) + pkg_search_module(JSCORE REQUIRED javascriptcoregtk-4.1 javascriptcoregtk-4.0) + find_path (JSC_INCDIR JavaScriptCore/JavaScript.h HINTS ${JSCORE_INCLUDE_DIRS} REQUIRED) +endif() + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_GST1 -ggdb") +if(NOT CMAKE_SYSTEM_NAME MATCHES "Linux") + add_compile_options(-fsanitize=address) + add_link_options(-fsanitize=address) +endif() +STRING(REPLACE " -Werror=effc++" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) #disabling effc++ compiler warnings for utest directory +#if (CMAKE_PLATFORM_UBUNTU ) +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override") +#endif() + +add_definitions(-DENABLE_LOGGING) + +add_subdirectory(fakes) +if (CMAKE_XCODE_BUILD_SYSTEM) + # ARM64 will fail to build utest schemes in XCode unless this is set + set(CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE PRE_TEST) +endif() + +enable_testing() + +# Add the player/test/common directory to the module include path for access to +# common CMake test functionality, like the CodeCoverage.cmake module. +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../common") + +if (CMAKE_PLATFORM_UBUNTU) + link_directories(${GTEST_LIBRARY_DIRS} ${GMOCK_LIBRARY_DIRS}) +endif() + +function(player_utest_run_add test_suite) + if (CMAKE_RDKE_TEST_RUN) + # Add the entire googletest test suite to ctest. This means that ctest runs each test + # suite executable only once, so the test_details.json googletest JSON output file + # required by RDK-E does not get overwritten. + add_test(NAME ${test_suite} COMMAND ${test_suite}) + else() + # Discover tests by running the googletest test suite executable with "--gtest_list_tests", + # and add each test individually to ctest. This results in ctest running each test suite + # executable separately for each test, giving greater opportunity for parallelism and + # stdout per-test rather than per-suite, amongst other advantages. There is no issue with + # overwriting of googletest JSON output files, because ctest itself handles the output to + # file via its "--output-junit" argument, which creates a JUnit XML output file instead. + gtest_discover_tests(${test_suite} DISCOVERY_TIMEOUT 10 TEST_PREFIX ${test_suite}:) + endif() +endfunction() +add_subdirectory(tests) diff --git a/test/utests/ReadMe.md b/test/utests/ReadMe.md new file mode 100644 index 00000000..abd6b476 --- /dev/null +++ b/test/utests/ReadMe.md @@ -0,0 +1,143 @@ +# AAMP Microtests + +A test infrastructure using GoogleTest C++ testing and mocking framework, to verify the behavior of individual AAMP objects. + +CTest is a testing tool that is part of CMake, and is used to automatically execute all the tests, and provides a report of the tests run, whether they passed/failed and time taken. It can be configured to run tests in parallel, output logging on failure, run specific tests etc. + +These tests should be extended on addition of any new functionality. + +These tests should be run on any change to: + - Test any new functionality + - Check for any regression caused by the change + - Check the build has not been broken due to an API change + +NOTE: Writing microtests is a really useful tool in improving code quality but if they are implemented incorrectly they can have a detrimental impact on build times and fail to find the errors they are meant to highlight. If you are new to microtests we strongly recommend you read the following to understand how to write them well: + + - **See [GoogleTest User's Guide](https://google.github.io/googletest/)** + - **See [Testing With CMake and CTest](https://cmake.org/cmake/help/book/mastering-cmake/chapter/Testing%20With%20CMake%20and%20CTest.html)** + +## Pre-requisites to building: + +AAMP installed using install-aamp.sh (-c if code coverage is neeeded) script which: + - installs headers from dependent libraries + - installs GoogleTest and GoogleMock + - installs jq + +## Build and run microtests using script: + +From the *utests* folder run: + +``` +./run.sh +``` +## To run tests and generate combined report in json format + +./run.sh -e + +Report can be found in utests/TestReport.json + +## Check line coverage in microtests: + +For code coverage install-aamp.sh -c +must have been run first to generate a baseline set of aamp files. + +From the *utests* directory, run: + +``` +./run.sh -c +``` + +The aggregated results can be found in the following html file: +*utests/CombinedCoverage/index.html* + +**Note:** + +This takes considerably longer than running the script with no options + +## To build and run the microtests manually: + +From the *utests* folder run: + +``` +mkdir build +cd build +cmake ../ +make +ctest +``` + +## Some examples of additional parameters that can be used with ctest + +To output logging run ctest with verbose option: + +``` +ctest --verbose +``` + +To output logging when a test fails : + +``` +ctest --output-on-failure +``` + +Tests can be run in parallel using -j option, for example: + +``` +ctest -j 4 +``` + +Specific tests can be run using ctest's regex selectors, see ctest --help. For example: + +``` +ctest -R PrivateInstance.*PositionAlready +``` + +## Directory Structure + +### fakes + +A CMake library containing fake/stub implementations of class methods, to allow compiling of class under test in isolation; these fakes are common to all tests. + +Implementation can be extended to call a mock instance, to allow testing of expectations. For example, see FakePrivateInstanceAAMP.cpp where some methods being used by existing tests have been extended to call a mock of PrivateInstanceAAMP if the mock has been constructed. + +The files in here will likely need to be updated for any API changes/additions made to AAMP modules, otherwise unresolved symbol errors are likely to be seen. + +### mocks + +A directory containing Google mocks; these mocks are common to all tests. + +See [gMock for Dummies](https://google.github.io/googletest/gmock_for_dummies.html) + +### tests + +A directory containing the tests for each of AAMP's modules contained within their own sub-directory. +The CMakeLists.txt file adds all the modules' subdirectories. + +See [CMake Modules - GoogleTest](https://cmake.org/cmake/help/latest/module/GoogleTest.html) + +### *Module* test folder + +One or more Googletest executables generated from CMake. + +The CMakeLists.txt contains the instructions for creating the module's target. e.g. +- EXEC_NAME to be same as directory name //Required to generate json report +- Necessary include paths for that module +- The module source file +- The google test file(s) +- The directive, gtest_discover_tests, to discover google tests from the test executable + +General guidance: + - A test class for each area of functionality of the module under test. + - Use of mocks, and testing of expectations, for external calls made by the module + - Use of microtests should not significantly impact build times, and are intended to be run on every change, as such they should be implemented to run as quickly as possible (all tests to run in seconds rather than minutes); avoiding sleeps and other timing delays. + +It may be desired to use the real implementation of an external class, rather than the mock; which can be done in CMakeLists.txt. Also if some tests are best implemented using a mock, and others using the real implementation then it should be possible to create multiple executables configured as such. + +For guidance on creating GoogleTest please see [GoogleTest User's Guide](https://google.github.io/googletest/). + +### Running debugger + +gdb can be run on an individual test via: +cd build/tests/SomeTest +gdb .. +. diff --git a/test/utests/cmake_exclude_file.list b/test/utests/cmake_exclude_file.list new file mode 100644 index 00000000..fbfbd7e9 --- /dev/null +++ b/test/utests/cmake_exclude_file.list @@ -0,0 +1,16 @@ +# A list of files to exclude from the coverage report. +# Set NO_EXCLUDE_DIR in the CMakeLists.txt of any new test so it can be removed from the exclude list. + + get_filename_component(PARENT_DIR ${PROJECT_SOURCE_DIR} DIRECTORY) + get_filename_component(BASE_DIR ${PARENT_DIR} DIRECTORY) + set(COVERAGE_EXCLUDES + "/usr/*" + "${BASE_DIR}/.libs/lib/include/*" + "${BASE_DIR}/subtec/subtecparser/*" + "${BASE_DIR}/test/*" + "/Applications/*" + "./v1/*") + + if (NO_EXCLUDE_DIR) + list(REMOVE_ITEM COVERAGE_EXCLUDES ${NO_EXCLUDE_DIR}) + endif() diff --git a/test/utests/drm/mocks/FakeID3Metadata.cpp b/test/utests/drm/mocks/FakeID3Metadata.cpp new file mode 100644 index 00000000..66345891 --- /dev/null +++ b/test/utests/drm/mocks/FakeID3Metadata.cpp @@ -0,0 +1,81 @@ + +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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 "ID3Metadata.hpp" + +#include +#include +#include + +namespace aamp +{ +namespace id3_metadata +{ +namespace helpers +{ +//constexpr size_t min_id3_header_length = 3u; +//constexpr size_t id3v2_header_size = 10u; + +bool IsValidMediaType(AampMediaType) +{ + return true; +} + +bool IsValidHeader(const uint8_t*, size_t) +{ + return true; +} + +size_t DataSize(const uint8_t*) +{ + return 0; +} + +std::string ToString(const uint8_t*, size_t) +{ + std::string out{}; + return out; +} + +} // namespace helpers + +MetadataCache::MetadataCache() : mCache{} +{ +} + +MetadataCache::~MetadataCache() +{ +} + +void MetadataCache::Reset() +{ +} + +bool MetadataCache::CheckNewMetadata(AampMediaType mediaType, const std::vector& data) const +{ + return false; +} + +void MetadataCache::UpdateMetadataCache(AampMediaType mediaType, std::vector data) +{ +} + +} // namespace id3_metadata +} // namespace aamp diff --git a/test/utests/drm/mocks/Fakeopencdm.cpp b/test/utests/drm/mocks/Fakeopencdm.cpp new file mode 100644 index 00000000..7ef1edb6 --- /dev/null +++ b/test/utests/drm/mocks/Fakeopencdm.cpp @@ -0,0 +1,163 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "open_cdm.h" +#include "open_cdm_adapter.h" +#include + +#include "Fakeopencdm.h" +#include "MockOpenCdm.h" +#include "PlayerLogManager.h" + +MockOpenCdm* g_mockopencdm = nullptr; + +typedef struct _MockOpenCdmInstanceData +{ + MockOpenCdmSessionInfo sessionInfo; + MockOpenCdmCallbacks callbacks; + void* mockUserData; // User data from the client of the mock +} MockOpenCdmInstanceData; + +static MockOpenCdmInstanceData f_mockInstance; + +/* BEGIN - methods to access mock functionality */ +MockOpenCdmSessionInfo* MockOpenCdmGetSessionInfo() +{ + return &f_mockInstance.sessionInfo; +} + +void MockOpenCdmSetCallbacks(MockOpenCdmCallbacks callbacks, void* mockUserData) +{ + f_mockInstance.callbacks = callbacks; + f_mockInstance.mockUserData = mockUserData; +} + +void MockOpenCdmReset(void) +{ + memset(&f_mockInstance, 0, sizeof(f_mockInstance)); +} + +/* END - methods to access mock functionality */ + +struct OpenCDMSystem* opencdm_create_system(const char keySystem[]) +{ + if (g_mockopencdm != nullptr) + { + return g_mockopencdm->opencdm_create_system(keySystem); + } + return nullptr; +} + +OpenCDMError opencdm_construct_session(struct OpenCDMSystem* system, const LicenseType licenseType, + const char initDataType[], const uint8_t initData[], + const uint16_t initDataLength, const uint8_t CDMData[], + const uint16_t CDMDataLength, + OpenCDMSessionCallbacks* callbacks, void* userData, + struct OpenCDMSession** session) +{ + OpenCDMError retValue = ERROR_NONE; + *session = nullptr; + MW_LOG_ERR("TRACE Enter opencdm_constructSession"); + if (g_mockopencdm != nullptr) + { + retValue = g_mockopencdm->opencdm_construct_session( + system, licenseType, initDataType, initData, initDataLength, CDMData, CDMDataLength, + callbacks, userData, session); + } +#if 0 + MW_LOG_ERR("TRACE2"); + f_mockInstance.sessionInfo.session = *session; + f_mockInstance.sessionInfo.callbacks = *callbacks; + f_mockInstance.sessionInfo.userData = userData; + MW_LOG_ERR("TRACE3"); + if (f_mockInstance.callbacks.constructSessionCallback) + { + f_mockInstance.callbacks.constructSessionCallback(&f_mockInstance.sessionInfo, + f_mockInstance.mockUserData); + } + MW_LOG_ERR("TRACE4"); +#endif + return retValue; +} + +OpenCDMError opencdm_destruct_system(struct OpenCDMSystem* system) +{ + return ERROR_NONE; +} + +KeyStatus opencdm_session_status(const struct OpenCDMSession* session, const uint8_t keyId[], + const uint8_t length) +{ + return Usable; +} + +OpenCDMError opencdm_session_update(struct OpenCDMSession* session, const uint8_t keyMessage[], + const uint16_t keyLength) +{ + OpenCDMError retValue = ERROR_NONE; + + if (g_mockopencdm != nullptr) + { + retValue = g_mockopencdm->opencdm_session_update(session, keyMessage, keyLength); + } + + if (f_mockInstance.callbacks.sessionUpdateCallback) + { + f_mockInstance.callbacks.sessionUpdateCallback(&f_mockInstance.sessionInfo, keyMessage, + keyLength); + } + + return retValue; +} + +OpenCDMError opencdm_gstreamer_session_decrypt(struct OpenCDMSession* session, GstBuffer* buffer, + GstBuffer* subSample, const uint32_t subSampleCount, + GstBuffer* IV, GstBuffer* keyID, + uint32_t initWithLast15) +{ + return ERROR_NONE; +} + +OpenCDMError opencdm_session_decrypt(struct OpenCDMSession* session, uint8_t encrypted[], + const uint32_t encryptedLength, + const EncryptionScheme encScheme, + const EncryptionPattern pattern, const uint8_t* IV, + uint16_t IVLength, const uint8_t* keyId, + const uint16_t keyIdLength, uint32_t initWithLast15) +{ + if (g_mockopencdm != nullptr) + { + return g_mockopencdm->opencdm_session_decrypt(session, encrypted, encryptedLength, + encScheme, pattern, IV, IVLength, keyId, + keyIdLength, initWithLast15); + } + return ERROR_NONE; +} + +OpenCDMError opencdm_session_close(struct OpenCDMSession* session) +{ + return ERROR_NONE; +} + +OpenCDMError opencdm_destruct_session(struct OpenCDMSession* session) +{ + return ERROR_NONE; +} diff --git a/test/utests/drm/mocks/Fakeopencdm.h b/test/utests/drm/mocks/Fakeopencdm.h new file mode 100644 index 00000000..2b7bb157 --- /dev/null +++ b/test/utests/drm/mocks/Fakeopencdm.h @@ -0,0 +1,57 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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. + */ + +#ifndef FAKE_OPEN_CDM_H +#define FAKE_OPEN_CDM_H + +#include "open_cdm.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + typedef struct _MockSessionInfo + { + void *session; + void *userData; // User data from the client of OCDM + OpenCDMSessionCallbacks callbacks; + } MockOpenCdmSessionInfo; + + typedef void (*MockConstructSessionCallback)(const MockOpenCdmSessionInfo *session, + void *mockUserData); + typedef void (*MockSessionUpdateCallback)(const MockOpenCdmSessionInfo *session, + const uint8_t keyMessage[], const uint16_t keyLength); + + typedef struct _MockOpenCdmCallbacks + { + MockConstructSessionCallback constructSessionCallback; + MockSessionUpdateCallback sessionUpdateCallback; + } MockOpenCdmCallbacks; + + MockOpenCdmSessionInfo *MockOpenCdmGetSessionInfo(); + + void MockOpenCdmSetCallbacks(MockOpenCdmCallbacks callbacks, void *mockUserData); + + void MockOpenCdmReset(void); + +#ifdef __cplusplus +} +#endif + +#endif /* FAKE_OPEN_CDM_H */ diff --git a/test/utests/drm/mocks/MockOpenCdm.h b/test/utests/drm/mocks/MockOpenCdm.h new file mode 100644 index 00000000..2e4bcc87 --- /dev/null +++ b/test/utests/drm/mocks/MockOpenCdm.h @@ -0,0 +1,54 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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. + */ + +#ifndef AAMP_MOCK_OPEN_CDM_H +#define AAMP_MOCK_OPEN_CDM_H + +#include "open_cdm.h" +#include + +class MockOpenCdm +{ +public: + MOCK_METHOD(OpenCDMError, opencdm_session_decrypt, + (struct OpenCDMSession * session, uint8_t encrypted[], + const uint32_t encryptedLength, const EncryptionScheme encScheme, + const EncryptionPattern pattern, const uint8_t* IV, uint16_t IVLength, + const uint8_t* keyId, const uint16_t keyIdLength, uint32_t initWithLast15)); + MOCK_METHOD(OpenCDMError, opencdm_destruct_system, (struct OpenCDMSystem* system)); + MOCK_METHOD(OpenCDMSystem*, opencdm_create_system, (const char keySystem[])); + MOCK_METHOD(OpenCDMError, opencdm_construct_session, + (struct OpenCDMSystem * system, const LicenseType licenseType, + const char initDataType[], const uint8_t initData[], const uint16_t initDataLength, + const uint8_t CDMData[], const uint16_t CDMDataLength, + OpenCDMSessionCallbacks* callbacks, void* userData, + struct OpenCDMSession** session)); + MOCK_METHOD(OpenCDMError, opencdm_session_update, + (struct OpenCDMSession * session, const uint8_t keyMessage[], + const uint16_t keyLength)); + MOCK_METHOD(OpenCDMError, opencdm_session_close, (struct OpenCDMSession* session)); + MOCK_METHOD(OpenCDMError, opencdm_destruct_session, (struct OpenCDMSession* session)); + MOCK_METHOD(KeyStatus, opencdm_session_status, (const struct OpenCDMSession* session, + const uint8_t keyId[], + const uint8_t length)); +}; + +extern MockOpenCdm* g_mockopencdm; + +#endif /* AAMP_MOCK_OPEN_CDM_H */ diff --git a/test/utests/drm/mocks/gstMocks.c b/test/utests/drm/mocks/gstMocks.c new file mode 100644 index 00000000..3e58725f --- /dev/null +++ b/test/utests/drm/mocks/gstMocks.c @@ -0,0 +1,100 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +GType _gst_caps_type = 0; +GType _gst_buffer_type = 0; + + +GstVideoTimeCodeMeta * gst_buffer_add_video_time_code_meta_full( + GstBuffer * buffer, + guint fps_n, + guint fps_d, + GDateTime * latest_daily_jam, + GstVideoTimeCodeFlags flags, + guint hours, + guint minutes, + guint seconds, + guint frames, + guint field_count) +{ + return NULL; +} + +gboolean gst_buffer_map(GstBuffer *buffer, GstMapInfo *info, GstMapFlags flags) +{ + return TRUE; +} + +void gst_buffer_unmap(GstBuffer *buffer, GstMapInfo *info) +{ +} + +GstByteReader *gst_byte_reader_new(const guint8 *data, guint size) +{ + static GstByteReader byte_reader; + return &byte_reader; +} + +gboolean gst_byte_reader_set_pos(GstByteReader *reader, guint pos) +{ + return TRUE; +} + +void gst_byte_reader_free(GstByteReader *reader) +{ +} + +gboolean gst_caps_is_empty (const GstCaps * caps) +{ + return FALSE; +} + +GstMeta * gst_buffer_get_meta (GstBuffer * buffer, GType api) +{ + return NULL; +} + +GstStructure * gst_structure_new (const gchar * name, const gchar * firstfield, ...) +{ + return NULL; +} + +void gst_structure_set (GstStructure * structure, const gchar * field, ...) +{ +} + +GstProtectionMeta * gst_buffer_add_protection_meta (GstBuffer * buffer, GstStructure * info) +{ + return NULL; +} + +GType gst_protection_meta_api_get_type (void) +{ + return 0; +} + +void g_object_get(gpointer object, const gchar *first_property_name, ...) +{ +} diff --git a/test/utests/drm/ocdm/open_cdm.h b/test/utests/drm/ocdm/open_cdm.h new file mode 100644 index 00000000..0d87f42d --- /dev/null +++ b/test/utests/drm/ocdm/open_cdm.h @@ -0,0 +1,639 @@ +/* + * Copyright 2016-2017 TATA ELXSI + * Copyright 2016-2017 Metrological + * + * 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. + */ + +#ifndef OPEN_CDM_H +#define OPEN_CDM_H + +// WPEWebkit implementation is using the following header file to integrate +// their solution with +// DRM systems (PlayReady/WideVine/ClearKey). +// The implementation behind this class/interface exists in two flavors. +// 1) Fraunhofers adapted reference implementation, based on SUNRPC +// 2) Metrologicals framework, based on their proprietary RPC mechanism. +// +// The second option exists because during testing the reference/adapted +// implementation of Frauenhofer +// it was observed: +// - Older implementations of ucLibc had different dynamic characteristics that +// caused deadlocks +// - Message exchange over the SUNRPC mechanism is using continous heap memory +// allocations/deallocactions, +// leading to a higher risk of memory fragmentation. +// - SUNRPC only works on UDP/TCP, given the nature and size of the messages, +// UDP was not an option so TCP +// is used. There is no domain socket implementation for the SUNRPC mechanism. +// Domain sockets transfer +// data, as an average, twice as fast as TCP sockets. +// - SUNRPC requires an external process (bind) to do program number lookup to +// TCP port connecting. Currently +// the Frauenhofer OpenCDMi reference implementation is the only +// implementation requiring this service on +// most deplyments with the WPEWebkit. +// - Common Vulnerabilities and Exposures (CVE's) have been reported with the +// SUNRPC that have not been resolved +// on most platforms where the solution is deployed. +// - The Metrological RPC mechanism allows for a configurable in or out of +// process deplyment of the OpenCDMi +// deployment without rebuilding. +// +// So due to performance and security exploits it was decided to offer a second +// implementation of the OpenCDMi +// specification that did notrequire to change the WPEWebKit + +#include +#include + +#include +#include + +#ifndef EXTERNAL +#ifdef _MSVC_LANG +#ifdef OCDM_EXPORTS +#define EXTERNAL __declspec(dllexport) +#else +#define EXTERNAL __declspec(dllimport) +#endif +#else +#define EXTERNAL __attribute__ ((visibility ("default"))) +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WINDOWS) + #if !defined(OCDM_EXPORTS) + #pragma comment(lib, "ocdm.lib") + #endif + + /** + * Sometimes the compiler would like to be smart, if we do not reference + * anything here + * and you enable the rightflags, the linker drops the dependency. Than + * Proxy/Stubs do + * not get loaded, so lets make the instantiation of the ProxyStubs explicit !!! + */ + EXTERNAL void ForceLinkingOfOpenCDM(); +#endif + +#define SESSION_ID_LEN 16 +#define MAX_NUM_SECURE_STOPS 8 + +/** + * Represents an OCDM system + */ +struct OpenCDMSystem; + +/** + * Represents a OpenCDM session, use this one to decrypt. + */ +struct OpenCDMSession; + +typedef enum { + Temporary = 0, + PersistentUsageRecord, + PersistentLicense +} LicenseType; + +// ISO/IEC 23001-7 defines two Common Encryption Schemes with Full Sample and Subsample modes +typedef enum { + Clear = 0, + AesCtr_Cenc, // AES-CTR mode and Sub-Sample encryption + AesCbc_Cbc1, // AES-CBC mode and Sub-Sample encryption + AesCtr_Cens, // AES-CTR mode and Sub-Sample + patterned encryption + AesCbc_Cbcs // AES-CBC mode and Sub-Sample + patterned encryption + Constant IV +} EncryptionScheme; + +typedef enum +{ + MediaType_Unknown = 0, + MediaType_Video, + MediaType_Audio, + MediaType_Data +} OcdmMediaType; // Renamed from "MediaType" to avoid compile error, as AAMP also has a MediaType enum + +//CENC3.0 pattern is a number of encrypted blocks followed a number of clear blocks after which the pattern repeats. +typedef struct { + uint32_t encrypted_blocks; + uint32_t clear_blocks; +} EncryptionPattern; + +typedef struct { + uint16_t clear_bytes; + uint32_t encrypted_bytes; +} SubSampleInfo; + +typedef struct { + EncryptionScheme scheme; // Encryption scheme used in this sample + EncryptionPattern pattern; // Encryption Pattern used in this sample + uint8_t* iv; // Initialization vector(IV) to decrypt this sample. Can be NULL, in that case and IV of all zeros is assumed. + uint8_t ivLength; // Length of IV + uint8_t* keyId; // ID of Key required to decrypt this sample + uint8_t keyIdLength; // Length of KeyId + uint8_t subSampleCount; // Number or Sub-Samples in this sample + SubSampleInfo* subSample; // SubSample mapping - Repeating pair of Clear bytes and Encrypted Bytes representing each subsample. +} SampleInfo; + +// Provides information about the current stream +typedef struct { + uint16_t height; + uint16_t width; + OcdmMediaType media_type; +} MediaProperties; + + +/** + * Key status. + */ +typedef enum { + Usable = 0, + Expired, + Released, + OutputRestricted, + OutputRestrictedHDCP22, + OutputDownscaled, + StatusPending, + InternalError, + HWError +} KeyStatus; + +/** + * OpenCDM error code. Zero always means success. + */ +typedef enum { + ERROR_NONE = 0, + ERROR_UNKNOWN = 1, + ERROR_MORE_DATA_AVAILABLE = 2, + ERROR_INTERFACE_NOT_IMPLEMENTED = 3, + ERROR_BUFFER_TOO_SMALL = 4, + ERROR_INVALID_ACCESSOR = 0x80000001, + ERROR_KEYSYSTEM_NOT_SUPPORTED = 0x80000002, + ERROR_INVALID_SESSION = 0x80000003, + ERROR_INVALID_DECRYPT_BUFFER = 0x80000004, + ERROR_OUT_OF_MEMORY = 0x80000005, + ERROR_METHOD_NOT_IMPLEMENTED = 0x80000006, + ERROR_FAIL = 0x80004005, + ERROR_INVALID_ARG = 0x80070057, + ERROR_SERVER_INTERNAL_ERROR = 0x8004C600, + ERROR_SERVER_INVALID_MESSAGE = 0x8004C601, + ERROR_SERVER_SERVICE_SPECIFIC = 0x8004C604, + ERROR_BUSY_CANNOT_INITIALIZE = 0x8004DD00 + +} OpenCDMError; + +/** + * OpenCDM bool type. 0 is false, 1 is true. + */ +typedef enum { + OPENCDM_BOOL_FALSE = 0, + OPENCDM_BOOL_TRUE = 1 +} OpenCDMBool; + +/** + * Registered callbacks with OCDM sessions. + */ +typedef struct { + /** + * Request of process of DRM challenge data. Server is indicated by \ref url. The response of the server + * needs to be send to \ref opencdm_session_update. + * + * \param session The session the notification applies to. + * \param userData Pointer passed along when \ref opencdm_construct_session was issued. + * \param url Target URL to send challenge to. + * \param challenge Buffer containing challenge. + * \param challengeLength Length of challenge (in bytes). + */ + void (*process_challenge_callback)(struct OpenCDMSession* session, void* userData, const char url[], const uint8_t challenge[], const uint16_t challengeLength); + + /** + * Called when status of a key changes. Use \ref opencdm_session_status to find out new key status. + * + * \param session The session the notification applies to. + * \param userData Pointer passed along when \ref opencdm_construct_session was issued. + * \param keyId Buffer containing key ID. + * \param length Length of key ID buffer. + */ + void (*key_update_callback)(struct OpenCDMSession* session, void* userData, const uint8_t keyId[], const uint8_t length); + + /** + * Called when an error message is received from the DRM system + * + * \param session The session the notification applies to. + * \param userData Pointer passed along when \ref opencdm_construct_session was issued. + * \param message Text string, null terminated, from the DRM session. + */ + void (*error_message_callback)(struct OpenCDMSession* session, void* userData, const char message[]); + + /** + * Called after all known key status changes were reported. + * + * \param session The session the notification applies to. + * \param userData Pointer passed along when \ref opencdm_construct_session was issued. + */ + void (*keys_updated_callback)(const struct OpenCDMSession* session, void* userData); +} OpenCDMSessionCallbacks; + +/** + * \brief Creates DRM system. + * + * \return \ref OpenCDMAccessor instance, NULL on error. + */ +EXTERNAL struct OpenCDMSystem* opencdm_create_system(const char keySystem[]); + +/** + * \brief Creates DRM system. + * + * \param system Output parameter that will contain pointer to instance of \ref OpenCDMSystem. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_create_system_extended(const char keySystem[], struct OpenCDMSystem** system); + +/** + * Destructs an \ref OpenCDMAccessor instance. + * \param system \ref OpenCDMAccessor instance to desctruct. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_destruct_system(struct OpenCDMSystem* system); + +/** + * \brief Checks if a DRM system is supported. + * + * \param system Instance of \ref OpenCDMAccessor. + * \param keySystem Name of required key system (e.g. + * "com.microsoft.playready"). + * \param mimeType MIME type. + * \return Zero if supported, Non-zero otherwise. + * \remark mimeType is currently ignored. + */ +EXTERNAL OpenCDMError opencdm_is_type_supported(const char keySystem[], + const char mimeType[]); + +/** + * \brief Retrieves DRM system specific metadata. + * + * \param system Instance of \ref OpenCDMAccessor. + * \param metadata, buffer to write metadata into, always 0 terminated (also when not large enough to hold all data) except when metadata is + * Null of course. Null allowed to retrieve required size needed for this buffer in metadataSize to be able to allocate required buffer + * for subsequent call to opencdm_is_type_supported + * \param metadataSize, in: size of metadata buffer, out: required size to hold all data available when return value is ERROR_MORE_DATA_AVAILBALE, + * , number of characters written into metadata (incl 0 terminator) otherwise. Note in case metadata could not hold all data but was not of zero + * length it is filled up to the maximum size (still zero terminated) but also ERROR_MORE_DATA_AVAILBALE is returned with the required size needed + * to hold all data + * \return Zero on success, non-zero on error. ERROR_MORE_DATA_AVAILBALE when the buffer was not large enough to hold all the data available. + */ +EXTERNAL OpenCDMError opencdm_system_get_metadata(struct OpenCDMSystem* system, + char metadata[], + uint16_t* metadataSize); + +/** + * \brief Returns string describing version of DRM system. + * + * \param system Instance of \ref OpenCDMAccessor. + * \param keySystem Name of queried key system (e.g. + * "com.microsoft.playready"). + * \param versionStr Char buffer to receive NULL-terminated version string. + * (Should as least be 64 chars long.) + * \return Zero if successful, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_system_get_version(struct OpenCDMSystem* system, + char versionStr[]); + +/** + * \brief Returns time according to DRM system. + * Some systems (e.g. PlayReady) keep their own clocks, for example to prevent + * rollback. Systems + * not implementing their own clock can return the system time. + * + * \param system Instance of \ref OpenCDMAccessor. + * \param keySystem Name of queried key system (e.g. "com.microsoft.playready"). + * \param time Output variable that will contain DRM system time. + * \return Zero if successful, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_system_get_drm_time(struct OpenCDMSystem* system, + uint64_t* time); + +/** + * \brief Maps key ID to \ref OpenCDMSession instance. + * + * In some situations we only have the key ID, but need the specific \ref + * OpenCDMSession instance that + * belongs to this key ID. This method facilitates this requirement. + * \param system Instance of \ref OpenCDMAccessor. + * \param keyId Array containing key ID. + * \param length Length of keyId array. + * \param maxWaitTime Maximum allowed time to block (in milliseconds). + * \return \ref OpenCDMSession belonging to key ID, or NULL when not found or + * timed out. This instance + * also needs to be destructed using \ref opencdm_session_destruct. + */ +EXTERNAL struct OpenCDMSession* opencdm_get_session(const uint8_t keyId[], + const uint8_t length, + const uint32_t waitTime); + +/** + * \brief Maps key ID to \ref OpenCDMSession instance within the given system instance. + * + * In some situations we only have the key ID, but need the specific \ref + * OpenCDMSession instance that + * belongs to this key ID. This method facilitates this requirement. + * \param system Instance of \ref OpenCDMSystem. + * \param keyId Array containing key ID. + * \param length Length of keyId array. + * \param maxWaitTime Maximum allowed time to block (in milliseconds). + * \return \ref OpenCDMSession belonging to key ID, or NULL when not found or + * timed out. This instance + * also needs to be destructed using \ref opencdm_session_destruct. + */ +EXTERNAL struct OpenCDMSession* opencdm_get_system_session(struct OpenCDMSystem* system, const uint8_t keyId[], + const uint8_t length, const uint32_t waitTime); + +/** + * \brief Gets support server certificate. + * + * Some DRMs (e.g. WideVine) use a system-wide server certificate. This method + * gets if system has support for that certificate. + * \param system Instance of \ref OpenCDMAccessor. + * \return Non-zero on success, zero on error. + */ +EXTERNAL OpenCDMBool opencdm_system_supports_server_certificate( + struct OpenCDMSystem* system); + +/** + * \brief Sets server certificate. + * + * Some DRMs (e.g. WideVine) use a system-wide server certificate. This method + * will set that certificate. Other DRMs will ignore this call. + * \param system Instance of \ref OpenCDMAccessor. + * \param keySystem Name of key system to set server certificate for. + * \param serverCertificate Buffer containing certificate data. + * \param serverCertificateLength Buffer length of certificate data. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_system_set_server_certificate( + struct OpenCDMSystem* system, + const uint8_t serverCertificate[], const uint16_t serverCertificateLength); + +/** + * \brief Get metrics associated with a DRM system. + * + * Some DRMs (e.g. WideVine) offer metric data that can be used for any + * analyses. This function retrieves the metric data of the passed in + * system. It is up to the callee to interpret the baniary data correctly. + * \param system Instance of \ref OpenCDMAccessor. + * \param bufferLength Actual buffer length of the buffer parameter, on return + * it holds the number of bytes actually written in it. + * \param buffer Buffer length of buffer that can hold the metric data. + * \return Zero on success, non-zero on error. + */ + +EXTERNAL OpenCDMError opencdm_get_metric_system_data(struct OpenCDMSystem* system, + uint32_t* bufferLength, + uint8_t* buffer); + +/** + * \brief Create DRM session (for actual decrypting of data). + * + * Creates an instance of \ref OpenCDMSession using initialization data. + * \param system Instance of \ref OpenCDMAccessor. + * \param keySystem DRM system to create the session for. + * \param licenseType DRM specifc signed integer selecting License Type (e.g. + * "Limited Duration" for PlayReady). + * \param initDataType Type of data passed in \ref initData. + * \param initData Initialization data. + * \param initDataLength Length (in bytes) of initialization data. + * \param CDMData CDM data. + * \param CDMDataLength Length (in bytes) of \ref CDMData. + * \param callbacks the instance of \ref OpenCDMSessionCallbacks with callbacks to be called on events. + * \param userData the user data to be passed back to the \ref OpenCDMSessionCallbacks callbacks. + * \param session Output parameter that will contain pointer to instance of \ref OpenCDMSession. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_construct_session(struct OpenCDMSystem* system, const LicenseType licenseType, + const char initDataType[], const uint8_t initData[], const uint16_t initDataLength, + const uint8_t CDMData[], const uint16_t CDMDataLength, OpenCDMSessionCallbacks* callbacks, void* userData, + struct OpenCDMSession** session); + +/** + * Destructs an \ref OpenCDMSession instance. + * \param system \ref OpenCDMSession instance to desctruct. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_destruct_session(struct OpenCDMSession* session); + +/** + * Loads the data stored for a specified OpenCDM session into the CDM context. + * \param session \ref OpenCDMSession instance. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_session_load(struct OpenCDMSession* session); + +/** + * Process a key message response. + * \param session \ref OpenCDMSession instance. + * \param keyMessage Key message to process. + * \param keyLength Length of key message buffer (in bytes). + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_session_update(struct OpenCDMSession* session, + const uint8_t keyMessage[], + const uint16_t keyLength); + +/** + * Removes all keys/licenses related to a session. + * \param session \ref OpenCDMSession instance. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_session_remove(struct OpenCDMSession* session); + +/** + * Retrieves DRM session specific metadata of a session. + * \param session \ref OpenCDMSession instance. +* \param metadata, buffer to write metadata into, always 0 terminated (also when not large enough to hold all data) except when metadata is + * Null of course. Null allowed to retrieve required size needed for this buffer in metadataSize to be able to allocate required buffer + * for subsequent call to opencdm_session_metadata + * \param metadataSize, in: size of metadata buffer, out: required size to hold all data available when return value is ERROR_MORE_DATA_AVAILBALE, + * , number of characters written into metadata (incl 0 terminator) otherwise. Note in case metadata could not hold all data but was not of zero + * length it is filled up to the maximum size (still zero terminated) but also ERROR_MORE_DATA_AVAILBALE is returned with the required size needed + * to hold all data + * \return Zero on success, non-zero on error. ERROR_MORE_DATA_AVAILBALE when the buffer was not large enough to hold all the data available. + + */ +EXTERNAL OpenCDMError opencdm_session_metadata(const struct OpenCDMSession* session, + char metadata[], + uint16_t* metadataSize); + +/** + * Let CDM know playback stopped and reset output protection + * \param session \ref OpenCDMSession instance. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_session_resetoutputprotection(struct OpenCDMSession* session); + +/** + * Gets Session ID for a session. + * \param session \ref OpenCDMSession instance. + * \return Session ID, valid as long as \ref session is valid. + */ +EXTERNAL const char* opencdm_session_id(const struct OpenCDMSession* session); + +/** + * Checks if a session has a specific keyid. Will check both BE/LE + * \param session \ref OpenCDMSession instance. + * \param length Length of key ID buffer (in bytes). + * \param keyId Key ID. + * \return 1 if keyID found else 0. + */ +EXTERNAL uint32_t opencdm_session_has_key_id(struct OpenCDMSession* session, + const uint8_t length, const uint8_t keyId[]); + +/** + * Returns status of a particular key assigned to a session. + * \param session \ref OpenCDMSession instance. + * \param keyId Key ID. + * \param length Length of key ID buffer (in bytes). + * \return key status. + */ +EXTERNAL KeyStatus opencdm_session_status(const struct OpenCDMSession* session, + const uint8_t keyId[], const uint8_t length); + +/** + * Returns error for key (if any). + * \param session \ref OpenCDMSession instance. + * \param keyId Key ID. + * \param length Length of key ID buffer (in bytes). + * \return Key error (zero if no error, non-zero if error). + */ +EXTERNAL uint32_t opencdm_session_error(const struct OpenCDMSession* session, + const uint8_t keyId[], const uint8_t length); + +/** + * Returns system error. This reference general system, instead of specific key. + * \param session \ref OpenCDMSession instance. + * \return System error code, zero if no error. + */ +EXTERNAL OpenCDMError opencdm_session_system_error(const struct OpenCDMSession* session); + +/** + * Gets buffer ID for a session. + * \param session \ref OpenCDMSession instance. + * \return Buffer ID, valid as long as \ref session is valid. + */ +EXTERNAL const char* opencdm_session_buffer_id(const struct OpenCDMSession* session); + +/** + * Closes a session. + * \param session \ref OpenCDMSession instance. + * \return zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_session_close(struct OpenCDMSession* session); + +/** + * \brief Performs decryption. + * + * This method accepts encrypted data and will typically decrypt it + * out-of-process (for security reasons). The actual data copying is performed + * using a memory-mapped file (for performance reasons). If the DRM system + * allows access to decrypted data (i.e. decrypting is not + * performed in a TEE), the decryption is performed in-place. + * \param session \ref OpenCDMSession instance. + * \param encrypted Buffer containing encrypted data. If applicable, decrypted + * data will be stored here after this call returns. + * \param encryptedLength Length of encrypted data buffer (in bytes). + * \param encScheme CENC Schemes as defined in EncryptionScheme enum + * \param pattern Encryption pattern containing number of Encrypted and Clear blocks. + * \param IV Initial vector (IV) used during decryption. Can be NULL, in that + * case and IV of all zeroes is assumed. + * \param IVLength Length of IV buffer (in bytes). + * \param keyID keyID to use for decryption + * \param keyIDLength Length of keyID buffer (in bytes). + * \param initWithLast15 Whether decryption context needs to be initialized with + * last 15 bytes. Currently this only applies to PlayReady DRM. + * \return Zero on success, non-zero on error. + */ +#ifdef __cplusplus +EXTERNAL OpenCDMError opencdm_session_decrypt(struct OpenCDMSession* session, + uint8_t encrypted[], + const uint32_t encryptedLength, + const EncryptionScheme encScheme, + const EncryptionPattern pattern, + const uint8_t* IV, uint16_t IVLength, + const uint8_t* keyId, const uint16_t keyIdLength, + uint32_t initWithLast15 = 0); + +#else +EXTERNAL OpenCDMError opencdm_session_decrypt(struct OpenCDMSession* session, + uint8_t encrypted[], + const uint32_t encryptedLength, + const EncryptionScheme encScheme, + const EncryptionPattern pattern, + const uint8_t* IV, uint16_t IVLength, + const uint8_t* keyId, const uint16_t keyIdLength, + uint32_t initWithLast15); +#endif // __cplusplus + +/** + * \brief Get metrics associated with a DRM session. + * + * Some DRMs (e.g. WideVine) offer metric data that can be used for any + * analyses. This function retrieves the metric data of the passed in + * system. It is up to the callee to interpret the baniary data correctly. + * \param session Instance of \ref OpenCDMSession. + * \param bufferLength Actual buffer length of the buffer parameter, on return + * it holds the number of bytes actually written in it. + * \param buffer Buffer length of buffer that can hold the metric data. + * \return Zero on success, non-zero on error. + */ + +EXTERNAL OpenCDMError opencdm_get_metric_session_data(struct OpenCDMSession* session, + uint32_t* bufferLength, + uint8_t* buffer); + +/** + * \brief Performs decryption. + * + * This method accepts encrypted data and will typically decrypt it + * out-of-process (for security reasons). The actual data copying is performed + * using a memory-mapped file (for performance reasons). If the DRM system + * allows access to decrypted data (i.e. decrypting is not + * performed in a TEE), the decryption is performed in-place. + * \param session \ref OpenCDMSession instance. + * \param encrypted Buffer containing encrypted data. If applicable, decrypted + * data will be stored here after this call returns. + * \param encryptedLength Length of encrypted data buffer (in bytes). + * \param sampleInfo Per Sample information needed to decrypt this sample + * \param streamProperties Provides info about current stream + * \return Zero on success, non-zero on error. + */ + +EXTERNAL OpenCDMError opencdm_session_decrypt_v2(struct OpenCDMSession* session, + uint8_t encrypted[], + const uint32_t encryptedLength, + const SampleInfo* sampleInfo, + const MediaProperties* streamProperties); + +/** + * @brief Close the cached open connection if it exists. + * + */ +EXTERNAL void opencdm_dispose(); + +#ifdef __cplusplus +} +#endif + +#endif // OPEN_CDM_H diff --git a/test/utests/drm/ocdm/open_cdm_adapter.h b/test/utests/drm/ocdm/open_cdm_adapter.h new file mode 100644 index 00000000..d4300d3a --- /dev/null +++ b/test/utests/drm/ocdm/open_cdm_adapter.h @@ -0,0 +1,96 @@ + /* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2020 Metrological + * + * 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. + */ + +#ifndef __OPEN_CDM_ADAPTER_H +#define __OPEN_CDM_ADAPTER_H + +#include "open_cdm.h" + +struct _GstBuffer; +typedef struct _GstBuffer GstBuffer; + +struct _GstCaps; +typedef struct _GstCaps GstCaps; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Performs decryption based on adapter implementation. + * + * This method accepts encrypted data and will typically decrypt it out-of-process (for security reasons). The actual data copying is performed + * using a memory-mapped file (for performance reasons). If the DRM system allows access to decrypted data (i.e. decrypting is not + * performed in a TEE), the decryption is performed in-place. + * \param session \ref OpenCDMSession instance. + * \param buffer Gstreamer buffer containing encrypted data and related meta data. If applicable, decrypted data will be stored here after this call returns. + * \param subSample Gstreamer buffer containing subsamples size which has been parsed from protection meta data. + * \param subSampleCount count of subsamples + * \param IV Gstreamer buffer containing initial vector (IV) used during decryption. + * \param keyID Gstreamer buffer containing keyID to use for decryption + * + * This method handles the Subsample mapping by consolidating all the encrypted data into one buffer before decrypting. This means the Subsample mappings are + * not passed on to the DRM implementation side. + * + * For CBCS support, EncryptionScheme and EncryptionPattern information can be added as part of the ProtectionMeta in the given format below + * "cipher-mode" G_TYPE_STRING (One of the Four Character Code (FOURCC) Protection schemes as defined in https://www.iso.org/obp/ui/#iso:std:iso-iec:23001:-7:ed-3:v1:en) + * "crypt_byte_block" G_TYPE_UINT (Present only if cipher-mode is "cbcs") + * "skip_byte_block" G_TYPE_UINT (Present only cipher-mode is "cbcs") + + * \return Zero on success, non-zero on error. + */ + EXTERNAL OpenCDMError opencdm_gstreamer_session_decrypt(struct OpenCDMSession* session, GstBuffer* buffer, GstBuffer* subSample, const uint32_t subSampleCount, + GstBuffer* IV, GstBuffer* keyID, uint32_t initWithLast15); + +/** + * \brief Performs decryption based on adapter implementation. + * + * This version 3 method accepts encrypted data and will typically decrypt it out-of-process (for security reasons). The actual data copying is performed + * using a memory-mapped file (for performance reasons). If the DRM system allows access to decrypted data (i.e. decrypting is not + * performed in a TEE), the decryption is performed in-place. + * This version assumes all data required is attached as metadata to the buffer. Specification for this data is as follows: + * + * Typically, the caller would parse the protection information for a video/audio frame from its input data and use this information to populate the + * GstStructure info field, which is then encapsulated in a GstProtectionMeta object and attached to the corresponding GstBuffer using the + * gst_buffer_add_protection_meta function. + * + * gst_structure [application/x-cenc] + * "iv" GST_TYPE_BUFFER + * "kid" GST_TYPE_BUFFER + * "subsample_count" G_TYPE_UINT + * "subsamples" GST_TYPE_BUFFER + * "cipher-mode" G_TYPE_STRING (One of the Four Character Code (FOURCC) Protection schemes as defined in https://www.iso.org/obp/ui/#iso:std:iso-iec:23001:-7:ed-3:v1:en) + * "crypt_byte_block" G_TYPE_UINT (Present only if cipher-mode is "cbcs") + * "skip_byte_block" G_TYPE_UINT (Present only cipher-mode is "cbcs") + * + * This method passes on the subsample mapping to the DRM implementation and assumes that the DRM implementaion will handle the decryption based on subsample mapping. + * + * \param session \ref OpenCDMSession instance. + * \param buffer Gstreamer buffer containing encrypted data and related meta data. If applicable, decrypted data will be stored here after this call returns. + * \return Zero on success, non-zero on error. + */ + + EXTERNAL OpenCDMError opencdm_gstreamer_session_decrypt_buffer(struct OpenCDMSession* session, GstBuffer* buffer, GstCaps* caps); + + +#ifdef __cplusplus +} +#endif + +#endif // __OPEN_CDM_ADAPTER_H diff --git a/test/utests/fakes/CMakeLists.txt b/test/utests/fakes/CMakeLists.txt new file mode 100644 index 00000000..a4ef12d4 --- /dev/null +++ b/test/utests/fakes/CMakeLists.txt @@ -0,0 +1,65 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2022 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. + +file(GLOB fakes_SRC "*.cpp") + +set(PLAYER_ROOT "../../../") +set(UTESTS_ROOT "..") + +include_directories(${PLAYER_ROOT}) +include_directories(${PLAYER_ROOT}/subtec/subtecparser) +include_directories(${PLAYER_ROOT}/subtec/libsubtec) +include_directories(${PLAYER_ROOT}/playerjsonobject) +include_directories(${PLAYER_ROOT}/vendor) +include_directories(${PLAYER_ROOT}/playerLogManager) +include_directories(${PLAYER_ROOT}/externals) +include_directories(${PLAYER_ROOT}/vendor) +include_directories(${PLAYER_ROOT}/playerLogManager) +include_directories(${PLAYER_ROOT}/drm/helper) +include_directories(${UTESTS_ROOT}/drm/ocdm) +include_directories(${UTESTS_ROOT}/drm/mocks) +include_directories(${UTESTS_ROOT}/mocks) +include_directories(${UTESTS_ROOT}/ocdm) +include_directories(${PLAYER_ROOT}/drm) +include_directories(${PLAYER_ROOT}/drm/ocdm) +include_directories(${PLAYER_ROOT}/baseConversion) +include_directories(${PLAYER_ROOT}/externals/playersecmanager) +include_directories(${GTEST_INCLUDE_DIRS}) +include_directories(${GMOCK_INCLUDE_DIRS}) +include_directories(${GLIB_INCLUDE_DIRS}) +include_directories(${GSTREAMER_INCLUDE_DIRS}) +include_directories(${LIBCJSON_INCLUDE_DIRS}) +include_directories(${LibXml2_INCLUDE_DIRS}) +message(STATUS "PLAYER_ROOT=${PLAYER_ROOT}") + + +if (JSC_INCDIR) + include_directories(${JSC_INCDIR}) +endif() + +# Mac OS X +if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + include_directories(${PLAYER_ROOT}/.libs/systemd/src) +endif(CMAKE_SYSTEM_NAME STREQUAL Darwin) + +include_directories(${PLAYER_ROOT}/.libs/include) +include_directories(${UTESTS_ROOT}/mocks) + +add_library(fakes ${fakes_SRC}) +target_include_directories(fakes PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../) +set_target_properties(fakes PROPERTIES FOLDER "utests") +set_target_properties(fakes PROPERTIES COMPILE_FLAGS "-Wno-effc++ -Wno-varargs") diff --git a/test/utests/fakes/FakeBase16.cpp b/test/utests/fakes/FakeBase16.cpp new file mode 100644 index 00000000..c0970cc9 --- /dev/null +++ b/test/utests/fakes/FakeBase16.cpp @@ -0,0 +1,25 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2023 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 "base16.h" + +unsigned char *base16_Decode( const char *srcPtr, size_t srcLen, size_t *len ) +{ + return NULL; +} diff --git a/test/utests/fakes/FakeDRMHelper.cpp b/test/utests/fakes/FakeDRMHelper.cpp new file mode 100644 index 00000000..3721bb4a --- /dev/null +++ b/test/utests/fakes/FakeDRMHelper.cpp @@ -0,0 +1,38 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2024 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 "MockDrmHelper.h" + +MockDrmHelper *g_mockDrmHelper = nullptr; + +DrmHelperEngine& DrmHelperEngine::getInstance() +{ + static DrmHelperEngine instance; + return instance; +} + +DrmHelperPtr DrmHelperEngine::createHelper(const struct DrmInfo& drmInfo) const +{ + return nullptr; +} + +bool DrmHelperEngine::hasDRM(const struct DrmInfo& drmInfo) const +{ + return false; +} \ No newline at end of file diff --git a/test/utests/fakes/FakeDRMSession.cpp b/test/utests/fakes/FakeDRMSession.cpp new file mode 100644 index 00000000..da347f6d --- /dev/null +++ b/test/utests/fakes/FakeDRMSession.cpp @@ -0,0 +1,25 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2024 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 "DrmSession.h" + +string DrmSession::getKeySystem() +{ + return ""; +} diff --git a/test/utests/fakes/FakeGLib.cpp b/test/utests/fakes/FakeGLib.cpp new file mode 100644 index 00000000..3ed69311 --- /dev/null +++ b/test/utests/fakes/FakeGLib.cpp @@ -0,0 +1,252 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "MockGLib.h" + +using namespace std; + +#if 0 +#define TRACE_FUNC() printf("%s\n" ,__func__) +#else +#define TRACE_FUNC() ((void)0) +#endif + +MockGLib *g_mockGLib = nullptr; + +void g_object_set(gpointer object, const gchar *first_property_name, ...) +{ + TRACE_FUNC(); + + if (g_mockGLib != nullptr) + { + va_list args_list; + va_start(args_list, first_property_name); + const gchar *property_name = first_property_name; + + while (property_name) + { + if ((strcmp(property_name, "mute") == 0) || + (strcmp(property_name, "show-video-window") == 0) || + (strcmp(property_name, "zoom-mode") == 0) + ) + { + g_mockGLib->g_object_set(object, property_name, va_arg(args_list, int)); + } + else if((strcmp(property_name, "rectangle") == 0)) + { + g_mockGLib->g_object_set(object, property_name, va_arg(args_list, char *)); + } + else if((strcmp(property_name, "volume") == 0)) + { + g_mockGLib->g_object_set(object, property_name, va_arg(args_list, double)); + } + else + { + va_arg(args_list, int); + } + property_name = va_arg(args_list, gchar *); + } + va_end(args_list); + } +} + +void g_object_get(gpointer object, const gchar *first_property_name, ...) +{ + TRACE_FUNC(); +} + +gulong g_signal_connect_data(gpointer instance, const gchar *detailed_signal, GCallback c_handler, + gpointer data, GClosureNotify destroy_data, + GConnectFlags connect_flags) +{ + TRACE_FUNC(); + return 0; +} + +gboolean g_type_check_instance_is_a(GTypeInstance *instance, GType iface_type) +{ + TRACE_FUNC(); + return FALSE; +} + +gboolean g_signal_handler_is_connected(gpointer instance, gulong handler_id) +{ + TRACE_FUNC(); + return FALSE; +} + +void g_signal_handler_disconnect(gpointer instance, gulong handler_id) +{ + TRACE_FUNC(); +} + +GTypeInstance *g_type_check_instance_cast(GTypeInstance *instance, GType iface_type) +{ + TRACE_FUNC(); + return instance; +} + +GValue *g_value_init(GValue *value, GType g_type) +{ + TRACE_FUNC(); + return NULL; +} + +void g_value_set_pointer(GValue *value, gpointer v_pointer) +{ + TRACE_FUNC(); +} + +GParamSpec* g_object_class_find_property(GObjectClass* oclass, const gchar* property_name) +{ + GParamSpec* retval = NULL; + + if (g_mockGLib != nullptr) + { + retval = g_mockGLib->g_object_class_find_property(oclass, property_name); + } + + return retval; +} + + +void g_object_set_property(GObject *object, const gchar *property_name, const GValue *value) +{ + TRACE_FUNC(); +} + +void g_signal_emit_by_name(gpointer instance, const gchar *detailed_signal, ...) +{ +} + +gboolean g_type_check_instance(GTypeInstance *instance) +{ + TRACE_FUNC(); + return FALSE; +} + +gpointer g_value_get_object(const GValue *value) +{ + TRACE_FUNC(); + return NULL; +} + +gpointer g_object_new(GType object_type, const gchar *first_property_name, ...) +{ + TRACE_FUNC(); + return NULL; +} + +void g_object_unref(gpointer object) +{ + TRACE_FUNC(); +} + +guint g_timeout_add(guint interval, GSourceFunc function, gpointer data) +{ + guint retval = 0; + + if (g_mockGLib != nullptr) + { + retval = g_mockGLib->g_timeout_add(interval, function, data); + } + + return retval; +} + +gboolean g_source_remove(guint tag) +{ + gboolean retval = FALSE; + + if (g_mockGLib != nullptr) + { + retval = g_mockGLib->g_source_remove(tag); + } + return retval; +} + +GSource *g_main_current_source(void) +{ + return nullptr; +} + +guint g_source_get_id(GSource *source) +{ + return 0; +} + +void g_printerr(const gchar *format, ...) +{ + +} + +void g_clear_error(GError **err) +{ + +} + +void g_free(gpointer mem) +{ + if (g_mockGLib != nullptr) + { + g_mockGLib->g_free(mem); + } +} + +int g_strcmp0(const char *str1, const char *str2) +{ + return 0; +} + +guint g_timeout_add_full(gint priority, guint interval, GSourceFunc function, gpointer data, GDestroyNotify notify) +{ + return 0; +} + +void g_usleep(gulong microseconds) +{ + +} + +gpointer g_malloc(gsize n_bytes) +{ + gpointer ptr = NULL; + + if (g_mockGLib != nullptr) + { + ptr = g_mockGLib->g_malloc(n_bytes); + } + return ptr; +} + +gpointer g_realloc (gpointer mem, gsize n_bytes) +{ + gpointer ptr = NULL; + + if (g_mockGLib != nullptr) + { + ptr = g_mockGLib->g_realloc(mem, n_bytes); + } + return ptr; + +} diff --git a/test/utests/fakes/FakeGStreamer.cpp b/test/utests/fakes/FakeGStreamer.cpp new file mode 100644 index 00000000..f151c20f --- /dev/null +++ b/test/utests/fakes/FakeGStreamer.cpp @@ -0,0 +1,878 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "MockGStreamer.h" + +MockGStreamer *g_mockGStreamer = nullptr; + +GstDebugCategory *GST_CAT_DEFAULT; +GstDebugLevel _gst_debug_min; + +#if 0 +#define TRACE_FUNC_ARG(format,...) printf("%s " ,__func__); printf(format,__VA_ARGS__) +#define TRACE_FUNC() printf("%s\n" ,__func__) +#else +#define TRACE_FUNC() ((void)0) +#define TRACE_FUNC_ARG(format,...) ((void)0) +#endif + +void gst_debug_bin_to_dot_file(GstBin *bin, GstDebugGraphDetails details, const gchar *file_name) +{ +} + +GType gst_object_get_type(void) +{ + TRACE_FUNC(); + return 0; +} + +GType gst_bin_get_type(void) +{ + TRACE_FUNC(); + return 0; +} + +GstMiniObject *gst_mini_object_ref(GstMiniObject *mini_object) +{ + TRACE_FUNC(); + return NULL; +} + +void gst_mini_object_unref(GstMiniObject *mini_object) +{ + TRACE_FUNC(); + if (g_mockGStreamer != nullptr) + { + g_mockGStreamer->gst_mini_object_unref(mini_object); + } +} + +GType gst_app_src_get_type(void) +{ + TRACE_FUNC(); + return 0; +} + +void gst_app_src_set_caps(GstAppSrc *appsrc, const GstCaps *caps) +{ + TRACE_FUNC(); +} + +void gst_app_src_set_stream_type(GstAppSrc *appsrc, GstAppStreamType type) +{ + TRACE_FUNC(); +} + +GstFlowReturn gst_app_src_push_buffer(GstAppSrc *appsrc, GstBuffer *buffer) +{ + TRACE_FUNC(); + return GST_FLOW_OK; +} + +GstBuffer *gst_buffer_new(void) +{ + + TRACE_FUNC(); + return NULL; +} + +GstBuffer *gst_buffer_new_allocate(GstAllocator *allocator, gsize size, GstAllocationParams *params) +{ + + TRACE_FUNC(); + return NULL; +} + +GstBuffer *gst_buffer_new_wrapped(gpointer data, gsize size) +{ + TRACE_FUNC(); + return NULL; +} + +gboolean gst_buffer_map(GstBuffer *buffer, GstMapInfo *info, GstMapFlags flags) +{ + TRACE_FUNC(); + return FALSE; +} + +void gst_buffer_unmap(GstBuffer *buffer, GstMapInfo *info) +{ + TRACE_FUNC(); +} + +const gchar *gst_element_state_get_name(GstState state) +{ + const char *ptr = NULL; + const char *tbl[] = { + "GST_STATE_VOID_PENDING", //(0) – no pending state. + "GST_STATE_NULL", // (1) – the NULL state or initial state of an element. + "GST_STATE_READY", // (2) – the element is ready to go to PAUSED. + "GST_STATE_PAUSED", // (3) – the element is PAUSED, it is ready to accept and process data. Sink elements however only accept one buffer and then block. + "GST_STATE_PLAYING", // (4) – + }; + + if (state < (sizeof(tbl) / sizeof(tbl[0]))) + { + ptr = tbl[state]; + } + else + { + ptr = "error"; + printf("GstState %d\n",state); + } + TRACE_FUNC_ARG("%s \n",ptr); + + + return (const gchar *)ptr; +} + +GType gst_element_get_type(void) +{ + TRACE_FUNC(); + return 0; +} + +void gst_message_parse_warning(GstMessage *message, GError **gerror, gchar **debug) +{ + + TRACE_FUNC(); +} + +void gst_message_parse_error(GstMessage *message, GError **gerror, gchar **debug) +{ + TRACE_FUNC(); +} + +void gst_message_parse_state_changed(GstMessage *message, GstState *oldstate, GstState *newstate, + GstState *pending) +{ + TRACE_FUNC(); + if (g_mockGStreamer != nullptr) + { + g_mockGStreamer->gst_message_parse_state_changed(message, oldstate, newstate, pending); + } +} + +void gst_message_parse_qos(GstMessage *message, gboolean *live, guint64 *running_time, + guint64 *stream_time, guint64 *timestamp, guint64 *duration) +{ + TRACE_FUNC(); +} + +const GstStructure *gst_message_get_structure(GstMessage *message) +{ + + TRACE_FUNC(); + return NULL; +} + +gboolean gst_structure_has_name(const GstStructure *structure, const gchar *name) +{ + TRACE_FUNC(); + return FALSE; +} + +const gchar *gst_message_type_get_name(GstMessageType type) +{ + TRACE_FUNC(); + return NULL; +} + +gboolean gst_message_parse_context_type(GstMessage *message, const gchar **context_type) +{ + + TRACE_FUNC(); + return FALSE; +} + +GstContext *gst_context_new(const gchar *context_type, gboolean persistent) +{ + TRACE_FUNC(); + return NULL; +} + +GstStructure *gst_context_writable_structure(GstContext *context) +{ + TRACE_FUNC(); + return NULL; +} + +void gst_structure_set(GstStructure *structure, const gchar *fieldname, ...) +{ + TRACE_FUNC(); +} + +void gst_element_set_context(GstElement *element, GstContext *context) +{ + TRACE_FUNC(); +} + +GstElement *gst_pipeline_new(const gchar *name) +{ + + TRACE_FUNC(); + GstElement *return_ptr = nullptr; + if (g_mockGStreamer != nullptr) + { + return_ptr = g_mockGStreamer->gst_pipeline_new(name); + } + return return_ptr; +} + +GType gst_pipeline_get_type(void) +{ + TRACE_FUNC(); + return 0; +} + +GstBus *gst_pipeline_get_bus(GstPipeline *pipeline) +{ + GstBus *return_ptr = nullptr; + TRACE_FUNC(); + if (g_mockGStreamer != nullptr) + { + return_ptr = g_mockGStreamer->gst_pipeline_get_bus(pipeline); + } + return return_ptr; +} + +guint gst_bus_add_watch(GstBus *bus, GstBusFunc func, gpointer user_data) +{ + guint id = 0; + TRACE_FUNC(); + if (g_mockGStreamer != nullptr) + { + id = g_mockGStreamer->gst_bus_add_watch(bus,func,user_data); + } + return id; +} + +void gst_bus_set_sync_handler(GstBus *bus, GstBusSyncHandler func, gpointer user_data, + GDestroyNotify notify) +{ + TRACE_FUNC(); + if (g_mockGStreamer != nullptr) + { + g_mockGStreamer->gst_bus_set_sync_handler(bus, func, user_data, notify); + } +} + +GstQuery *gst_query_new_position(GstFormat format) +{ + GstQuery *return_ptr = nullptr; + TRACE_FUNC(); + if (g_mockGStreamer != nullptr) + { + return_ptr = g_mockGStreamer->gst_query_new_position(format); + } + return return_ptr; +} + +gpointer gst_object_ref(gpointer object) +{ + TRACE_FUNC(); + return NULL; +} + +void gst_object_unref(gpointer object) +{ + TRACE_FUNC(); + + if (g_mockGStreamer != nullptr) + { + g_mockGStreamer->gst_object_unref(object); + } +} + +void gst_debug_log(GstDebugCategory *category, GstDebugLevel level, const gchar *file, + const gchar *function, gint line, GObject *object, const gchar *format, ...) +{ + TRACE_FUNC(); +} + +GstElement *gst_element_factory_make(const gchar *factoryname, const gchar *name) +{ + TRACE_FUNC_ARG("%s\n",(char *)factoryname); + + GstElement *return_ptr = nullptr; + if (g_mockGStreamer != nullptr) + { + return_ptr = g_mockGStreamer->gst_element_factory_make(factoryname,name); + } + return return_ptr; +} + +gboolean gst_element_seek_simple(GstElement *element, GstFormat format, GstSeekFlags seek_flags, + gint64 seek_pos) +{ + TRACE_FUNC(); + return FALSE; +} + +gboolean gst_bin_add(GstBin *bin, GstElement *element) +{ + TRACE_FUNC(); + gboolean rtn = FALSE; + if (g_mockGStreamer != nullptr) + { + rtn = g_mockGStreamer->gst_bin_add(bin, element); + } + + return rtn; +} + +gboolean gst_bin_remove(GstBin *bin, GstElement *element) +{ + TRACE_FUNC(); + return FALSE; +} + +void gst_bin_add_many(GstBin *bin, GstElement *element_1, ...) +{ + TRACE_FUNC(); +} + +gboolean gst_element_link(GstElement *src, GstElement *dest) +{ + TRACE_FUNC(); + return FALSE; +} + +gboolean gst_element_link_many(GstElement *element_1, GstElement *element_2, ...) +{ + TRACE_FUNC(); + return FALSE; +} + +gboolean gst_element_sync_state_with_parent(GstElement *element) +{ + TRACE_FUNC(); + return FALSE; +} + +GstPad *gst_element_get_static_pad(GstElement *element, const gchar *name) +{ + TRACE_FUNC(); + return NULL; +} + +GstEvent *gst_event_new_segment(const GstSegment *segment) +{ + TRACE_FUNC(); + return NULL; +} + +GstEvent *gst_event_new_flush_start(void) +{ + TRACE_FUNC(); + return NULL; +} + +GstEvent *gst_event_new_flush_stop(gboolean reset_time) +{ + TRACE_FUNC(); + return NULL; +} + +GstEvent *gst_event_new_step (GstFormat format, + guint64 amount, + gdouble rate, + gboolean flush, + gboolean intermediate) +{ + TRACE_FUNC(); + GstEvent *rtn = nullptr; + if (g_mockGStreamer != nullptr) + { + rtn = g_mockGStreamer->gst_event_new_step(format, amount, rate, flush, intermediate); + } + return rtn; +} + +gboolean gst_pad_push_event(GstPad *pad, GstEvent *event) +{ + TRACE_FUNC(); + return FALSE; +} + +void gst_segment_init(GstSegment *segment, GstFormat format) +{ + TRACE_FUNC(); +} + +const gchar *gst_flow_get_name(GstFlowReturn ret) +{ + TRACE_FUNC(); + return NULL; +} + +gboolean gst_element_query_position(GstElement *element, GstFormat format, gint64 *cur) +{ + TRACE_FUNC(); + bool rtn = FALSE; + if (g_mockGStreamer != nullptr) + { + rtn = g_mockGStreamer->gst_element_query_position(element, format, cur ); + } + return rtn; +} + +GstStateChangeReturn gst_element_get_state(GstElement *element, GstState *state, GstState *pending, + GstClockTime timeout) +{ + TRACE_FUNC(); + GstStateChangeReturn rtn = GST_STATE_CHANGE_FAILURE; + if (g_mockGStreamer != nullptr) + { + rtn = g_mockGStreamer->gst_element_get_state(element, state, pending, timeout); + } + return rtn; +} + +GstEvent *gst_event_new_eos(void) +{ + TRACE_FUNC(); + return NULL; +} + +GstMessage *gst_bus_timed_pop_filtered(GstBus *bus, GstClockTime timeout, GstMessageType types) +{ + TRACE_FUNC(); + return NULL; +} + +gboolean gst_bus_remove_watch(GstBus *bus) +{ + TRACE_FUNC(); + return FALSE; +} + +gchar *gst_object_get_name(GstObject *object) +{ + if (object && object->name) + { + TRACE_FUNC_ARG("%s \n", object->name); + // See SafeName() in aampgstplayer.cpp + char *ptr = object->name ; + char *g_ptr = (char *)malloc(strlen(ptr) + 1); + strcpy(g_ptr, ptr); + + return (gchar *)g_ptr; + } + + return NULL; +} + +GstStateChangeReturn gst_element_set_state(GstElement *element, GstState state) +{ + TRACE_FUNC_ARG("%d \n",state); + + GstStateChangeReturn rtn = GST_STATE_CHANGE_FAILURE; + if (g_mockGStreamer != nullptr) + { + rtn = g_mockGStreamer->gst_element_set_state(element, state); + } + + return rtn; +} + +gboolean gst_element_send_event(GstElement *element, GstEvent *event) +{ + TRACE_FUNC(); + gboolean rtn = FALSE; + if (g_mockGStreamer != nullptr) + { + rtn = g_mockGStreamer->gst_element_send_event(element, event); + } + return rtn; +} + +GstQuery *gst_query_new_duration(GstFormat format) +{ + TRACE_FUNC(); + return NULL; +} + +gboolean gst_element_query(GstElement *element, GstQuery *query) +{ + TRACE_FUNC(); + return FALSE; +} + +void gst_query_parse_duration(GstQuery *query, GstFormat *format, gint64 *duration) +{ + TRACE_FUNC(); +} + +GstQuery *gst_query_new_segment(GstFormat format) +{ + TRACE_FUNC(); + return NULL; +} + +void gst_query_parse_segment(GstQuery *query, gdouble *rate, GstFormat *format, gint64 *start_value, + gint64 *stop_value) +{ + + TRACE_FUNC(); +} + +void gst_query_parse_position(GstQuery *query, GstFormat *format, gint64 *cur) +{ + TRACE_FUNC(); +} + +gboolean gst_element_seek(GstElement *element, gdouble rate, GstFormat format, GstSeekFlags flags, + GstSeekType start_type, gint64 start, GstSeekType stop_type, gint64 stop) +{ + TRACE_FUNC(); + return FALSE; +} + +guint64 gst_app_src_get_current_level_bytes(GstAppSrc *appsrc) +{ + TRACE_FUNC(); + return 0; +} + +GType gst_registry_get_type(void) +{ + + TRACE_FUNC(); + return 0; +} + +GstRegistry *gst_registry_get(void) +{ + TRACE_FUNC(); + return NULL; +} + +GstPluginFeature *gst_registry_lookup_feature(GstRegistry *registry, const char *name) +{ + + TRACE_FUNC(); + return NULL; +} + +GstStructure *gst_structure_new(const gchar *name, const gchar *firstfield, ...) +{ + TRACE_FUNC(); + return NULL; +} + +GstEvent *gst_event_new_custom(GstEventType type, GstStructure *structure) +{ + TRACE_FUNC(); + return NULL; +} + +gboolean gst_buffer_copy_into(GstBuffer *dest, GstBuffer *src, GstBufferCopyFlags flags, + gsize offset, gsize size) +{ + + TRACE_FUNC(); + return FALSE; +} + +void gst_plugin_feature_set_rank(GstPluginFeature *feature, guint rank) +{ +} + +gboolean gst_object_replace(GstObject **oldobj, GstObject *newobj) +{ + TRACE_FUNC(); + gboolean rtn = FALSE; + if (g_mockGStreamer != nullptr) + { + rtn = g_mockGStreamer->gst_object_replace(oldobj, newobj); + } + + return rtn; +} + +void gst_message_parse_stream_status(GstMessage *message, GstStreamStatusType *type, + GstElement **owner) +{ + TRACE_FUNC(); +} + +const GValue *gst_message_get_stream_status_object(GstMessage *message) +{ + TRACE_FUNC(); + return NULL; +} + +GType gst_task_get_type(void) +{ + TRACE_FUNC(); + return 0; +} + +void gst_task_set_pool(GstTask *task, GstTaskPool *pool) +{ + TRACE_FUNC(); +} + +gpointer gst_object_ref_sink(gpointer object) +{ + TRACE_FUNC_ARG("%p\n",object); + return object; +} + +const GValue *gst_structure_get_value(const GstStructure *structure, const gchar *fieldname) +{ + TRACE_FUNC(); + return NULL; +} + +guint64 g_value_get_uint64(const GValue *value) +{ + TRACE_FUNC(); + return 0; +} + +void gst_structure_free(GstStructure *structure) +{ + TRACE_FUNC(); +} + +gboolean gst_init_check(int *argc, char **argv[], GError **error) +{ + TRACE_FUNC(); + return TRUE; +} + +GstCaps *gst_caps_new_simple(const char *media_type, const char *fieldname, ...) +{ + GstCaps *return_ptr = NULL; + TRACE_FUNC(); + if (g_mockGStreamer != nullptr) + { + va_list ap; + va_start(ap, fieldname); + GType var1 = va_arg(ap, GType); + int var2 = va_arg(ap, int); + void *ptr = va_arg(ap, void *); + return_ptr = g_mockGStreamer->gst_caps_new_simple(media_type, fieldname, var1, var2, ptr); + va_end(ap); + } + + return return_ptr; +} + +void gst_debug_set_threshold_from_string(const gchar *list, gboolean reset) +{ + TRACE_FUNC(); + if (g_mockGStreamer != nullptr) + { + g_mockGStreamer->gst_debug_set_threshold_from_string(list, reset); + } +} + +GstFlowReturn gst_app_src_end_of_stream (GstAppSrc * appsrc) +{ + return GST_FLOW_OK; +} + +gulong gst_pad_add_probe (GstPad * pad, + GstPadProbeType mask, + GstPadProbeCallback callback, + gpointer user_data, + GDestroyNotify destroy_data) +{ + TRACE_FUNC(); + return 0; +} + +GstCaps *gst_pad_get_current_caps (GstPad * pad) +{ + TRACE_FUNC(); + return NULL; +} + +gchar *gst_caps_to_string (const GstCaps * caps) +{ + TRACE_FUNC(); + return NULL; +} + +void gst_pad_remove_probe (GstPad * pad, gulong id) +{ + TRACE_FUNC(); +} + +gboolean gst_mini_object_replace (GstMiniObject **olddata, GstMiniObject *newdata) +{ + TRACE_FUNC(); + return FALSE; +} + +void gst_event_copy_segment (GstEvent *event, GstSegment *segment) +{ + TRACE_FUNC(); +} + +void gst_event_parse_seek (GstEvent *event, gdouble *rate, GstFormat *format, + GstSeekFlags *flags, + GstSeekType *start_type, gint64 *start, + GstSeekType *stop_type, gint64 *stop) +{ + TRACE_FUNC(); +} + +GstSegment * gst_segment_new(void) +{ + TRACE_FUNC(); + return NULL; +} + +void gst_segment_free (GstSegment *segment) +{ + TRACE_FUNC(); +} + +GstEvent * gst_event_new_instant_rate_change (gdouble rate_multiplier, + GstSegmentFlags new_flags) +{ + TRACE_FUNC(); + return NULL; +} + +void gst_event_set_seqnum(GstEvent *event, guint32 seqnum) +{ + TRACE_FUNC(); +} + +GstPad* gst_pad_get_peer(GstPad *pad) +{ + TRACE_FUNC(); + return NULL; +} + +gboolean gst_pad_send_event(GstPad *pad, GstEvent *event) +{ + TRACE_FUNC(); + return false; +} + +guint32 gst_event_get_seqnum(GstEvent *event) +{ + TRACE_FUNC(); + return 0; +} + +gboolean gst_base_sink_is_async_enabled (GstBaseSink * sink) +{ + TRACE_FUNC(); + return false; +} + +void gst_base_sink_set_async_enabled (GstBaseSink * sink, gboolean enabled) +{ + TRACE_FUNC(); +} + +GstEvent* gst_event_new_seek(gdouble rate, GstFormat format, GstSeekFlags flags, + GstSeekType start_type, gint64 start, + GstSeekType stop_type, gint64 stop) +{ + TRACE_FUNC(); + return NULL; +} + +void gst_caps_set_simple (GstCaps * caps, const char *field, ...) +{ + TRACE_FUNC(); +} + +GType gst_base_sink_get_type (void) +{ + TRACE_FUNC(); + return 0; +} + +gboolean gst_element_add_pad (GstElement * element, GstPad * pad) +{ + TRACE_FUNC(); + return FALSE; +} + +GstEvent* gst_event_new_protection(const gchar * system_id, GstBuffer * data, const gchar * origin) +{ + TRACE_FUNC(); + return NULL; +} + +void gst_message_parse_reset_time(GstMessage *message, GstClockTime *running_time) +{ + TRACE_FUNC(); +} + +gchar * gst_structure_to_string(const GstStructure *structure) +{ + TRACE_FUNC(); + return NULL; +} + +GstElement * gst_bin_new (const gchar * name) +{ + TRACE_FUNC(); + return NULL; +} +void gst_deinit (void) +{ + TRACE_FUNC(); +} + +void gst_init(int *argc, char **argv[]) +{ + TRACE_FUNC(); +} + +GstPlugin *gst_plugin_load_by_name (const gchar * name) +{ + TRACE_FUNC(); + return NULL; +} + +void gst_registry_remove_feature (GstRegistry * registry, + GstPluginFeature * feature) +{ + TRACE_FUNC(); +} + +gboolean +gst_registry_add_feature (GstRegistry * registry, + GstPluginFeature * feature) + +{ + TRACE_FUNC(); + return false; +} + +GstPad * gst_ghost_pad_new (const gchar * name, GstPad * target) +{ + TRACE_FUNC(); + return NULL; +} + diff --git a/test/utests/fakes/FakeGstHandlerControl.cpp b/test/utests/fakes/FakeGstHandlerControl.cpp new file mode 100644 index 00000000..6e58019e --- /dev/null +++ b/test/utests/fakes/FakeGstHandlerControl.cpp @@ -0,0 +1,51 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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 "MockGstHandlerControl.h" +#include "GstHandlerControl.h" + +MockGstHandlerControl *g_mockGstHandlerControl = nullptr; + +GstHandlerControl::ScopeHelper& GstHandlerControl::ScopeHelper::operator=(GstHandlerControl::ScopeHelper&& other) +{ + return *this; +} + +void GstHandlerControl::handlerEnd() +{ +} + +bool GstHandlerControl::isEnabled() const +{ + bool retvalue = false; + if (g_mockGstHandlerControl != nullptr) + { + retvalue = g_mockGstHandlerControl->isEnabled(); + } + return retvalue; +} + +GstHandlerControl::ScopeHelper GstHandlerControl::getScopeHelper() +{ + return GstHandlerControl::ScopeHelper(this); +} + +bool GstHandlerControl::waitForDone(int MaximumDelayMilliseconds, std::string name) +{ + return true; +} diff --git a/test/utests/fakes/FakeGstPlayerTaskPool.cpp b/test/utests/fakes/FakeGstPlayerTaskPool.cpp new file mode 100644 index 00000000..eaefcef2 --- /dev/null +++ b/test/utests/fakes/FakeGstPlayerTaskPool.cpp @@ -0,0 +1,25 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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 "gstplayertaskpool.h" + +GType gst_player_taskpool_get_type(void) +{ + return 0; +} diff --git a/test/utests/fakes/FakeGstUtils.cpp b/test/utests/fakes/FakeGstUtils.cpp new file mode 100644 index 00000000..9b3e9224 --- /dev/null +++ b/test/utests/fakes/FakeGstUtils.cpp @@ -0,0 +1,28 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2023 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 "GstUtils.h" +#include "InterfacePlayerPriv.h" + +GstCaps *GetCaps(GstStreamOutputFormat format) +{ + return nullptr; +} + + + diff --git a/test/utests/fakes/FakePlayerJsonObject.cpp b/test/utests/fakes/FakePlayerJsonObject.cpp new file mode 100644 index 00000000..1e457ece --- /dev/null +++ b/test/utests/fakes/FakePlayerJsonObject.cpp @@ -0,0 +1,227 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2022 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 "MockPlayerJsonObject.h" +#include "PlayerJsonObject.h" + +std::shared_ptr g_mockPlayerJsonObject; + +PlayerJsonObject::PlayerJsonObject() : mParent(NULL), mJsonObj() +{ +} + +PlayerJsonObject::PlayerJsonObject(const std::string& jsonStr) : mParent(NULL), mJsonObj() +{ +} + +PlayerJsonObject::PlayerJsonObject(const char* jsonStr) : mParent(NULL), mJsonObj() +{ +} + +PlayerJsonObject::~PlayerJsonObject() +{ +} + +bool PlayerJsonObject::add(const std::string& name, const std::string& value, const ENCODING encoding) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->add(name, value, encoding); + } + return false; +} + +bool PlayerJsonObject::add(const std::string& name, const char *value, const ENCODING encoding) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->add(name, value, encoding); + } + return false; +} + +bool PlayerJsonObject::add(const std::string& name, const std::vector& values) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->add(name, values); + } + return false; +} + +bool PlayerJsonObject::add(const std::string& name, const std::vector& values, const ENCODING encoding) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->add(name, values, encoding); + } + return false; +} + +bool PlayerJsonObject::add(const std::string& name, PlayerJsonObject& value) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->add(name, value); + } + return false; +} + +bool PlayerJsonObject::add(const std::string& name, std::vector& values) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->add(name, values); + } + return false; +} + +bool PlayerJsonObject::add(const std::string& name, cJSON *value) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->add(name, value); + } + return false; +} + +bool PlayerJsonObject::add(const std::string& name, bool value) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->add(name, value); + } + return false; +} + +bool PlayerJsonObject::add(const std::string& name, int value) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->add(name, value); + } + return false; +} + +bool PlayerJsonObject::add(const std::string& name, double value) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->add(name, value); + } + return false; +} + +bool PlayerJsonObject::add(const std::string& name, long value) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->add(name, value); + } + return false; +} + +bool PlayerJsonObject::set(PlayerJsonObject *parent, cJSON *object) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->set(parent, object); + } + return false; +} + +bool PlayerJsonObject::get(const std::string& name, PlayerJsonObject &value) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->get(name, value); + } + return false; +} + +bool PlayerJsonObject::get(const std::string& name, std::string& value) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->get(name, value); + } + return false; +} + +bool PlayerJsonObject::get(const std::string& name, int& value) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->get(name, value); + } + return false; +} + +bool PlayerJsonObject::get(const std::string& name, std::vector& values) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->get(name, values); + } + return false; +} + +bool PlayerJsonObject::get(const std::string& name, std::vector& values, const ENCODING encoding) +{ + if (g_mockPlayerJsonObject != nullptr) + { + return g_mockPlayerJsonObject->get(name, values, encoding); + } + return false; +} + +std::string PlayerJsonObject::print() +{ + return ""; +} + +std::string PlayerJsonObject::print_UnFormatted() +{ + return ""; +} + +void PlayerJsonObject::print(std::vector& data) +{ +} + +bool PlayerJsonObject::isArray(const std::string& name) +{ + return false; +} + +bool PlayerJsonObject::isString(const std::string& name) +{ + return false; +} + +bool PlayerJsonObject::isNumber(const std::string& name) +{ + return false; +} + +bool PlayerJsonObject::isObject(const std::string& name) +{ + return false; +} + diff --git a/test/utests/fakes/FakePlayerScheduler.cpp b/test/utests/fakes/FakePlayerScheduler.cpp new file mode 100644 index 00000000..8d37d1d7 --- /dev/null +++ b/test/utests/fakes/FakePlayerScheduler.cpp @@ -0,0 +1,69 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2025 RDK Management +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "MockPlayerScheduler.h" +#include "PlayerScheduler.h" + +MockPlayerScheduler *g_mockPlayerScheduler = nullptr; + +PlayerScheduler::PlayerScheduler() +{ +} + +PlayerScheduler::~PlayerScheduler() +{ +} + +void PlayerScheduler::StartScheduler() +{ +} + +void PlayerScheduler::StopScheduler() +{ +} + +void PlayerScheduler::SuspendScheduler() +{ +} + +void PlayerScheduler::ResumeScheduler() +{ +} + +void PlayerScheduler::RemoveAllTasks() +{ +} + +int PlayerScheduler::ScheduleTask(PlayerAsyncTaskObj obj) +{ + if (g_mockPlayerScheduler != nullptr) + { + return g_mockPlayerScheduler->ScheduleTask(obj); + } + else + { + return 0; + } +} + +bool PlayerScheduler::RemoveTask(int id) +{ + return false; +} + diff --git a/test/utests/fakes/FakePlayerThunderInterface.cpp b/test/utests/fakes/FakePlayerThunderInterface.cpp new file mode 100644 index 00000000..085c4b71 --- /dev/null +++ b/test/utests/fakes/FakePlayerThunderInterface.cpp @@ -0,0 +1,174 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2025 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +/** + * @file FakePlayerThunderInterface.cpp + * @brief Fake Player Thunder Interface + */ + +#include "PlayerThunderInterface.h" + +PlayerThunderInterface::PlayerThunderInterface(PlayerThunderAccessPlugin callsign) +{ +} + +PlayerThunderInterface::~PlayerThunderInterface() +{ +} + +bool PlayerThunderInterface::ActivatePlugin() +{ + return false; +} + +bool PlayerThunderInterface::UnSubscribeEvent(std::string eventName) +{ + return false; +} + +bool PlayerThunderInterface::SetVideoRectangle(int x, int y, int w, int h, std::string videoInputType, PlayerThunderAccessShim shim) +{ + return false; +} + + +void PlayerThunderInterface::RegisterAllEventsVideoin(std::function OnSignalChangedCb, std::function OnInputStatusChangedCb) +{ +} + +void PlayerThunderInterface::UnRegisterAllEventsVideoin() +{ +} + +void PlayerThunderInterface::StartHelperVideoin(int port, std::string videoInputType) +{ +} + +void PlayerThunderInterface::StopHelperVideoin(std::string videoInputType) +{ +} + +void PlayerThunderInterface::RegisterEventOnVideoStreamInfoUpdateHdmiin(std::function videoInfoUpdatedMethodCb) +{ +} + +void PlayerThunderInterface::RegisterOnPlayerStatusOta(std::function onPlayerStatusCb) +{ +} + +void PlayerThunderInterface::ReleaseOta() +{ +} + +void PlayerThunderInterface::StartOta(std::string url, std::string waylandDisplay, std::string preferredLanguagesString, std::string atsc_preferredLanguagesString, std::string preferredRenditionString, std::string atsc_preferredRenditionString) +{ +} + +void PlayerThunderInterface::StopOta() +{ +} + +std::string PlayerThunderInterface::GetAudioTracksOta(std::vector audData) +{ + std::string ret = ""; + return ret; +} + +std::string PlayerThunderInterface::SetAudioTrackOta(int index, int primaryKey) +{ + std::string ret = ""; + return ret; +} + +bool PlayerThunderInterface::GetTextTracksOta(std::vector txtData) +{ + return false; +} + +void PlayerThunderInterface::DisableContentRestrictionsOta(long grace, long time, bool eventChange) +{ +} + +void PlayerThunderInterface::EnableContentRestrictionsOta() +{ +} + +bool PlayerThunderInterface::InitRmf() +{ + return false; +} + +bool PlayerThunderInterface::StartRmf(std::string url, std::function onPlayerStatusHandlerCb, std::function onPlayerErrorHandlerCb) +{ + return false; +} + +void PlayerThunderInterface::SetPreferredAudioLanguages(PlayerPreferredAudioData data, PlayerThunderAccessShim shim) +{ +} + +void PlayerThunderInterface::StopRmf() +{ +} + +bool PlayerThunderInterface::DeleteWatermark(int layerID) +{ + return false; +} + +bool PlayerThunderInterface::CreateWatermark(int layerID) +{ + return false; +} + +bool PlayerThunderInterface::ShowWatermark(int opacity) +{ + return false; +} + +bool PlayerThunderInterface::HideWatermark() +{ + return false; +} + +bool PlayerThunderInterface::UpdateWatermark(int layerID, int sharedMemoryKey, int size) +{ + return false; +} + +std::string PlayerThunderInterface::GetMetaDataWatermark() +{ + std::string ret = ""; + return ret; +} + +bool PlayerThunderInterface::PersistentStoreSaveWatermark(const char* base64Image, std::string metaData) +{ + return false; +} + +bool PlayerThunderInterface::PersistentStoreLoadWatermark(int layerID) +{ + return false; +} + +bool PlayerThunderInterface::IsThunderAccess() +{ + return false; +} \ No newline at end of file diff --git a/test/utests/fakes/FakePlayerUtils.cpp b/test/utests/fakes/FakePlayerUtils.cpp new file mode 100644 index 00000000..7d46ba91 --- /dev/null +++ b/test/utests/fakes/FakePlayerUtils.cpp @@ -0,0 +1,64 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2025 RDK Management +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "PlayerUtils.h" +#include "MockPlayerUtils.h" +#include + +MockPlayerUtils *g_mockPlayerUtils = nullptr; + +char *base64_URL_Encode(const unsigned char *src, size_t len) +{ + return NULL; +} + +unsigned char *base64_URL_Decode(const char *src, size_t *len, size_t srcLen) +{ + return NULL; +} +long long GetCurrentTimeMS(void) +{ + long long timeMS = 0; + + if (g_mockPlayerUtils) + { + timeMS = g_mockPlayerUtils->GetCurrentTimeMS(); + } + + return timeMS; +} + +static std::hash std_thread_hasher; + +std::size_t GetThreadID( const std::thread &t ) +{ + return std_thread_hasher( t.get_id() ); +} +std::size_t GetThreadID( void ) +{ + return std_thread_hasher( std::this_thread::get_id() ); +} +/** + * @brief support for POSIX threads + */ +std::size_t GetThreadID( const pthread_t &t ) +{ + static std::hash pthread_hasher; + return pthread_hasher( t ); +} diff --git a/test/utests/fakes/FakeSocInterface.cpp b/test/utests/fakes/FakeSocInterface.cpp new file mode 100644 index 00000000..accd5f40 --- /dev/null +++ b/test/utests/fakes/FakeSocInterface.cpp @@ -0,0 +1,227 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2025 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +#include "SocInterface.h" +#include "vendor/default/DefaultSocInterface.h" +#include "vendor/amlogic/AmlogicSocInterface.h" +#include "vendor/brcm/BrcmSocInterface.h" +#include "vendor/realtek/RealtekSocInterface.h" +DefaultSocInterface::DefaultSocInterface() +{ +} +std::shared_ptr SocInterface::CreateSocInterface() +{ + std::shared_ptr obj = std::make_shared(); + return obj; +} +bool DefaultSocInterface::UseAppSrc() +{ +#if defined (__APPLE__) + return true; +#endif + return false; +} + +void DefaultSocInterface::SetAudioProperty(const char * &volume, const char * &mute, bool& isSinkBinVolume) +{ + isSinkBinVolume = false; + volume = "volume"; + mute = "mute"; +#if defined(__APPLE__) + isSinkBinVolume = true; +#endif +} +/** + * @brief Set AC4 tracks. + * @param src Source element. + * @param trackId Track ID. + */ +void DefaultSocInterface::SetAC4Tracks(GstElement *src, int trackId) +{ + g_object_set(src, "ac4-presentation-group-index", trackId, NULL); +} +bool DefaultSocInterface::IsVideoSink(const char* name, bool isRialto) +{ + return (!mUsingWesterosSink && StartsWith(name, "brcmvideosink") == true) || // brcmvideosink0, brcmvideosink1, ... + ( mUsingWesterosSink && StartsWith(name, "westerossink") == true) || + (isRialto && StartsWith(name, "rialtomsevideosink") == true); +} +/** + * @brief Check if the given name is a video decoder. + * @param name Element name. + * @param isRialto Rialto flag. + * @param isWesteros Westeros flag. + * @return True if it's a video decoder, false otherwise. + */ +bool DefaultSocInterface::IsVideoDecoder(const char* name, bool isRialto) +{ + if(mUsingWesterosSink) + { + return StartsWith(name, "westerossink"); + } + else if (isRialto) + { + return StartsWith(name, "rialtomsevideosink"); + } + return false; +} +/** + * @brief Check if the given name is an audio or video decoder. + * @param name Element name. + * @param IsWesteros Westeros flag. + * @return True if it's an audio or video decoder, false otherwise. + */ +bool DefaultSocInterface::IsAudioOrVideoDecoder(const char* name, bool isRialto) +{ + bool AudioOrVideoDecoder = false; + if(mUsingWesterosSink && StartsWith(name, "westerossink")) + { + AudioOrVideoDecoder = true; + } + else if(isRialto && StartsWith(name, "rialtomse")) + { + AudioOrVideoDecoder = true; + } + return AudioOrVideoDecoder; +} +/** + * @brief Set playback flags. + * + * Sets the playback flags based on the given parameters. + * @param flags Reference to the flags integer. + * @param isSub Flag indicating whether the content is a subtitle. + */ +void DefaultSocInterface::SetPlaybackFlags(gint &flags, bool isSub) +{ +#if (defined(__APPLE__)) + flags = PLAY_FLAG_VIDEO | PLAY_FLAG_AUDIO | PLAY_FLAG_SOFT_VOLUME; +#else + flags = PLAY_FLAG_VIDEO | PLAY_FLAG_AUDIO | PLAY_FLAG_NATIVE_AUDIO | PLAY_FLAG_NATIVE_VIDEO; +#endif + flags = PLAY_FLAG_VIDEO | PLAY_FLAG_AUDIO | PLAY_FLAG_SOFT_VOLUME; + if(isSub) + { + flags = PLAY_FLAG_TEXT; + } +} +bool DefaultSocInterface::IsSimulatorFirstFrame() +{ +#if (defined(RPI) || defined(__APPLE__) || defined(UBUNTU)) + return true; +#endif + return false; +} +bool DefaultSocInterface::IsSimulatorSink() +{ +#if !defined(UBUNTU) + return false; +#endif + return true; +} +void DefaultSocInterface::ConfigurePluginPriority() +{ +#ifdef UBUNTU + GstPluginFeature* pluginFeature = gst_registry_lookup_feature(gst_registry_get(), "pulsesink"); + if (pluginFeature != NULL) + { + gst_plugin_feature_set_rank(pluginFeature, GST_RANK_SECONDARY); + gst_object_unref(pluginFeature); + } +#endif +} +bool DefaultSocInterface::ShouldTearDownForTrickplay() +{ +#if defined(__APPLE__) || defined(UBUNTU) + return true; +#endif + return false; +} +bool DefaultSocInterface::IsSimulatorVideoSample() +{ +#if defined(__APPLE__) + return true; +#endif + return true; +} +void DefaultSocInterface::SetH264Caps(GstCaps *caps) +{ +#ifdef UBUNTU + // below required on Ubuntu - harmless on OSX, but breaks RPI + gst_caps_set_simple (caps, + "alignment", G_TYPE_STRING, "au", + "stream-format", G_TYPE_STRING, "avc", + NULL); +#endif +} +void DefaultSocInterface::SetHevcCaps(GstCaps *caps) +{ +#ifdef UBUNTU + // below required on Ubuntu - harmless on OSX, but breaks RPI +gst_caps_set_simple(caps, + "alignment", G_TYPE_STRING, "au", + "stream-format", G_TYPE_STRING, "hev1", + NULL); +#endif +} +void SocInterface::SetDecodeError(GstObject* src) +{ + g_object_set(src, "report_decode_errors", TRUE, NULL); +} +void SocInterface::SetWesterosSinkState(bool status) +{ + mUsingWesterosSink = true; +} +long long SocInterface::GetVideoPts(GstElement *video_sink, GstElement *video_dec, bool isWesteros) +{ + gint64 currentPTS = 0; + GstElement *element; + element = video_dec; + if(element) + { + g_object_get(element, "video-pts", ¤tPTS, NULL);/* Gets the 'video-pts' from the element into the currentPTS */ + if(!isWesteros) + { + currentPTS = currentPTS * 2; + } + } + return (long long)currentPTS; +} +bool SocInterface::StartsWith( const char *inputStr, const char *prefix ) +{ + bool rc = true; + while( *prefix ) + { + if( *inputStr++ != *prefix++ ) + { + rc = false; + break; + } + } + return rc; +} +bool DefaultSocInterface::ConfigureAudioSink(GstElement **audio_sink, GstObject *src, bool decStreamSync) +{ + bool status = false; + if (StartsWith(GST_OBJECT_NAME(src), "amlhalasink") == true) + { + gst_object_replace((GstObject **)audio_sink, src); + g_object_set(audio_sink, "disable-xrun", TRUE, NULL); + status = true; + } + return status; +} diff --git a/test/utests/fakes/FakeSocUtils.cpp b/test/utests/fakes/FakeSocUtils.cpp new file mode 100644 index 00000000..fb556477 --- /dev/null +++ b/test/utests/fakes/FakeSocUtils.cpp @@ -0,0 +1,75 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2025 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SocUtils.h" + +namespace SocUtils +{ + void InitializePlatformConfigs() + { + } + bool UseAppSrcForProgressivePlayback( void ) + { + return false; + } + bool IsSupportedAC4( void ) + { + return false; + } + bool UseWesterosSink( void ) + { + return false; + } + bool IsAudioFragmentSyncSupported( void ) + { + return false; + } + bool EnableLiveLatencyCorrection( void ) + { + return false; + } + bool DisableAC3( void ) + { + return false; + } + + bool IsSupportedAC3() + { + return false; + } + + int RequiredQueuedFrames( void ) + { + return 0; + } + bool EnablePTSRestamp(void) + { + return false; + } + + bool ResetNewSegmentEvent() + { + return false; + } + + bool isGstSubtecEnabled() + { + return false; + } +} diff --git a/test/utests/fakes/FakeTextStyleAttributes.cpp b/test/utests/fakes/FakeTextStyleAttributes.cpp new file mode 100644 index 00000000..3980268d --- /dev/null +++ b/test/utests/fakes/FakeTextStyleAttributes.cpp @@ -0,0 +1,30 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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 "TextStyleAttributes.h" + +TextStyleAttributes::TextStyleAttributes() +{ +} + +int TextStyleAttributes::getAttributes(std::string options, attributesType &attributesValues, + uint32_t &attributesMask) +{ + return 0; +} diff --git a/test/utests/fakes/FakeThunderAccessPlayer.cpp b/test/utests/fakes/FakeThunderAccessPlayer.cpp new file mode 100644 index 00000000..7ae22bde --- /dev/null +++ b/test/utests/fakes/FakeThunderAccessPlayer.cpp @@ -0,0 +1,74 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2018 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. + */ + +/** + * @file ThunderAccess.cpp + * @brief wrapper class for accessing thunder plugins + */ +#include "ThunderAccessPlayer.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Weffc++" + +/** + * @brief Structure to save the Thunder security token details + **/ +typedef struct ThunderSecurityPlayer +{ + std::string securityToken; + int tokenStatus; + bool tokenQueried; + ThunderSecurityPlayer(){ }; +}ThunderSecurityPlayerData; + +ThunderSecurityPlayerData gSecurityPlayerData; + + +/** + * @brief ThunderAccessPlayer constructor + */ +ThunderAccessPlayer::ThunderAccessPlayer(std::string callsign) +{ + +} + +/** + * @brief ThunderAccessPlayer destructor + */ +ThunderAccessPlayer::~ThunderAccessPlayer() +{ +} + +/** + * @brief ActivatePlugin + */ +bool ThunderAccessPlayer::ActivatePlugin() +{ + return false; +} + +/*To Do: Only JSON Object can be used as parameter now*/ + +/** + * @brief unSubscribeEvent + */ +bool ThunderAccessPlayer::UnSubscribeEvent (std::string eventName) +{ + return false; +} diff --git a/test/utests/fakes/Fakeopencdm.cpp b/test/utests/fakes/Fakeopencdm.cpp new file mode 100644 index 00000000..8ee2b314 --- /dev/null +++ b/test/utests/fakes/Fakeopencdm.cpp @@ -0,0 +1,124 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2024 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 "open_cdm.h" +#include "open_cdm_adapter.h" +#include "MockOpenCdm.h" + +MockOpenCdm *g_mockopencdm = nullptr; + +struct OpenCDMSystem* opencdm_create_system(const char keySystem[]) +{ + OpenCDMSystem *system = nullptr; + if (g_mockopencdm != nullptr) + { + system = g_mockopencdm->opencdm_create_system(keySystem); + } + return system; +} + +OpenCDMError opencdm_destruct_system(struct OpenCDMSystem* system) +{ + OpenCDMError ret = ERROR_NONE; + if (g_mockopencdm != nullptr) + { + ret = g_mockopencdm->opencdm_destruct_system(system); + } + return ret; +} + +OpenCDMError opencdm_construct_session(struct OpenCDMSystem* system, const LicenseType licenseType, + const char initDataType[], const uint8_t initData[], const uint16_t initDataLength, + const uint8_t CDMData[], const uint16_t CDMDataLength, OpenCDMSessionCallbacks* callbacks, void* userData, + struct OpenCDMSession** session) +{ + OpenCDMError ret = ERROR_NONE; + if (g_mockopencdm != nullptr) + { + ret = g_mockopencdm->opencdm_construct_session(system, licenseType, initDataType, initData, initDataLength, CDMData, CDMDataLength, callbacks, userData, session); + } + return ret; +} + +KeyStatus opencdm_session_status(const struct OpenCDMSession* session, + const uint8_t keyId[], const uint8_t length) +{ + KeyStatus ret = KeyStatus::Usable; + if (g_mockopencdm != nullptr) + { + ret = g_mockopencdm->opencdm_session_status(session, keyId, length); + } + return ret; +} + +OpenCDMError opencdm_session_update(struct OpenCDMSession* session, + const uint8_t keyMessage[], + const uint16_t keyLength) +{ + OpenCDMError ret = ERROR_NONE; + if (g_mockopencdm != nullptr) + { + ret = g_mockopencdm->opencdm_session_update(session, keyMessage, keyLength); + } + return ret; +} + +OpenCDMError opencdm_session_close(struct OpenCDMSession* session) +{ + OpenCDMError ret = ERROR_NONE; + if (g_mockopencdm != nullptr) + { + ret = g_mockopencdm->opencdm_session_close(session); + } + return ret; +} + +OpenCDMError opencdm_destruct_session(struct OpenCDMSession* session) +{ + OpenCDMError ret = ERROR_NONE; + if (g_mockopencdm != nullptr) + { + ret = g_mockopencdm->opencdm_destruct_session(session); + } + return ret; +} + +OpenCDMError opencdm_gstreamer_session_decrypt(struct OpenCDMSession* session, GstBuffer* buffer, + GstBuffer* subSample, const uint32_t subSampleCount, + GstBuffer* IV, GstBuffer* keyID, + uint32_t initWithLast15) +{ + return ERROR_NONE; +} + +OpenCDMError opencdm_session_decrypt(struct OpenCDMSession* session, uint8_t encrypted[], + const uint32_t encryptedLength, + const EncryptionScheme encScheme, + const EncryptionPattern pattern, const uint8_t* IV, + uint16_t IVLength, const uint8_t* keyId, + const uint16_t keyIdLength, uint32_t initWithLast15) +{ + if (g_mockopencdm != nullptr) + { + return g_mockopencdm->opencdm_session_decrypt(session, encrypted, encryptedLength, + encScheme, pattern, IV, IVLength, keyId, + keyIdLength, initWithLast15); + } + return ERROR_NONE; +} diff --git a/test/utests/fakes/Fakeopencdmsessionadapter.cpp b/test/utests/fakes/Fakeopencdmsessionadapter.cpp new file mode 100644 index 00000000..70f3843d --- /dev/null +++ b/test/utests/fakes/Fakeopencdmsessionadapter.cpp @@ -0,0 +1,71 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2024 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 "opencdmsessionadapter.h" +#include "DrmData.h" +#include "DrmSession.h" +#include "MockOpenCdmSessionAdapter.h" + +MockOpenCdmSessionAdapter *g_mockOpenCdmSessionAdapter = nullptr; +std::vector g_mockKeyId{1,2,3,4,5,6,7,8,9,0,1,2,3,4}; + +OCDMSessionAdapter::OCDMSessionAdapter(std::shared_ptr drmHelper, DrmCallbacks *callbacks) : + DrmSession("ocdmkeysystem"), m_keyId{g_mockKeyId}, m_drmHelper{drmHelper} +{ +} + +OCDMSessionAdapter::~OCDMSessionAdapter() +{} +bool OCDMSessionAdapter::verifyOutputProtection() +{ + bool ret_val = true; + if (g_mockOpenCdmSessionAdapter != nullptr) + { + ret_val = g_mockOpenCdmSessionAdapter->verifyOutputProtection(); + } + return ret_val; +} + +void OCDMSessionAdapter::generateDRMSession(const uint8_t *f_pbInitData, uint32_t f_cbInitData, std::string &customData) +{ + +} + +DrmData * OCDMSessionAdapter::generateKeyRequest(string& destinationURL, uint32_t timeout) +{ + return nullptr; +} + +int OCDMSessionAdapter::processDRMKey(DrmData* key, uint32_t timeout) +{ + return 0; +} + +KeyState OCDMSessionAdapter::getState() +{ + return KEY_INIT; +} +void OCDMSessionAdapter::clearDecryptContext() +{ +} +bool OCDMSessionAdapter::waitForState(KeyState state, const uint32_t timeout) +{ + return true; +} + diff --git a/test/utests/mocks/MockDrmHelper.h b/test/utests/mocks/MockDrmHelper.h new file mode 100644 index 00000000..fce08b34 --- /dev/null +++ b/test/utests/mocks/MockDrmHelper.h @@ -0,0 +1,85 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2022 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. +*/ + +#ifndef AAMP_MOCK_AAMP_DRM_HELPER_H +#define AAMP_MOCK_AAMP_DRM_HELPER_H + +#include +#include "DrmHelper.h" + +class MockDrmHelper : public DrmHelper +{ +public: + + MockDrmHelper() : DrmHelper(DrmInfo{}) + { + + } + + MOCK_METHOD(const std::string&, ocdmSystemId, (), (const, override)); + + MOCK_METHOD(void, createInitData, (std::vector& initData), (const, override)); + + MOCK_METHOD(bool, parsePssh, (const uint8_t* initData, uint32_t initDataLen), (override)); + + MOCK_METHOD(bool, isClearDecrypt, (), (const)); + + MOCK_METHOD(bool, isHdcp22Required, (), (const, override)); + + MOCK_METHOD(const std::string&, getDrmMetaData, (), (const, override)); + + MOCK_METHOD(void, setDrmMetaData, (const std::string& metaData), (override)); + + MOCK_METHOD(void, setDefaultKeyID, (const std::string& cencData), (override)); + + MOCK_METHOD(int, getDrmCodecType, (), (const, override)); + + MOCK_METHOD(uint32_t, licenseGenerateTimeout, (), (const, override)); + + MOCK_METHOD(uint32_t, keyProcessTimeout, (), (const, override)); + + MOCK_METHOD(void, getKey, (std::vector& keyID), (const, override)); + + MOCK_METHOD(void, getKeys, ((std::map>)& keyIDs), (const, override)); + + MOCK_METHOD(const std::string&, getUuid, (), (const, override)); + + MOCK_METHOD(bool, isExternalLicense, (), (const, override)); + + MOCK_METHOD(void, generateLicenseRequest, (const ChallengeInfo& challengeInfo, LicenseRequest& licenseRequest), (const, override)); + + MOCK_METHOD(void, transformLicenseResponse, (std::shared_ptr licenseResponse), (const, override)); + + MOCK_METHOD(DRMMemorySystem*, getMemorySystem, (), (override)); + + MOCK_METHOD(void, cancelDrmSession, (), (override)); + + MOCK_METHOD(bool, canCancelDrmSession, (), (override)); + + MOCK_METHOD(const std::string&, friendlyName, (), (const, override)); + + MOCK_METHOD(void, setOutputProtectionFlag, (bool bValue)); + + MOCK_METHOD(bool, isDecryptClearSamplesRequired,()); + + +}; + + +#endif /* AAMP_MOCK_AAMP_CONFIG_H */ diff --git a/test/utests/mocks/MockDrmMemorySystem.h b/test/utests/mocks/MockDrmMemorySystem.h new file mode 100644 index 00000000..65755bcf --- /dev/null +++ b/test/utests/mocks/MockDrmMemorySystem.h @@ -0,0 +1,43 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2024 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. +*/ + +#ifndef DRM_MOCK_MEMORY_SYSTEM_H +#define DRM_MOCK_MEMORY_SYSTEM_H + +#include +#include "DrmMemorySystem.h" + +class MockDrmMemorySystem : public DRMMemorySystem +{ +public: + + MockDrmMemorySystem() : DRMMemorySystem() + { + + } + + MOCK_METHOD(bool, encode, (const uint8_t *dataIn, uint32_t dataInSz, std::vector& dataOut), (override)); + + MOCK_METHOD(bool, decode, (const uint8_t* dataIn, uint32_t dataInSz, uint8_t *dataOut, uint32_t dataOutSz), (override)); + + MOCK_METHOD(void, terminateEarly, ()); +}; + + +#endif /* DRM_MOCK_MEMORY_SYSTEM_H */ diff --git a/test/utests/mocks/MockGLib.h b/test/utests/mocks/MockGLib.h new file mode 100644 index 00000000..7730a766 --- /dev/null +++ b/test/utests/mocks/MockGLib.h @@ -0,0 +1,45 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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. + */ + +#ifndef AAMP_MOCK_GLIB_H +#define AAMP_MOCK_GLIB_H + +#include +#include +#include + + +class MockGLib +{ +public: + MOCK_METHOD(GParamSpec*, g_object_class_find_property, (GObjectClass* oclass, const gchar* property_name)); + MOCK_METHOD(guint, g_timeout_add, (guint interval, GSourceFunc function, gpointer data)); + MOCK_METHOD(gboolean, g_source_remove, (guint tag)); + MOCK_METHOD(gpointer, g_malloc, (gsize n_bytes)); + MOCK_METHOD(void, g_free, (gpointer mem)); + MOCK_METHOD(gpointer, g_realloc, (gpointer mem, gsize n_bytes)); + + MOCK_METHOD(void, g_object_set, (gpointer object, const gchar *property_name, int value)); + MOCK_METHOD(void, g_object_set, (gpointer object, const gchar *property_name, char * value)); + MOCK_METHOD(void, g_object_set, (gpointer object, const gchar *property_name, double value)); +}; + +extern MockGLib *g_mockGLib; + +#endif /* AAMP_MOCK_GLIB_H */ diff --git a/test/utests/mocks/MockGStreamer.h b/test/utests/mocks/MockGStreamer.h new file mode 100644 index 00000000..9278e5e2 --- /dev/null +++ b/test/utests/mocks/MockGStreamer.h @@ -0,0 +1,70 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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. + */ + +#ifndef AAMP_MOCK_GSTREAMER_H +#define AAMP_MOCK_GSTREAMER_H + +#include +#include +#include + +class MockGStreamer +{ +public: + MOCK_METHOD(GstCaps *, gst_caps_new_simple, + (const char *media_type, const char *fieldname, GType var, const int val, + void *ptr)); + MOCK_METHOD(void, gst_debug_set_threshold_from_string, (const gchar *list, gboolean reset)); + MOCK_METHOD(GstElement *, gst_pipeline_new, (const gchar *name)); + MOCK_METHOD(GstBus *, gst_pipeline_get_bus, (GstPipeline *pipeline)); + MOCK_METHOD(guint , gst_bus_add_watch, (GstBus *bus, GstBusFunc func, gpointer user_data)); + MOCK_METHOD(void, gst_bus_set_sync_handler, (GstBus *bus, GstBusSyncHandler func, gpointer user_data, GDestroyNotify notify)); + MOCK_METHOD(GstQuery *, gst_query_new_position, (GstFormat format)); + MOCK_METHOD(GstStateChangeReturn, gst_element_get_state, (GstElement *element, GstState *state, GstState *pending, + GstClockTime timeout)); + MOCK_METHOD(GstElement *, gst_element_factory_make, (const gchar *factoryname,const gchar *name)); + MOCK_METHOD(GstStateChangeReturn, gst_element_set_state,(GstElement *element, GstState state)); + MOCK_METHOD(gboolean, gst_bin_add, (GstBin *bin, GstElement *element)); + MOCK_METHOD(void, gst_object_unref,(gpointer object)); + MOCK_METHOD(void, gst_mini_object_unref,(GstMiniObject *mini_object)); + + MOCK_METHOD(GstSample *,gst_app_sink_pull_sample,(GstAppSink *appsink)); + MOCK_METHOD(GstStructure *,gst_app_sink_set_caps,(GstAppSink *appsink, const GstCaps *caps)); + MOCK_METHOD(GstStructure *,gst_caps_get_structure,(const GstCaps *caps, guint index)); + MOCK_METHOD(void, gst_message_parse_state_changed, (GstMessage * message, GstState * oldstate, GstState * newstate, GstState * pending)); + + MOCK_METHOD(gboolean, gst_object_replace, (GstObject ** oldobj, GstObject * newobj)); + MOCK_METHOD(gboolean, gst_element_send_event, (GstElement *element, GstEvent *event)); + MOCK_METHOD(GstEvent *, gst_event_new_step, (GstFormat format, guint64 amount, gdouble rate, gboolean flush, gboolean intermediate)); + MOCK_METHOD(gboolean, gst_element_query_position, (GstElement *element, GstFormat format, gint64 *cur)); + + /* +gst_app_sink_get_type +gst_app_sink_pull_sample +gst_app_sink_set_caps +gst_caps_get_structure +gst_sample_get_buffer +gst_sample_get_caps +gst_structure_get_int + */ +}; + +extern MockGStreamer *g_mockGStreamer; + +#endif /* AAMP_MOCK_GSTREAMER_H */ diff --git a/test/utests/mocks/MockGstHandlerControl.h b/test/utests/mocks/MockGstHandlerControl.h new file mode 100644 index 00000000..03704238 --- /dev/null +++ b/test/utests/mocks/MockGstHandlerControl.h @@ -0,0 +1,35 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2024 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. +*/ + +#ifndef GST_MOCK_GST_HANDLER_CONTROL_H +#define GST_MOCK_GST_HANDLER_CONTROL_H + +#include +#include "GstHandlerControl.h" + +class MockGstHandlerControl +{ +public: + + MOCK_METHOD(bool, isEnabled, ()); +}; + +extern MockGstHandlerControl *g_mockGstHandlerControl; + +#endif /* GST_MOCK_GST_HANDLER_CONTROL_H */ diff --git a/test/utests/mocks/MockOpenCdm.h b/test/utests/mocks/MockOpenCdm.h new file mode 100644 index 00000000..d036231a --- /dev/null +++ b/test/utests/mocks/MockOpenCdm.h @@ -0,0 +1,56 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2024 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. +*/ + +#ifndef PLAYER_MOCK_OPEN_CDM_H +#define PLAYER_MOCK_OPEN_CDM_H + +#include "open_cdm.h" +#include + +struct _GstBuffer; +typedef struct _GstBuffer GstBuffer; + +class MockOpenCdm +{ +public: + MOCK_METHOD(OpenCDMError, opencdm_session_decrypt, + (struct OpenCDMSession * session, uint8_t encrypted[], + const uint32_t encryptedLength, const EncryptionScheme encScheme, + const EncryptionPattern pattern, const uint8_t* IV, uint16_t IVLength, + const uint8_t* keyId, const uint16_t keyIdLength, uint32_t initWithLast15)); + MOCK_METHOD(OpenCDMError, opencdm_destruct_system, (struct OpenCDMSystem* system)); + MOCK_METHOD(OpenCDMSystem*, opencdm_create_system, (const char keySystem[])); + MOCK_METHOD(OpenCDMError, opencdm_construct_session, + (struct OpenCDMSystem * system, const LicenseType licenseType, + const char initDataType[], const uint8_t initData[], const uint16_t initDataLength, + const uint8_t CDMData[], const uint16_t CDMDataLength, + OpenCDMSessionCallbacks* callbacks, void* userData, + struct OpenCDMSession** session)); + MOCK_METHOD(OpenCDMError, opencdm_session_update, + (struct OpenCDMSession * session, const uint8_t keyMessage[], + const uint16_t keyLength)); + MOCK_METHOD(OpenCDMError, opencdm_session_close, (struct OpenCDMSession* session)); + MOCK_METHOD(OpenCDMError, opencdm_destruct_session, (struct OpenCDMSession* session)); + MOCK_METHOD(KeyStatus, opencdm_session_status, (const struct OpenCDMSession* session, const uint8_t keyId[], const uint8_t length)); + +}; + +extern MockOpenCdm* g_mockopencdm; + +#endif /* PLAYER_MOCK_OPEN_CDM_H */ diff --git a/test/utests/mocks/MockOpenCdmSessionAdapter.h b/test/utests/mocks/MockOpenCdmSessionAdapter.h new file mode 100644 index 00000000..5c5fcc84 --- /dev/null +++ b/test/utests/mocks/MockOpenCdmSessionAdapter.h @@ -0,0 +1,36 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2024 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. +*/ + +#ifndef PLAYER_MOCK_OPEN_CDM_SESSION_ADAPTER_H +#define PLAYER_MOCK_OPEN_CDM_SESSION_ADAPTER_H + +#include + +extern std::vector g_mockKeyId; +class MockOpenCdmSessionAdapter +{ + public: + + MOCK_METHOD(bool, verifyOutputProtection, ()); + +}; + +extern MockOpenCdmSessionAdapter *g_mockOpenCdmSessionAdapter; + +#endif /* PLAYER_MOCK_OPEN_CDM_SESSION_ADAPTER_H */ diff --git a/test/utests/mocks/MockPlayerConfig.h b/test/utests/mocks/MockPlayerConfig.h new file mode 100644 index 00000000..2dfce0f5 --- /dev/null +++ b/test/utests/mocks/MockPlayerConfig.h @@ -0,0 +1,53 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2022 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. +*/ + +#ifndef AAMP_MOCK_AAMP_CONFIG_H +#define AAMP_MOCK_AAMP_CONFIG_H + +#include +#include "AampConfig.h" + +class MockAampConfig +{ +public: + MOCK_METHOD(void, SetConfigValue, (AAMPConfigSettingBool cfg, const bool &value)); + MOCK_METHOD(void, SetConfigValue, (AAMPConfigSettingInt cfg, const int &value)); + MOCK_METHOD(void, SetConfigValue, (AAMPConfigSettingFloat cfg, const double &value)); + MOCK_METHOD(void, SetConfigValue, (AAMPConfigSettingString cfg, const std::string &value)); + + MOCK_METHOD(bool, IsConfigSet, (AAMPConfigSettingBool cfg)); + MOCK_METHOD(int, GetConfigValue, (AAMPConfigSettingInt cfg)); + MOCK_METHOD(double, GetConfigValue, (AAMPConfigSettingFloat cfg)); + MOCK_METHOD(std::string, GetConfigValue, (AAMPConfigSettingString cfg)); + + MOCK_METHOD(ConfigPriority, GetConfigOwner, (AAMPConfigSettingBool cfg)); + MOCK_METHOD(ConfigPriority, GetConfigOwner, (AAMPConfigSettingInt cfg)); + MOCK_METHOD(ConfigPriority, GetConfigOwner, (AAMPConfigSettingFloat cfg)); + MOCK_METHOD(ConfigPriority, GetConfigOwner, (AAMPConfigSettingString cfg)); + + MOCK_METHOD(void, RestoreConfiguration, (ConfigPriority owner, AAMPConfigSettingBool cfg)); + MOCK_METHOD(void, RestoreConfiguration, (ConfigPriority owner, AAMPConfigSettingInt cfg)); + MOCK_METHOD(void, RestoreConfiguration, (ConfigPriority owner, AAMPConfigSettingFloat cfg)); + MOCK_METHOD(void, RestoreConfiguration, (ConfigPriority owner, AAMPConfigSettingString cfg)); + +}; + +extern MockAampConfig *g_mockAampConfig; + +#endif /* AAMP_MOCK_AAMP_CONFIG_H */ diff --git a/test/utests/mocks/MockPlayerJsonObject.h b/test/utests/mocks/MockPlayerJsonObject.h new file mode 100644 index 00000000..939eadab --- /dev/null +++ b/test/utests/mocks/MockPlayerJsonObject.h @@ -0,0 +1,50 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2025 RDK Management +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#pragma once + +#include +#include "PlayerJsonObject.h" + +class MockPlayerJsonObject : public PlayerJsonObject +{ +public: + MOCK_METHOD(bool, add, (const std::string& name, const std::string& value, const ENCODING encoding)); + MOCK_METHOD(bool, add, (const std::string& name, const char *value, const ENCODING encoding)); + MOCK_METHOD(bool, add, (const std::string& name, const std::vector& values)); + MOCK_METHOD(bool, add, (const std::string& name, const std::vector& values, const ENCODING encoding)); + MOCK_METHOD(bool, add, (const std::string& name, PlayerJsonObject& value)); + MOCK_METHOD(bool, add, (const std::string& name, std::vector& values)); + MOCK_METHOD(bool, add, (const std::string& name, cJSON *value)); + MOCK_METHOD(bool, add, (const std::string& name, bool value)); + MOCK_METHOD(bool, add, (const std::string& name, int value)); + MOCK_METHOD(bool, add, (const std::string& name, long value)); + MOCK_METHOD(bool, add, (const std::string& name, double value)); + + MOCK_METHOD(bool, set, (PlayerJsonObject *parent, cJSON *object)); + + MOCK_METHOD(bool, get, (const std::string& name, PlayerJsonObject &value)); + MOCK_METHOD(bool, get, (const std::string& name, std::string& value)); + MOCK_METHOD(bool, get, (const std::string& name, int& value)); + MOCK_METHOD(bool, get, (const std::string& name, std::vector& values)); + MOCK_METHOD(bool, get, (const std::string& name, std::vector& values, const ENCODING encoding)); +}; + +extern std::shared_ptr g_mockPlayerJsonObject; + diff --git a/test/utests/mocks/MockPlayerScheduler.h b/test/utests/mocks/MockPlayerScheduler.h new file mode 100644 index 00000000..d854c750 --- /dev/null +++ b/test/utests/mocks/MockPlayerScheduler.h @@ -0,0 +1,37 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2024 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. +*/ + +#ifndef MOCK_PLAYER_SCHEDULER_H +#define MOCK_PLAYER_SCHEDULER_H + +#include +#include "PlayerScheduler.h" + +class MockPlayerScheduler +{ +public: + + MOCK_METHOD(int, ScheduleTask, (PlayerAsyncTaskObj obj)); + +}; + +extern MockPlayerScheduler *g_mockPlayerScheduler; + +#endif /* PLAYER_MOCK_PLAYER_SCHEDULER_H */ + diff --git a/test/utests/mocks/MockPlayerUtils.h b/test/utests/mocks/MockPlayerUtils.h new file mode 100644 index 00000000..bf618d8a --- /dev/null +++ b/test/utests/mocks/MockPlayerUtils.h @@ -0,0 +1,33 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2024 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. +*/ + +#ifndef MOCK_PLAYER_UTILS_H +#define MOCK_PLAYER_UTILS_H + +#include +class MockPlayerUtils +{ +public: + + MOCK_METHOD(long long, GetCurrentTimeMS, ()); +}; + +extern MockPlayerUtils *g_mockPlayerUtils; +#endif + diff --git a/test/utests/mocks/opencdmMocks.cpp b/test/utests/mocks/opencdmMocks.cpp new file mode 100755 index 00000000..f03ecc12 --- /dev/null +++ b/test/utests/mocks/opencdmMocks.cpp @@ -0,0 +1,103 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2022 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 "opencdmMocks.h" + +MockOpenCdm *g_mockOpenCdm; + +struct OpenCDMSystem* opencdm_create_system(const char keySystem[]) +{ + return g_mockOpenCdm->opencdm_create_system(keySystem); +} + +OpenCDMError opencdm_construct_session(struct OpenCDMSystem* system, + const LicenseType licenseType, + const char initDataType[], + const uint8_t initData[], + const uint16_t initDataLength, + const uint8_t CDMData[], + const uint16_t CDMDataLength, + OpenCDMSessionCallbacks* callbacks, + void* userData, + struct OpenCDMSession** session) +{ + return g_mockOpenCdm->opencdm_construct_session(system, + licenseType, + initDataType, + initData, + initDataLength, + CDMData, + CDMDataLength, + callbacks, + userData, + session); +} + +OpenCDMError opencdm_destruct_system(struct OpenCDMSystem* system) +{ + return g_mockOpenCdm->opencdm_destruct_system(system); +} + +KeyStatus opencdm_session_status(const struct OpenCDMSession* session, + const uint8_t keyId[], + const uint8_t length) +{ + return g_mockOpenCdm->opencdm_session_status(session, keyId, length); +} + +OpenCDMError opencdm_session_update(struct OpenCDMSession* session, + const uint8_t keyMessage[], + const uint16_t keyLength) +{ + return g_mockOpenCdm->opencdm_session_update(session, keyMessage, keyLength); +} + +OpenCDMError opencdm_gstreamer_session_decrypt(struct OpenCDMSession* session, + GstBuffer* buffer, + GstBuffer* subSample, + const uint32_t subSampleCount, + GstBuffer* IV, + GstBuffer* keyID, + uint32_t initWithLast15) +{ + return g_mockOpenCdm->opencdm_gstreamer_session_decrypt(session, buffer, subSample, subSampleCount, IV, keyID,initWithLast15); +} + +OpenCDMError opencdm_session_decrypt( struct OpenCDMSession* session, + uint8_t encrypted[], + const uint32_t encryptedLength, + const uint8_t* IV, + uint16_t IVLength, + const uint8_t* keyId, + const uint16_t keyIdLength, + uint32_t initWithLast15, + uint8_t* streamInfo, + uint16_t streamInfoLength) +{ + return g_mockOpenCdm->opencdm_session_decrypt(session, encrypted, encryptedLength, IV, IVLength, keyId, keyIdLength, initWithLast15, streamInfo, streamInfoLength); +} + +OpenCDMError opencdm_session_close(struct OpenCDMSession* session) +{ + return g_mockOpenCdm->opencdm_session_close(session); +} + +OpenCDMError opencdm_destruct_session(struct OpenCDMSession* session) +{ + return ERROR_NONE; +} diff --git a/test/utests/mocks/opencdmMocks.h b/test/utests/mocks/opencdmMocks.h new file mode 100755 index 00000000..fddcfe20 --- /dev/null +++ b/test/utests/mocks/opencdmMocks.h @@ -0,0 +1,70 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2022 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. + */ + +#ifndef AAMP_OPENCDM_MOCKS +#define AAMP_OPENCDM_MOCKS + +#include "open_cdm.h" +#include "open_cdm_adapter.h" +#include +#include + +class MockOpenCdm +{ + public: + MOCK_METHOD(struct OpenCDMSystem *, opencdm_create_system, (const char keySystem[])); + MOCK_METHOD(OpenCDMError, opencdm_construct_session, (struct OpenCDMSystem* system, + const LicenseType licenseType, + const char initDataType[], + const uint8_t initData[], + const uint16_t initDataLength, + const uint8_t CDMData[], + const uint16_t CDMDataLength, + OpenCDMSessionCallbacks* callbacks, + void* userData, + struct OpenCDMSession** session)); + MOCK_METHOD(OpenCDMError, opencdm_destruct_system, (struct OpenCDMSystem* system)); + MOCK_METHOD(KeyStatus, opencdm_session_status, (const struct OpenCDMSession* session, + const uint8_t keyId[], + const uint8_t length)); + MOCK_METHOD(OpenCDMError, opencdm_session_update, (struct OpenCDMSession* session, + const uint8_t keyMessage[], + const uint16_t keyLength)); + MOCK_METHOD(OpenCDMError, opencdm_gstreamer_session_decrypt, (struct OpenCDMSession* session, + GstBuffer* buffer, + GstBuffer* subSample, + const uint32_t subSampleCount, + GstBuffer* IV, + GstBuffer* keyID, + uint32_t initWithLast15)); + MOCK_METHOD(OpenCDMError, opencdm_session_decrypt, (struct OpenCDMSession* session, + uint8_t encrypted[], + const uint32_t encryptedLength, + const uint8_t* IV, + uint16_t IVLength, + const uint8_t* keyId, + const uint16_t keyIdLength, + uint32_t initWithLast15, + uint8_t* streamInfo, + uint16_t streamInfoLength)); + MOCK_METHOD(OpenCDMError, opencdm_session_close, (struct OpenCDMSession* session)); + MOCK_METHOD(OpenCDMError, opencdm_destruct_session, (struct OpenCDMSession* session)); +}; + +#endif /* AAMP_OPENCDM_MOCKS */ diff --git a/test/utests/ocdm/open_cdm.h b/test/utests/ocdm/open_cdm.h new file mode 100644 index 00000000..e9e3497b --- /dev/null +++ b/test/utests/ocdm/open_cdm.h @@ -0,0 +1,639 @@ +/* + * Copyright 2016-2017 TATA ELXSI + * Copyright 2016-2017 Metrological + * + * 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. + */ + +#ifndef OPEN_CDM_H +#define OPEN_CDM_H + +// WPEWebkit implementation is using the following header file to integrate +// their solution with +// DRM systems (PlayReady/WideVine/ClearKey). +// The implementation behind this class/interface exists in two flavors. +// 1) Fraunhofers adapted reference implementation, based on SUNRPC +// 2) Metrologicals framework, based on their proprietary RPC mechanism. +// +// The second option exists because during testing the reference/adapted +// implementation of Frauenhofer +// it was observed: +// - Older implementations of ucLibc had different dynamic characteristics that +// caused deadlocks +// - Message exchange over the SUNRPC mechanism is using continous heap memory +// allocations/deallocactions, +// leading to a higher risk of memory fragmentation. +// - SUNRPC only works on UDP/TCP, given the nature and size of the messages, +// UDP was not an option so TCP +// is used. There is no domain socket implementation for the SUNRPC mechanism. +// Domain sockets transfer +// data, as an average, twice as fast as TCP sockets. +// - SUNRPC requires an external process (bind) to do program number lookup to +// TCP port connecting. Currently +// the Frauenhofer OpenCDMi reference implementation is the only +// implementation requiring this service on +// most deplyments with the WPEWebkit. +// - Common Vulnerabilities and Exposures (CVE's) have been reported with the +// SUNRPC that have not been resolved +// on most platforms where the solution is deployed. +// - The Metrological RPC mechanism allows for a configurable in or out of +// process deplyment of the OpenCDMi +// deployment without rebuilding. +// +// So due to performance and security exploits it was decided to offer a second +// implementation of the OpenCDMi +// specification that did notrequire to change the WPEWebKit + +#include +#include + +#include +#include + +#ifndef EXTERNAL +#ifdef _MSVC_LANG +#ifdef OCDM_EXPORTS +#define EXTERNAL __declspec(dllexport) +#else +#define EXTERNAL __declspec(dllimport) +#endif +#else +#define EXTERNAL __attribute__ ((visibility ("default"))) +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WINDOWS) + #if !defined(OCDM_EXPORTS) + #pragma comment(lib, "ocdm.lib") + #endif + + /** + * Sometimes the compiler would like to be smart, if we do not reference + * anything here + * and you enable the rightflags, the linker drops the dependency. Than + * Proxy/Stubs do + * not get loaded, so lets make the instantiation of the ProxyStubs explicit !!! + */ + EXTERNAL void ForceLinkingOfOpenCDM(); +#endif + +#define SESSION_ID_LEN 16 +#define MAX_NUM_SECURE_STOPS 8 + +/** + * Represents an OCDM system + */ +struct OpenCDMSystem; + +/** + * Represents a OpenCDM session, use this one to decrypt. + */ +struct OpenCDMSession; + +typedef enum { + Temporary = 0, + PersistentUsageRecord, + PersistentLicense +} LicenseType; + +// ISO/IEC 23001-7 defines two Common Encryption Schemes with Full Sample and Subsample modes +typedef enum { + Clear = 0, + AesCtr_Cenc, // AES-CTR mode and Sub-Sample encryption + AesCbc_Cbc1, // AES-CBC mode and Sub-Sample encryption + AesCtr_Cens, // AES-CTR mode and Sub-Sample + patterned encryption + AesCbc_Cbcs // AES-CBC mode and Sub-Sample + patterned encryption + Constant IV +} EncryptionScheme; + +typedef enum +{ + MediaType_Unknown = 0, + MediaType_Video, + MediaType_Audio, + MediaType_Data +} OcdmMediaType; + +//CENC3.0 pattern is a number of encrypted blocks followed a number of clear blocks after which the pattern repeats. +typedef struct { + uint32_t encrypted_blocks; + uint32_t clear_blocks; +} EncryptionPattern; + +typedef struct { + uint16_t clear_bytes; + uint32_t encrypted_bytes; +} SubSampleInfo; + +typedef struct { + EncryptionScheme scheme; // Encryption scheme used in this sample + EncryptionPattern pattern; // Encryption Pattern used in this sample + uint8_t* iv; // Initialization vector(IV) to decrypt this sample. Can be NULL, in that case and IV of all zeros is assumed. + uint8_t ivLength; // Length of IV + uint8_t* keyId; // ID of Key required to decrypt this sample + uint8_t keyIdLength; // Length of KeyId + uint8_t subSampleCount; // Number or Sub-Samples in this sample + SubSampleInfo* subSample; // SubSample mapping - Repeating pair of Clear bytes and Encrypted Bytes representing each subsample. +} SampleInfo; + +// Provides information about the current stream +typedef struct { + uint16_t height; + uint16_t width; + OcdmMediaType media_type; +} MediaProperties; + + +/** + * Key status. + */ +typedef enum { + Usable = 0, + Expired, + Released, + OutputRestricted, + OutputRestrictedHDCP22, + OutputDownscaled, + StatusPending, + InternalError, + HWError +} KeyStatus; + +/** + * OpenCDM error code. Zero always means success. + */ +typedef enum { + ERROR_NONE = 0, + ERROR_UNKNOWN = 1, + ERROR_MORE_DATA_AVAILABLE = 2, + ERROR_INTERFACE_NOT_IMPLEMENTED = 3, + ERROR_BUFFER_TOO_SMALL = 4, + ERROR_INVALID_ACCESSOR = 0x80000001, + ERROR_KEYSYSTEM_NOT_SUPPORTED = 0x80000002, + ERROR_INVALID_SESSION = 0x80000003, + ERROR_INVALID_DECRYPT_BUFFER = 0x80000004, + ERROR_OUT_OF_MEMORY = 0x80000005, + ERROR_METHOD_NOT_IMPLEMENTED = 0x80000006, + ERROR_FAIL = 0x80004005, + ERROR_INVALID_ARG = 0x80070057, + ERROR_SERVER_INTERNAL_ERROR = 0x8004C600, + ERROR_SERVER_INVALID_MESSAGE = 0x8004C601, + ERROR_SERVER_SERVICE_SPECIFIC = 0x8004C604, + ERROR_BUSY_CANNOT_INITIALIZE = 0x8004DD00 + +} OpenCDMError; + +/** + * OpenCDM bool type. 0 is false, 1 is true. + */ +typedef enum { + OPENCDM_BOOL_FALSE = 0, + OPENCDM_BOOL_TRUE = 1 +} OpenCDMBool; + +/** + * Registered callbacks with OCDM sessions. + */ +typedef struct { + /** + * Request of process of DRM challenge data. Server is indicated by \ref url. The response of the server + * needs to be send to \ref opencdm_session_update. + * + * \param session The session the notification applies to. + * \param userData Pointer passed along when \ref opencdm_construct_session was issued. + * \param url Target URL to send challenge to. + * \param challenge Buffer containing challenge. + * \param challengeLength Length of challenge (in bytes). + */ + void (*process_challenge_callback)(struct OpenCDMSession* session, void* userData, const char url[], const uint8_t challenge[], const uint16_t challengeLength); + + /** + * Called when status of a key changes. Use \ref opencdm_session_status to find out new key status. + * + * \param session The session the notification applies to. + * \param userData Pointer passed along when \ref opencdm_construct_session was issued. + * \param keyId Buffer containing key ID. + * \param length Length of key ID buffer. + */ + void (*key_update_callback)(struct OpenCDMSession* session, void* userData, const uint8_t keyId[], const uint8_t length); + + /** + * Called when an error message is received from the DRM system + * + * \param session The session the notification applies to. + * \param userData Pointer passed along when \ref opencdm_construct_session was issued. + * \param message Text string, null terminated, from the DRM session. + */ + void (*error_message_callback)(struct OpenCDMSession* session, void* userData, const char message[]); + + /** + * Called after all known key status changes were reported. + * + * \param session The session the notification applies to. + * \param userData Pointer passed along when \ref opencdm_construct_session was issued. + */ + void (*keys_updated_callback)(const struct OpenCDMSession* session, void* userData); +} OpenCDMSessionCallbacks; + +/** + * \brief Creates DRM system. + * + * \return \ref OpenCDMAccessor instance, NULL on error. + */ +EXTERNAL struct OpenCDMSystem* opencdm_create_system(const char keySystem[]); + +/** + * \brief Creates DRM system. + * + * \param system Output parameter that will contain pointer to instance of \ref OpenCDMSystem. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_create_system_extended(const char keySystem[], struct OpenCDMSystem** system); + +/** + * Destructs an \ref OpenCDMAccessor instance. + * \param system \ref OpenCDMAccessor instance to desctruct. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_destruct_system(struct OpenCDMSystem* system); + +/** + * \brief Checks if a DRM system is supported. + * + * \param system Instance of \ref OpenCDMAccessor. + * \param keySystem Name of required key system (e.g. + * "com.microsoft.playready"). + * \param mimeType MIME type. + * \return Zero if supported, Non-zero otherwise. + * \remark mimeType is currently ignored. + */ +EXTERNAL OpenCDMError opencdm_is_type_supported(const char keySystem[], + const char mimeType[]); + +/** + * \brief Retrieves DRM system specific metadata. + * + * \param system Instance of \ref OpenCDMAccessor. + * \param metadata, buffer to write metadata into, always 0 terminated (also when not large enough to hold all data) except when metadata is + * Null of course. Null allowed to retrieve required size needed for this buffer in metadataSize to be able to allocate required buffer + * for subsequent call to opencdm_is_type_supported + * \param metadataSize, in: size of metadata buffer, out: required size to hold all data available when return value is ERROR_MORE_DATA_AVAILBALE, + * , number of characters written into metadata (incl 0 terminator) otherwise. Note in case metadata could not hold all data but was not of zero + * length it is filled up to the maximum size (still zero terminated) but also ERROR_MORE_DATA_AVAILBALE is returned with the required size needed + * to hold all data + * \return Zero on success, non-zero on error. ERROR_MORE_DATA_AVAILBALE when the buffer was not large enough to hold all the data available. + */ +EXTERNAL OpenCDMError opencdm_system_get_metadata(struct OpenCDMSystem* system, + char metadata[], + uint16_t* metadataSize); + +/** + * \brief Returns string describing version of DRM system. + * + * \param system Instance of \ref OpenCDMAccessor. + * \param keySystem Name of queried key system (e.g. + * "com.microsoft.playready"). + * \param versionStr Char buffer to receive NULL-terminated version string. + * (Should as least be 64 chars long.) + * \return Zero if successful, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_system_get_version(struct OpenCDMSystem* system, + char versionStr[]); + +/** + * \brief Returns time according to DRM system. + * Some systems (e.g. PlayReady) keep their own clocks, for example to prevent + * rollback. Systems + * not implementing their own clock can return the system time. + * + * \param system Instance of \ref OpenCDMAccessor. + * \param keySystem Name of queried key system (e.g. "com.microsoft.playready"). + * \param time Output variable that will contain DRM system time. + * \return Zero if successful, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_system_get_drm_time(struct OpenCDMSystem* system, + uint64_t* time); + +/** + * \brief Maps key ID to \ref OpenCDMSession instance. + * + * In some situations we only have the key ID, but need the specific \ref + * OpenCDMSession instance that + * belongs to this key ID. This method facilitates this requirement. + * \param system Instance of \ref OpenCDMAccessor. + * \param keyId Array containing key ID. + * \param length Length of keyId array. + * \param maxWaitTime Maximum allowed time to block (in milliseconds). + * \return \ref OpenCDMSession belonging to key ID, or NULL when not found or + * timed out. This instance + * also needs to be destructed using \ref opencdm_session_destruct. + */ +EXTERNAL struct OpenCDMSession* opencdm_get_session(const uint8_t keyId[], + const uint8_t length, + const uint32_t waitTime); + +/** + * \brief Maps key ID to \ref OpenCDMSession instance within the given system instance. + * + * In some situations we only have the key ID, but need the specific \ref + * OpenCDMSession instance that + * belongs to this key ID. This method facilitates this requirement. + * \param system Instance of \ref OpenCDMSystem. + * \param keyId Array containing key ID. + * \param length Length of keyId array. + * \param maxWaitTime Maximum allowed time to block (in milliseconds). + * \return \ref OpenCDMSession belonging to key ID, or NULL when not found or + * timed out. This instance + * also needs to be destructed using \ref opencdm_session_destruct. + */ +EXTERNAL struct OpenCDMSession* opencdm_get_system_session(struct OpenCDMSystem* system, const uint8_t keyId[], + const uint8_t length, const uint32_t waitTime); + +/** + * \brief Gets support server certificate. + * + * Some DRMs (e.g. WideVine) use a system-wide server certificate. This method + * gets if system has support for that certificate. + * \param system Instance of \ref OpenCDMAccessor. + * \return Non-zero on success, zero on error. + */ +EXTERNAL OpenCDMBool opencdm_system_supports_server_certificate( + struct OpenCDMSystem* system); + +/** + * \brief Sets server certificate. + * + * Some DRMs (e.g. WideVine) use a system-wide server certificate. This method + * will set that certificate. Other DRMs will ignore this call. + * \param system Instance of \ref OpenCDMAccessor. + * \param keySystem Name of key system to set server certificate for. + * \param serverCertificate Buffer containing certificate data. + * \param serverCertificateLength Buffer length of certificate data. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_system_set_server_certificate( + struct OpenCDMSystem* system, + const uint8_t serverCertificate[], const uint16_t serverCertificateLength); + +/** + * \brief Get metrics associated with a DRM system. + * + * Some DRMs (e.g. WideVine) offer metric data that can be used for any + * analyses. This function retrieves the metric data of the passed in + * system. It is up to the callee to interpret the baniary data correctly. + * \param system Instance of \ref OpenCDMAccessor. + * \param bufferLength Actual buffer length of the buffer parameter, on return + * it holds the number of bytes actually written in it. + * \param buffer Buffer length of buffer that can hold the metric data. + * \return Zero on success, non-zero on error. + */ + +EXTERNAL OpenCDMError opencdm_get_metric_system_data(struct OpenCDMSystem* system, + uint32_t* bufferLength, + uint8_t* buffer); + +/** + * \brief Create DRM session (for actual decrypting of data). + * + * Creates an instance of \ref OpenCDMSession using initialization data. + * \param system Instance of \ref OpenCDMAccessor. + * \param keySystem DRM system to create the session for. + * \param licenseType DRM specifc signed integer selecting License Type (e.g. + * "Limited Duration" for PlayReady). + * \param initDataType Type of data passed in \ref initData. + * \param initData Initialization data. + * \param initDataLength Length (in bytes) of initialization data. + * \param CDMData CDM data. + * \param CDMDataLength Length (in bytes) of \ref CDMData. + * \param callbacks the instance of \ref OpenCDMSessionCallbacks with callbacks to be called on events. + * \param userData the user data to be passed back to the \ref OpenCDMSessionCallbacks callbacks. + * \param session Output parameter that will contain pointer to instance of \ref OpenCDMSession. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_construct_session(struct OpenCDMSystem* system, const LicenseType licenseType, + const char initDataType[], const uint8_t initData[], const uint16_t initDataLength, + const uint8_t CDMData[], const uint16_t CDMDataLength, OpenCDMSessionCallbacks* callbacks, void* userData, + struct OpenCDMSession** session); + +/** + * Destructs an \ref OpenCDMSession instance. + * \param system \ref OpenCDMSession instance to desctruct. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_destruct_session(struct OpenCDMSession* session); + +/** + * Loads the data stored for a specified OpenCDM session into the CDM context. + * \param session \ref OpenCDMSession instance. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_session_load(struct OpenCDMSession* session); + +/** + * Process a key message response. + * \param session \ref OpenCDMSession instance. + * \param keyMessage Key message to process. + * \param keyLength Length of key message buffer (in bytes). + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_session_update(struct OpenCDMSession* session, + const uint8_t keyMessage[], + const uint16_t keyLength); + +/** + * Removes all keys/licenses related to a session. + * \param session \ref OpenCDMSession instance. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_session_remove(struct OpenCDMSession* session); + +/** + * Retrieves DRM session specific metadata of a session. + * \param session \ref OpenCDMSession instance. +* \param metadata, buffer to write metadata into, always 0 terminated (also when not large enough to hold all data) except when metadata is + * Null of course. Null allowed to retrieve required size needed for this buffer in metadataSize to be able to allocate required buffer + * for subsequent call to opencdm_session_metadata + * \param metadataSize, in: size of metadata buffer, out: required size to hold all data available when return value is ERROR_MORE_DATA_AVAILBALE, + * , number of characters written into metadata (incl 0 terminator) otherwise. Note in case metadata could not hold all data but was not of zero + * length it is filled up to the maximum size (still zero terminated) but also ERROR_MORE_DATA_AVAILBALE is returned with the required size needed + * to hold all data + * \return Zero on success, non-zero on error. ERROR_MORE_DATA_AVAILBALE when the buffer was not large enough to hold all the data available. + + */ +EXTERNAL OpenCDMError opencdm_session_metadata(const struct OpenCDMSession* session, + char metadata[], + uint16_t* metadataSize); + +/** + * Let CDM know playback stopped and reset output protection + * \param session \ref OpenCDMSession instance. + * \return Zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_session_resetoutputprotection(struct OpenCDMSession* session); + +/** + * Gets Session ID for a session. + * \param session \ref OpenCDMSession instance. + * \return Session ID, valid as long as \ref session is valid. + */ +EXTERNAL const char* opencdm_session_id(const struct OpenCDMSession* session); + +/** + * Checks if a session has a specific keyid. Will check both BE/LE + * \param session \ref OpenCDMSession instance. + * \param length Length of key ID buffer (in bytes). + * \param keyId Key ID. + * \return 1 if keyID found else 0. + */ +EXTERNAL uint32_t opencdm_session_has_key_id(struct OpenCDMSession* session, + const uint8_t length, const uint8_t keyId[]); + +/** + * Returns status of a particular key assigned to a session. + * \param session \ref OpenCDMSession instance. + * \param keyId Key ID. + * \param length Length of key ID buffer (in bytes). + * \return key status. + */ +EXTERNAL KeyStatus opencdm_session_status(const struct OpenCDMSession* session, + const uint8_t keyId[], const uint8_t length); + +/** + * Returns error for key (if any). + * \param session \ref OpenCDMSession instance. + * \param keyId Key ID. + * \param length Length of key ID buffer (in bytes). + * \return Key error (zero if no error, non-zero if error). + */ +EXTERNAL uint32_t opencdm_session_error(const struct OpenCDMSession* session, + const uint8_t keyId[], const uint8_t length); + +/** + * Returns system error. This reference general system, instead of specific key. + * \param session \ref OpenCDMSession instance. + * \return System error code, zero if no error. + */ +EXTERNAL OpenCDMError opencdm_session_system_error(const struct OpenCDMSession* session); + +/** + * Gets buffer ID for a session. + * \param session \ref OpenCDMSession instance. + * \return Buffer ID, valid as long as \ref session is valid. + */ +EXTERNAL const char* opencdm_session_buffer_id(const struct OpenCDMSession* session); + +/** + * Closes a session. + * \param session \ref OpenCDMSession instance. + * \return zero on success, non-zero on error. + */ +EXTERNAL OpenCDMError opencdm_session_close(struct OpenCDMSession* session); + +/** + * \brief Performs decryption. + * + * This method accepts encrypted data and will typically decrypt it + * out-of-process (for security reasons). The actual data copying is performed + * using a memory-mapped file (for performance reasons). If the DRM system + * allows access to decrypted data (i.e. decrypting is not + * performed in a TEE), the decryption is performed in-place. + * \param session \ref OpenCDMSession instance. + * \param encrypted Buffer containing encrypted data. If applicable, decrypted + * data will be stored here after this call returns. + * \param encryptedLength Length of encrypted data buffer (in bytes). + * \param encScheme CENC Schemes as defined in EncryptionScheme enum + * \param pattern Encryption pattern containing number of Encrypted and Clear blocks. + * \param IV Initial vector (IV) used during decryption. Can be NULL, in that + * case and IV of all zeros is assumed. + * \param IVLength Length of IV buffer (in bytes). + * \param keyID keyID to use for decryption + * \param keyIDLength Length of keyID buffer (in bytes). + * \param initWithLast15 Whether decryption context needs to be initialized with + * last 15 bytes. Currently this only applies to PlayReady DRM. + * \return Zero on success, non-zero on error. + */ +#ifdef __cplusplus +EXTERNAL OpenCDMError opencdm_session_decrypt(struct OpenCDMSession* session, + uint8_t encrypted[], + const uint32_t encryptedLength, + const EncryptionScheme encScheme, + const EncryptionPattern pattern, + const uint8_t* IV, uint16_t IVLength, + const uint8_t* keyId, const uint16_t keyIdLength, + uint32_t initWithLast15 = 0); + +#else +EXTERNAL OpenCDMError opencdm_session_decrypt(struct OpenCDMSession* session, + uint8_t encrypted[], + const uint32_t encryptedLength, + const EncryptionScheme encScheme, + const EncryptionPattern pattern, + const uint8_t* IV, uint16_t IVLength, + const uint8_t* keyId, const uint16_t keyIdLength, + uint32_t initWithLast15); +#endif // __cplusplus + +/** + * \brief Get metrics associated with a DRM session. + * + * Some DRMs (e.g. WideVine) offer metric data that can be used for any + * analyses. This function retrieves the metric data of the passed in + * system. It is up to the callee to interpret the baniary data correctly. + * \param session Instance of \ref OpenCDMSession. + * \param bufferLength Actual buffer length of the buffer parameter, on return + * it holds the number of bytes actually written in it. + * \param buffer Buffer length of buffer that can hold the metric data. + * \return Zero on success, non-zero on error. + */ + +EXTERNAL OpenCDMError opencdm_get_metric_session_data(struct OpenCDMSession* session, + uint32_t* bufferLength, + uint8_t* buffer); + +/** + * \brief Performs decryption. + * + * This method accepts encrypted data and will typically decrypt it + * out-of-process (for security reasons). The actual data copying is performed + * using a memory-mapped file (for performance reasons). If the DRM system + * allows access to decrypted data (i.e. decrypting is not + * performed in a TEE), the decryption is performed in-place. + * \param session \ref OpenCDMSession instance. + * \param encrypted Buffer containing encrypted data. If applicable, decrypted + * data will be stored here after this call returns. + * \param encryptedLength Length of encrypted data buffer (in bytes). + * \param sampleInfo Per Sample information needed to decrypt this sample + * \param streamProperties Provides info about current stream + * \return Zero on success, non-zero on error. + */ + +EXTERNAL OpenCDMError opencdm_session_decrypt_v2(struct OpenCDMSession* session, + uint8_t encrypted[], + const uint32_t encryptedLength, + const SampleInfo* sampleInfo, + const MediaProperties* streamProperties); + +/** + * @brief Close the cached open connection if it exists. + * + */ +EXTERNAL void opencdm_dispose(); + +#ifdef __cplusplus +} +#endif + +#endif // OPEN_CDM_H diff --git a/test/utests/ocdm/open_cdm_adapter.h b/test/utests/ocdm/open_cdm_adapter.h new file mode 100644 index 00000000..e48858d0 --- /dev/null +++ b/test/utests/ocdm/open_cdm_adapter.h @@ -0,0 +1,96 @@ + /* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2020 Metrological + * + * 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. + */ + +#ifndef __OPEN_CDM_ADAPTER_H +#define __OPEN_CDM_ADAPTER_H + +#include "open_cdm.h" + +struct _GstBuffer; +typedef struct _GstBuffer GstBuffer; + +struct _GstCaps; +typedef struct _GstCaps GstCaps; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Performs decryption based on adapter implementation. + * + * This method accepts encrypted data and will typically decrypt it out-of-process (for security reasons). The actual data copying is performed + * using a memory-mapped file (for performance reasons). If the DRM system allows access to decrypted data (i.e. decrypting is not + * performed in a TEE), the decryption is performed in-place. + * \param session \ref OpenCDMSession instance. + * \param buffer Gstreamer buffer containing encrypted data and related meta data. If applicable, decrypted data will be stored here after this call returns. + * \param subSample Gstreamer buffer containing subsamples size which has been parsed from protection meta data. + * \param subSampleCount count of subsamples + * \param IV Gstreamer buffer containing initial vector (IV) used during decryption. + * \param keyID Gstreamer buffer containing keyID to use for decryption + * + * This method handles the Subsample mapping by consolidating all the encrypted data into one buffer before decrypting. This means the Subsample mappings are + * not passed on to the DRM implementation side. + * + * For CBCS support, EncryptionScheme and EncryptionPattern information can be added as part of the ProtectionMeta in the given format below + * "cipher-mode" G_TYPE_STRING (One of the Four Character Code (FOURCC) Protection schemes as defined in https://www.iso.org/obp/ui/#iso:std:iso-iec:23001:-7:ed-3:v1:en) + * "crypt_byte_block" G_TYPE_UINT (Present only if cipher-mode is "cbcs") + * "skip_byte_block" G_TYPE_UINT (Present only cipher-mode is "cbcs") + + * \return Zero on success, non-zero on error. + */ + EXTERNAL OpenCDMError opencdm_gstreamer_session_decrypt(struct OpenCDMSession* session, GstBuffer* buffer, GstBuffer* subSample, const uint32_t subSampleCount, + GstBuffer* IV, GstBuffer* keyID, uint32_t initWithLast15); + +/** + * \brief Performs decryption based on adapter implementation. + * + * This version 3 method accepts encrypted data and will typically decrypt it out-of-process (for security reasons). The actual data copying is performed + * using a memory-mapped file (for performance reasons). If the DRM system allows access to decrypted data (i.e. decrypting is not + * performed in a TEE), the decryption is performed in-place. + * This version assumes all data required is attached as metadata to the buffer. Specification for this data is as follows: + * + * Typically, the caller would parse the protection information for a video/audio frame from its input data and use this information to populate the + * GstStructure info field, which is then encapsulated in a GstProtectionMeta object and attached to the corresponding GstBuffer using the + * gst_buffer_add_protection_meta function. + * + * gst_structure [application/x-cenc] + * "iv" GST_TYPE_BUFFER + * "kid" GST_TYPE_BUFFER + * "subsample_count" G_TYPE_UINT + * "subsamples" GST_TYPE_BUFFER + * "cipher-mode" G_TYPE_STRING (One of the Four Character Code (FOURCC) Protection schemes as defined in https://www.iso.org/obp/ui/#iso:std:iso-iec:23001:-7:ed-3:v1:en) + * "crypt_byte_block" G_TYPE_UINT (Present only if cipher-mode is "cbcs") + * "skip_byte_block" G_TYPE_UINT (Present only cipher-mode is "cbcs") + * + * This method passes on the subsample mapping to the DRM implementation and assumes that the DRM implementaion will handle the decryption based on subsample mapping. + * + * \param session \ref OpenCDMSession instance. + * \param buffer Gstreamer buffer containing encrypted data and related meta data. If applicable, decrypted data will be stored here after this call returns. + * \return Zero on success, non-zero on error. + */ + + EXTERNAL OpenCDMError opencdm_gstreamer_session_decrypt_buffer(struct OpenCDMSession* session, GstBuffer* buffer, GstCaps* caps); + + +#ifdef __cplusplus +} +#endif + +#endif // __OPEN_CDM_ADAPTER_H diff --git a/test/utests/run.sh b/test/utests/run.sh new file mode 100755 index 00000000..2a0b5137 --- /dev/null +++ b/test/utests/run.sh @@ -0,0 +1,207 @@ +#!/bin/bash -e +# +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2020 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. +# +# This script will build and run microtests. +# Use option: -c to additionally build coverage tests +# Use option: -h to halt coverage tests on error + +if [[ -z "${MAKEFLAGS}" ]]; then + export MAKEFLAGS=-j$(nproc) +fi + +# If a test crashes or has AS trap, provide an error test report +error_report() +{ +cat << EOF > test_details.json +{ + "tests": 1, + "failures": 0, + "disabled": 0, + "errors": 1, + "timestamp": "`date`", + "time": "0s", + "name": "AllTests", + "testsuites": [ + { + "name": "$1", + "tests": 1, + "failures": 0, + "disabled": 0, + "errors": 1 + } + ] +} +EOF +} + +# "corrupt arc tag" +(find . -name "*.gcda" -print0 | xargs -0 rm) || true + +build_coverage=0 +halt_on_error=0 +rdke_build=0 + +while getopts "ceh" opt; do + case ${opt} in + c ) echo Do build coverage + build_coverage=1 + ;; + e ) echo RDK-E build + rdke_build=1 + ;; + h ) echo Halt on error + halt_on_error=1 + ;; + * ) + ;; + esac +done + +TEST_DIR=$PWD +PLAYERDIR=$(realpath ${TEST_DIR}/../..) + +PLAYER_BUILD_GCNO="" + +if [ "$build_coverage" -eq "1" ]; then + #Find where player .gcno files get put when player-cli is built via install-middleware.sh -c + A_GCNO=$(find ${PLAYERDIR}/build -name 'AampConfig*gcno' -print -quit) + + if [ -z "$A_GCNO" ]; then + echo "ERROR need to run 'install-middleware.sh -c' first to get baseline list of middleware files for coverage" + exit 1 + fi + PLAYER_BUILD_GCNO=$(dirname $A_GCNO) +fi + +# Build and run microtests: +set -e + +mkdir -p build + +cd build + +if [[ "$OSTYPE" == "darwin"* ]]; then + PKG_CONFIG_PATH=/Library/Frameworks/GStreamer.framework/Versions/1.0/lib/pkgconfig:${PLAYERDIR}/.libs/lib/pkgconfig:/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCOVERAGE_ENABLED=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_RDKE_TEST_RUN=$rdke_build ../ +elif [[ "$OSTYPE" == "linux"* ]]; then + echo "PLAYER DIR[${PLAYERDIR}]" + PKG_CONFIG_PATH=${PLAYERDIR}/.libs/lib/pkgconfig cmake --no-warn-unused-cli -DCMAKE_INSTALL_PREFIX=${PLAYERDIR}/.libs -DCMAKE_PLATFORM_UBUNTU=1 -DCOVERAGE_ENABLED=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_LIBRARY_PATH=${PLAYERDIR}/.libs/lib -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++ -DCMAKE_RDKE_TEST_RUN=$rdke_build -S../ -B$PWD -G "Unix Makefiles" + export LD_LIBRARY_PATH=${PLAYERDIR}/.libs/lib +else + #abort the script if its not macOS or linux + echo "Aborting unsupported OS detected" + echo $OSTYPE + exit 1 +fi +make +# Work around for cmake deprecation of --testdir option for version 3.21.0 and above +cmake_version=$(cmake --version | head -n 1 | awk '{print $3}') +major_version=$(echo "$cmake_version" | cut -d. -f1) +minor_version=$(echo "$cmake_version" | cut -d. -f2) +if [[ "$major_version" -gt 3 ]] || [[ "$major_version" -eq 3 && "$minor_version" -ge 21 ]]; then + CT_TESTDIR="" +else + CT_TESTDIR="--testdir build" + +fi + +if [ "$rdke_build" -eq "1" ]; then + echo "RDKE build" + + export GTEST_OUTPUT="json" + ctest -j 4 --output-on-failure --no-compress-output -T Test $CT_TESTDIR || true # Don't exit script if a test fails + + cd tests + + for test_dir in */; do + if [ -d "$test_dir" ] && [ "$test_dir" != "CMakeFiles/" ] && [ "$test_dir" != "tsb/" ]; then + if [ ! -f "$test_dir/test_detail.json" ]; then + echo "Missing: $test_dir/test_detail.json" + + # Create a fallback test_detail.json + cat < "$test_dir/test_detail.json" +{ + "tests": 1, + "failures": 1, + "disabled": 0, + "errors": 0, + "time": "0.0s", + "name": "${test_dir%/}", + "testsuites": [ + { + "name": "${test_dir%/}", + "tests": 1, + "failures": 1, + "disabled": 0, + "errors": 0, + "time": "0.0s", + "testsuite": [ + { + "name": "${test_dir%/}", + "status": "failed", + "time": "0.0s", + "classname": "${test_dir%/}", + "failure": { + "message": "Testing ended abruptly", + "type": "SEGFAULT (probably)" + } + } + ] + } + ] +} +EOF + fi + fi + done + + cd .. + + find . -name test_detail\*.json | xargs cat | jq -s '{test_cases_results: {tests: map(.tests) | add,failures: map(.failures) | add,disabled: map(.disabled) | add,errors: map(.errors) | add,time: ((map(.time | rtrimstr("s") | tonumber) | add) | tostring + "s"),name: .[0].name,testsuites: map(.testsuites[])}}' > L1Report.json + +else + ctest -j 4 --output-on-failure --no-compress-output -T Test $CT_TESTDIR --output-junit ctest-results.xml +fi + +if [ "$build_coverage" -eq "1" ]; then +#We are in utests/build + +LCOV=lcov + +#Get initial baseline of files from player-cli build +$LCOV --initial $IGNORE --directory ${PLAYER_BUILD_GCNO} -b $PLAYERDIR --capture --output-file baseline.info + +#Get a list of dirs which contain coverage data for player source files. +TEST_DIRS=$(find tests -name '*.dir' -type d | grep -v _coverage.dir ) +COMBINE="" +for DIR in $TEST_DIRS; do + info_file=$DIR/TEST.info + cmd="$LCOV --directory $DIR -b $TESTDIR --capture --output-file ${info_file}" + echo $cmd + $cmd + COMBINE=$COMBINE" -a $info_file" +done +HTML_OUT=$(realpath ../CombinedCoverage) +XML_OUT=$(realpath ../coverage.xml) +$LCOV $COMBINE -a baseline.info --output-file all.info.1 +$LCOV --remove all.info.1 --output-file all.info "*/aamp/tsb/test/*" "*/aamp/.libs/*" "*/aamp/test/*" "*/aamp/Linux/*" "*/aamp/subtec/subtecparser/*" "/usr/*" +genhtml --demangle-cpp -o ${HTML_OUT} all.info +# Generate coverage.xml +lcov_cobertura all.info -b ${PLAYERDIR} --demangle -o ${XML_OUT} || true +echo "Coverage written to ${HTML_OUT}" +fi diff --git a/test/utests/tests/Base64PLAYER/Base64PLAYERTests.cpp b/test/utests/tests/Base64PLAYER/Base64PLAYERTests.cpp new file mode 100755 index 00000000..f51285d1 --- /dev/null +++ b/test/utests/tests/Base64PLAYER/Base64PLAYERTests.cpp @@ -0,0 +1,26 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2022 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 + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/utests/tests/Base64PLAYER/Base64Tests.cpp b/test/utests/tests/Base64PLAYER/Base64Tests.cpp new file mode 100644 index 00000000..891f24f8 --- /dev/null +++ b/test/utests/tests/Base64PLAYER/Base64Tests.cpp @@ -0,0 +1,334 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2020 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#include +#include +#include + +//include the google test dependencies +#include + +// unit under test +#include "_base64.h" + +namespace base64Test { + + // Test Vectors + // Swap 'inp' and 'exp' when going from encode to decode, base64 is reversible + const unsigned char base64Inp1[] = "1234"; + const char base64Exp1[] = "MTIzNA=="; + const unsigned char base64Inp2[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" "+/"; + const char base64Exp2[] = "QUJDRA=="; + const char base64Exp3[] = "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLw=="; + const unsigned char base64Inp4[] = "_"; // RFC 4648 §5 URL- and filename-safe standard + const char base64Exp4[] = "Xw=="; + const unsigned char base64Inp5[] = ""; + const char base64Exp5[] = ""; + const unsigned char base64Inp6[] = "light work."; + const char base64Exp6[] = "bGlnaHQgd29yay4="; + + TEST(_base64Suite, encode) + { + size_t size = 4; + char *result; + + // padded output + result = ::base64_Encode(base64Inp1, size); + EXPECT_EQ(memcmp(result, base64Exp1, strlen(base64Exp1)), 0) << "The base64 encode of " << base64Inp1 << ", size " << size << " is not correct"; + free(result); + + // all supported characters limited length + size = 4; + result = ::base64_Encode(base64Inp2, size); + EXPECT_EQ(memcmp(result, base64Exp2, strlen(base64Exp2)), 0) << "The base64 encode of " << base64Inp2 << ", size " << size << " is not correct"; + free(result); + + // all supported characters full length + size = strlen((char *)base64Inp2); + result = ::base64_Encode(base64Inp2, size); + EXPECT_EQ(memcmp(result, base64Exp3, strlen(base64Exp3)), 0) << "The base64 encode of " << base64Inp2 << ", size " << size << " is not correct"; + free(result); + + // unsupported character should return empty result? + size = 1; + result = ::base64_Encode(base64Inp4, size); + EXPECT_EQ(memcmp(result, base64Exp4, strlen(base64Exp4)), 0) << "The base64 encode of " << base64Inp4 << ", size " << size << " is not correct"; + free(result); + + // empty input + size = 0; + result = ::base64_Encode(base64Inp5, size); + EXPECT_EQ(memcmp(result, base64Exp5, size), 0) << "The base64 encode of " << base64Inp5 << ", size " << size << " is not correct"; + free(result); + + // NULL doesn't upset us if size is 0, crashes if > 0 + size = 0; + result = ::base64_Encode(NULL, size); + EXPECT_EQ(memcmp(result, "", size), 0) << "The base64 encode of NULL, size 1 is not correct"; + free(result); + + size = 0; + for (int i=7; i < 12; i++) + { + char exp[17]; // max expected output is 16 bytes + switch (i) { + case 7: + strncpy(exp, "bGlnaHQgdw==", sizeof(exp)); + break; + case 8: + strncpy(exp, "bGlnaHQgd28=", sizeof(exp)); + break; + case 9: + strncpy(exp, "bGlnaHQgd29y", sizeof(exp)); + break; + case 10: + strncpy(exp, "bGlnaHQgd29yaw==", sizeof(exp)); + break; + default: + case 11: + strncpy(exp, "bGlnaHQgd29yay4=", sizeof(exp)); + break; + } + size = i; + result = ::base64_Encode(base64Inp6, size); + EXPECT_EQ(memcmp(result, exp, strlen(exp)), 0) << "The base64 encode of " << base64Inp6 << ", size " << size << " is not correct"; + free(result); + } + } + + TEST(_base64Suite, decode) + { + size_t len = 0; + size_t size = 0; + char *result; + + // padded output used truncated input of length 4 + result = (char *)::base64_Decode(base64Exp1, &len); + int cmp = strncmp(result, (char*)base64Inp1, len); + EXPECT_EQ(cmp, 0) << "The base64 decode of " << base64Exp1 << " is not correct"; + EXPECT_EQ(len, strlen((char *)base64Inp1)) << "The base64 decode of " << base64Exp1 << " is not correct"; + memset(result, 0, len); + free(result); + + // all supported characters full length + result = (char *)::base64_Decode(base64Exp3, &len); + cmp = strncmp(result, (char*)base64Inp2, len); + EXPECT_EQ(cmp, 0) << "The base64 decode of " << base64Exp2 << " is not correct"; + EXPECT_EQ(len, strlen((char *)base64Inp2)) << "The base64 decode of " << base64Exp2 << " is not correct"; + memset(result, 0, len); + free(result); + + // unsupported character should return empty result? + result = (char *)::base64_Decode(base64Exp4, &len); + EXPECT_EQ(memcmp(result, base64Inp4, strlen((char *)base64Inp4)), 0) << "The base64 decode of " << base64Exp4 << " is not correct"; + EXPECT_EQ(len, strlen((char *)base64Inp4)) << "The base64 decode of " << base64Exp4 << " is not correct"; + memset(result, 0, len); + free(result); + + // Check for invalid sizes, should not trigger address sanitizer. + size = 1; + result = (char *)::base64_Decode(base64Exp4, &len, size); + EXPECT_EQ( len, 0 ); + free(result); + + size = 2; + result = (char *)::base64_Decode(base64Exp4, &len, size); + EXPECT_EQ( len, 1 ); + EXPECT_EQ(result[0], '_') << "The base64 decode of " << base64Exp4 << " is not correct"; + memset(result, 0, len); + free(result); + + size = 3; + result = (char *)::base64_Decode(base64Exp4, &len, size); + EXPECT_EQ( len, 1 ); + EXPECT_EQ(result[0], '_') << "The base64 decode of " << base64Exp4 << " is not correct"; + memset(result, 0, len); + free(result); + + // NULL crashes + //result = (char *)::base64_Decode(NULL, &len); + //EXPECT_STREQ(result, (char *)base64Inp2) << "The base64 decode of NULL is not correct"; + //free(result); + + result = (char *)::base64_Decode(base64Exp6, &len); + cmp = strncmp(result, (char*)base64Inp6, len); + EXPECT_EQ(cmp, 0) << "The base64 decode of " << base64Exp6 << " is not correct"; + EXPECT_EQ(len, strlen((char *)base64Inp6)) << "The base64 decode of " << base64Exp6 << " is not correct"; + memset(result, 0, len); + free(result); + + } + TEST(_base64Suite, decodeLen) + { + size_t len = 0; + size_t size = 4; + char *result; + + // Not checking returned len, checked in decode() + + // padded output + result = (char *)::base64_Decode(base64Exp1, &len, size); + int cmp = strncmp(result, (char *)base64Inp1, len); + EXPECT_EQ(cmp, 0) << "The base64 decode of " << base64Exp1 << " is not correct"; + memset(result, 0, len); + free(result); + + // all supported characters limited length + size = 3; + result = (char *)::base64_Decode(base64Exp2, &len, size); + cmp = strncmp(result, (char *)base64Inp2, len); + EXPECT_EQ(cmp, 0) << "The base64 decode of " << base64Exp2 << " is not correct"; + free(result); + + // all supported characters full length + size = sizeof(base64Exp3); + result = (char *)::base64_Decode(base64Exp3, &len, size); + cmp = strncmp(result, (char *)base64Inp2, len); + EXPECT_EQ(cmp, 0) << "The base64 decode of " << base64Exp3 << " is not correct"; + memset(result, 0, len); + free(result); + + // empty input + size = 0; + result = (char *)::base64_Decode(base64Exp5, &len, size); + EXPECT_EQ(len, 0) << "The base64 decode of " << base64Exp5 << " is not correct"; + memset(result, 0, len); + free(result); + + // NULL doesn't upset us if size is 0, crashes if > 0 + size = 0; + result = (char *)::base64_Decode(NULL, &len, size); + EXPECT_EQ(memcmp(result, base64Inp5, strlen((char *)base64Inp5)), 0) << "The base64 decode of NULL is not correct"; + memset(result, 0, len); + free(result); + + size = 0; + for (int i=7; i < 12; i++) + { + char exp[17]; // max expected output is 16 bytes + switch (i) { + case 7: + strncpy(exp, "bGlnaHQgdw==", sizeof(exp)); + break; + case 8: + strncpy(exp, "bGlnaHQgd28=", sizeof(exp)); + break; + case 9: + strncpy(exp, "bGlnaHQgd29y", sizeof(exp)); + break; + case 10: + strncpy(exp, "bGlnaHQgd29yaw==", sizeof(exp)); + break; + default: + case 11: + strncpy(exp, "bGlnaHQgd29yay4=", sizeof(exp)); + break; + } + size = strlen(exp); + result = (char *)::base64_Decode(exp, &len, size); + int cmp = strncmp(result, (char *)base64Inp6, i); + EXPECT_EQ(cmp, 0) << "The base64 decode of " << exp << " is not correct"; + memset(result, 0, len); + free(result); + } + } + +TEST(_base64Suite, bad ) +{ + const char *badBase64 = "!@#*("; + size_t srcLen = strlen(badBase64); + size_t len = 999; + unsigned char *result = ::base64_Decode( badBase64, &len, srcLen); + EXPECT_TRUE( result==NULL ); + EXPECT_EQ( len, 0 ); +} + +TEST(_base64Suite, encodedecode ) +{ + struct + { + const char *base64; + const char *expected; + size_t expectedLen; + bool oldSyntax; + } testData[] = + { + {"",""}, + {"Zg==","f"}, + {"Zm8=","fo"}, + {"Zm9v","foo"}, + {"Zm9vYg==","foob"}, + {"Zm9vYmE=","fooba"}, + {"Zm9vYmFy","foobar"}, + { + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5MCEiwqMkJV4mKigpQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVp8XDw+PywuLzo7QCd+I3t9W10tXw==", + "abcdefghijklmnopqrstuvwxyz01234567890!\"£$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ|\\<>?,./:;@'~#{}[]-_" + }, + { "bGlnaHQgd29yay4=", "light work." }, + + { "AAAASnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAACoIARIQL38/m5MtSFqBGT0XY2KM4yIUTkJDVTA0Mzg3NjU0MDA1NjMwMDc=", + "\000\000\000Jpssh\000\000\000\000\355\357\213\251y\326J\316\243\310'\334\325\035!\355\000\000\000*\010\001\022\020/?\233\223-HZ\201\031=\027cb\214\343\042\024NBCU0438765400563007", + 74 // binary data size - can't use strlen + }, + { "AAAASnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAACoIARIQL38-m5MtSFqBGT0XY2KM4yIUTkJDVTA0Mzg3NjU0MDA1NjMwMDc=", + "\000\000\000Jpssh\000\000\000\000\355\357\213\251y\326J\316\243\310'\334\325\035!\355\000\000\000*\010\001\022\020/?\233\223-HZ\201\031=\027cb\214\343\042\024NBCU0438765400563007", + 74, // binary data size - can't use strlen + true // old syntax, with "-" instead of "/" + }, + }; + + for( int i=0; i +#include +#include +#include +#include +#include +#include "MockDrmHelper.h" + + +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::_; + +std::shared_ptr drmHelper; + +class DrmHLSTests : public ::testing::Test +{ + public: + protected: + void SetUp() override + { + drmHelper = std::make_shared(); + } + + void TearDown() override + { + drmHelper = nullptr; + } +}; + +extern std::shared_ptr ProcessContentProtection( std::string attrName, bool param , bool isRequired); + +TEST_F(DrmHLSTests, ProcessContentProtection) +{ + { /* Widevine */ + std::string attrName = "#EXT-X-KEY:METHOD=SAMPLE-AES-CTR, KEYFORMAT=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\",KEYFORMATVERSIONS=\"1\",URI=\"data:text/plain;base64,AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIgZTI1ZmFkYjQ4YmZiNDkyMjljZTBhNGFmZGZlMDUxOTcaB3NsaW5ndHYiBUhHVFZEKgVTRF9IRA==\",KEYID=0xe25fadb48bfb49229ce0a4afdfe05197"; + + EXPECT_CALL(*drmHelper, isDecryptClearSamplesRequired()).WillOnce(Return(false)); + + auto rc = ProcessContentProtection(attrName,drmHelper->getPropogateUriParam(),drmHelper->isDecryptClearSamplesRequired()); + ASSERT_NE( rc, nullptr ); + + } + + { /* PlayReady */ + std::string attrName = "#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI=\"data:text/plain;charset=UTF-16;base64,BgIAAAEAAQD8ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AbgA0AEkARABBAEsATwAxAHMARwByAGcAegBpAHkAOAA4AFgAcgBqAGYAQQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgB1AGkAbwA4AFcAVQBwAFQANAA0ADAAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA=\",KEYFORMAT=\"com.microsoft.playready\",KEYFORMATVERSIONS=\"1\""; + + EXPECT_CALL(*drmHelper, isDecryptClearSamplesRequired()).WillOnce(Return(false)); + auto rc = ProcessContentProtection(attrName,drmHelper->getPropogateUriParam(),drmHelper->isDecryptClearSamplesRequired()); + + // getting nullptr here + // comments elsewhere indicate PlayReady helper currently supports DASH only, so known issue + // ASSERT_NE( rc, nullptr ); + } +} diff --git a/test/utests/tests/DrmOcdm/DrmHelperTests.cpp b/test/utests/tests/DrmOcdm/DrmHelperTests.cpp new file mode 100644 index 00000000..90fd017e --- /dev/null +++ b/test/utests/tests/DrmOcdm/DrmHelperTests.cpp @@ -0,0 +1,817 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include "_base64.h" +#include "DrmHelper.h" + +struct CreateHelperTestData +{ + DrmMethod method; + MediaFormat mediaFormat; + std::string uri; + std::string keyFormat; + std::string systemUUID; + std::vector expectedKeyPayload; +}; +#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0])) + +DrmInfo createDrmInfo(DrmMethod method, MediaFormat mediaFormat, const std::string& uri = "", + const std::string& keyFormat = "", const std::string& systemUUID = "", + const std::string& initData = "") +{ + DrmInfo drmInfo; + + drmInfo.method = method; + drmInfo.mediaFormat = mediaFormat; + drmInfo.keyURI = uri; + drmInfo.keyFormat = keyFormat; + drmInfo.systemUUID = systemUUID; + drmInfo.initData = initData; + + return drmInfo; +} + +class DrmHelperTests : public ::testing::Test +{ +protected: + void SetUp() override + { + } + + void TearDown() override + { + } + +public: +}; + +TEST_F(DrmHelperTests, TestDrmIds) +{ + std::vector expectedIds({ + "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b", // ClearKey + "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed", // Widevine + "9a04f079-9840-4286-ab92-e65be0885f95" // PlayReady + }); + std::sort(expectedIds.begin(), expectedIds.end()); + + std::vector actualIds; + DrmHelperEngine::getInstance().getSystemIds(actualIds); + std::sort(actualIds.begin(), actualIds.end()); + + ASSERT_EQ(expectedIds, actualIds); +} + +TEST_F(DrmHelperTests, TestCreateClearKeyHelper) +{ + const std::vector testData = { + // Valid KEYFORMAT, HLS + {eMETHOD_AES_128, + eMEDIAFORMAT_HLS_MP4, + "file.key", + "urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b", + "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b", + {'1'}}, + + // Valid KEYFORMAT, DASH + {eMETHOD_AES_128, + eMEDIAFORMAT_DASH, + "file.key", + "urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b", + "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b", + {}}, // For DASH, the key should come from the PSSH, so we won't check that here + + // Textual identifier rather than UUID + {eMETHOD_AES_128, + eMEDIAFORMAT_HLS_MP4, + "file.key", + "org.w3.clearkey", + "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b", + {'1'}}, + + }; + DrmInfo drmInfo; + + for (auto& test_data : testData) + { + drmInfo = createDrmInfo(eMETHOD_AES_128, test_data.mediaFormat, test_data.uri, + test_data.keyFormat, test_data.systemUUID); + + ASSERT_TRUE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + + std::shared_ptr clearKeyHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + ASSERT_TRUE(clearKeyHelper != nullptr); + ASSERT_EQ("org.w3.clearkey", clearKeyHelper->ocdmSystemId()); + ASSERT_EQ(true, clearKeyHelper->isClearDecrypt()); + ASSERT_EQ(false, clearKeyHelper->isHdcp22Required()); + ASSERT_EQ(0, clearKeyHelper->getDrmCodecType()); + ASSERT_EQ(false, clearKeyHelper->isExternalLicense()); + ASSERT_EQ(5000U, clearKeyHelper->licenseGenerateTimeout()); + ASSERT_EQ(5000U, clearKeyHelper->keyProcessTimeout()); + + if (test_data.expectedKeyPayload.size() != 0) + { + std::vector keyID; + clearKeyHelper->getKey(keyID); + ASSERT_EQ(test_data.expectedKeyPayload, keyID); + } + } +} + +TEST_F(DrmHelperTests, TestClearKeyHelperHlsInitDataCreation) +{ + DrmInfo drmInfo = createDrmInfo(eMETHOD_AES_128, eMEDIAFORMAT_HLS_MP4, "file.key", + "urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"); + ASSERT_TRUE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + std::shared_ptr clearKeyHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + + std::vector initData; + clearKeyHelper->createInitData(initData); +} + +TEST_F(DrmHelperTests, TestClearKeyHelperParsePssh) +{ + DrmInfo drmInfo = createDrmInfo(eMETHOD_AES_128, eMEDIAFORMAT_DASH, "file.key", + "urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"); + ASSERT_TRUE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + std::shared_ptr clearKeyHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + + // For DASH the init data should have come from the PSSH, so when asked to create + // the init data, the helper should just return that + std::vector psshData = { + 0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68, 0x01, 0x00, 0x00, 0x00, 0x10, + 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, + 0xfb, 0x4b, 0x00, 0x00, 0x00, 0x01, 0xfe, 0xed, 0xf0, 0x0d, 0xee, 0xde, 0xad, + 0xbe, 0xef, 0xf0, 0xba, 0xad, 0xf0, 0x0d, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00}; + + ASSERT_TRUE(clearKeyHelper->parsePssh(psshData.data(), (uint32_t)psshData.size())); + + std::vector initData; + clearKeyHelper->createInitData(initData); + ASSERT_EQ(psshData, initData); + + // KeyId should have been extracted from the PSSH + std::vector keyID; + const std::vector expectedKeyID = {0xfe, 0xed, 0xf0, 0x0d, 0xee, 0xde, 0xad, 0xbe, + 0xef, 0xf0, 0xba, 0xad, 0xf0, 0x0d, 0xd0, 0x0d}; + clearKeyHelper->getKey(keyID); + ASSERT_EQ(expectedKeyID, keyID); +} + +TEST_F(DrmHelperTests, TestClearKeyHelperGenerateLicenseRequest) +{ + DrmInfo drmInfo = createDrmInfo(eMETHOD_AES_128, eMEDIAFORMAT_HLS_MP4, "file.key", + "urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"); + drmInfo.manifestURL = "http://stream.example/hls/playlist.m3u8"; + ASSERT_TRUE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + std::shared_ptr clearKeyHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + + ChallengeInfo challengeInfo; + challengeInfo.url = "http://challengeinfourl.example"; + LicenseRequest licenseRequest; + + // No ClearKey license URL in the license request, expect the URL to be + // constructed from the information in the DrmInfo + clearKeyHelper->generateLicenseRequest(challengeInfo, licenseRequest); + ASSERT_EQ(LicenseRequest::POST, licenseRequest.method); + ASSERT_EQ("http://stream.example/hls/file.key", licenseRequest.url); + ASSERT_EQ("", licenseRequest.payload); + + // Setting a ClearKey license URL in the license request, expect + // that to take precedence + const std::string fixedCkLicenseUrl = "http://cklicenseserver.example"; + licenseRequest.url = fixedCkLicenseUrl; + clearKeyHelper->generateLicenseRequest(challengeInfo, licenseRequest); + ASSERT_EQ(fixedCkLicenseUrl, licenseRequest.url); + + // Clearing ClearKey license URL in the license request and creating a + // helper with no key URI in the DrmInfo. Should use the URI from the challenge + licenseRequest.url.clear(); + DrmInfo drmInfoNoKeyUri = createDrmInfo(eMETHOD_AES_128, eMEDIAFORMAT_HLS_MP4, "", + "urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"); + std::shared_ptr clearKeyHelperNoKeyUri = + DrmHelperEngine::getInstance().createHelper(drmInfoNoKeyUri); + clearKeyHelperNoKeyUri->generateLicenseRequest(challengeInfo, licenseRequest); + ASSERT_EQ(challengeInfo.url, licenseRequest.url); +} + +TEST_F(DrmHelperTests, TestClearKeyHelperTransformHlsLicenseResponse) +{ + struct TransformLicenseResponseTestData + { + std::vector keyResponse; + std::string expectedEncodedKey; + }; + + DrmInfo drmInfo = createDrmInfo(eMETHOD_AES_128, eMEDIAFORMAT_HLS_MP4, "file.key", + "urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"); + ASSERT_TRUE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + std::shared_ptr clearKeyHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + + const std::vector testData{ + // Empty response - should lead to empty string + {{}, {""}}, + // Most basic case - 1 maps to AQ + {{0x1}, {"AQ"}}, + // Should lead to a string containing every possible base64url character + {{0x00, 0x10, 0x83, 0x10, 0x51, 0x87, 0x20, 0x92, 0x8b, 0x30, 0xd3, 0x8f, + 0x41, 0x14, 0x93, 0x51, 0x55, 0x97, 0x61, 0x96, 0x9b, 0x71, 0xd7, 0x9f, + 0x82, 0x18, 0xa3, 0x92, 0x59, 0xa7, 0xa2, 0x9a, 0xab, 0xb2, 0xdb, 0xaf, + 0xc3, 0x1c, 0xb3, 0xd3, 0x5d, 0xb7, 0xe3, 0x9e, 0xbb, 0xf3, 0xdf, 0xbf}, + {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"}}}; + + for (auto& testCase : testData) + { + std::shared_ptr drmData = std::make_shared( reinterpret_cast(testCase.keyResponse.data()), testCase.keyResponse.size()); + clearKeyHelper->transformLicenseResponse(drmData); + } +} + +TEST_F(DrmHelperTests, TestTransformDashLicenseResponse) +{ + // Unlike HLS (where we do expect a ClearKey license to be transformed), + // for DASH we expect the response to be given back untouched + std::vector drmInfoList; + + // ClearKey + drmInfoList.push_back(createDrmInfo(eMETHOD_AES_128, eMEDIAFORMAT_DASH, "file.key", + "urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b")); + + // PlayReady + drmInfoList.push_back(createDrmInfo(eMETHOD_NONE, eMEDIAFORMAT_DASH, "", "", + "9a04f079-9840-4286-ab92-e65be0885f95")); + + for (auto& drmInfo : drmInfoList) + { + ASSERT_TRUE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + std::shared_ptr clearKeyHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + char licenseResponse[] = {'D', 'A', 'S', 'H', 'L', 'I', 'C'}; + std::shared_ptr drmData = + std::make_shared(licenseResponse, sizeof(licenseResponse)); + + clearKeyHelper->transformLicenseResponse(drmData); + ASSERT_EQ(sizeof(licenseResponse), drmData->getDataLength()); + ASSERT_EQ(std::string("DASHLIC"), drmData->getData()); + } +} + +TEST_F(DrmHelperTests, TestCreatePlayReadyHelper) +{ + const std::vector testData = { + // Valid UUID + {eMETHOD_AES_128, + eMEDIAFORMAT_DASH, // Note: PlayReady helper currently supports DASH only + "file.key", + "", + "9a04f079-9840-4286-ab92-e65be0885f95", + {}}, // For DASH, the key should come from the PSSH, so we won't check that here + + // Valid UUID, no method (method not required) + {eMETHOD_NONE, + eMEDIAFORMAT_DASH, // Note: PlayReady helper currently supports DASH only + "file.key", + "", + "9a04f079-9840-4286-ab92-e65be0885f95", + {}}, // For DASH, the key should come from the PSSH, so we won't check that here + + // Textual identifier rather than UUID + {eMETHOD_AES_128, + eMEDIAFORMAT_DASH, // Note: PlayReady helper currently supports DASH only + "file.key", + "com.microsoft.playready", + "", + {}} // For DASH, the key should come from the PSSH, so we won't check that here + }; + DrmInfo drmInfo; + + for (auto& test_data : testData) + { + drmInfo = createDrmInfo(test_data.method, test_data.mediaFormat, test_data.uri, + test_data.keyFormat, test_data.systemUUID); + + ASSERT_TRUE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + + std::shared_ptr playReadyHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + ASSERT_TRUE(playReadyHelper != nullptr); + ASSERT_EQ("com.microsoft.playready", playReadyHelper->ocdmSystemId()); + ASSERT_EQ(false, playReadyHelper->isClearDecrypt()); + ASSERT_EQ(eDRM_PlayReady, playReadyHelper->getDrmCodecType()); + ASSERT_EQ(false, playReadyHelper->isExternalLicense()); + ASSERT_EQ(5000U, playReadyHelper->licenseGenerateTimeout()); + ASSERT_EQ(5000U, playReadyHelper->keyProcessTimeout()); + + // TODO: HDCP checks + } +} + +TEST_F(DrmHelperTests, TestCreatePlayReadyHelperNegative) +{ + const std::vector testData = { + // Valid UUID but HLS media format, which isn't supported for the PlayReady helper + {eMETHOD_NONE, + eMEDIAFORMAT_HLS, + "file.key", + "", + "9a04f079-9840-4286-ab92-e65be0885f95", + {}}}; + DrmInfo drmInfo; + + for (auto& test_data : testData) + { + drmInfo = createDrmInfo(test_data.method, test_data.mediaFormat, test_data.uri, + test_data.keyFormat, test_data.systemUUID); + + ASSERT_FALSE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + + std::shared_ptr playReadyHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + ASSERT_TRUE(playReadyHelper == nullptr); + } +} + +TEST_F(DrmHelperTests, TestWidevineHelperParsePsshDrmMetaData) +{ + struct + { + const char *psshData; + const char *expectedKey[4]; + uint32_t protectionScheme; + } testData[] = + { + { "AAAANXBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABUyBnBvbGljeTjAxAdQlZrvOioCU0Q=", // psshData + {}, + 0 + // various deprecated fields: + //Policy: 'policy' + //Track Type: 'SD' + //Crypto Period Index: 123456 + //Crypto Period: 204 weeks, 27 days, 21 hours, 33 minutes, 9 seconds + }, + { "AAAAJnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAAZI89yVmwY=", // psshData + {}, + 'cens' + }, + { "AAAAJnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAAZIscaJmwY=", // psshData + {}, + 'cbc1' + }, + { "AAAAPnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAB4iFnNoYWthX2NlYzJmNjRhYTc4OTBhMTFI49yVmwY=", // psshData + { + "0x73,0x68,0x61,0x6B,0x61,0x5F,0x63,0x65,0x63,0x32,0x66,0x36,0x34,0x61,0x61,0x37,0x38,0x39,0x30,0x61,0x31,0x31" + }, 'cenc' + // Version 0, AES-CTR full sample encryption + // no key ids! + // Content ID = shaka_cec2f64aa7890a11 + }, + { "AAAANHBzc2gBAAAA7e+LqXnWSs6jyCfc1R0h7QAAAAEttsSNMB9I6rt3G6eorJBCAAAAAA==", // psshData + { + "0x2D,0xB6,0xC4,0x8D,0x30,0x1F,0x48,0xEA,0xBB,0x77,0x1B,0xA7,0xA8,0xAC,0x90,0x42" + }, 0 + // Version 1, single KeyID + }, + { "AAAAOHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABgSEC22xI0wH0jqu3cbp6iskEJI49yVmwY=", // psshData + { + "0x2D,0xB6,0xC4,0x8D,0x30,0x1F,0x48,0xEA,0xBB,0x77,0x1B,0xA7,0xA8,0xAC,0x90,0x42" + },'cenc' + // Version 0, 'cenc' + }, + { "AAAAOHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABgSEC22xI0wH0jqu3cbp6iskEJI88aJmwY=", // psshData + { + "0x2D,0xB6,0xC4,0x8D,0x30,0x1F,0x48,0xEA,0xBB,0x77,0x1B,0xA7,0xA8,0xAC,0x90,0x42" + },'cbcs' + // Version 0, 'cbcs' + }, + { "AAAARHBzc2gBAAAA7e+LqXnWSs6jyCfc1R0h7QAAAAIAAAAAAAAAAAAAAAAAAAAAEREREREREREREREREREREQAAAAA=", // psshData + { + "0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00", + "0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11" + },0 + // Version 1, two KeyIDs + }, + {"AAAAP3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAB8SEFYWbwTmlTrikzbYc0PLv+IaBWV6ZHJtSPPGiZsG", // psshData + { + "0x56,0x16,0x6f,0x04,0xe6,0x95,0x3a,0xe2,0x93,0x36,0xd8,0x73,0x43,0xcb,0xbf,0xe2" + },'cbcs' + // Protection Scheme: 63 62 63 73 (cbcs) + // Provider: ezdrm + }, + {"AAAASnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAACoIARIQL38/m5MtSFqBGT0XY2KM4yIUTkJDVTA0Mzg3NjU0MDA1NjMwMDc=", // psshData + { + "0x2f,0x7f,0x3f,0x9b,0x93,0x2d,0x48,0x5a,0x81,0x19,0x3d,0x17,0x63,0x62,0x8c,0xe3" + },0 + // includes 'author id' + // algorithm: AES-CTR full sample encryption + // Content ID: NBCU0438765400563007 + }, + {"AAAASnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAACoIARIQ7zHnTYhMQv+k86p90K3+rCIUTkJDVTkwMDAxOTI5MTUxMzAwMDM=", // psshData + { + "0xef,0x31,0xe7,0x4d,0x88,0x4c,0x42,0xff,0xa4,0xf3,0xaa,0x7d,0xd0,0xad,0xfe,0xac" + },0 + // algorithm: AES-CTR full sample encryption + // Content ID: NBCU9000192915130003 + }, + {"AAAAfXBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAF0SJDhlY2ZiOWZkLTNhODktNTNlMy05YjgwLTg4OTBmM2IyMzNmYiI1aW5kZW1hbmQuY29tSU5UTDAyMTgyMjIwMDA0MTQ5OTMtSU5NVjAyMTgyMjIwMDA0MTQ5OTM=", // psshData + { + "0x38,0x65,0x63,0x66,0x62,0x39,0x66,0x64,0x2D,0x33,0x61,0x38,0x39,0x2D,0x35,0x33,0x65,0x33,0x2D,0x39,0x62,0x38,0x30,0x2D,0x38,0x38,0x39,0x30,0x66,0x33,0x62,0x32,0x33,0x33,0x66,0x62" + },0 + // Content ID: indemand.comINTL0218222000414993-INMV0218222000414993 + // Key ID is 36 bytes long instead of required 16 + }, + {"AAAAMnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABISEG3fTdGQ1VJtmPL1WTLb1a8=", // psshData + { + "0x6d,0xdf,0x4d,0xd1,0x90,0xd5,0x52,0x6d,0x98,0xf2,0xf5,0x59,0x32,0xdb,0xd5,0xaf" + },0 + }, + {"AAAA93Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAANcSJDQ3OTZiNjY3LWZkZjYtYjI0My04MTM4LTNmM2VmZmQzN2E0NRIkNjdlZGIwZjQtMzIyYS1hNDgyLWZlNmQtZThiNjZiYWFhOGU4EiRhZWYyZjE3YS0xOWUwLWQ2MTctMGI4Ny02MTdmNjQ5OWNlZjQSJGM2NzE5YWJjLTY4YzctMWYxZC0xOWRiLTUxMjU5YWY2MDJmZSI9dXBmYWl0aGFuZGZhbWlseS5jb21VUFRMMDAwMDAwMDAwODM3Mzg2MS1VUE1WMDAwMDAwMDAwODM3Mzg2MQ==", // psshData + { + "0x34,0x37,0x39,0x36,0x62,0x36,0x36,0x37,0x2D,0x66,0x64,0x66,0x36,0x2D,0x62,0x32,0x34,0x33,0x2D,0x38,0x31,0x33,0x38,0x2D,0x33,0x66,0x33,0x65,0x66,0x66,0x64,0x33,0x37,0x61,0x34,0x35", + "0x36,0x37,0x65,0x64,0x62,0x30,0x66,0x34,0x2D,0x33,0x32,0x32,0x61,0x2D,0x61,0x34,0x38,0x32,0x2D,0x66,0x65,0x36,0x64,0x2D,0x65,0x38,0x62,0x36,0x36,0x62,0x61,0x61,0x61,0x38,0x65,0x38", + "0x61,0x65,0x66,0x32,0x66,0x31,0x37,0x61,0x2D,0x31,0x39,0x65,0x30,0x2D,0x64,0x36,0x31,0x37,0x2D,0x30,0x62,0x38,0x37,0x2D,0x36,0x31,0x37,0x66,0x36,0x34,0x39,0x39,0x63,0x65,0x66,0x34", + "0x63,0x36,0x37,0x31,0x39,0x61,0x62,0x63,0x2D,0x36,0x38,0x63,0x37,0x2D,0x31,0x66,0x31,0x64,0x2D,0x31,0x39,0x64,0x62,0x2D,0x35,0x31,0x32,0x35,0x39,0x61,0x66,0x36,0x30,0x32,0x66,0x65" + },0 + // Content ID: upfaithandfamily.comUPTL0000000008373861-UPMV0000000008373861 + // Key ID is 36 bytes long instead of required 16 + }, + {"AAAAOHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABgSEABFDiYaE6QUtKoKcLv0s6hI49yVmwY=", // psshData + { + "0x00,0x45,0x0e,0x26,0x1a,0x13,0xa4,0x14,0xb4,0xaa,0x0a,0x70,0xbb,0xf4,0xb3,0xa8" + },'cenc' + // Protection Scheme: 63 65 6E 63 (cenc) + // AES-CTR full sample encryption + } + }; + + for( int i=0; i widevineHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + ASSERT_TRUE(widevineHelper != nullptr); + + bool rc = widevineHelper->parsePssh(psshDataPtr, (uint32_t)psshDataLen); + if( testData[i].expectedKey[0] ) + { // at least one keyid expected + ASSERT_TRUE(rc); + } + + std::vector initData; + widevineHelper->createInitData(initData); + for( int j=0; j> keyIDs; + widevineHelper->getKeys(keyIDs); + + printf( "protection scheme=0x%08x\n", widevineHelper->getProtectionScheme() ); + ASSERT_EQ( widevineHelper->getProtectionScheme(), testData[i].protectionScheme ); + + for( int iKey=0; iKey<4; iKey++ ) + { + const char *expected = testData[i].expectedKey[iKey]; + if( expected ) + { + int count = (int)(strlen(expected)+1)/5; + ASSERT_EQ( keyIDs[iKey].size(), count ); + for( int j=0; jgetDrmMetaData(); + ASSERT_EQ("", contentMetadata); + + std::string metaData("content meta data"); + widevineHelper->setDrmMetaData(metaData); + contentMetadata = widevineHelper->getDrmMetaData(); + ASSERT_EQ(metaData, contentMetadata); + + free( psshDataPtr ); + } +} + +TEST_F(DrmHelperTests, TestCreateWidevineHelper) +{ + const std::vector testData = { + {eMETHOD_NONE, + eMEDIAFORMAT_DASH, + "file.key", + "", + "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed", + {}}, + + {eMETHOD_AES_128, + eMEDIAFORMAT_DASH, + "file.key", + "", + "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed", + {}}, + + // Textual identifier rather than UUID + {eMETHOD_AES_128, eMEDIAFORMAT_DASH, "file.key", "com.widevine.alpha", "", {}}}; + DrmInfo drmInfo; + + for (auto& test_data : testData) + { + drmInfo = createDrmInfo(test_data.method, test_data.mediaFormat, test_data.uri, + test_data.keyFormat, test_data.systemUUID); + + ASSERT_TRUE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + + std::shared_ptr widevineHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + ASSERT_TRUE(widevineHelper != nullptr); + ASSERT_EQ("com.widevine.alpha", widevineHelper->ocdmSystemId()); + ASSERT_EQ(false, widevineHelper->isClearDecrypt()); + ASSERT_EQ(false, widevineHelper->isHdcp22Required()); + ASSERT_EQ(eDRM_WideVine, widevineHelper->getDrmCodecType()); + ASSERT_EQ(false, widevineHelper->isExternalLicense()); + ASSERT_EQ(5000U, widevineHelper->licenseGenerateTimeout()); + ASSERT_EQ(5000U, widevineHelper->keyProcessTimeout()); + } +} + +TEST_F(DrmHelperTests, TestCreateWidevineHelperNegative) +{ + const std::vector testData = { + // Valid UUID but HLS media format, which isn't supported for the Widevine helper + {eMETHOD_NONE, + eMEDIAFORMAT_HLS, + "file.key", + "", + "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed", + {}}}; + DrmInfo drmInfo; + + for (auto& test_data : testData) + { + drmInfo = createDrmInfo(test_data.method, test_data.mediaFormat, test_data.uri, + test_data.keyFormat, test_data.systemUUID); + + ASSERT_FALSE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + + std::shared_ptr widevineHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + ASSERT_TRUE(widevineHelper == nullptr); + } +} + +TEST_F(DrmHelperTests, TestPlayReadyHelperParsePssh) +{ + DrmInfo drmInfo = createDrmInfo(eMETHOD_NONE, eMEDIAFORMAT_DASH, "", "", + "9a04f079-9840-4286-ab92-e65be0885f95"); + ASSERT_TRUE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + std::shared_ptr playReadyHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + + const std::string expectedMetadata = "testpolicydata"; + + std::ostringstream psshSs; + psshSs + << "" + << "" + << "16bytebase64enckeydata==" + << "" << expectedMetadata << "" + << "" + << ""; + const std::string psshStr = psshSs.str(); + + ASSERT_TRUE(playReadyHelper->parsePssh((const unsigned char*)psshStr.data(), (uint32_t)psshStr.size())); + + // Check keyId and metadata, both of which should be based on the PSSH + std::vector keyId; + playReadyHelper->getKey(keyId); + + const std::string expectedKeyId = "b5f2a6d7-dae6-eeb1-b87a-77247b275ab5"; + const std::string actualKeyId = std::string(keyId.begin(), keyId.begin() + keyId.size()); + + ASSERT_EQ(expectedKeyId, actualKeyId); + ASSERT_EQ(expectedMetadata, playReadyHelper->getDrmMetaData()); + // Ensure the helper doesn't set the meta data + playReadyHelper->setDrmMetaData("content meta data that should be ignored"); + ASSERT_EQ(expectedMetadata, playReadyHelper->getDrmMetaData()); + + // Dodgy PSSH data should lead to false return value + const std::string badPssh = "somerandomdatawhichisntevenxml"; + ASSERT_FALSE(playReadyHelper->parsePssh((const unsigned char*)badPssh.data(), (uint32_t)badPssh.size())); +} + +TEST_F(DrmHelperTests, TestPlayReadyHelperParsePsshNoPolicy) +{ + // As before but with no ckm:policy in the PSSH data. + // Should be OK but lead to empty metadata + DrmInfo drmInfo = createDrmInfo(eMETHOD_NONE, eMEDIAFORMAT_DASH, "", "", + "9a04f079-9840-4286-ab92-e65be0885f95"); + ASSERT_TRUE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + std::shared_ptr playReadyHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + + const std::string psshStr = + "" + "" + "16bytebase64enckeydata==" + "" + ""; + + ASSERT_TRUE(playReadyHelper->parsePssh((const unsigned char*)psshStr.data(), (uint32_t)psshStr.size())); + + // Check keyId and metadata, both of which should be based on the PSSH + std::vector keyId; + playReadyHelper->getKey(keyId); + + const std::string expectedKeyId = "b5f2a6d7-dae6-eeb1-b87a-77247b275ab5"; + const std::string actualKeyId = std::string(keyId.begin(), keyId.begin() + keyId.size()); + + ASSERT_EQ(expectedKeyId, actualKeyId); + // Not expecting any metadata + ASSERT_EQ("", playReadyHelper->getDrmMetaData()); +} + +TEST_F(DrmHelperTests, TestPlayReadyHelperGenerateLicenseRequest) +{ + DrmInfo drmInfo = createDrmInfo(eMETHOD_NONE, eMEDIAFORMAT_DASH, "", "", + "9a04f079-9840-4286-ab92-e65be0885f95"); + ASSERT_TRUE(DrmHelperEngine::getInstance().hasDRM(drmInfo)); + std::shared_ptr playReadyHelper = + DrmHelperEngine::getInstance().createHelper(drmInfo); + + ChallengeInfo challengeInfo; + challengeInfo.url = "http://challengeinfourl.example"; + std::string challengeData = "OCDM_CHALLENGE_DATA"; + + challengeInfo.data = + std::make_shared( challengeData.c_str(), challengeData.length()); + challengeInfo.accessToken = "ACCESS_TOKEN"; + + // No PSSH parsed. Expecting data from the provided challenge to be given back in the request + // info + LicenseRequest licenseRequest1; + playReadyHelper->generateLicenseRequest(challengeInfo, licenseRequest1); + ASSERT_EQ(challengeInfo.url, licenseRequest1.url); + ASSERT_EQ(challengeInfo.data->getData(), licenseRequest1.payload); + + // Parse a PSSH with a ckm:policy. This should cause generateLicenseRequest to return a JSON + // payload + LicenseRequest licenseRequest2; + const std::string psshStr = + "" + "" + "16bytebase64enckeydata==" + "policy" + "" + ""; + ASSERT_TRUE(playReadyHelper->parsePssh((const unsigned char*)psshStr.data(), (uint32_t)psshStr.size())); + + playReadyHelper->generateLicenseRequest(challengeInfo, licenseRequest2); + ASSERT_EQ(challengeInfo.url, licenseRequest2.url); + + // Finally, checking the license uri override works + LicenseRequest licenseRequest3; + const std::string fixedPrLicenseUrl = "http://prlicenseserver.example"; + licenseRequest3.url = fixedPrLicenseUrl; + + playReadyHelper->generateLicenseRequest(challengeInfo, licenseRequest3); + ASSERT_EQ(fixedPrLicenseUrl, licenseRequest3.url); +} + +TEST_F(DrmHelperTests, TestCompareHelpers) +{ + std::shared_ptr playreadyHelper = + DrmHelperEngine::getInstance().createHelper( + createDrmInfo(eMETHOD_AES_128, eMEDIAFORMAT_DASH, "file.key", "", + "9a04f079-9840-4286-ab92-e65be0885f95")); + ASSERT_TRUE(playreadyHelper != nullptr); + + std::shared_ptr widevineHelper = DrmHelperEngine::getInstance().createHelper( + createDrmInfo(eMETHOD_AES_128, eMEDIAFORMAT_DASH, "file.key", "", + "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed")); + ASSERT_TRUE(widevineHelper != nullptr); + + std::shared_ptr clearKeyHelperHls = + DrmHelperEngine::getInstance().createHelper( + createDrmInfo(eMETHOD_AES_128, eMEDIAFORMAT_HLS_MP4, "file.key", "", + "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b")); + ASSERT_TRUE(clearKeyHelperHls != nullptr); + + std::shared_ptr clearKeyHelperDash = + DrmHelperEngine::getInstance().createHelper( + createDrmInfo(eMETHOD_AES_128, eMEDIAFORMAT_DASH, "file.key", "", + "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b")); + ASSERT_TRUE(clearKeyHelperDash != nullptr); + + // All helpers should equal themselves + ASSERT_TRUE(widevineHelper->compare(widevineHelper)); + ASSERT_TRUE(playreadyHelper->compare(playreadyHelper)); + ASSERT_TRUE(clearKeyHelperHls->compare(clearKeyHelperHls)); + + // Different helper types, should not equal + ASSERT_FALSE(playreadyHelper->compare(widevineHelper) || + playreadyHelper->compare(clearKeyHelperHls)); + ASSERT_FALSE(widevineHelper->compare(playreadyHelper) || + widevineHelper->compare(clearKeyHelperHls)); + + // Same helper type but one is HLS and the other is DASH, so should not equal + ASSERT_FALSE(clearKeyHelperHls->compare(clearKeyHelperDash)); + + // Comparison against null helper, should not equal, should not cause a problem + std::shared_ptr nullHelper; + ASSERT_FALSE(clearKeyHelperHls->compare(nullHelper)); + + std::shared_ptr playreadyHelper2 = + DrmHelperEngine::getInstance().createHelper( + createDrmInfo(eMETHOD_AES_128, eMEDIAFORMAT_DASH, "file.key", "", + "9a04f079-9840-4286-ab92-e65be0885f95")); + ASSERT_TRUE(playreadyHelper2 != nullptr); + + const std::string pssh1 = + "" + "" + "16bytebase64enckeydata==" + "" + ""; + playreadyHelper->parsePssh((const unsigned char*)pssh1.data(), (uint32_t)pssh1.size()); + playreadyHelper2->parsePssh((const unsigned char*)pssh1.data(), (uint32_t)pssh1.size()); + + // Same key in the PSSH data, should equal + ASSERT_TRUE(playreadyHelper->compare(playreadyHelper2)); + + const std::string pssh2 = + "" + "" + "differentbase64keydata==" + "" + ""; + playreadyHelper2->parsePssh((const unsigned char*)pssh2.data(), (uint32_t)pssh2.size()); + + // Different key in the PSSH data, should not equal + ASSERT_FALSE(playreadyHelper->compare(playreadyHelper2)); + + // Create another PR helper, same details as PR helper 1 + std::shared_ptr playreadyHelper3 = + DrmHelperEngine::getInstance().createHelper( + createDrmInfo(eMETHOD_AES_128, eMEDIAFORMAT_DASH, "file.key", "", + "9a04f079-9840-4286-ab92-e65be0885f95")); + ASSERT_TRUE(playreadyHelper3 != nullptr); + + // But no PSSH parsed for the 3rd PR helper, so shouldn't be equal + ASSERT_FALSE(playreadyHelper->compare(playreadyHelper3)); + + // Parse the same PSSH as used for 1, now should be equal + playreadyHelper3->parsePssh((const unsigned char*)pssh1.data(), (uint32_t)pssh1.size()); + ASSERT_TRUE(playreadyHelper->compare(playreadyHelper3)); + + // Finally keep the same key but add in metadata. Now PR helpers 1 & 3 shouldn't be equal + const std::string pssh3 = + "" + "" + "16bytebase64enckeydata==" + "policy" + "" + ""; + playreadyHelper3->parsePssh((const unsigned char*)pssh3.data(), (uint32_t)pssh3.size()); + ASSERT_FALSE(playreadyHelper->compare(playreadyHelper3)); +} diff --git a/test/utests/tests/DrmOcdm/DrmSessionTests.cpp b/test/utests/tests/DrmOcdm/DrmSessionTests.cpp new file mode 100644 index 00000000..9d2b870d --- /dev/null +++ b/test/utests/tests/DrmOcdm/DrmSessionTests.cpp @@ -0,0 +1,349 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "DrmSessionFactory.h" +#include "DrmSessionManager.h" +#include "ClearKeyHelper.h" +#include "open_cdm.h" + +#include "aampMocks.h" + +#include "Fakeopencdm.h" +#include "curlMocks.h" + +#include "DrmTestUtils.h" + +#include "MockOpenCdm.h" +#include "MockPrivateInstanceAAMP.h" +#include "PlayerUtils.h" +using ::testing::_; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::StrEq; + +class DrmSessionTests : public ::testing::Test +{ +protected: + //PrivateInstanceAAMP *mAamp = nullptr; + //TestUtilDrm *mUtils = nullptr; + + // The URL AAMP uses to fetch the session token + const std::string mSessionTokenUrl = "http://localhost:50050/authService/getSessionToken"; + // A fixed session token response - any tests which require a session token can use this, + // since the manager is singleton and will only ever fetch it once. Test order is + // non-deterministic, so it's not guaranteed which test will actually trigger the fetch + const std::string mSessionTokenResponse = "{\"token\":\"SESSIONTOKEN\", \"status\":0}"; + + void SetUp() override + { + //MockAampReset(); + //MockCurlReset(); + MockOpenCdmReset(); + + g_mockopencdm = new NiceMock(); + //g_mockPrivateInstanceAAMP = new NiceMock(); + //mAamp = new PrivateInstanceAAMP(gpGlobalConfig); + //mUtils = new TestUtilDrm(mAamp); + } + + void TearDown() override + { + //delete mUtils; + //mUtils = nullptr; + + //delete mAamp; + //mAamp = nullptr; + + //delete g_mockPrivateInstanceAAMP; + //g_mockPrivateInstanceAAMP = nullptr; + + delete g_mockopencdm; + g_mockopencdm = nullptr; + + //MockAampReset(); + //MockCurlReset(); + MockOpenCdmReset(); + } + +public: +}; + +TEST_F(DrmSessionTests, TestClearKeyLicenseAcquisition) +{ + // Setup Curl and OpenCDM mocks. We expect that curl_easy_perform will be called to fetch + // the key and that OpenCDM will be called to construct the session and handle the fetched key. + std::string testKeyData = "TESTKEYDATA"; + //mUtils->setupCurlPerformResponse(testKeyData); + //mUtils->setupChallengeCallbacks(); + + // Begin test + DrmInfo drmInfo; + drmInfo.method = eMETHOD_AES_128; + drmInfo.manifestURL = "http://example.com/assets/test.m3u8"; + drmInfo.keyURI = "file.key"; + std::shared_ptr drmHelper = + std::make_shared(drmInfo); + + // We expect the key data to be transformed by the helper before being passed to + // opencdm_session_update. Thus we call the helper ourselves here (with the data our mock Curl + // will return) so we know what to expect. Note: testing of the transformation is done in the + // helper tests, here we just want to ensure that whatever the helper returns is what OpenCDM + // gets. + const shared_ptr expectedDrmData = + make_shared(testKeyData.c_str(), testKeyData.size()); + drmHelper->transformLicenseResponse(expectedDrmData); + + EXPECT_CALL(*g_mockopencdm, opencdm_session_update(OCDM_SESSION, + MemBufEq(expectedDrmData->getData().c_str(), + expectedDrmData->getDataLength()), + expectedDrmData->getDataLength())) + .WillOnce(Return(ERROR_NONE)); + + DrmSession *drmSession = mUtils->createDrmSessionForHelper(drmHelper, "org.w3.clearkey"); + ASSERT_TRUE(drmSession != nullptr); + ASSERT_STREQ("org.w3.clearkey", drmSession->getKeySystem().c_str()); + + const MockCurlOpts *curlOpts = MockCurlGetOpts(); + // Key URL should been constructed based on manifestURL and keyURI from the DrmInfo + ASSERT_STREQ("http://example.com/assets/file.key", curlOpts->url); + // POST is used + ASSERT_EQ(0L, curlOpts->httpGet); +} + +TEST_F(DrmSessionTests, TestMultipleSessionsSameKey) +{ + std::string testKeyData = "TESTKEYDATA"; + mUtils->setupCurlPerformResponse(testKeyData); + mUtils->setupChallengeCallbacks(); + + DrmInfo drmInfo; + drmInfo.method = eMETHOD_AES_128; + drmInfo.manifestURL = "http://example.com/assets/test.m3u8"; + drmInfo.keyURI = "file.key"; + std::shared_ptr drmHelper = + std::make_shared(drmInfo); + + const shared_ptr expectedDrmData = + make_shared(testKeyData.c_str(), testKeyData.size()); + drmHelper->transformLicenseResponse(expectedDrmData); + + // Only 1 session update called expected, since a single session should be shared + EXPECT_CALL(*g_mockopencdm, opencdm_session_update(OCDM_SESSION, + MemBufEq(expectedDrmData->getData().c_str(), + expectedDrmData->getDataLength()), + expectedDrmData->getDataLength())) + .WillOnce(Return(ERROR_NONE)); + + // 1st time around - expecting standard session creation + DrmSession *drmSession1 = mUtils->createDrmSessionForHelper(drmHelper, "org.w3.clearkey"); + ASSERT_TRUE(drmSession1 != nullptr); + ASSERT_STREQ("org.w3.clearkey", drmSession1->getKeySystem().c_str()); + + // 2nd time around - expecting the existing session will be shared, so no OCDM session created + AampDRMLicenseManager *sessionManager = mUtils->getSessionManager(); + DrmMetaDataEventPtr event = mUtils->createDrmMetaDataEvent(); + + EXPECT_CALL(*g_mockopencdm, opencdm_create_system).Times(0); + EXPECT_CALL(*g_mockopencdm, opencdm_construct_session).Times(0); + + int err =-1; + DrmSession *drmSession2 = + sessionManager->createDrmSession(drmHelper, mAamp, event , (int)eMEDIATYPE_VIDEO); + ASSERT_EQ(drmSession1, drmSession2); + + // Clear out the sessions. Now a new OCDM session is expected again + sessionManager->mDRMSessionManager->clearSessionData(); + + EXPECT_CALL(*g_mockopencdm, opencdm_session_update(OCDM_SESSION, + MemBufEq(expectedDrmData->getData().c_str(), + expectedDrmData->getDataLength()), + expectedDrmData->getDataLength())) + .WillOnce(Return(ERROR_NONE)); + + DrmSession *drmSession3 = mUtils->createDrmSessionForHelper(drmHelper, "org.w3.clearkey"); + ASSERT_TRUE(drmSession3 != nullptr); + ASSERT_STREQ("org.w3.clearkey", drmSession3->getKeySystem().c_str()); +} + +TEST_F(DrmSessionTests, TestDashPlayReadySession) +{ + string prLicenseServerURL = "http://licenseserver.example/license"; + const std::string testKeyData = "TESTKEYDATA"; + const std::string testChallengeData = "PLAYREADY_CHALLENGE_DATA"; + + // Setting a PlayReady license server URL in the global config. This + // should get used to request the license + gpGlobalConfig->SetConfigValue(AAMP_APPLICATION_SETTING, eAAMPConfig_PRLicenseServerUrl, + prLicenseServerURL); + + // Setting up Curl callbacks for the session token and license requests + mUtils->setupCurlPerformResponses( + {{mSessionTokenUrl, mSessionTokenResponse}, {prLicenseServerURL, testKeyData}}); + + mUtils->setupChallengeCallbacks(MockChallengeData("playready.example", testChallengeData)); + + // PSSH string which will get passed to the helper for parsing, so needs to be in valid format + const std::string psshStr = + "" + "" + "16bytebase64enckeydata==" + "" + ""; + + DrmMetaDataEventPtr event = mUtils->createDrmMetaDataEvent(); + DrmSession *drmSession = mUtils->createDashDrmSession(testKeyData, psshStr, event); + ASSERT_TRUE(drmSession != nullptr); + ASSERT_STREQ("com.microsoft.playready", drmSession->getKeySystem().c_str()); + + const TestCurlResponse *licenseResponse = mUtils->getCurlPerformResponse(prLicenseServerURL); + ASSERT_EQ(1, licenseResponse->callCount); + + // Check the post data set on Curl, this should be the challenge data returned by OCDM + ASSERT_EQ(testChallengeData.size(), licenseResponse->opts.postFieldSize); + ASSERT_EQ(testChallengeData, licenseResponse->opts.postFields); +} + +TEST_F(DrmSessionTests, TestDashPlayReadySessionNoCkmPolicy) +{ + string prLicenseServerURL = "http://licenseserver.example/license"; + std::string testKeyData = "TESTKEYDATA"; + + // Setting a PlayReady license server URL in the global config. This + // should get used to request the license + gpGlobalConfig->SetConfigValue(AAMP_APPLICATION_SETTING, eAAMPConfig_PRLicenseServerUrl, + prLicenseServerURL); + + // Setting up Curl callbacks for the session token and license requests + mUtils->setupCurlPerformResponses( + {{mSessionTokenUrl, mSessionTokenResponse}, {prLicenseServerURL, testKeyData}}); + + mUtils->setupChallengeCallbacks(); + + // PSSH string which will get passed to the helper for parsing, so needs to be in valid format + const std::string psshStr = + "" + "" + "16bytebase64enckeydata==" + "" + ""; + + DrmMetaDataEventPtr event = mUtils->createDrmMetaDataEvent(); + DrmSession *drmSession = mUtils->createDashDrmSession(testKeyData, psshStr, event); + ASSERT_TRUE(drmSession != nullptr); + ASSERT_STREQ("com.microsoft.playready", drmSession->getKeySystem().c_str()); + + const MockCurlOpts *curlOpts = MockCurlGetOpts(); + + // Check license URL from the global config was used + std::string url = gpGlobalConfig->GetConfigValue(eAAMPConfig_PRLicenseServerUrl); + ASSERT_STREQ(url.c_str(), curlOpts->url); + + // Check the post data set on Curl. Since we didn't pass any metadata (ckm:policy) in the init + // data, we expect the challenge data returned by OCDM to just be used as-is + ASSERT_TRUE(curlOpts->postFieldSize > 0); + ASSERT_STREQ("OCDM_CHALLENGE_DATA", curlOpts->postFields); +} + +TEST_F(DrmSessionTests, TestSessionBadChallenge) +{ + DrmInfo drmInfo; + drmInfo.method = eMETHOD_AES_128; + drmInfo.manifestURL = "http://example.com/assets/test.m3u8"; + drmInfo.keyURI = "file.key"; + std::shared_ptr drmHelper = + std::make_shared(drmInfo); + + // Cause OpenCDM to return an empty challenge. This should cause an error + mUtils->setupChallengeCallbacks(MockChallengeData("", "")); + + EXPECT_CALL(*g_mockopencdm, opencdm_create_system(StrEq("org.w3.clearkey"))) + .WillOnce(Return(OCDM_SYSTEM)); + EXPECT_CALL(*g_mockopencdm, opencdm_construct_session) + .WillOnce(DoAll(SetArgPointee<9>(OCDM_SESSION), Return(ERROR_NONE))); + + int err = -1; + DrmMetaDataEventPtr event = mUtils->createDrmMetaDataEvent(); + DrmSession *drmSession = + mUtils->getSessionManager()->createDrmSession(drmHelper, mAamp,event, (int)eMEDIATYPE_VIDEO); + ASSERT_EQ(nullptr, drmSession); + ASSERT_EQ(AAMP_TUNE_DRM_CHALLENGE_FAILED, event->getFailure()); +} + +TEST_F(DrmSessionTests, TestSessionBadLicenseResponse) +{ + DrmInfo drmInfo; + drmInfo.method = eMETHOD_AES_128; + drmInfo.manifestURL = "http://example.com/assets/test.m3u8"; + drmInfo.keyURI = "file.key"; + std::shared_ptr drmHelper = + std::make_shared(drmInfo); + + // Make curl return empty data for the key. This should cause an error + mUtils->setupCurlPerformResponses({{"http://example.com/assets/file.key", ""}}); + + EXPECT_CALL(*g_mockopencdm, opencdm_create_system(StrEq("org.w3.clearkey"))) + .WillOnce(Return(OCDM_SYSTEM)); + EXPECT_CALL(*g_mockopencdm, opencdm_construct_session) + .WillOnce(DoAll(SetArgPointee<9>(OCDM_SESSION), Return(ERROR_NONE))); + + mUtils->setupChallengeCallbacks(); + + DrmMetaDataEventPtr event = mUtils->createDrmMetaDataEvent(); + int err = -1; + DrmSession *drmSession = + mUtils->getSessionManager()->createDrmSession( drmHelper, mAamp,event , (int)eMEDIATYPE_VIDEO); + ASSERT_EQ(nullptr, drmSession); + ASSERT_EQ(AAMP_TUNE_LICENCE_REQUEST_FAILED, event->getFailure()); +} + +TEST_F(DrmSessionTests, TestDashSessionBadPssh) +{ + std::string testKeyData = "TESTKEYDATA"; + + // Pass a bad PSSH string. This should cause an error + const std::string psshStr = "bad data with no KID"; + + DrmMetaDataEventPtr event = mUtils->createDrmMetaDataEvent(); + void *ptr= static_cast(&event); + int err =-1; + DrmSession *drmSession = mUtils->getSessionManager()->mDRMSessionManager->createDrmSession(err, + "9a04f079-9840-4286-ab92-e65be0885f95", eMEDIAFORMAT_DASH, + (const unsigned char *)psshStr.c_str(), psshStr.length(), eMEDIATYPE_VIDEO, mAamp, ptr); + ASSERT_EQ(nullptr, drmSession); + AAMPTuneFailure val = mUtils->getSessionManager()->MapDrmToAampTuneFailure((DrmTuneFailure)err); +printf("val = %d", val); + if(err != -1) + { + event->setFailure(val); + } + + ASSERT_EQ(AAMP_TUNE_CORRUPT_DRM_METADATA, event->getFailure()); +} diff --git a/test/utests/tests/DrmOcdm/DrmTestsRun.cpp b/test/utests/tests/DrmOcdm/DrmTestsRun.cpp new file mode 100644 index 00000000..2034179e --- /dev/null +++ b/test/utests/tests/DrmOcdm/DrmTestsRun.cpp @@ -0,0 +1,26 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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 + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/utests/tests/DrmOcdm/DrmUtilsTests.cpp b/test/utests/tests/DrmOcdm/DrmUtilsTests.cpp new file mode 100644 index 00000000..dea99b26 --- /dev/null +++ b/test/utests/tests/DrmOcdm/DrmUtilsTests.cpp @@ -0,0 +1,112 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "DrmUtils.h" +#include "PlayerUtils.h" + +class DrmUtilsTests : public ::testing::Test +{ + +protected: + void SetUp() override + { + } + + void TearDown() override + { + } + +public: +}; + +TEST_F(DrmUtilsTests, TestGetAbsoluteKeyUri) +{ + struct GetAbsoluteKeyUriTestData + { + std::string manifestUrl; + std::string keyUri; + std::string expectedUri; + }; + + const std::vector testData = { + {"http://stream.example/manifest.m3u8", "basic1.key", "http://stream.example/basic1.key"}, + {"http://stream.example/manifest.m3u8", "basic2", "http://stream.example/basic2"}, + {"http://stream.example/manifest", "basic3", "http://stream.example/basic3"}, + {"http://stream.example/assets/hls/manifest.m3u8", "basic4.key", + "http://stream.example/assets/hls/basic4.key"}, + + // Relative path which refers to a parent directory. We copy ../ instances as-is, these can + // be resolved by curl + {"http://stream.example/asset/1080p/manifest.m3u8", "../relkey1.key", + "http://stream.example/asset/1080p/../relkey1.key"}, + {"http://stream.example/asset/1080p/../manifest.m3u8", "../relkey2.key", + "http://stream.example/asset/1080p/../../relkey2.key"}, + + // Port number included + {"http://stream.example:1234/manifest.m3u8", "port1.key", + "http://stream.example:1234/port1.key"}, + + // HTTPS + {"https://stream.example/manifest.m3u8", "secure1.key", + "https://stream.example/secure1.key"}, + + // Absolute path reference on key URI + {"http://stream.example/manifest.m3u8", "/absref1.key", + "http://stream.example/absref1.key"}, + {"http://stream.example/assets/hls/manifest.m3u8", "/absref2.key", + "http://stream.example/absref2.key"}, + + // Absolute key URIs + {"http://stream.example/manifest.m3u8", "http://key.example/abs1.key", + "http://key.example/abs1.key"}, + {"", "http://key.example/abs2.key", "http://key.example/abs2.key"}, + + // Keys with arguments + {"http://stream.example/manifest.m3u8", "arg1.key?a=test", + "http://stream.example/arg1.key?a=test"}, + {"http://stream.example/manifest.m3u8", "arg2.key?a=http://", + "http://stream.example/arg2.key?a=http://"}, + + // Only domain present on manifest URL (not normally expected, but should be handled OK) + {"http://stream.example", "domonly1.key", "http://stream.example/domonly1.key"}, + {"http://stream.example/", "domonly2.key", "http://stream.example/domonly2.key"}, + {"http://stream.example", "/domonly3.key", "http://stream.example/domonly3.key"}, + + // Other protocols for the key (HTTP expected, but this utility is expected to be protocol + // agnostic) + {"http://example/manifest.m3u8", "file://prot1.key", "file://prot1.key"}, + // Still a valid scheme (- . and + are allowed) + {"http://example/manifest.m3u8", "a-b.c+d://prot2.key", "a-b.c+d://prot2.key"}, + // Not a valid scheme - will default to relative + {"http://example/manifest.m3u8", "#abc!://prot3.key", "http://example/#abc!://prot3.key"}, + // Capitalised protocol accepted + {"http://example/manifest.m3u8", "HTTP://key.example/prot4.key", + "HTTP://key.example/prot4.key"}, + }; + + for (auto test : testData) + { + std::string keyURI; + ResolveURL(keyURI, test.manifestUrl, test.keyUri.c_str(), false); + ASSERT_EQ(test.expectedUri, keyURI); + } +} diff --git a/test/utests/tests/DrmSecureClient/CMakeLists.txt b/test/utests/tests/DrmSecureClient/CMakeLists.txt new file mode 100644 index 00000000..c1454620 --- /dev/null +++ b/test/utests/tests/DrmSecureClient/CMakeLists.txt @@ -0,0 +1,112 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2024 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(GoogleTest) + +pkg_check_modules(UUID REQUIRED uuid) + +set(PLAYER_ROOT "../../../..") +set(UTESTS_ROOT "../..") +set(DRM_ROOT ${UTESTS_ROOT}/drm) +set(SEC_CLIENT_ROOT ${PLAYER_ROOT}/../secclient) +set(EXEC_NAME DrmSecureClient) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DREALTEKCE=1") + +# The Secure Client header files must exist in aamp/../secclient/ for these tests to build and run +file(GLOB SEC_CLIENT_HEADERS "${SEC_CLIENT_ROOT}/*") + +include_directories(${GTEST_INCLUDE_DIRS}) +include_directories(${GMOCK_INCLUDE_DIRS}) +include_directories(${UUID_INCLUDE_DIRS}) + +include_directories(${PLAYER_ROOT} ${PLAYER_ROOT}/drm ${PLAYER_ROOT}/drm/helper ${PLAYER_ROOT}/subtitle ${PLAYER_ROOT}/middleware/subtitle ${PLAYER_ROOT}/downloader ${PLAYER_ROOT}/isobmff ${PLAYER_ROOT}/middleware/subtec/subtecparser ${PLAYER_ROOT}/middleware/playerjsonobject ${PLAYER_ROOT}/middleware/subtec/libsubtec) +include_directories(${PLAYER_ROOT}/tsb/api) +include_directories(${GLIB_INCLUDE_DIRS}) +include_directories(${GSTREAMER_INCLUDE_DIRS}) +include_directories(${LIBCJSON_INCLUDE_DIRS}) +include_directories(${DRM_ROOT}) +include_directories(${DRM_ROOT}/ocdm) +include_directories(${PLAYER_ROOT}/../secclient) +include_directories(${DRM_ROOT}/mocks) +include_directories(${PLAYER_ROOT}/externals/playersecmanager) +include_directories(${PLAYER_ROOT}/playerLogManager) + +message(GSTREAMER_INCLUDE_DIRS=${GSTREAMER_INCLUDE_DIRS}) + +set(TEST_SOURCES DrmTestsRun.cpp + DrmSessionTests.cpp) + +if(SEC_CLIENT_HEADERS) + message("Found Secure Client headers - building ${EXEC_NAME}") + + set(MOCK_SOURCES ${DRM_ROOT}/mocks/curlMocks.c + ${PLAYER_ROOT}test/utests/drm/mocks/gstMocks.c + ${DRM_ROOT}/mocks/pthreadMocks.c + ${DRM_ROOT}/mocks/openSslMocks.c + ${DRM_ROOT}/mocks/Fakeopencdm.cpp + ${DRM_ROOT}/mocks/Fakesecclient.cpp) + + set(PLAYER_SOURCES ${PLAYER_ROOT}/externals/playersecmanager/ThunderAccessPlayer.cpp + ${PLAYER_ROOT}/externals/playersecmanager/PlayerSecManager.cpp + ${PLAYER_ROOT}/drm/DrmSessionFactory.cpp + ${PLAYER_ROOT}/drm/helper/DrmHelper.cpp + ${PLAYER_ROOT}/drm/helper/DrmHelperFactory.cpp + ${PLAYER_ROOT}/drm/DRMSessionManager.cpp + ${PLAYER_ROOT}/drm/DrmSession.cpp + ${PLAYER_ROOT}/drm/ocdm/opencdmsessionadapter.cpp + ${PLAYER_ROOT}/drm/ocdm/opencdmsessionadapter.cpp + ${PLAYER_ROOT}/drm/ocdm/OcdmBasicSessionAdapter.cpp + ${PLAYER_ROOT}/drm/ocdm/OcdmGstSessionAdapter.cpp + ${PLAYER_ROOT}/drm/HlsOcdmBridge.cpp + ${PLAYER_ROOT}/drm/helper/ClearKeyHelper.cpp + ${PLAYER_ROOT}/drm/helper/WidevineDrmHelper.cpp + ${PLAYER_ROOT}/drm/helper/PlayReadyHelper.cpp) + + add_definitions(-DUSE_SHARED_MEMORY) + add_definitions(-DUSE_OPENCDM -DUSE_OPENCDM_ADAPTER) + add_definitions(-DUSE_THUNDER_OCDM_API_0_2) + add_definitions(-DUSE_SECCLIENT) + + add_executable(${EXEC_NAME} + ${TEST_SOURCES} + ${MOCK_SOURCES} + ${PLAYER_SOURCES}) +else() + get_filename_component(SEC_CLIENT_ROOT_ABS ${SEC_CLIENT_ROOT} ABSOLUTE) + message(WARNING "Secure Client headers not present in ${SEC_CLIENT_ROOT_ABS}, so skipping ${EXEC_NAME}.") + + add_executable(${EXEC_NAME} + ${TEST_SOURCES}) +endif() + + +set_target_properties(${EXEC_NAME} PROPERTIES FOLDER "utests") + + +if (CMAKE_XCODE_BUILD_SYSTEM) +# XCode schema target +xcode_define_schema(${EXEC_NAME}) +endif() + +if (COVERAGE_ENABLED) + include(CodeCoverage) + APPEND_COVERAGE_COMPILER_FLAGS() +endif() + +target_link_libraries(${EXEC_NAME} ${LIBCJSON_LINK_LIBRARIES} ${UUID_LINK_LIBRARIES} pthread ${GLIB_LINK_LIBRARIES} ${OS_LD_FLAGS} ${GMOCK_LINK_LIBRARIES} ${GTEST_LINK_LIBRARIES}) + +player_utest_run_add(${EXEC_NAME}) diff --git a/test/utests/tests/DrmSecureClient/DrmSessionTests.cpp b/test/utests/tests/DrmSecureClient/DrmSessionTests.cpp new file mode 100644 index 00000000..4188c79a --- /dev/null +++ b/test/utests/tests/DrmSecureClient/DrmSessionTests.cpp @@ -0,0 +1,152 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef USE_SECCLIENT +#include "aampDrmSessionFactory.h" +#include "DRMSessionManager.h" +#include "AampClearKeyHelper.h" +#include "open_cdm.h" + +#include "aampMocks.h" + +#include "Fakeopencdm.h" +#include "curlMocks.h" + +#include "DrmTestUtils.h" + +#include "MockOpenCdm.h" +#include "MockSecureClient.h" +#include "MockPrivateInstanceAAMP.h" +#endif // USE_SECCLIENT + +using ::testing::_; +using ::testing::DoAll; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::StrEq; + + +class AampDrmSessionTests : public ::testing::Test +{ +#ifdef USE_SECCLIENT +protected: + PrivateInstanceAAMP *mAamp = nullptr; + AampLogManager mLogging; + TestUtilDrm *mUtils = nullptr; + + // The URL AAMP uses to fetch the session token + const std::string mSessionTokenUrl = "http://localhost:50050/authService/getSessionToken"; + // A fixed session token response - any tests which require a session token can use this, + // since the manager is singleton and will only ever fetch it once. Test order is + // non-deterministic, so it's not guaranteed which test will actually trigger the fetch + const std::string mSessionTokenResponse = "{\"token\":\"SESSIONTOKEN\", \"status\":0}"; + + void SetUp() override + { + MockAampReset(); + MockCurlReset(); + MockOpenCdmReset(); + + g_mockopencdm = new NiceMock(); + g_mocksecclient = new NiceMock(); + g_mockPrivateInstanceAAMP = new NiceMock(); + mAamp = new PrivateInstanceAAMP(gpGlobalConfig); + mUtils = new TestUtilDrm(mAamp); + } + + void TearDown() override + { + delete mUtils; + mUtils = nullptr; + + delete mAamp; + mAamp = nullptr; + + delete g_mockPrivateInstanceAAMP; + g_mockPrivateInstanceAAMP = nullptr; + + delete g_mocksecclient; + g_mocksecclient = nullptr; + + delete g_mockopencdm; + g_mockopencdm = nullptr; + + MockAampReset(); + MockCurlReset(); + MockOpenCdmReset(); + } + +public: +#endif // USE_SECCLIENT +}; + +TEST_F(AampDrmSessionTests, TestDashPlayReadySessionSecClient) +{ +#ifdef USE_SECCLIENT + std::string prLicenseServerURL = "http://licenseserver.example/license"; + std::string expectedServiceHostUrl = "licenseserver.example"; + + // Setting a PlayReady license server URL in the global config. This + // should get used to request the license + gpGlobalConfig->SetConfigValue(AAMP_APPLICATION_SETTING, eAAMPConfig_PRLicenseServerUrl, + prLicenseServerURL); + + // Setting up Curl repsonse for the session token + mUtils->setupCurlPerformResponses({{mSessionTokenUrl, mSessionTokenResponse}}); + + mUtils->setupChallengeCallbacks(); + + // PSSH string which will get passed to the helper for parsing, so needs to be in valid format + const std::string psshStr = + "" + "" + "16bytebase64enckeydata==" + "policy" + "" + ""; + + std::string expectedKeyData = "TESTSECKEYDATA"; + size_t respLength = expectedKeyData.length(); + const char *respPtr = expectedKeyData.c_str(); + + // The license should be acquired using the secure client, rather than curl + EXPECT_CALL(*g_mocksecclient, + SecClient_AcquireLicense(StrEq(expectedServiceHostUrl.c_str()), _, _)) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(respPtr)), SetArgPointee<2>(respLength), + Return(0))); + + DrmMetaDataEventPtr event = mUtils->createDrmMetaDataEvent(); + AampDrmSession *drmSession = mUtils->createDashDrmSession(expectedKeyData, psshStr, event); + ASSERT_TRUE(drmSession != nullptr); + ASSERT_STREQ("com.microsoft.playready", drmSession->getKeySystem().c_str()); +#else + GTEST_SKIP() << "Skipping test due to Secure Client headers not present"; +#endif // USE_SECCLIENT +} diff --git a/test/utests/tests/DrmSecureClient/DrmTestsRun.cpp b/test/utests/tests/DrmSecureClient/DrmTestsRun.cpp new file mode 100644 index 00000000..2034179e --- /dev/null +++ b/test/utests/tests/DrmSecureClient/DrmTestsRun.cpp @@ -0,0 +1,26 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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 + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/utests/tests/DrmUrlTests/CMakeLists.txt b/test/utests/tests/DrmUrlTests/CMakeLists.txt new file mode 100755 index 00000000..94654f6a --- /dev/null +++ b/test/utests/tests/DrmUrlTests/CMakeLists.txt @@ -0,0 +1,72 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2024 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(GoogleTest) + +set(PLAYER_ROOT "../../../..") +set(UTESTS_ROOT "../..") +set(DRM_ROOT ${UTESTS_ROOT}/drm) +set(EXEC_NAME DrmUrlTests) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DREALTEKCE=1") + +include_directories(${PLAYER_ROOT} ${PLAYER_ROOT}/drm ${PLAYER_ROOT}/drm/helper ${PLAYER_ROOT}/subtitle ${PLAYER_ROOT}/middleware/subtitle ${PLAYER_ROOT}/downloader ${PLAYER_ROOT}/isobmff ${PLAYER_ROOT}/middleware/subtec/subtecparser ${PLAYER_ROOT}/middleware/playerjsonobject ${PLAYER_ROOT}/middleware/subtec/libsubtec ${PLAYER_ROOT}/middleware/externals/playersecmanager) +include_directories(${PLAYER_ROOT}/tsb/api) +include_directories(${PLAYER_ROOT}) +include_directories(${GTEST_INCLUDE_DIRS}) +include_directories(${GMOCK_INCLUDE_DIRS}) +include_directories(${GLIB_INCLUDE_DIRS}) +include_directories(${GSTREAMER_INCLUDE_DIRS}) +include_directories(${UTESTS_ROOT}/mocks) +include_directories(${DRM_ROOT}) +include_directories(${PLAYER_ROOT}/drm) +include_directories(${DRM_ROOT}/ocdm) +include_directories(${DRM_ROOT}/mocks) +include_directories(${PLAYER_ROOT}/vendor) +include_directories(${PLAYER_ROOT}/playerLogManager) +include_directories(${PLAYER_ROOT}/externals/playersecmanager) +include_directories(${PLAYER_ROOT}/../base16_64) + + +message(GSTREAMER_INCLUDE_DIRS=${GSTREAMER_INCLUDE_DIRS}) + +set(TEST_SOURCES DrmTestsRun.cpp + DrmSessionTests.cpp) + +set(PLAYER_SOURCES ${PLAYER_ROOT}/playerLogManager/PlayerLogManager.cpp) + +add_definitions(-DAAMP_SIMULATOR_BUILD) + +add_executable(${EXEC_NAME} + ${TEST_SOURCES} + ${PLAYER_SOURCES}) + +set_target_properties(${EXEC_NAME} PROPERTIES FOLDER "utests") + + +if (CMAKE_XCODE_BUILD_SYSTEM) + # XCode schema target + xcode_define_schema(${EXEC_NAME}) +endif() + +if (COVERAGE_ENABLED) + include(CodeCoverage) + APPEND_COVERAGE_COMPILER_FLAGS() +endif() + +target_link_libraries(${EXEC_NAME} fakes ${OS_LD_FLAGS} -pthread ${GLIB_LINK_LIBRARIES} ${OS_LD_FLAGS} ${LIBCJSON_LINK_LIBRARIES} ${GMOCK_LINK_LIBRARIES} ${GTEST_LINK_LIBRARIES}) + +player_utest_run_add(${EXEC_NAME}) diff --git a/test/utests/tests/DrmUrlTests/DrmSessionTests.cpp b/test/utests/tests/DrmUrlTests/DrmSessionTests.cpp new file mode 100644 index 00000000..a190bf2f --- /dev/null +++ b/test/utests/tests/DrmUrlTests/DrmSessionTests.cpp @@ -0,0 +1,211 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "DrmJsonObject.h" + + +/** + * @brief Get formatted URL of license server + * + * @param[in] url URL of license server + * @return formatted url for secclient license acquisition. + */ +std::string playerGetFormattedLicenseServerURL( const std::string &url) +{ + size_t startpos = 0; + size_t len = url.length(); + if( url.rfind( "https://",0)==0 ) + { + startpos = 8; + } + else if( url.rfind( "http://",0)==0 ) + { + startpos = 7; + } + if( startpos!=0 ) + { + size_t endpos = url.find('/', startpos); + if( endpos != std::string::npos ) + { + len = endpos - startpos; + } + } + return url.substr(startpos, len); +} + +class DrmSessionTests : public ::testing::Test { +protected: + + void SetUp() override { + + } + + void TearDown() override { + + } +}; + +TEST_F(DrmSessionTests, HandlesRandomString) { + std::string url = "6f4dssfg564"; + std::string expected = "6f4dssfg564"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesRandomString2) { + std::string url = "super/bad"; + std::string expected = "super/bad"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesHttpUrl) { + std::string url = "http://example.com/path/to/resource"; + std::string expected = "example.com"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesHttpsUrl) { + std::string url = "http://example.com/path/to/resource"; + std::string expected = "example.com"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesHttpsUrl2) { + std::string url = "https://example.com"; + std::string expected = "example.com"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesHttpsUrlWithWWW) { + std::string url = "www.drmexample.com/path/to/resource"; + std::string expected = "www.drmexample.com/path/to/resource"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesUrlWithNoScheme) { + std::string url = "drmexample.com/path/to/resource"; + std::string expected = "drmexample.com/path/to/resource"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesUrlWithTrailingSlash) { + std::string url = "https://example.com"; + std::string expected = "example.com"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesUrlWithMultipleSlashes) { + std::string url = "https://drmexample.com//path/to/resource"; + std::string expected = "drmexample.com"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesUrlWithoutPath) { + std::string url = "https://drmexample.com"; + std::string expected = "drmexample.com"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesUrlWithoutPathWithWWW) { + std::string url = "www.drmexample.com"; + std::string expected = "www.drmexample.com"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesUrlWithOnlyScheme) { + std::string url = "https://"; + std::string expected = ""; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesEmptyUrl) { + std::string url = ""; + std::string expected = ""; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesUrlWithPort) { + std::string url = "https://drmexample.com:8080"; + std::string expected = "drmexample.com:8080"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesUrlWithPortWithWWW) { + std::string url = "www.drmexample.com:8080"; + std::string expected = "www.drmexample.com:8080"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesUrlWithPortWithPath) { + std::string url = "https://drmexample.com:8080/path"; + std::string expected = "drmexample.com:8080"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesUrlWithPortWithPathWithWWW) { + std::string url = "www.drmexample.com:8080/path"; + std::string expected = "www.drmexample.com:8080/path"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesUrlWithQueryParameters) { + std::string url = "https://drmexample.com/path?query=param"; + std::string expected = "drmexample.com"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, HandlesUrlWithFragment) { + std::string url = "https://drmexample.com/path#fragment"; + std::string expected = "drmexample.com"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, UrlEncodingInDomain) { + std::string url = "https://drmexample.com%20with%20space"; + std::string expected = "drmexample.com%20with%20space"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; + +TEST_F(DrmSessionTests, UrlEncodingInPath) { + std::string url = "http://drmexample.com/path/to/%20resource"; + std::string expected = "drmexample.com"; + std::string result = playerGetFormattedLicenseServerURL(url); + EXPECT_EQ(result, expected); +}; diff --git a/test/utests/tests/DrmUrlTests/DrmTestsRun.cpp b/test/utests/tests/DrmUrlTests/DrmTestsRun.cpp new file mode 100644 index 00000000..2034179e --- /dev/null +++ b/test/utests/tests/DrmUrlTests/DrmTestsRun.cpp @@ -0,0 +1,26 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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 + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/utests/tests/GstHandlerControlTests/CMakeLists.txt b/test/utests/tests/GstHandlerControlTests/CMakeLists.txt new file mode 100644 index 00000000..4387bf1e --- /dev/null +++ b/test/utests/tests/GstHandlerControlTests/CMakeLists.txt @@ -0,0 +1,62 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2024 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(GoogleTest) + +set(PLAYER_ROOT "../../../../") +set(UTESTS_ROOT "../../") +set(EXEC_NAME GstHandlerControlTests) + +include_directories(${PLAYER_ROOT} ${PLAYER_ROOT}/subtitle) +include_directories(${PLAYER_ROOT}/subtec/libsubtec) +include_directories(${PLAYER_ROOT}/subtec/subtecparser) +include_directories(${PLAYER_ROOT}/playerjsonobject) +include_directories(${PLAYER_ROOT}/playerLogManager) + +include_directories(${GTEST_INCLUDE_DIRS}) +include_directories(${GMOCK_INCLUDE_DIRS}) +include_directories(${GLIB_INCLUDE_DIRS}) +include_directories(${GSTREAMER_INCLUDE_DIRS}) +include_directories(${LibXml2_INCLUDE_DIRS}) +include_directories(SYSTEM ${UTESTS_ROOT}/mocks) +include_directories(${LIBCJSON_INCLUDE_DIRS}) + + +set(TEST_SOURCES GstHandlerControlTests.cpp + GstHandlerControlPlayerTests.cpp) + +set(PLAYER_SOURCES ${PLAYER_ROOT}/GstHandlerControl.cpp ${PLAYER_ROOT}/playerLogManager/PlayerLogManager.cpp) + +add_executable(${EXEC_NAME} + ${TEST_SOURCES} + ${PLAYER_SOURCES}) + +set_target_properties(${EXEC_NAME} PROPERTIES FOLDER "utests") + +if (CMAKE_XCODE_BUILD_SYSTEM) + # XCode schema target + xcode_define_schema(${EXEC_NAME}) +endif() + +if (COVERAGE_ENABLED) + include(CodeCoverage) + APPEND_COVERAGE_COMPILER_FLAGS() +endif() + +target_link_libraries(${EXEC_NAME} fakes -pthread ${GLIB_LINK_LIBRARIES} ${OS_LD_FLAGS} ${GMOCK_LINK_LIBRARIES} ${GTEST_LINK_LIBRARIES}) + +player_utest_run_add(${EXEC_NAME}) diff --git a/test/utests/tests/GstHandlerControlTests/GstHandlerControlPlayerTests.cpp b/test/utests/tests/GstHandlerControlTests/GstHandlerControlPlayerTests.cpp new file mode 100644 index 00000000..f51285d1 --- /dev/null +++ b/test/utests/tests/GstHandlerControlTests/GstHandlerControlPlayerTests.cpp @@ -0,0 +1,26 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2022 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 + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/utests/tests/GstHandlerControlTests/GstHandlerControlTests.cpp b/test/utests/tests/GstHandlerControlTests/GstHandlerControlTests.cpp new file mode 100644 index 00000000..46d0548f --- /dev/null +++ b/test/utests/tests/GstHandlerControlTests/GstHandlerControlTests.cpp @@ -0,0 +1,195 @@ + +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2024 RDK Management +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include +#include "GstHandlerControl.h" + +class FunctionalTests : public ::testing::Test { +public: + GstHandlerControl* mControl; + void SetUp() override + { + mControl = new GstHandlerControl; + } + + void TearDown() override + { + delete mControl; + } +}; + +TEST_F(FunctionalTests, instancesRunning) +{ + ASSERT_EQ(0, mControl->instancesRunning()); + + std::vector helpers; + constexpr size_t MAX_INSTANCES = 10; + for(int i=1; i<=MAX_INSTANCES; i++) + { + helpers.push_back(mControl->getScopeHelper()); + ASSERT_EQ(i, mControl->instancesRunning()); + } + + while(helpers.size()) + { + helpers.pop_back(); + ASSERT_EQ(helpers.size(), mControl->instancesRunning()); + } +} + +TEST_F(FunctionalTests, returnStraightAway) +{ + ASSERT_FALSE(mControl->getScopeHelper().returnStraightAway()); + mControl->disable(); + ASSERT_TRUE(mControl->getScopeHelper().returnStraightAway()); + mControl->enable(); + ASSERT_FALSE(mControl->getScopeHelper().returnStraightAway()); + mControl->waitForDone(0, "test"); + ASSERT_TRUE(mControl->getScopeHelper().returnStraightAway()); + mControl->enable(); + ASSERT_FALSE(mControl->getScopeHelper().returnStraightAway()); +} + + +TEST_F(FunctionalTests, waitForDoneSingle) +{ + { + auto scopedHelper=mControl->getScopeHelper(); + ASSERT_FALSE(mControl->waitForDone(0, "test")); + } + + ASSERT_TRUE(mControl->waitForDone(0, "test")); +} + +TEST_F(FunctionalTests, waitForDoneMultiple) +{ + ASSERT_EQ(0, mControl->instancesRunning()); + ASSERT_TRUE(mControl->waitForDone(0, "test")); + + std::vector helpers; + constexpr size_t MAX_INSTANCES = 10; + for(int i=1; i<=MAX_INSTANCES; i++) + { + helpers.push_back(mControl->getScopeHelper()); + ASSERT_FALSE(mControl->waitForDone(0, "test")); + } + + while(helpers.size()) + { + ASSERT_FALSE(mControl->waitForDone(0, "test")); + helpers.pop_back(); + } + + ASSERT_TRUE(mControl->waitForDone(0, "test")); +} + +TEST_F(FunctionalTests, moveAssignToDefault) +{ + ASSERT_EQ(0, mControl->instancesRunning()); + { + GstHandlerControl::ScopeHelper helperA = mControl->getScopeHelper(); + ASSERT_EQ(1, mControl->instancesRunning()); + { + GstHandlerControl::ScopeHelper helperB; + ASSERT_EQ(1, mControl->instancesRunning()); + ASSERT_TRUE(helperB.returnStraightAway()); + ASSERT_FALSE(helperA.returnStraightAway()); + + helperB = std::move(helperA); + ASSERT_EQ(1, mControl->instancesRunning()); + ASSERT_TRUE(helperA.returnStraightAway()); + ASSERT_FALSE(helperB.returnStraightAway()); + } + } + + ASSERT_EQ(0, mControl->instancesRunning()); +} + +TEST_F(FunctionalTests, moveAssignOverwriteWithDefault) +{ + ASSERT_EQ(0, mControl->instancesRunning()); + + GstHandlerControl::ScopeHelper helperC = mControl->getScopeHelper(); + ASSERT_EQ(1, mControl->instancesRunning()); + + GstHandlerControl::ScopeHelper helperD; + ASSERT_EQ(1, mControl->instancesRunning()); + ASSERT_TRUE(helperD.returnStraightAway()); + ASSERT_FALSE(helperC.returnStraightAway()); + + helperC = std::move(helperD); + ASSERT_EQ(0, mControl->instancesRunning()); + ASSERT_TRUE(helperD.returnStraightAway()); + ASSERT_TRUE(helperC.returnStraightAway()); +} + +TEST_F(FunctionalTests, moveAssignOverwriteValidWithValid) +{ + ASSERT_EQ(0, mControl->instancesRunning()); + { + GstHandlerControl::ScopeHelper helperE = mControl->getScopeHelper(); + ASSERT_EQ(1, mControl->instancesRunning()); + ASSERT_FALSE(helperE.returnStraightAway()); + + + GstHandlerControl::ScopeHelper helperF = mControl->getScopeHelper(); + ASSERT_EQ(2, mControl->instancesRunning()); + ASSERT_FALSE(helperE.returnStraightAway()); + ASSERT_FALSE(helperF.returnStraightAway()); + + helperE = std::move(helperF); + ASSERT_EQ(1, mControl->instancesRunning()); + ASSERT_FALSE(helperE.returnStraightAway()); + ASSERT_TRUE(helperF.returnStraightAway()); + } + + ASSERT_EQ(0, mControl->instancesRunning()); +} + + +TEST_F(FunctionalTests, moveConstruct) +{ + ASSERT_EQ(0, mControl->instancesRunning()); + + GstHandlerControl::ScopeHelper helperA = mControl->getScopeHelper(); + ASSERT_EQ(1, mControl->instancesRunning()); + ASSERT_FALSE(helperA.returnStraightAway()); + + { + GstHandlerControl::ScopeHelper helperB{std::move(helperA)}; + ASSERT_EQ(1, mControl->instancesRunning()); + ASSERT_TRUE(helperA.returnStraightAway()); + ASSERT_FALSE(helperB.returnStraightAway()); + } + + ASSERT_EQ(0, mControl->instancesRunning()); + ASSERT_TRUE(helperA.returnStraightAway()); +} + +TEST_F(FunctionalTests, defaultConstruct) +{ + ASSERT_EQ(0, mControl->instancesRunning()); + + { + GstHandlerControl::ScopeHelper helper; + ASSERT_EQ(0, mControl->instancesRunning()); + } + + ASSERT_EQ(0, mControl->instancesRunning()); +} diff --git a/test/utests/tests/GstPlayer/CMakeLists.txt b/test/utests/tests/GstPlayer/CMakeLists.txt new file mode 100644 index 00000000..34c68d45 --- /dev/null +++ b/test/utests/tests/GstPlayer/CMakeLists.txt @@ -0,0 +1,74 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2024 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(GoogleTest) + +set(PLAYER_ROOT "../../../../") +set(UTESTS_ROOT "../../") +set(EXEC_NAME PlayerGstPlayer) + +include_directories(${PLAYER_ROOT}) +include_directories(${PLAYER_ROOT}/playerLogManager) +include_directories(${PLAYER_ROOT}/subtec/subtecparser) +include_directories(${PLAYER_ROOT}/subtec/libsubtec) +include_directories(${PLAYER_ROOT}/vendor) +include_directories(${UTESTS_ROOT}/fakes) +include_directories(${GTEST_INCLUDE_DIRS}) +include_directories(${GMOCK_INCLUDE_DIRS}) +include_directories(${GLIB_INCLUDE_DIRS}) +include_directories(${GSTREAMERBASE_INCLUDE_DIRS}) +include_directories(${GSTREAMER_INCLUDE_DIRS}) +include_directories(${LIBCJSON_INCLUDE_DIRS}) +include_directories(SYSTEM ${UTESTS_ROOT}/mocks) +include_directories(${UTESTS_ROOT}/mocks) +include_directories(${PLAYER_ROOT}/externals) + +message(GSTREAMER_INCLUDE_DIRS=${GSTREAMER_INCLUDE_DIRS}) + +set(TEST_SOURCES PauseOnPlaybackTests.cpp + FunctionalTests.cpp + GstPlayerTests.cpp + ) + +set(PLAYER_SOURCES ${PLAYER_ROOT}/InterfacePlayerRDK.cpp + ${PLAYER_ROOT}/playerLogManager/PlayerLogManager.cpp + ${PLAYER_ROOT}/externals/PlayerExternalsInterface.cpp + ${PLAYER_ROOT}/externals/PlayerExternalUtils.cpp) + +set(FAKE_SOURCES ${UTESTS_ROOT}/fakes/FakeGStreamer.cpp + ${UTESTS_ROOT}fakes/FakeGLib.cpp + ${UTESTS_ROOT}/fakes/FakeGstUtils.cpp) + +add_executable(${EXEC_NAME} + ${TEST_SOURCES} + ${PLAYER_SOURCES} + ${FAKE_SOURCES}) +set_target_properties(${EXEC_NAME} PROPERTIES FOLDER "utests") + +if (CMAKE_XCODE_BUILD_SYSTEM) + # XCode schema target + xcode_define_schema(${EXEC_NAME}) +endif() + +if (COVERAGE_ENABLED) + include(CodeCoverage) + APPEND_COVERAGE_COMPILER_FLAGS() +endif() + +target_link_libraries(${EXEC_NAME} fakes -lpthread ${GLIB_LINK_LIBRARIES} ${OS_LD_FLAGS} ${GMOCK_LINK_LIBRARIES} ${GTEST_LINK_LIBRARIES} ${GSTREAMERBASE_LINK_LIBRARIES} ${GSTREAMER_LINK_LIBRARIES}) + +player_utest_run_add(${EXEC_NAME}) diff --git a/test/utests/tests/GstPlayer/FunctionalTests.cpp b/test/utests/tests/GstPlayer/FunctionalTests.cpp new file mode 100644 index 00000000..887742f9 --- /dev/null +++ b/test/utests/tests/GstPlayer/FunctionalTests.cpp @@ -0,0 +1,626 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "InterfacePlayerRDK.h" +#include "InterfacePlayerPriv.h" +#include "GstUtils.h" +#include "MockGStreamer.h" +#include "MockGLib.h" +#include "MockGstHandlerControl.h" +#include "MockPlayerUtils.h" + +#define GST_NORMAL_PLAY_RATE 1 + +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::StrEq; +using ::testing::Eq; +using ::testing::_; +using ::testing::Address; +using ::testing::DoAll; +using ::testing::SetArgPointee; +using ::testing::NotNull; +using ::testing::SaveArgPointee; +using ::testing::SaveArg; +using ::testing::Pointer; +using ::testing::Matcher; + +class GstPlayerTests : public ::testing::Test +{ + +protected: + bool isPipelineSetup = false; + GstElement gst_element_pipeline = {.object = {.name = (gchar *)"Pipeline"}}; + GstBus bus = {}; + GstQuery query = {}; + InterfacePlayerRDK *mInterfaceGstPlayer; + + void SetUp() override + { + g_mockPlayerUtils = new MockPlayerUtils(); + g_mockGStreamer = new NiceMock(); + g_mockGLib = new MockGLib(); + g_mockGstHandlerControl= new MockGstHandlerControl(); + } + + void TearDown() override + { + delete g_mockGstHandlerControl; + g_mockGstHandlerControl= nullptr; + + delete g_mockGLib; + g_mockGLib = nullptr; + + delete g_mockGStreamer; + g_mockGStreamer = nullptr; + + delete g_mockPlayerUtils; + g_mockPlayerUtils = nullptr; + + } + +public: + typedef struct + { + GstStreamOutputFormat auxFormat; + bool bESChangeStatus; + bool forwardAudioToAux; + bool setReadyAfterPipelineCreation; + bool enableRectangleProperty; + bool usingWesteros; + bool usingRialto; + } Config_Params; + + static gboolean ProgressCallbackOnTimeout(gpointer user_data) + { + return FALSE; + } + + void ConstructAMPGstPlayer() + { + std::string debug_level{"test_level"}; + gboolean reset{TRUE}; + + mInterfaceGstPlayer = new InterfacePlayerRDK(); + + //init callback to avoid bad_function_call error + mInterfaceGstPlayer->TearDownCallback([this](bool status, int mediaType) { + if (status) { + }}); + mInterfaceGstPlayer->StopCallback([this](bool status) + { + printf("StopCallback status: %d\n", status); + }); + + mInterfaceGstPlayer->RegisterBusEvent([this](const BusEventData& event) { + printf("busMessageCallback called\n"); + }); + } + + void DestroyAMPGstPlayer() + { + if (isPipelineSetup) + { + EXPECT_CALL(*g_mockGStreamer, gst_object_unref(&gst_element_pipeline)) + .Times(1); + EXPECT_CALL(*g_mockGStreamer, gst_object_unref(&bus)) + .Times(1); + EXPECT_CALL(*g_mockGStreamer, gst_mini_object_unref(GST_MINI_OBJECT_CAST(&query))) + .Times(1); /* AKA gst_query_unref()*/ + } + + delete mInterfaceGstPlayer; + mInterfaceGstPlayer = nullptr; + } + + void SetupPipeline(Config_Params *setup) + { + GstElement gst_element_bin = {.object = {.name = (gchar *)"bin"}}; + GstElement gst_element_audsrvsink = {.object = {.name = (gchar *)"audosrv"}}; + GstElement westeros_video_sink = {.object = {.name = (gchar *)"westerossink0"}}; + GstElement rialto_video_sink = {.object = {.name = (gchar *)"rialtomsevideosink0"}}; + GstElement brcm_video_sink = {.object = {.name = (gchar *)"brcmvideosink0"}}; + GstElement audio_sink = {.object = {.name = (gchar *)"amlhalasink0"}}; + GstElement *p_video_sink = nullptr; + GstElement *p_audio_sink = &audio_sink; + GstPipeline *pipeline = GST_PIPELINE(&gst_element_pipeline); + + GstBusFunc bus_message_func = nullptr; + GstBusSyncHandler bus_sync_func = nullptr; + + isPipelineSetup = true; + if (setup->usingRialto) + { + p_video_sink = &rialto_video_sink; + } + else if (setup->usingWesteros) + { + p_video_sink = &westeros_video_sink; + } + else + { + p_video_sink = &brcm_video_sink; + } + + mInterfaceGstPlayer->m_gstConfigParam->useWesterosSink = setup->usingWesteros; + mInterfaceGstPlayer->m_gstConfigParam->useRialtoSink = setup->usingRialto; + mInterfaceGstPlayer->m_gstConfigParam->enableRectPropertyCfg = setup->enableRectangleProperty; + + // CreatePipeline() + + EXPECT_CALL(*g_mockGStreamer, gst_pipeline_new(StrEq("testPipeline"))) + .WillOnce(Return(&gst_element_pipeline)); + + EXPECT_CALL(*g_mockGStreamer, gst_pipeline_get_bus(pipeline)) + .WillOnce(Return(&bus)); + + // Save the bus_message function for later use + EXPECT_CALL(*g_mockGStreamer, gst_bus_add_watch(&bus, NotNull(), mInterfaceGstPlayer)) + .WillOnce(DoAll( + SaveArgPointee<1>(&bus_message_func), + Return(0))); + + // Save the bus_sync_handler function for later use + EXPECT_CALL(*g_mockGStreamer, gst_bus_set_sync_handler(&bus, NotNull(), mInterfaceGstPlayer, NULL)) + .WillOnce(SaveArgPointee<1>(&bus_sync_func)); + + EXPECT_CALL(*g_mockGStreamer, gst_query_new_position(GST_FORMAT_TIME)) + .WillOnce(Return(&query)); + // End CreatePipeline() + + if (setup->setReadyAfterPipelineCreation) + { + EXPECT_CALL(*g_mockGStreamer, gst_element_get_state(&gst_element_pipeline, _, _, _)) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_VOID_PENDING), + SetArgPointee<2>(GST_STATE_NULL), + Return(GST_STATE_CHANGE_SUCCESS))) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_READY), + SetArgPointee<2>(GST_STATE_READY), + Return(GST_STATE_CHANGE_SUCCESS))); + + EXPECT_CALL(*g_mockGStreamer, gst_element_set_state(&gst_element_pipeline, GST_STATE_READY)) + .WillOnce(Return(GST_STATE_CHANGE_SUCCESS)); + } + else + { + EXPECT_CALL(*g_mockGStreamer, gst_element_get_state(&gst_element_pipeline, _, _, _)) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_VOID_PENDING), + SetArgPointee<2>(GST_STATE_NULL), + Return(GST_STATE_CHANGE_SUCCESS))); + } + EXPECT_CALL(*g_mockGStreamer, gst_element_factory_make(_, NULL)) + .WillRepeatedly(Return(&gst_element_bin)); + if (setup->forwardAudioToAux) + { + EXPECT_CALL(*g_mockGStreamer, gst_element_factory_make(StrEq("audsrvsink"), NULL)) + .WillOnce(Return(&gst_element_audsrvsink)); + } + + if (setup->usingRialto) + { + EXPECT_CALL(*g_mockGStreamer, gst_element_factory_make(StrEq("rialtomsevideosink"), NULL)) + .WillRepeatedly(Return(p_video_sink)); + // IsGstreamerSubsEnabled fake impl returns false and hence EXPECT_CALL for subtitle pipeline is not required + } + else if (setup->usingWesteros) + { + EXPECT_CALL(*g_mockGStreamer, gst_element_factory_make(StrEq("westerossink"), NULL)) + .WillRepeatedly(Return(p_video_sink)); + } + else + { + EXPECT_CALL(*g_mockGStreamer, gst_element_factory_make(StrEq("brcmvideosink"), NULL)) + .WillRepeatedly(Return(p_video_sink)); + } + + EXPECT_CALL(*g_mockGStreamer, gst_bin_add(GST_BIN(pipeline), NotNull())) + .WillRepeatedly(Return(TRUE)); + + EXPECT_CALL(*g_mockGStreamer, gst_element_set_state(&gst_element_pipeline, GST_STATE_PLAYING)) + .WillOnce(Return(GST_STATE_CHANGE_SUCCESS)); + + mInterfaceGstPlayer->ConfigurePipeline(GST_FORMAT_VIDEO_ES_H264, + GST_FORMAT_AUDIO_ES_AAC, + setup->auxFormat, + GST_FORMAT_SUBTITLE_WEBVTT, + setup->bESChangeStatus, + setup->forwardAudioToAux, + setup->setReadyAfterPipelineCreation, + false, 0, GST_NORMAL_PLAY_RATE, "testPipeline", 0, false, "testManifest"); + + ASSERT_TRUE(bus_sync_func != nullptr); + ASSERT_TRUE(bus_message_func != nullptr); + + GstMessage sync_message = {.type = GST_MESSAGE_STATE_CHANGED, .src = GST_OBJECT(p_video_sink) }; + + EXPECT_CALL(*g_mockGstHandlerControl, isEnabled()) + .WillRepeatedly(Return(true)); + + EXPECT_CALL(*g_mockGStreamer, gst_message_parse_state_changed(Pointer(&sync_message),NotNull(),NotNull(),_)) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_READY), + SetArgPointee<2>(GST_STATE_PAUSED))); + + if (setup->enableRectangleProperty) + { + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("rectangle"), Matcher(_))).Times(1); + } + else + { + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("rectangle"), Matcher(_))).Times(0); + } + if (setup->usingRialto) + { + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("zoom-mode"), Matcher(_))).Times(0); + } + else + { + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("zoom-mode"), Matcher(GST_VIDEO_ZOOM_NONE))).Times(1); + } + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("show-video-window"), Matcher(true))).Times(1); + + EXPECT_CALL(*g_mockGStreamer, gst_object_replace(NotNull(),NotNull())) + .WillOnce(DoAll( + SetArgPointee<0>(GST_OBJECT(p_video_sink)), + Return(1))); + + // Call the bus_sync_handler function with video sink READY -> PAUSED + bus_sync_func(&bus, &sync_message, mInterfaceGstPlayer); + + sync_message = {.type = GST_MESSAGE_STATE_CHANGED, .src = GST_OBJECT(p_audio_sink) }; + + EXPECT_CALL(*g_mockGStreamer, gst_message_parse_state_changed(Pointer(&sync_message),NotNull(),NotNull(),_)) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_READY), + SetArgPointee<2>(GST_STATE_PAUSED))); + + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("volume"), Matcher(1.0))).Times(1); + + EXPECT_CALL(*g_mockGStreamer, gst_object_replace(NotNull(),NotNull())) + .WillOnce(DoAll( + SetArgPointee<0>(GST_OBJECT(p_audio_sink)), + Return(1))); + + // Call the bus_sync_handler function with audio sink READY -> PAUSED + bus_sync_func(&bus, &sync_message, mInterfaceGstPlayer); + + GstMessage bus_message = {.type = GST_MESSAGE_STATE_CHANGED, .src = GST_OBJECT(&gst_element_pipeline) }; + + EXPECT_CALL(*g_mockGStreamer, gst_message_parse_state_changed(Pointer(&bus_message),NotNull(),NotNull(),NotNull())) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_READY), + SetArgPointee<2>(GST_STATE_PAUSED), + SetArgPointee<3>(GST_STATE_NULL))); + + // Call the bus_message function + bus_message_func(&bus, &bus_message, mInterfaceGstPlayer); + } + +}; + +TEST_F(GstPlayerTests, Constructor) +{ + ConstructAMPGstPlayer(); + DestroyAMPGstPlayer(); +} + + +// typedef struct +// { +// GstStreamOutputFormat auxFormat; +// bool bESChangeStatus; +// bool forwardAudioToAux; +// bool setReadyAfterPipelineCreation; +// bool enableRectangleProperty; +// bool usingWesteros; +// bool usingRialto; +// } Config_Params; + +static GstPlayerTests::Config_Params tbl[] = { + {GST_FORMAT_INVALID, false, false, false, false, true, false }, + {GST_FORMAT_INVALID, false, false, false, false, true, true }, + {GST_FORMAT_INVALID, false, false, false, true, true, false }, + {GST_FORMAT_AUDIO_ES_AC3, true, true, true, false, true, false } }; + +// Parameter test class, for running same tests with different settings + +class GstPlayerTestsP : public GstPlayerTests, + public testing::WithParamInterface +{ +}; + +TEST_P(GstPlayerTestsP, Configure) +{ + int idx = GetParam(); + ASSERT_TRUE(idx < (sizeof(tbl) / sizeof(tbl[0]))); + GstPlayerTests::Config_Params *setup = &tbl[idx]; + + ConstructAMPGstPlayer(); + + SetupPipeline(setup); + + DestroyAMPGstPlayer(); +} + + +TEST_P(GstPlayerTestsP, SetAudioVolume) +{ + int idx = GetParam(); + ASSERT_TRUE(idx < (sizeof(tbl) / sizeof(tbl[0]))); + GstPlayerTests::Config_Params *setup = &tbl[idx]; + + // Setup + ConstructAMPGstPlayer(); + SetupPipeline(setup); + + // Code under test + + // Muted, and volume not set (note this is not the case for non-rialto AMLOGIC builds) + int volume = 0; + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("mute"), Matcher(true))).Times(1); + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("volume"), Matcher(_))).Times(0); + mInterfaceGstPlayer->SetAudioVolume(volume); + mInterfaceGstPlayer->SetVolumeOrMuteUnMute(); + + // Unmuted and volume set to 100.0 + volume = 100; + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("mute"), Matcher(false))).Times(1); + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("volume"), Matcher(volume / 100.0))).Times(1); + mInterfaceGstPlayer->SetAudioVolume(volume); + mInterfaceGstPlayer->SetVolumeOrMuteUnMute(); + + // No change to mute, and volume set to 50.0 + volume = 50; + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("mute"), Matcher(_))).Times(0); + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("volume"), Matcher(volume / 100.0))).Times(1); + mInterfaceGstPlayer->SetAudioVolume(volume); + mInterfaceGstPlayer->SetVolumeOrMuteUnMute(); + + //Tidy Up + DestroyAMPGstPlayer(); +} + +TEST_P(GstPlayerTestsP, SetVideoMute) +{ + // Setup + ConstructAMPGstPlayer(); + SetupPipeline(&tbl[0]); + + bool mute = true; + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("show-video-window"), Matcher(!mute))).Times(1); + mInterfaceGstPlayer->SetVideoMute(mute); + + mute = false; + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("show-video-window"), Matcher(!mute))).Times(1); + mInterfaceGstPlayer->SetVideoMute(mute); + + //Tidy Up + DestroyAMPGstPlayer(); +} + +INSTANTIATE_TEST_SUITE_P(GstPlayer,GstPlayerTestsP, testing::Values(0,1,2,3)); + +TEST_F(GstPlayerTests, TimerAdd) +{ + // Setup + gpointer user_data = nullptr; + int repeatTimeout = 100; + guint taskId = 0; + GstElement dummyelement; + mInterfaceGstPlayer = new InterfacePlayerRDK(); + ConstructAMPGstPlayer(); + + // Expectations + + // Code under test - Callback Pointer = Null, user_data = Null + EXPECT_CALL(*g_mockGLib, g_timeout_add(_, _, _)) .Times(0); + mInterfaceGstPlayer->TimerAdd(nullptr, repeatTimeout, taskId, user_data, "TimerAdd"); + EXPECT_EQ(0,taskId); + + // Code under test - user_data = Null + EXPECT_CALL(*g_mockGLib, g_timeout_add(_, _, _)) .Times(0); + mInterfaceGstPlayer->TimerAdd(ProgressCallbackOnTimeout, repeatTimeout, taskId, user_data, "TimerAdd"); + EXPECT_EQ(0,taskId); + + user_data = &dummyelement; + taskId = 1; + + // Code under test - taskId = 1 timer already added + EXPECT_CALL(*g_mockGLib, g_timeout_add(_, _, _)) .Times(0); + mInterfaceGstPlayer->TimerAdd(ProgressCallbackOnTimeout, repeatTimeout, taskId, user_data, "TimerAdd"); + EXPECT_EQ(1,taskId); + + taskId = 0; + + // Code under test - Success Path + EXPECT_CALL(*g_mockGLib, g_timeout_add(_, _, _)) .WillOnce(Return(1)); + mInterfaceGstPlayer->TimerAdd(ProgressCallbackOnTimeout, repeatTimeout, taskId, user_data, "TimerAdd"); + EXPECT_EQ(1,taskId); + + //Tidy Up + DestroyAMPGstPlayer(); +} + + +TEST_F(GstPlayerTests, TimerRemove) +{ + // Setup + guint taskId = 0; + + ConstructAMPGstPlayer(); + + // Expectations + + mInterfaceGstPlayer = new InterfacePlayerRDK(); + EXPECT_CALL(*g_mockGLib, g_source_remove(_)) .Times(0); + + // Code under test - taskId = 0 timer not added to be removed + mInterfaceGstPlayer->TimerRemove(taskId, "TimerRemove"); + EXPECT_EQ(0,taskId); + + taskId = 1; + + // Code under test - Success Path + EXPECT_CALL(*g_mockGLib, g_source_remove(_)) .WillOnce(Return(TRUE)); + mInterfaceGstPlayer->TimerRemove(taskId, "TimerRemove"); + EXPECT_EQ(0,taskId); +} + + +TEST_F(GstPlayerTests, SetAudioVolume_NoSink) +{ + // Setup + ConstructAMPGstPlayer(); + + // Code under test + + // No sink, so no call to set volume or mute expected + int volume = 0; + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("mute"), Matcher(_))).Times(0); + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("volume"), Matcher(_))).Times(0); + mInterfaceGstPlayer->SetAudioVolume(volume); + + volume = 100; + mInterfaceGstPlayer->SetAudioVolume(volume); + + volume = 50; + mInterfaceGstPlayer->SetAudioVolume(volume); + + //Tidy Up + DestroyAMPGstPlayer(); +} + +TEST_F(GstPlayerTests, SetVideoMute_NoSink) +{ + // Setup + ConstructAMPGstPlayer(); + + bool mute = true; + EXPECT_CALL(*g_mockGLib, g_object_set(NotNull(), StrEq("show-video-window"), Matcher(_))).Times(0); + mInterfaceGstPlayer->SetVideoMute(mute); + + //Tidy Up + DestroyAMPGstPlayer(); +} + +extern void MonitorAV( InterfacePlayerRDK *_this ); + +TEST_F(GstPlayerTests, MonitorAV ) +{ + const int avpos[][2] = + { + { 280, 243}, + { 540, 503}, + { 780, 743},// ok + { 1040, 1003},// ok + { 1280, 1243},// ok + { 1540, 1503},// ok + { 1780, 1743},// ok + { 2040, 2003},// ok + { 2280, 2263},// ok + { 2540, 2503},// ok + { 2800, 2763},// ok + { 3040, 3003},// ok + { 3300, 3263},// ok + { 3540, 3503},// ok + { 3940, 5653},// video-only + { 5140, 5893},// video-only + { 6180, 6153},// ok + { 6420, 6393},// ok + { 6680, 6653},// ok + { 6920, 6893},// ok + { 7180, 7153},// ok + { 7420, 7413},// ok + { 7680, 7653},// ok + { 7940, 7913},// ok + { 8180, 8153},// ok + { 8440, 8413},// ok + { 8680, 8653},// ok + { 8940, 8913},// ok + { 9180, 9153},// ok + { 9440, 9413},// ok + // av gap + {11560,11520},// ok + {11820,11780},// ok + {12060,12020},// ok + {12320,12280},// ok + {12560,12520},// ok + {12820,12780},// ok + {13080,13040},// ok + {13320,13280},// ok + {13580,13540},// ok + {13820,13780},// ok + {14080,14040},// ok + {14320,14280},// ok + {14580,14540},// ok + {14820,14780},// ok + {15080,15040},// ok + {15320,15280},// ok + {15380,15540},// audio only + {15380,15780},// audio only + {15380,16040},// audio only + {15380,16280},// audio only + {15380,16540},// audio only + {15380,16780},// audio only + {15380,17040},// audio only + {17320,17300},// ok + {17580,17540},// ok + {17840,17800},// ok + {18080,18040},// ok + {18340,18300},// ok + {18580,18540},// ok + {18840,18800},// ok + {19080,19040},// ok + {19220,19321},// bad avsync + {19220,19321},// stalled av + {19220,19321},// stalled av + {19220,19321},// stalled av + {19220,19321},// stalled av + {19220,19321},// stalled av + }; + ConstructAMPGstPlayer(); + SetupPipeline(&tbl[0]); + + EXPECT_CALL(*g_mockGStreamer, gst_element_get_state(&gst_element_pipeline, _, _, _)) + .WillRepeatedly(DoAll( + SetArgPointee<1>(GST_STATE_PLAYING), + SetArgPointee<2>(GST_STATE_PLAYING), + Return(GST_STATE_CHANGE_SUCCESS))); + for( int idx=0; idx(G_GINT64_CONSTANT(1000000)*avpos[idx][eGST_MEDIATYPE_VIDEO]), + Return(TRUE))) + .WillOnce(DoAll( + SetArgPointee<2>(G_GINT64_CONSTANT(1000000)*avpos[idx][eGST_MEDIATYPE_AUDIO]), + Return(TRUE))); + MonitorAV(mInterfaceGstPlayer); + } + DestroyAMPGstPlayer(); +} + + diff --git a/test/utests/tests/GstPlayer/GstPlayerTests.cpp b/test/utests/tests/GstPlayer/GstPlayerTests.cpp new file mode 100644 index 00000000..2034179e --- /dev/null +++ b/test/utests/tests/GstPlayer/GstPlayerTests.cpp @@ -0,0 +1,26 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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 + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/utests/tests/GstPlayer/PauseOnPlaybackTests.cpp b/test/utests/tests/GstPlayer/PauseOnPlaybackTests.cpp new file mode 100644 index 00000000..f0f4d24c --- /dev/null +++ b/test/utests/tests/GstPlayer/PauseOnPlaybackTests.cpp @@ -0,0 +1,387 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "MockGStreamer.h" +#include "MockGLib.h" +#include "MockGstHandlerControl.h" +#include "MockPlayerScheduler.h" +#include "InterfacePlayerRDK.h" +#include "InterfacePlayerPriv.h" +#include "GstUtils.h" + +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::StrEq; +using ::testing::Eq; +using ::testing::_; +using ::testing::Address; +using ::testing::DoAll; +using ::testing::SetArgPointee; +using ::testing::NotNull; +using ::testing::SaveArgPointee; +using ::testing::SaveArg; +using ::testing::Pointer; + +class PauseOnPlaybackTests : public ::testing::Test +{ + +protected: + InterfacePlayerRDK *mInterfaceGstPlayer; + int cbResponse = 0; + void SetUp() override + { + g_mockGStreamer = new NiceMock();//new MockGStreamer(); + g_mockGLib = new NiceMock(); + g_mockGstHandlerControl = new MockGstHandlerControl(); + g_mockPlayerScheduler = new MockPlayerScheduler(); + mInterfaceGstPlayer = new InterfacePlayerRDK(); + + //init callback to avoid bad_function_call error + mInterfaceGstPlayer->TearDownCallback([this](bool status, int mediaType) { + if (status) { + cbResponse = 5; + }}); + mInterfaceGstPlayer->StopCallback([this](bool status) + { + printf("StopCallback status: %d\n", status); + }); + + /*mInterfaceGstPlayer->busMessageCallback([this](BusEventData data) + { + printf("busMessageCallback called\n"); + }); + */ + mInterfaceGstPlayer->RegisterBusEvent([this](const BusEventData& event) { + printf("busMessageCallback called\n"); + }); + } + + void TearDown() override + { + delete g_mockGLib; + g_mockGLib = nullptr; + + delete g_mockGStreamer; + g_mockGStreamer = nullptr; + + delete mInterfaceGstPlayer; + mInterfaceGstPlayer = nullptr; + + delete g_mockGstHandlerControl; + g_mockGstHandlerControl = nullptr; + + delete g_mockPlayerScheduler; + g_mockPlayerScheduler = nullptr; + } + +public: +}; + +// Test API SetPauseOnStartPlayback +// No external checks available to check anything occurs, however checked in +// test EnteredPausedSteHandler_ConfigurePauseOnPlayback that property is enabled +TEST_F(PauseOnPlaybackTests, SetPauseOnStartPlayback) +{ + mInterfaceGstPlayer->SetPauseOnStartPlayback(true); + mInterfaceGstPlayer->SetPauseOnStartPlayback(false); +} + +// Test configuration of pipeline with PauseOnPlayback enabled +// Checks that the state set is GST_STATE_PAUSED +TEST_F(PauseOnPlaybackTests, EnteredPausedSteHandler_ConfigurePauseOnPlayback) +{ + GstElement gst_element_pipeline = {.object = {.name = (gchar *)"Pipeline"}}; + GstElement gst_element_bin = {.object = {.name = (gchar *)"bin"}}; + GstBus bus = {}; + GstPipeline *pipeline = GST_PIPELINE(&gst_element_pipeline); + + // CreatePipeline() + EXPECT_CALL(*g_mockGStreamer, gst_pipeline_new(StrEq("testPipeline"))) + .WillOnce(Return(&gst_element_pipeline)); + + EXPECT_CALL(*g_mockGStreamer, gst_pipeline_get_bus(pipeline)) + .WillOnce(Return(&bus)); + + // End CreatePipeline() + + EXPECT_CALL(*g_mockGStreamer, gst_element_get_state(&gst_element_pipeline, _, _, _)) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_VOID_PENDING), + SetArgPointee<2>(GST_STATE_NULL), + Return(GST_STATE_CHANGE_SUCCESS))); + + EXPECT_CALL(*g_mockGStreamer, gst_element_factory_make(StrEq("playbin"), NULL)) + .WillRepeatedly(Return(&gst_element_bin)); + + EXPECT_CALL(*g_mockGStreamer, gst_bin_add(GST_BIN(pipeline), NotNull())) + .WillRepeatedly(Return(TRUE)); + + EXPECT_CALL(*g_mockGStreamer, gst_element_set_state(&gst_element_pipeline, GST_STATE_PAUSED)) + .WillOnce(Return(GST_STATE_CHANGE_SUCCESS)); + + // Enable PauseOnPlayback + mInterfaceGstPlayer->SetPauseOnStartPlayback(true); + + mInterfaceGstPlayer->ConfigurePipeline(GST_FORMAT_VIDEO_ES_H264, GST_FORMAT_AUDIO_ES_AAC, GST_FORMAT_INVALID, GST_FORMAT_SUBTITLE_WEBVTT, false, false, false, false, 0, GST_NORMAL_PLAY_RATE, "testPipeline", 0, false, "testManifest"); +} + +// Test configuration of pipeline with PauseOnPlayback not enabled +// Checks that the state set is GST_STATE_PLAYING +TEST_F(PauseOnPlaybackTests, EnteredPausedSteHandler_ConfigureNormalPlayback) +{ + GstElement gst_element_pipeline = {.object = {.name = (gchar *)"Pipeline"}}; + GstElement gst_element_bin = {.object = {.name = (gchar *)"bin"}}; + GstBus bus = {}; + GstPipeline *pipeline = GST_PIPELINE(&gst_element_pipeline); + + // CreatePipeline() + EXPECT_CALL(*g_mockGStreamer, gst_pipeline_new(StrEq("testPipeline"))) + .WillOnce(Return(&gst_element_pipeline)); + + EXPECT_CALL(*g_mockGStreamer, gst_pipeline_get_bus(pipeline)) + .WillOnce(Return(&bus)); + // End CreatePipeline() + + EXPECT_CALL(*g_mockGStreamer, gst_element_get_state(&gst_element_pipeline, _, _, _)) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_VOID_PENDING), + SetArgPointee<2>(GST_STATE_NULL), + Return(GST_STATE_CHANGE_SUCCESS))); + + EXPECT_CALL(*g_mockGStreamer, gst_element_factory_make(StrEq("playbin"), NULL)) + .WillRepeatedly(Return(&gst_element_bin)); + + EXPECT_CALL(*g_mockGStreamer, gst_bin_add(GST_BIN(pipeline), NotNull())) + .WillRepeatedly(Return(TRUE)); + + EXPECT_CALL(*g_mockGStreamer, gst_element_set_state(&gst_element_pipeline, GST_STATE_PLAYING)) + .WillOnce(Return(GST_STATE_CHANGE_SUCCESS)); + + mInterfaceGstPlayer->ConfigurePipeline(GST_FORMAT_VIDEO_ES_H264, GST_FORMAT_AUDIO_ES_AAC, GST_FORMAT_INVALID, GST_FORMAT_SUBTITLE_WEBVTT, false, false, false, false, 0, GST_NORMAL_PLAY_RATE, "testPipeline", 0, false, "testManifest"); +} + +// Test bus_message callback when PauseOnPlayback has been enabled, and sink +// has the property frame-step-on-preroll +// Due to g_object_set being a variadic function it is not possible/simple to mock, +// and therefore confirm that the property is set. However it is checked that +// step event is sent. +// The task FirstFrameCallback is not exected as this would be triggered by the +// "first-video-frame-callback" callback from gstreamer when the frame is displayed +TEST_F(PauseOnPlaybackTests, bus_messsage_FrameStepPropertyAvailable) +{ + GstElement gst_element_pipeline = {.object = {.name = (gchar *)"Pipeline"}}; + GstElement gst_element_video_sink = {.object = {.name = (gchar *)"brcmvideosink0"}}; + GstElement gst_element_bin = {.object = {.name = (gchar *)"bin"}}; + GstBus bus = {}; + GstPipeline *pipeline = GST_PIPELINE(&gst_element_pipeline); + GstBusFunc bus_message_func = nullptr; + GstBusSyncHandler bus_sync_func = nullptr; + + // Expectations + // CreatePipeline() + EXPECT_CALL(*g_mockGStreamer, gst_pipeline_new(StrEq("testPipeline"))) + .WillOnce(Return(&gst_element_pipeline)); + + EXPECT_CALL(*g_mockGStreamer, gst_pipeline_get_bus(pipeline)) + .WillOnce(Return(&bus)); + + // Save the bus_message function for later use + EXPECT_CALL(*g_mockGStreamer, gst_bus_add_watch(&bus, NotNull(), mInterfaceGstPlayer)) + .WillOnce(DoAll( + SaveArgPointee<1>(&bus_message_func), + Return(0))); + + // Save the bus_sync_handler function for later use + EXPECT_CALL(*g_mockGStreamer, gst_bus_set_sync_handler(&bus, NotNull(), mInterfaceGstPlayer, NULL)) + .WillOnce(SaveArgPointee<1>(&bus_sync_func)); + // End CreatePipeline() + + EXPECT_CALL(*g_mockGStreamer, gst_element_get_state(&gst_element_pipeline, _, _, _)) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_VOID_PENDING), + SetArgPointee<2>(GST_STATE_NULL), + Return(GST_STATE_CHANGE_SUCCESS))); + + EXPECT_CALL(*g_mockGStreamer, gst_element_factory_make(StrEq("playbin"), NULL)) + .WillRepeatedly(Return(&gst_element_bin)); + + EXPECT_CALL(*g_mockGStreamer, gst_bin_add(GST_BIN(pipeline), NotNull())) + .WillRepeatedly(Return(TRUE)); + + EXPECT_CALL(*g_mockGStreamer, gst_element_set_state(&gst_element_pipeline, GST_STATE_PAUSED)) + .WillOnce(Return(GST_STATE_CHANGE_SUCCESS)); + + mInterfaceGstPlayer->SetPauseOnStartPlayback(true); + + mInterfaceGstPlayer->ConfigurePipeline(GST_FORMAT_VIDEO_ES_H264, GST_FORMAT_AUDIO_ES_AAC, GST_FORMAT_INVALID, GST_FORMAT_SUBTITLE_WEBVTT, false, false, false, false, 0, GST_NORMAL_PLAY_RATE, "testPipeline", 0, false, "testManifest"); + + ASSERT_TRUE(bus_sync_func != nullptr); + ASSERT_TRUE(bus_message_func != nullptr); + + GstMessage sync_message = {.type = GST_MESSAGE_STATE_CHANGED, .src = GST_OBJECT(&gst_element_video_sink) }; + + EXPECT_CALL(*g_mockGstHandlerControl, isEnabled()) + .WillRepeatedly(Return(true)); + + EXPECT_CALL(*g_mockGStreamer, gst_message_parse_state_changed(Pointer(&sync_message),NotNull(),NotNull(),_)) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_READY), + SetArgPointee<2>(GST_STATE_PAUSED))); + + EXPECT_CALL(*g_mockGStreamer, gst_object_replace(NotNull(),NotNull())) + .WillOnce(DoAll( + SetArgPointee<0>(GST_OBJECT(&gst_element_video_sink)), + Return(1))); + + // Call the bus_sync_handler function + bus_sync_func(&bus, &sync_message, mInterfaceGstPlayer); + + GstMessage pipeline_message = {.type = GST_MESSAGE_STATE_CHANGED, .src = GST_OBJECT(&gst_element_pipeline) }; + + EXPECT_CALL(*g_mockGStreamer, gst_message_parse_state_changed(Pointer(&pipeline_message),NotNull(),NotNull(),NotNull())) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_READY), + SetArgPointee<2>(GST_STATE_PAUSED), + SetArgPointee<3>(GST_STATE_NULL))); + + GParamSpec spec = {}; + // Property available + EXPECT_CALL(*g_mockGLib, g_object_class_find_property(_,StrEq("frame-step-on-preroll"))) + .WillOnce(Return(&spec)); + + // No simple solution to mock variadic functions, so cannot check calls to g_object_set + + EXPECT_CALL(*g_mockGStreamer, gst_event_new_step(GST_FORMAT_BUFFERS, 1, 1.0, FALSE, FALSE)) + .WillOnce(Return(nullptr)); + + EXPECT_CALL(*g_mockGStreamer, gst_element_send_event(_,_)) + .WillOnce(Return(1)); + + // Call the bus_message function + bus_message_func(&bus, &pipeline_message, mInterfaceGstPlayer); +} + +// Test bus_message callback when PauseOnPlayback has been enabled, and sink +// doesn't have the property frame-step-on-preroll +// As the frame-step-on-preroll is not available, the test confirms that +// the task FirstFrameCallback is called instead upon reaching PAUSED state. +TEST_F(PauseOnPlaybackTests, bus_message_FrameStepPropertyNotAvailable) +{ + GstElement gst_element_pipeline = {.object = {.name = (gchar *)"Pipeline"}}; + GstElement gst_element_video_sink = {.object = {.name = (gchar *)"brcmvideosink0"}}; + GstElement gst_element_bin = {.object = {.name = (gchar *)"bin"}}; + GstBus bus = {}; + GstPipeline *pipeline = GST_PIPELINE(&gst_element_pipeline); + + GstBusFunc bus_message_func = nullptr; + GstBusSyncHandler bus_sync_func = nullptr; + + // Expectations + // CreatePipeline() + EXPECT_CALL(*g_mockGStreamer, gst_pipeline_new(StrEq("testPipeline"))) + .WillOnce(Return(&gst_element_pipeline)); + + EXPECT_CALL(*g_mockGStreamer, gst_pipeline_get_bus(pipeline)) + .WillOnce(Return(&bus)); + + // Save the bus_message function for later use + EXPECT_CALL(*g_mockGStreamer, gst_bus_add_watch(&bus, NotNull(), mInterfaceGstPlayer)) + .WillOnce(DoAll( + SaveArgPointee<1>(&bus_message_func), + Return(0))); + + // Save the bus_sync_handler function for later use + EXPECT_CALL(*g_mockGStreamer, gst_bus_set_sync_handler(&bus, NotNull(), mInterfaceGstPlayer, NULL)) + .WillOnce(SaveArgPointee<1>(&bus_sync_func)); + + // End CreatePipeline() + + EXPECT_CALL(*g_mockGStreamer, gst_element_get_state(&gst_element_pipeline, _, _, _)) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_VOID_PENDING), + SetArgPointee<2>(GST_STATE_NULL), + Return(GST_STATE_CHANGE_SUCCESS))); + + EXPECT_CALL(*g_mockGStreamer, gst_element_factory_make(StrEq("playbin"), NULL)) + .WillRepeatedly(Return(&gst_element_bin)); + + EXPECT_CALL(*g_mockGStreamer, gst_bin_add(GST_BIN(pipeline), NotNull())) + .WillRepeatedly(Return(TRUE)); + + EXPECT_CALL(*g_mockGStreamer, gst_element_set_state(&gst_element_pipeline, GST_STATE_PAUSED)) + .WillOnce(Return(GST_STATE_CHANGE_SUCCESS)); + + mInterfaceGstPlayer->SetPauseOnStartPlayback(true); + + mInterfaceGstPlayer->ConfigurePipeline(GST_FORMAT_VIDEO_ES_H264, GST_FORMAT_AUDIO_ES_AAC, GST_FORMAT_INVALID, GST_FORMAT_SUBTITLE_WEBVTT, false, false, false, false, 0, GST_NORMAL_PLAY_RATE, "testPipeline", 0, false, "testManifest"); + + ASSERT_TRUE(bus_sync_func != nullptr); + ASSERT_TRUE(bus_message_func != nullptr); + + GstMessage sync_message = {.type = GST_MESSAGE_STATE_CHANGED, .src = GST_OBJECT(&gst_element_video_sink) }; + + EXPECT_CALL(*g_mockGstHandlerControl, isEnabled()) + .WillRepeatedly(Return(true)); + + EXPECT_CALL(*g_mockGStreamer, gst_message_parse_state_changed(Pointer(&sync_message),NotNull(),NotNull(),_)) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_READY), + SetArgPointee<2>(GST_STATE_PAUSED))); + + EXPECT_CALL(*g_mockGStreamer, gst_object_replace(NotNull(),NotNull())) + .WillOnce(DoAll( + SetArgPointee<0>(GST_OBJECT(&gst_element_video_sink)), + Return(1))); + + // Call the bus_sync_handler function + bus_sync_func(&bus, &sync_message, mInterfaceGstPlayer); + + GstMessage pipeline_message = {.type = GST_MESSAGE_STATE_CHANGED, .src = GST_OBJECT(&gst_element_pipeline) }; + + EXPECT_CALL(*g_mockGStreamer, gst_message_parse_state_changed(Pointer(&pipeline_message),NotNull(),NotNull(),NotNull())) + .WillOnce(DoAll( + SetArgPointee<1>(GST_STATE_READY), + SetArgPointee<2>(GST_STATE_PAUSED), + SetArgPointee<3>(GST_STATE_NULL))); + + // Property not available + //EXPECT_CALL(*g_mockGLib, g_object_class_find_property(_,StrEq("frame-step-on-preroll"))) + // .WillOnce(Return(nullptr)); + + // No simple solution to mock variadic functions, so cannot check calls to g_object_set + + // EXPECT_CALL(*g_mockGStreamer, gst_event_new_step(_,_,_,_,_)) + // .Times(0); + + //EXPECT_CALL(*g_mockGStreamer, gst_element_send_event(_,_)) + // .Times(0); + + //Note: Need to address once bus_message is migrated to interfacePlayer + //EXPECT_CALL(*g_mockPlayerScheduler, ScheduleTask(PlayerAsyncTaskObj((void *)mAAMPGstPlayer)))//ScheduleTask(_))//,mAAMPGstPlayer,_)) + // .WillRepeatedly(Return(1)); + + //EXPECT_CALL(*g_mockPlayerScheduler, ScheduleTask(PlayerAsyncTaskObj(_,mAAMPGstPlayer,StrEq("FirstFrameCallback")))) + // .WillOnce(Return(1)); + + // Call the bus_message function + bus_message_func(&bus, &pipeline_message, mInterfaceGstPlayer); +} diff --git a/test/utests/tests/GstUtilsTests/CMakeLists.txt b/test/utests/tests/GstUtilsTests/CMakeLists.txt new file mode 100644 index 00000000..76dcd0e5 --- /dev/null +++ b/test/utests/tests/GstUtilsTests/CMakeLists.txt @@ -0,0 +1,65 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2023 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(GoogleTest) + +set(PLAYER_ROOT "../../../../") +set(UTESTS_ROOT "../../") +set(EXEC_NAME GstUtilsTests) + +include_directories(${PLAYER_ROOT}) +include_directories(${PLAYER_ROOT}/vendor) +include_directories(${GTEST_INCLUDE_DIRS}) +include_directories(${GMOCK_INCLUDE_DIRS}) +include_directories(${GLIB_INCLUDE_DIRS}) +include_directories(${GSTREAMER_INCLUDE_DIRS}) +include_directories(${LibXml2_INCLUDE_DIRS}) +include_directories(SYSTEM ${UTESTS_ROOT}/mocks) +include_directories(${LIBCJSON_INCLUDE_DIRS}) +include_directories(${PLAYER_ROOT}/test/utests/mocks) +include_directories(${PLAYER_ROOT}/playerLogManager) +include_directories(${PLAYER_ROOT}/subtec/subtecparser) +include_directories(${PLAYER_ROOT}/subtec/libsubtec) +include_directories(${PLAYER_ROOT}/externals) +include_directories(${UTEST_ROOT}/fakes) + +set(TEST_SOURCES GstUtilsTests.cpp + GstUtilsPlayerTests.cpp) + +set(PLAYER_SOURCES + ${PLAYER_ROOT}/GstUtils.cpp + ${PLAYER_ROOT}/playerLogManager/PlayerLogManager.cpp ) + +add_executable(${EXEC_NAME} + ${TEST_SOURCES} + ${PLAYER_SOURCES}) + +if (CMAKE_XCODE_BUILD_SYSTEM) + # XCode schema target + xcode_define_schema(${EXEC_NAME}) +endif() + +if (COVERAGE_ENABLED) + include(CodeCoverage) + APPEND_COVERAGE_COMPILER_FLAGS() +endif() + +target_link_libraries(${EXEC_NAME} fakes -lpthread ${GLIB_LINK_LIBRARIES} ${OS_LD_FLAGS} ${GMOCK_LINK_LIBRARIES} ${GTEST_LINK_LIBRARIES}) + +set_target_properties(${EXEC_NAME} PROPERTIES FOLDER "utests") + +player_utest_run_add(${EXEC_NAME}) diff --git a/test/utests/tests/GstUtilsTests/GstUtilsPlayerTests.cpp b/test/utests/tests/GstUtilsTests/GstUtilsPlayerTests.cpp new file mode 100644 index 00000000..adccbc7e --- /dev/null +++ b/test/utests/tests/GstUtilsTests/GstUtilsPlayerTests.cpp @@ -0,0 +1,26 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2023 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 + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/utests/tests/GstUtilsTests/GstUtilsTests.cpp b/test/utests/tests/GstUtilsTests/GstUtilsTests.cpp new file mode 100644 index 00000000..399bb36b --- /dev/null +++ b/test/utests/tests/GstUtilsTests/GstUtilsTests.cpp @@ -0,0 +1,86 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2023 RDK Management +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include + +#include "GstUtils.h" +#include "MockGStreamer.h" + +using ::testing::_; +using ::testing::Return; +using ::testing::StrEq; + +class GstUtilsTests : public ::testing::Test +{ +protected: + + void SetUp() override + { + g_mockGStreamer = new MockGStreamer(); + } + + void TearDown() override + { + delete g_mockGStreamer; + g_mockGStreamer = nullptr; + } + +public: + +}; + +TEST_F(GstUtilsTests, esMP3test) +{ + GstCaps dummycaps; + GstCaps *caps{&dummycaps}; + EXPECT_CALL(*g_mockGStreamer,gst_caps_new_simple(StrEq("audio/mpeg"),StrEq("mpegversion"), G_TYPE_INT, 1, NULL)).WillOnce(Return(caps)); + + EXPECT_TRUE(GetCaps(GST_FORMAT_AUDIO_ES_MP3)==caps); +} + +TEST_F(GstUtilsTests, GstCapsFormatsTest) +{ + GstCaps dummycapslist; + GstCaps *caps{&dummycapslist}; + GstStreamOutputFormat GstCapsFormats[16] = { + GST_FORMAT_INVALID, /**< Invalid format */ + GST_FORMAT_MPEGTS, /**< MPEG Transport Stream */ + GST_FORMAT_ISO_BMFF, /**< ISO Base Media File format */ + GST_FORMAT_AUDIO_ES_MP3, /**< MP3 Audio Elementary Stream */ + GST_FORMAT_AUDIO_ES_AAC, /**< AAC Audio Elementary Stream */ + GST_FORMAT_AUDIO_ES_AC3, /**< AC3 Audio Elementary Stream */ + GST_FORMAT_AUDIO_ES_EC3, /**< Dolby Digital Plus Elementary Stream */ + GST_FORMAT_AUDIO_ES_ATMOS, /**< ATMOS Audio stream */ + GST_FORMAT_AUDIO_ES_AC4, /**< AC4 Dolby Audio stream */ + GST_FORMAT_VIDEO_ES_H264, /**< MPEG-4 Video Elementary Stream */ + GST_FORMAT_VIDEO_ES_HEVC, /**< HEVC video elementary stream */ + GST_FORMAT_VIDEO_ES_MPEG2, /**< MPEG-2 Video Elementary Stream */ + GST_FORMAT_SUBTITLE_WEBVTT, /**< WebVTT subtitle Stream */ + GST_FORMAT_SUBTITLE_TTML, /**< WebVTT subtitle Stream */ + GST_FORMAT_SUBTITLE_MP4, /**< Generic MP4 stream */ + GST_FORMAT_UNKNOWN /**< Unknown Format */ + }; + + for(int i=0;i<16;i++){ + GetCaps(GstCapsFormats[i]); + ASSERT_FALSE(GetCaps(GstCapsFormats[i])); + } +} diff --git a/test/utests/tests/OCDMSessionAdapter/CMakeLists.txt b/test/utests/tests/OCDMSessionAdapter/CMakeLists.txt new file mode 100644 index 00000000..110e4fa8 --- /dev/null +++ b/test/utests/tests/OCDMSessionAdapter/CMakeLists.txt @@ -0,0 +1,85 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2024 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(GoogleTest) + +set(PLAYER_ROOT "../../../../") +set(UTESTS_ROOT "../../") +set(EXEC_NAME OCDMSessionAdapterTests) + +include_directories(${PLAYER_ROOT} ${PLAYER_ROOT}/drm ${PLAYER_ROOT}/drm/helper ${PLAYER_ROOT} ${PLAYER_ROOT}/middleware/drm/ocdm ${PLAYER_ROOT}/drm/ ${PLAYER_ROOT}/subtitle ${PLAYER_ROOT}/subtitle ${PLAYER_ROOT}/downloader ${PLAYER_ROOT}/isobmff ${PLAYER_ROOT}/subtec/subtecparser ${PLAYER_ROOT}/subtec/playerjsonobject ${PLAYER_ROOT}/subtec/libsubtec ${PLAYER_ROOT}/externals/playersecmanager) +include_directories(${PLAYER_ROOT}/tsb/api) +include_directories("fakes/.") + +if(CMAKE_SYSTEM_NAME STREQUAL Linux) + include_directories(${PLAYER_ROOT}/Linux/include) +endif(CMAKE_SYSTEM_NAME STREQUAL Linux) + + +include_directories(${GTEST_INCLUDE_DIRS}) +include_directories(${GMOCK_INCLUDE_DIRS}) +include_directories(${GLIB_INCLUDE_DIRS}) +include_directories(${GSTREAMER_INCLUDE_DIRS}) +include_directories(SYSTEM ${UTESTS_ROOT}/mocks) +include_directories(${UTESTS_ROOT}/ocdm) +include_directories(${PLAYER_ROOT}/drm) +include_directories(${PLAYER_ROOT}/drm/ocdm) +include_directories(${PLAYER_ROOT}/drm/helper) +include_directories(${PLAYER_ROOT}/externals) +include_directories(${PLAYER_ROOT}/playerLogManager) +include_directories(${PLAYER_ROOT}/externals/playersecmanager) +include_directories(${PLAYER_ROOT}/baseConversion) + +set(TEST_SOURCES FunctionalTests.cpp + OCDMSessionAdapterTests.cpp) + +set(PLAYER_SOURCES ${PLAYER_ROOT}/drm/ocdm/opencdmsessionadapter.cpp + ${PLAYER_ROOT}/drm/helper/DrmHelper.cpp + ${PLAYER_ROOT}/drm/DrmSession.cpp + ${PLAYER_ROOT}/drm/DrmUtils.cpp + ${PLAYER_ROOT}/externals/PlayerExternalsInterface.cpp + ${PLAYER_ROOT}/externals/PlayerExternalUtils.cpp + ${PLAYER_ROOT}/playerLogManager/PlayerLogManager.cpp + ${PLAYER_ROOT}/ProcessHandler.cpp + ${PLAYER_ROOT}/PlayerUtils.cpp + ${PLAYER_ROOT}/baseConversion/_base64.cpp) + +add_definitions(-DUSE_THUNDER_OCDM_API_0_2) +add_definitions(-DUSE_OPENCDM_ADAPTER) + +add_executable(${EXEC_NAME} + ${TEST_SOURCES} + ${PLAYER_SOURCES}) +set_target_properties(${EXEC_NAME} PROPERTIES FOLDER "utests") + +if (CMAKE_XCODE_BUILD_SYSTEM) + # XCode schema target + xcode_define_schema(${EXEC_NAME}) +endif() + +if (COVERAGE_ENABLED) + include(CodeCoverage) + APPEND_COVERAGE_COMPILER_FLAGS() + #include("${PROJECT_SOURCE_DIR}/cmake_exclude_file.list") + SETUP_TARGET_FOR_COVERAGE_LCOV(NAME ${EXEC_NAME}_coverage + EXECUTABLE ${EXEC_NAME} + DEPENDENCIES ${EXEC_NAME}) +endif() + +target_link_libraries(${EXEC_NAME} fakes -lpthread ${OS_LD_FLAGS} ${GMOCK_LINK_LIBRARIES} ${GTEST_LINK_LIBRARIES}) + +player_utest_run_add(${EXEC_NAME}) diff --git a/test/utests/tests/OCDMSessionAdapter/FunctionalTests.cpp b/test/utests/tests/OCDMSessionAdapter/FunctionalTests.cpp new file mode 100644 index 00000000..54230357 --- /dev/null +++ b/test/utests/tests/OCDMSessionAdapter/FunctionalTests.cpp @@ -0,0 +1,88 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "opencdmsessionadapter.h" +#include "MockDrmHelper.h" +#include "MockOpenCdm.h" +#include +#include "_base64.h" +#include "PlayerUtils.h" + +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::ReturnRef; +using ::testing::_; + +std::shared_ptr drmHelper; + +// For comparing memory buffers such as C-style arrays +MATCHER_P2(MemBufEq, buffer, elementCount, "") +{ + return std::memcmp(arg, buffer, elementCount * sizeof(buffer[0])) == 0; +} + +class OCDMSessionAdapterTests : public ::testing::Test +{ + +protected: + OCDMSessionAdapter *m_ocdmsessionadapter = nullptr; + struct OpenCDMSystem *ocdmSystem = (OpenCDMSystem *)0x1234; + std::string systemId = "com.microsoft.playready"; + + void SetUp() override + { + drmHelper = std::make_shared(); + g_mockopencdm = new NiceMock(); + + EXPECT_CALL(*drmHelper, ocdmSystemId()).WillOnce(ReturnRef(systemId)); + EXPECT_CALL(*g_mockopencdm, opencdm_create_system(MemBufEq(systemId.c_str(), systemId.length() + 1))).WillOnce(Return(ocdmSystem)); + + m_ocdmsessionadapter = new OCDMSessionAdapter(drmHelper, nullptr); + } + + void TearDown() override + { + delete m_ocdmsessionadapter; + m_ocdmsessionadapter = nullptr; + + delete g_mockopencdm; + g_mockopencdm = nullptr; + + drmHelper = nullptr; + } + +public: +}; + +TEST_F(OCDMSessionAdapterTests, generateDRMSession) +{ + uint8_t initData[] = {0, 1, 2, 3}; + uint8_t initDataLen = sizeof(initData); + uint32_t f_cbInitData = 99; + std::string customData = "Custom Data"; + const char *initDataType = "cenc"; + uint8_t initDataTypeLen = strlen(initDataType); + + ((*g_mockopencdm).gmock_opencdm_construct_session(ocdmSystem, LicenseType::Temporary, MemBufEq(initDataType, initDataTypeLen), MemBufEq(initData, initDataLen), f_cbInitData, MemBufEq(customData.c_str(), customData.length()), customData.length(),_,_,_))(::testing::internal::GetWithoutMatchers(), nullptr) .InternalExpectedAt("/home/rekha/RDK/latest/l1_Final/aamp/middleware/test/utests/tests/OCDMSessionAdapter/FunctionalTests.cpp", 91, "*g_mockopencdm", "opencdm_construct_session(ocdmSystem, LicenseType::Temporary, MemBufEq(initDataType, initDataTypeLen), MemBufEq(initData, initDataLen), f_cbInitData, MemBufEq(customData.c_str(), customData.length()), customData.length(),_,_,_)").WillOnce(Return(ERROR_NONE)); + + m_ocdmsessionadapter->generateDRMSession(initData, f_cbInitData, customData); +} diff --git a/test/utests/tests/OCDMSessionAdapter/OCDMSessionAdapterTests.cpp b/test/utests/tests/OCDMSessionAdapter/OCDMSessionAdapterTests.cpp new file mode 100644 index 00000000..2034179e --- /dev/null +++ b/test/utests/tests/OCDMSessionAdapter/OCDMSessionAdapterTests.cpp @@ -0,0 +1,26 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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 + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/utests/tests/OCDMSessionAdapter/fakes/config.h b/test/utests/tests/OCDMSessionAdapter/fakes/config.h new file mode 100644 index 00000000..bdb47a66 --- /dev/null +++ b/test/utests/tests/OCDMSessionAdapter/fakes/config.h @@ -0,0 +1 @@ +// Empty header file to satisfy config.h inclusion from AAMP diff --git a/test/utests/tests/OcdmBasicSessionAdapterTests/CMakeLists.txt b/test/utests/tests/OcdmBasicSessionAdapterTests/CMakeLists.txt new file mode 100644 index 00000000..b91feef3 --- /dev/null +++ b/test/utests/tests/OcdmBasicSessionAdapterTests/CMakeLists.txt @@ -0,0 +1,85 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2024 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(GoogleTest) + +set(PLAYER_ROOT "../../../../") +set(UTESTS_ROOT "../../") +set(EXEC_NAME PlayerOcdmBasicSessionAdapterTests) + +include_directories(${PLAYER_ROOT} ${PLAYER_ROOT}/drm ${PLAYER_ROOT}/middleware/drm/helper ${PLAYER_ROOT}/middleware ${PLAYER_ROOT}/middleware/drm/ocdm ${PLAYER_ROOT}/middleware/drm/ ${PLAYER_ROOT}/subtitle ${PLAYER_ROOT}/middleware/subtitle ${PLAYER_ROOT}/downloader ${PLAYER_ROOT}/isobmff ${PLAYER_ROOT}/middleware/subtec/subtecparser ${PLAYER_ROOT}/middleware/subtec/playerjsonobject ${PLAYER_ROOT}/middleware/subtec/libsubtec ${PLAYER_ROOT}/middleware/externals/playersecmanager) +include_directories(${PLAYER_ROOT}/tsb/api) + +if(CMAKE_SYSTEM_NAME STREQUAL Linux) + include_directories(${PLAYER_ROOT}/Linux/include) +endif(CMAKE_SYSTEM_NAME STREQUAL Linux) + +include_directories(${GTEST_INCLUDE_DIRS}) +include_directories(${GMOCK_INCLUDE_DIRS}) +include_directories(${GLIB_INCLUDE_DIRS}) +include_directories(${GSTREAMER_INCLUDE_DIRS}) +include_directories(SYSTEM ${UTESTS_ROOT}/mocks) +include_directories(${UTESTS_ROOT}/ocdm) +include_directories(${UTESTS_ROOT}/mocks) +include_directories(${PLAYER_ROOT}/externals) +include_directories(${PLAYER_ROOT}/drm/ocdm) +include_directories(${PLAYER_ROOT}/externals/playersecmanager) +include_directories(${PLAYER_ROOT}/drm/helper) +include_directories(${PLAYER_ROOT}/playerLogManager) +include_directories(${PLAYER_ROOT}/baseConversion) + +set(TEST_SOURCES FunctionalTests.cpp + OcdmBasicSessionAdapterTests.cpp) + +set(PLAYER_SOURCES ${PLAYER_ROOT}/drm/ocdm/OcdmBasicSessionAdapter.cpp + ${PLAYER_ROOT}/drm/helper/DrmHelper.cpp + ${PLAYER_ROOT}/drm/DrmSession.cpp + ${PLAYER_ROOT}/playerLogManager/PlayerLogManager.cpp + ${PLAYER_ROOT}/ProcessHandler.cpp + ${PLAYER_ROOT}/PlayerUtils.cpp + ${PLAYER_ROOT}/baseConversion/_base64.cpp) + + +#[[class OCDMBasicSessionAdapter inherits from class OCDMSessionAdapter, +which inherits from the abstract class DrmSession. +Since the implementation of DrmSession is fairly simple, the real code is compiled. +However, OCDMSessionAdapter has a more complex implementation, so a fake has been written for this class.]] + +add_executable(${EXEC_NAME} + ${TEST_SOURCES} + ${PLAYER_SOURCES}) +set_target_properties(${EXEC_NAME} PROPERTIES FOLDER "utests") + +if (CMAKE_XCODE_BUILD_SYSTEM) + # XCode schema target + xcode_define_schema(${EXEC_NAME}) +endif() + + + +if (COVERAGE_ENABLED) + include(CodeCoverage) + APPEND_COVERAGE_COMPILER_FLAGS() + #include("${PROJECT_SOURCE_DIR}/cmake_exclude_file.list") + SETUP_TARGET_FOR_COVERAGE_LCOV(NAME ${EXEC_NAME}_coverage + EXECUTABLE ${EXEC_NAME} + DEPENDENCIES ${EXEC_NAME}) +endif() + +target_link_libraries(${EXEC_NAME} fakes -lpthread ${OS_LD_FLAGS} ${GMOCK_LINK_LIBRARIES} ${GTEST_LINK_LIBRARIES}) + +player_utest_run_add(${EXEC_NAME}) diff --git a/test/utests/tests/OcdmBasicSessionAdapterTests/FunctionalTests.cpp b/test/utests/tests/OcdmBasicSessionAdapterTests/FunctionalTests.cpp new file mode 100644 index 00000000..505bfe78 --- /dev/null +++ b/test/utests/tests/OcdmBasicSessionAdapterTests/FunctionalTests.cpp @@ -0,0 +1,243 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "OcdmBasicSessionAdapter.h" +#include "MockOpenCdmSessionAdapter.h" +#include "MockDrmHelper.h" +#include "MockOpenCdm.h" +#include "MockDrmMemorySystem.h" +#include + + +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::_; +using ::testing::SetArgReferee; +using ::testing::DoAll; + + +// For comparing memory buffers such as C-style arrays +MATCHER_P2(MemBufEq, buffer, elementCount, "") +{ + return std::memcmp(arg, buffer, elementCount * sizeof(buffer[0])) == 0; +} + +std::shared_ptr drmHelper; +DrmInfo drminfo; +MockDrmMemorySystem *g_mockMemorySystem; + +class OcdmBasicSessionAdapterTests : public ::testing::Test +{ + +protected: + OCDMBasicSessionAdapter *m_ocdmbasicsessionadapter = nullptr; + + void SetUp() override + { + drmHelper = std::make_shared(); + g_mockopencdm = new NiceMock(); + m_ocdmbasicsessionadapter = new OCDMBasicSessionAdapter(drmHelper,nullptr); + g_mockOpenCdmSessionAdapter = new NiceMock(); + g_mockMemorySystem = new NiceMock(); + } + + void TearDown() override + { + delete m_ocdmbasicsessionadapter; + m_ocdmbasicsessionadapter = nullptr; + + delete g_mockOpenCdmSessionAdapter; + g_mockOpenCdmSessionAdapter = nullptr; + + delete g_mockopencdm; + g_mockopencdm = nullptr; + + drmHelper = nullptr; + + delete g_mockMemorySystem; + g_mockMemorySystem = nullptr; + } + +public: +}; + +TEST_F(OcdmBasicSessionAdapterTests, DecryptHDCPComplianceFailure) +{ + int ret_value; + EXPECT_CALL(*g_mockOpenCdmSessionAdapter, verifyOutputProtection()).WillOnce(Return(false)); + EXPECT_CALL(*g_mockopencdm, opencdm_session_decrypt(_,_,_,_,_,_,_,_,_,_)).Times(0); + + ret_value = m_ocdmbasicsessionadapter->decrypt(nullptr, 0x0, nullptr, + 0, nullptr); + + EXPECT_EQ(ret_value,HDCP_COMPLIANCE_CHECK_FAILURE); +} + +TEST_F(OcdmBasicSessionAdapterTests, DecryptWithNullMemorySystem) +{ + int ret_value; + const uint8_t *f_pbIV = nullptr; + uint32_t f_cbIV = 0; + const uint8_t payloadData[] = {1,2,3}; + uint32_t payloadDataSize = sizeof(payloadData); + EncryptionScheme encScheme = AesCtr_Cenc; + uint32_t initWithLast15 = 0; + + EXPECT_CALL(*g_mockOpenCdmSessionAdapter, verifyOutputProtection()).WillOnce(Return(true)); + EXPECT_CALL(*drmHelper, getMemorySystem()).WillRepeatedly(Return(nullptr)); + EXPECT_CALL(*g_mockopencdm, + opencdm_session_decrypt(_, + MemBufEq(payloadData, payloadDataSize), + payloadDataSize, + encScheme, + _, + f_pbIV, + f_cbIV, + MemBufEq(g_mockKeyId.data(), g_mockKeyId.size()), + g_mockKeyId.size(), + initWithLast15)).WillOnce(Return(ERROR_NONE)); + ret_value = m_ocdmbasicsessionadapter->decrypt(f_pbIV, f_cbIV, payloadData, + payloadDataSize, nullptr); + + EXPECT_EQ(ret_value,0); +} + +TEST_F(OcdmBasicSessionAdapterTests, DecryptWithValidMemorySystem) +{ + int ret_value; + const uint8_t f_pbIV[] = {12}; + uint32_t f_cbIV = 2; + const uint8_t payloadData[] = {1,2,3}; + uint32_t payloadDataSize = sizeof(payloadData); + EncryptionScheme encScheme = AesCtr_Cenc; + uint32_t initWithLast15 = 0; + std::vector vdata {250, 3}; + uint32_t sizeToSend = vdata.size(); + uint8_t *dataToSend = vdata.data(); + + EXPECT_CALL(*g_mockOpenCdmSessionAdapter, verifyOutputProtection()).WillOnce(Return(true)); + EXPECT_CALL(*drmHelper, getMemorySystem()).WillRepeatedly(Return(g_mockMemorySystem)); + EXPECT_CALL(*g_mockMemorySystem, encode(payloadData,payloadDataSize,_)).WillOnce(DoAll(SetArgReferee<2>(vdata), Return(true))); + EXPECT_CALL(*g_mockopencdm, + opencdm_session_decrypt(_, + MemBufEq(dataToSend, sizeToSend), + sizeToSend, + encScheme, + _, + f_pbIV, + f_cbIV, + MemBufEq(g_mockKeyId.data(), g_mockKeyId.size()), + g_mockKeyId.size(), + initWithLast15)).WillOnce(Return(ERROR_NONE)); + EXPECT_CALL(*g_mockMemorySystem, decode(MemBufEq(dataToSend, sizeToSend), sizeToSend,const_cast(payloadData), payloadDataSize)).WillOnce(Return(true)); + ret_value = m_ocdmbasicsessionadapter->decrypt(f_pbIV, f_cbIV, payloadData, + payloadDataSize, nullptr); + EXPECT_EQ(ret_value,0); +} + +TEST_F(OcdmBasicSessionAdapterTests, DecryptWithValidMemorySystemEncodeFail) +{ + int ret_value; + const uint8_t f_pbIV[] = {12}; + uint32_t f_cbIV = 2; + const uint8_t payloadData[] = {1,2,3}; + uint32_t payloadDataSize = sizeof(payloadData); + EncryptionScheme encScheme = AesCtr_Cenc; + uint32_t initWithLast15 = 0; + std::vector vdata {250, 3}; + uint32_t sizeToSend = vdata.size(); + uint8_t *dataToSend = vdata.data(); + + EXPECT_CALL(*g_mockOpenCdmSessionAdapter, verifyOutputProtection()).WillOnce(Return(true)); + EXPECT_CALL(*drmHelper, getMemorySystem()).WillRepeatedly(Return(g_mockMemorySystem)); + EXPECT_CALL(*g_mockMemorySystem, encode(payloadData,payloadDataSize,_)).WillOnce(DoAll(SetArgReferee<2>(vdata), Return(false))); + EXPECT_CALL(*g_mockopencdm, opencdm_session_decrypt(_,_,_,_,_,_,_,_,_,_)).Times(0); + EXPECT_CALL(*g_mockMemorySystem, decode(_,_,_,_)).Times(0); + ret_value = m_ocdmbasicsessionadapter->decrypt(f_pbIV, f_cbIV, payloadData, + payloadDataSize, nullptr); + EXPECT_EQ(ret_value,-1); +} + +TEST_F(OcdmBasicSessionAdapterTests, DecryptWithValidMemorySystemDecodeFail) +{ + int ret_value; + const uint8_t f_pbIV[] = {12}; + uint32_t f_cbIV = 2; + const uint8_t payloadData[] = {1,2,3}; + uint32_t payloadDataSize = sizeof(payloadData); + EncryptionScheme encScheme = AesCtr_Cenc; + uint32_t initWithLast15 = 0; + std::vector vdata {250, 3}; + uint32_t sizeToSend = vdata.size(); + uint8_t *dataToSend = vdata.data(); + + EXPECT_CALL(*g_mockOpenCdmSessionAdapter, verifyOutputProtection()).WillOnce(Return(true)); + EXPECT_CALL(*drmHelper, getMemorySystem()).WillRepeatedly(Return(g_mockMemorySystem)); + EXPECT_CALL(*g_mockMemorySystem, encode(payloadData,payloadDataSize,_)).WillOnce(DoAll(SetArgReferee<2>(vdata), Return(true))); + EXPECT_CALL(*g_mockopencdm, + opencdm_session_decrypt(_, + MemBufEq(dataToSend, sizeToSend), + sizeToSend, + encScheme, + _, + f_pbIV, + f_cbIV, + MemBufEq(g_mockKeyId.data(), g_mockKeyId.size()), + g_mockKeyId.size(), + initWithLast15)).WillOnce(Return(ERROR_NONE)); + EXPECT_CALL(*g_mockMemorySystem, decode(MemBufEq(dataToSend, sizeToSend), sizeToSend,const_cast(payloadData), payloadDataSize)).WillOnce(Return(false)); + ret_value = m_ocdmbasicsessionadapter->decrypt(f_pbIV, f_cbIV, payloadData, payloadDataSize, nullptr); + + EXPECT_EQ(ret_value,-1); +} + +TEST_F(OcdmBasicSessionAdapterTests, DecryptFail) +{ + int ret_value; + const uint8_t f_pbIV[] = {12}; + uint32_t f_cbIV = 2; + const uint8_t payloadData[] = {1,2,3}; + uint32_t payloadDataSize = sizeof(payloadData); + EncryptionScheme encScheme = AesCtr_Cenc; + uint32_t initWithLast15 = 0; + std::vector vdata {250, 3}; + uint32_t sizeToSend = vdata.size(); + uint8_t *dataToSend = vdata.data(); + + EXPECT_CALL(*g_mockOpenCdmSessionAdapter, verifyOutputProtection()).WillOnce(Return(true)); + EXPECT_CALL(*drmHelper, getMemorySystem()).WillRepeatedly(Return(g_mockMemorySystem)); + EXPECT_CALL(*g_mockMemorySystem, encode(payloadData,payloadDataSize,_)).WillOnce(DoAll(SetArgReferee<2>(vdata), Return(true))); + EXPECT_CALL(*g_mockopencdm, + opencdm_session_decrypt(_, + MemBufEq(dataToSend, sizeToSend), + sizeToSend, + encScheme, + _, + f_pbIV, + f_cbIV, + MemBufEq(g_mockKeyId.data(), g_mockKeyId.size()), + g_mockKeyId.size(), + initWithLast15)).WillOnce(Return(ERROR_UNKNOWN)); + EXPECT_CALL(*g_mockMemorySystem, terminateEarly()); + ret_value = m_ocdmbasicsessionadapter->decrypt(f_pbIV, f_cbIV, payloadData, payloadDataSize, nullptr); + EXPECT_EQ(ret_value,ERROR_UNKNOWN); +} diff --git a/test/utests/tests/OcdmBasicSessionAdapterTests/OcdmBasicSessionAdapterTests.cpp b/test/utests/tests/OcdmBasicSessionAdapterTests/OcdmBasicSessionAdapterTests.cpp new file mode 100644 index 00000000..2034179e --- /dev/null +++ b/test/utests/tests/OcdmBasicSessionAdapterTests/OcdmBasicSessionAdapterTests.cpp @@ -0,0 +1,26 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2024 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 + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/utests/tests/TextStyleAttributes/CMakeLists.txt b/test/utests/tests/TextStyleAttributes/CMakeLists.txt new file mode 100644 index 00000000..fea8ff2a --- /dev/null +++ b/test/utests/tests/TextStyleAttributes/CMakeLists.txt @@ -0,0 +1,53 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2022 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. + +set(PLAYER_ROOT "../../../../") +set(UTESTS_ROOT "../../") +set(EXEC_NAME TextStyleAttributes) + +include_directories(${PLAYER_ROOT}) +include_directories(${PLAYER_ROOT}/subtitle) +include_directories(${PLAYER_ROOT}/subtec/libsubtec) +include_directories(${PLAYER_ROOT}/subtec/subtecparser) +include_directories(${PLAYER_ROOT}/playerjsonobject) +include_directories(${PLAYER_ROOT}/playerLogManager) +include_directories(${GTEST_INCLUDE_DIRS}) +include_directories(${GMOCK_INCLUDE_DIRS}) +include_directories(${GLIB_INCLUDE_DIRS}) +include_directories(${GSTREAMER_INCLUDE_DIRS}) +include_directories(SYSTEM ${UTESTS_ROOT}/mocks) +include_directories(${LIBCJSON_INCLUDE_DIRS}) + + +set(TEST_SOURCES GetTextStyleAttributesTests.cpp + TextStyleAttributesTests.cpp) + +set(PLAYER_SOURCES ${PLAYER_ROOT}/playerLogManager/PlayerLogManager.cpp + ${PLAYER_ROOT}/subtec/subtecparser/TextStyleAttributes.cpp) + +add_executable(${EXEC_NAME} + ${TEST_SOURCES} + ${PLAYER_SOURCES}) +set_target_properties(${EXEC_NAME} PROPERTIES FOLDER "utests") +if (CMAKE_XCODE_BUILD_SYSTEM) + include(CodeCoverage) + APPEND_COVERAGE_COMPILER_FLAGS() +endif() + +target_link_libraries(${EXEC_NAME} fakes ${GLIB_LINK_LIBRARIES} ${OS_LD_FLAGS} ${GMOCK_LINK_LIBRARIES} ${GTEST_LINK_LIBRARIES} -lpthread) + +player_utest_run_add(${EXEC_NAME}) diff --git a/test/utests/tests/TextStyleAttributes/GetTextStyleAttributesTests.cpp b/test/utests/tests/TextStyleAttributes/GetTextStyleAttributesTests.cpp new file mode 100644 index 00000000..9bac7ed9 --- /dev/null +++ b/test/utests/tests/TextStyleAttributes/GetTextStyleAttributesTests.cpp @@ -0,0 +1,2838 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2024 RDK Management +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include "PlayerLogManager.h" +#include "MockPlayerJsonObject.h" +#include "TextStyleAttributes.h" + +using ::testing::_; +using ::testing::Return; +using ::testing::SetArgReferee; +using ::testing::StrictMock; +using ::testing::An; +using ::testing::DoAll; + +class GetTextStyleAttributesTests : public ::testing::Test +{ +protected: + + std::unique_ptr mAttributes{}; + + void SetUp() override + { + mAttributes = std::unique_ptr(new TextStyleAttributes()); + + g_mockPlayerJsonObject = std::make_shared>(); + } + + void TearDown() override + { + mAttributes = nullptr; + + g_mockPlayerJsonObject = nullptr; + } +}; + +ACTION(ThrowJsonException) +{ + throw PlayerJsonParseException(); +} + +/* + Test the getAttributes function supplying it with empty Json string + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, EmptyJsonOptionsString) +{ + std::string options{}; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_EQ(-1, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes function when PlayerJsonObject throws exception + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, JsonExceptionThrown) +{ + std::string options = "{\"fontSize\":\"32.4px\"}"; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(ThrowJsonException()); + EXPECT_EQ(-1, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes function when PlayerJsonObject unsuccessfully retrieves value + A wrong key in the Json object (as set in options) is used to test the function. + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, JsonValueNotReturned) +{ + std::string options = "{\"fontSize\":\"32.4px\"}"; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes function supplying it with Right Key but invalid corresponding value. + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, FontSizeRightKeyInvalidValueJsonOptionsString) +{ + std::string penSizeValue = "32.4px"; + std::string options = "{\"penSize\":\"" + penSizeValue + "\"}"; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())) + .WillOnce(DoAll(SetArgReferee<1>(penSizeValue), Return(true))); + + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes with font size small, penSizevalue expressed in lower case + This will also test the output expected from the getFontSize function. + Expected values are: - a valid attributesMask and attributeValues as per penSizeValue +*/ +TEST_F(GetTextStyleAttributesTests, FontSizeExpectedJsonOptionsStringValueSmallLowerCase) +{ + std::string penSizeValue = "small"; + std::string options = "{\"penSize\":\"" + penSizeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())) + .WillOnce(DoAll(SetArgReferee<1>(penSizeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_SIZE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_SIZE_ARR_POSITION], mAttributes->FONT_SIZE_SMALL); +} + +/* + Test the getAttributes with font size small, penSizevalue expressed in Upper case + This will also test the output expected from the getFontSize function. + Expected values are: - a valid attributesMask and attributeValues as per penSizeValue +*/ +TEST_F(GetTextStyleAttributesTests, FontSizeExpectedJsonOptionsStringValueSmallUpperCase) +{ + std::string penSizeValue = "SMALL"; + std::string options = "{\"penSize\":\"" + penSizeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())) + .WillOnce(DoAll(SetArgReferee<1>(penSizeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_SIZE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_SIZE_ARR_POSITION], mAttributes->FONT_SIZE_SMALL); +} + +/* + Test the getAttributes with font size Medium, penSizevalue expressed in lower case + This will also test the output expected from the getFontSize function. + Expected values are: - a valid attributesMask and attributeValues as per penSizeValue +*/ +TEST_F(GetTextStyleAttributesTests, FontSizeExpectedJsonOptionsStringValueMediumLowerCase) +{ + std::string penSizeValue = "medium"; + std::string options = "{\"penSize\":\"" + penSizeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())) + .WillOnce(DoAll(SetArgReferee<1>(penSizeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_SIZE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_SIZE_ARR_POSITION], mAttributes->FONT_SIZE_STANDARD); +} + +/* + Test the getAttributes with font size Medium, penSizevalue expressed in Upper case + This will also test the output expected from the getFontSize function. + Expected values are: - a valid attributesMask and attributeValues as per penSizeValue + Two test cases are sufficient to prove that Upper case Json values are handled appropriately +*/ +TEST_F(GetTextStyleAttributesTests, FontSizeExpectedJsonOptionsStringValueMediumUpperCase) +{ + std::string penSizeValue = "MEDIUM"; + std::string options = "{\"penSize\":\"" + penSizeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())) + .WillOnce(DoAll(SetArgReferee<1>(penSizeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_SIZE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_SIZE_ARR_POSITION], mAttributes->FONT_SIZE_STANDARD); +} + +/* + Test the getAttributes with font size Standard + This will also test the output expected from the getFontSize function. + Expected values are: - a valid attributesMask and attributeValues as per penSizeValue +*/ +TEST_F(GetTextStyleAttributesTests, FontSizeExpectedJsonOptionsStringValueStandard) +{ + std::string penSizeValue = "standard"; + std::string options = "{\"penSize\":\"" + penSizeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())) + .WillOnce(DoAll(SetArgReferee<1>(penSizeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_SIZE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_SIZE_ARR_POSITION], mAttributes->FONT_SIZE_STANDARD); +} + +/* + Test the getAttributes with font size large + This will also test the output expected from the getFontSize function. + Expected values are: - a valid attributesMask and attributeValues as per penSizeValue +*/ +TEST_F(GetTextStyleAttributesTests, FontSizeExpectedJsonOptionsStringValueLarge) +{ + std::string penSizeValue = "large"; + std::string options = "{\"penSize\":\"" + penSizeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())) + .WillOnce(DoAll(SetArgReferee<1>(penSizeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_SIZE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_SIZE_ARR_POSITION], mAttributes->FONT_SIZE_LARGE); +} + +/* + Test the getAttributes with font size FONT_SIZE_EXTRALARGE + This will also test the output expected from the getFontSize function. + Expected values are: - a valid attributesMask and attributeValues as per penSizeValue +*/ +TEST_F(GetTextStyleAttributesTests, FontSizeExpectedJsonOptionsStringValueExtralarge) +{ + std::string penSizeValue = "extra_large"; + std::string options = "{\"penSize\":\"" + penSizeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())) + .WillOnce(DoAll(SetArgReferee<1>(penSizeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_SIZE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_SIZE_ARR_POSITION], mAttributes->FONT_SIZE_EXTRALARGE); +} + +/* + Test the getAttributes with font size auto i.e. embedded + This will also test the output expected from the getFontSize function. + Expected values are: - a valid attributesMask and attributeValues as per penSizeValue +*/ +TEST_F(GetTextStyleAttributesTests, FontSizeExpectedJsonOptionsStringValueAuto) +{ + std::string penSizeValue = "auto"; + std::string options = "{\"penSize\":\"" + penSizeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())) + .WillOnce(DoAll(SetArgReferee<1>(penSizeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_SIZE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_SIZE_ARR_POSITION], mAttributes->FONT_SIZE_EMBEDDED); +} + +/* + Test the getAttributes function supplying it with Right Key but invalid corresponding value. + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, FontStyleRightKeyInvalidValueJsonOptionsString) +{ + std::string fontStyleValue = "italics"; + std::string options = "{\"fontStyle\":\"" + fontStyleValue + "\"}"; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontStyleValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes with font size monospaced serif, fontstyle value expressed in lower case + This will also test the output expected from the getFontStyle function. + Expected values are: - a valid attributesMask and attributeValues as per fontStyleValue +*/ +TEST_F(GetTextStyleAttributesTests, FontStyleExpectedJsonOptionsStringValueMonospacedserifLowerCase) +{ + std::string fontStyleValue = "monospaced_serif"; + std::string options = "{\"fontStyle\":\"" + fontStyleValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontStyleValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_STYLE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_STYLE_ARR_POSITION], mAttributes->FONT_STYLE_MONOSPACED_SERIF); +} + +/* + Test the getAttributes with font size monospaced serif, fontstyle value expressed in lower case, separated by space + This will also test the output expected from the getFontStyle function. + Expected values are: - a valid attributesMask and attributeValues as per fontStyleValue +*/ +TEST_F(GetTextStyleAttributesTests, FontStyleExpectedJsonOptionsStringValueMonospacedserifLowerCaseSpaceSeparated) +{ + std::string fontStyleValue = "monospaced serif"; + std::string options = "{\"fontStyle\":\"" + fontStyleValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontStyleValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_STYLE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_STYLE_ARR_POSITION], mAttributes->FONT_STYLE_MONOSPACED_SERIF); +} + +/* + Test the getAttributes with font style monospaced serif, fontStyle value expressed in Upper case + This will also test the output expected from the getFontStyle function. + Expected values are: - a valid attributesMask and attributeValues as per penSizeValue +*/ +TEST_F(GetTextStyleAttributesTests, FontStyleExpectedJsonOptionsStringValueMonospacedserifUpperCase) +{ + std::string fontStyleValue = "MONOSPACED_SERIF"; + std::string options = "{\"fontStyle\":\"" + fontStyleValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontStyleValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_STYLE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_STYLE_ARR_POSITION], mAttributes->FONT_STYLE_MONOSPACED_SERIF); +} + +/* + Test the getAttributes with font style proportional serif. + This will also test the output expected from the getFontStyle function. + Expected values are: - a valid attributesMask and attributeValues as per fontStyleValue +*/ +TEST_F(GetTextStyleAttributesTests, FontStyleExpectedJsonOptionsStringValueProportionalserif) +{ + std::string fontStyleValue = "proportional_serif"; + std::string options = "{\"fontStyle\":\"" + fontStyleValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontStyleValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_STYLE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_STYLE_ARR_POSITION], mAttributes->FONT_STYLE_PROPORTIONAL_SERIF); +} + +/* + Test the getAttributes with font style monospaced sans serif. + This will also test the output expected from the getFontStyle function. + Expected values are: - a valid attributesMask and attributeValues as per fontStyleValue +*/ +TEST_F(GetTextStyleAttributesTests, FontStyleExpectedJsonOptionsStringValueMonospacedsansserif) +{ + std::string fontStyleValue = "monospaced_sanserif"; + std::string options = "{\"fontStyle\":\"" + fontStyleValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontStyleValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_STYLE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_STYLE_ARR_POSITION], mAttributes->FONT_STYLE_MONOSPACED_SANSSERIF); +} + +/* + Test the getAttributes with font style proportional sans serif. + This will also test the output expected from the getFontStyle function. + Expected values are: - a valid attributesMask and attributeValues as per fontStyleValue +*/ +TEST_F(GetTextStyleAttributesTests, FontStyleExpectedJsonOptionsStringValueProportionalsansserif) +{ + std::string fontStyleValue = "proportional_sanserif"; + std::string options = "{\"fontStyle\":\"" + fontStyleValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontStyleValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_STYLE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_STYLE_ARR_POSITION], mAttributes->FONT_STYLE_PROPORTIONAL_SANSSERIF); +} + +/* + Test the getAttributes with font style casual. + This will also test the output expected from the getFontStyle function. + Expected values are: - a valid attributesMask and attributeValues as per fontStyleValue +*/ +TEST_F(GetTextStyleAttributesTests, FontStyleExpectedJsonOptionsStringValueCasual) +{ + std::string fontStyleValue = "casual"; + std::string options = "{\"fontStyle\":\"" + fontStyleValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontStyleValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_STYLE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_STYLE_ARR_POSITION], mAttributes->FONT_STYLE_CASUAL); +} + +/* + Test the getAttributes with font style cursive. + This will also test the output expected from the getFontStyle function. + Expected values are: - a valid attributesMask and attributeValues as per fontStyleValue +*/ +TEST_F(GetTextStyleAttributesTests, FontStyleExpectedJsonOptionsStringValueCursive) +{ + std::string fontStyleValue = "cursive"; + std::string options = "{\"fontStyle\":\"" + fontStyleValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontStyleValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_STYLE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_STYLE_ARR_POSITION], mAttributes->FONT_STYLE_CURSIVE); +} + +/* + Test the getAttributes with font style small capital. + This will also test the output expected from the getFontStyle function. + Expected values are: - a valid attributesMask and attributeValues as per fontStyleValue +*/ +TEST_F(GetTextStyleAttributesTests, FontStyleExpectedJsonOptionsStringValueSmallcapital) +{ + std::string fontStyleValue = "small capital"; + std::string options = "{\"fontStyle\":\"" + fontStyleValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontStyleValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_STYLE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_STYLE_ARR_POSITION], mAttributes->FONT_STYLE_SMALL_CAPITALS); +} + +/* + Test the getAttributes with font style default. + This will also test the output expected from the getFontStyle function. + Expected values are: - a valid attributesMask and attributeValues as per fontStyleValue +*/ +TEST_F(GetTextStyleAttributesTests, FontStyleExpectedJsonOptionsStringValueDefault) +{ + std::string fontStyleValue = "default"; + std::string options = "{\"fontStyle\":\"" + fontStyleValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontStyleValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_STYLE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_STYLE_ARR_POSITION], mAttributes->FONT_STYLE_DEFAULT); +} + +/* + Test the getAttributes with font style auto. + This will also test the output expected from the getFontStyle function. + Expected values are: - a valid attributesMask and attributeValues as per fontStyleValue +*/ +TEST_F(GetTextStyleAttributesTests, FontStyleExpectedJsonOptionsStringValueAuto) +{ + std::string fontStyleValue = "auto"; + std::string options = "{\"fontStyle\":\"" + fontStyleValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontStyleValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_STYLE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_STYLE_ARR_POSITION], mAttributes->FONT_STYLE_EMBEDDED); +} + +/* + Test the getAttributes function supplying it with Right Key but invalid corresponding value. + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, FontColorRightKeyInvalidValueJsonOptionsString) +{ + std::string fontColorValue = "pink"; + std::string options = "{\"textForegroundColor\":\"" + fontColorValue + "\"}"; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes with font color black. + This will also test the output expected from the getColor function. Color value in lower case. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, FontColorExpectedJsonOptionsStringValueBlackLowerCase) +{ + std::string fontColorValue = "black"; + std::string options = "{\"textForegroundColor\":\"" + fontColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_COLOR_ARR_POSITION], mAttributes->COLOR_BLACK); +} + +/* + Test the getAttributes with font color black. + This will also test the output expected from the getColor function. Color value in upper case. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, FontColorExpectedJsonOptionsStringValueBlackUpperCase) +{ + std::string fontColorValue = "BLACK"; + std::string options = "{\"textForegroundColor\":\"" + fontColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_COLOR_ARR_POSITION], mAttributes->COLOR_BLACK); +} + +/* + Test the getAttributes with font color white. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, FontColorExpectedJsonOptionsStringValueWhite) +{ + std::string fontColorValue = "white"; + std::string options = "{\"textForegroundColor\":\"" + fontColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_COLOR_ARR_POSITION], mAttributes->COLOR_WHITE); +} + +/* + Test the getAttributes with font color red. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundColor value. +*/ +TEST_F(GetTextStyleAttributesTests, FontColorExpectedJsonOptionsStringValueRed) +{ + std::string fontColorValue = "red"; + std::string options = "{\"textForegroundColor\":\"" + fontColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_COLOR_ARR_POSITION], mAttributes->COLOR_RED); +} + +/* + Test the getAttributes with font color green. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, FontColorExpectedJsonOptionsStringValueGreen) +{ + std::string fontColorValue = "green"; + std::string options = "{\"textForegroundColor\":\"" + fontColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_COLOR_ARR_POSITION], mAttributes->COLOR_GREEN); +} + +/* + Test the getAttributes with font color blue. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundColor value. +*/ +TEST_F(GetTextStyleAttributesTests, FontColorExpectedJsonOptionsStringValueBlue) +{ + std::string fontColorValue = "blue"; + std::string options = "{\"textForegroundColor\":\"" + fontColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_COLOR_ARR_POSITION], mAttributes->COLOR_BLUE); +} + +/* + Test the getAttributes with font color yellow. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundColor value. +*/ +TEST_F(GetTextStyleAttributesTests, FontColorExpectedJsonOptionsStringValueBlack) +{ + std::string fontColorValue = "yellow"; + std::string options = "{\"textForegroundColor\":\"" + fontColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_COLOR_ARR_POSITION], mAttributes->COLOR_YELLOW); +} + +/* + Test the getAttributes with font color magenta. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundColor +*/ +TEST_F(GetTextStyleAttributesTests, FontColorExpectedJsonOptionsStringValueMagenta) +{ + std::string fontColorValue = "magenta"; + std::string options = "{\"textForegroundColor\":\"" + fontColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_COLOR_ARR_POSITION], mAttributes->COLOR_MAGENTA); +} + +/* + Test the getAttributes with font color cyan. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, FontColorExpectedJsonOptionsStringValueCyan) +{ + std::string fontColorValue = "cyan"; + std::string options = "{\"textForegroundColor\":\"" + fontColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_COLOR_ARR_POSITION], mAttributes->COLOR_CYAN); +} + +/* + Test the getAttributes with font color auto. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, FontColorExpectedJsonOptionsStringValueAuto) +{ + std::string fontColorValue = "auto"; + std::string options = "{\"textForegroundColor\":\"" + fontColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_COLOR_ARR_POSITION], mAttributes->COLOR_EMBEDDED); +} + +/* + Test the getAttributes function supplying it with Right Key but invalid corresponding value. + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundColorRightKeyInvalidValueJsonOptionsString) +{ + std::string backgroundColorValue = "pink"; + std::string options = "{\"textBackgroundColor\":\"" + backgroundColorValue + "\"}"; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes with background color black. + This will also test the output expected from the getColor function. Color value in lower case. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundColorExpectedJsonOptionsStringValueBlackLowerCase) +{ + std::string backgroundColorValue = "black"; + std::string options = "{\"textBackgroundColor\":\"" + backgroundColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_COLOR_ARR_POSITION], mAttributes->COLOR_BLACK); +} + +/* + Test the getAttributes with background color black. + This will also test the output expected from the getColor function. Color value in lower case. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundColorExpectedJsonOptionsStringValueBlackUpperCase) +{ + std::string backgroundColorValue = "BLACK"; + std::string options = "{\"textBackgroundColor\":\"" + backgroundColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_COLOR_ARR_POSITION], mAttributes->COLOR_BLACK); +} + +/* + Test the getAttributes with background color black. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundColorExpectedJsonOptionsStringValueWhite) +{ + std::string backgroundColorValue = "white"; + std::string options = "{\"textBackgroundColor\":\"" + backgroundColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_COLOR_ARR_POSITION], mAttributes->COLOR_WHITE); +} + +/* + Test the getAttributes with background color red. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundColorExpectedJsonOptionsStringValueRed) +{ + std::string backgroundColorValue = "red"; + std::string options = "{\"textBackgroundColor\":\"" + backgroundColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_COLOR_ARR_POSITION], mAttributes->COLOR_RED); +} + +/* + Test the getAttributes with background color green. + This will also test the output expected from the getColor function. Color value in lower case. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundColorExpectedJsonOptionsStringValueGreen) +{ + std::string backgroundColorValue = "green"; + std::string options = "{\"textBackgroundColor\":\"" + backgroundColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_COLOR_ARR_POSITION], mAttributes->COLOR_GREEN); +} + +/* + Test the getAttributes with background color blue. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundColorExpectedJsonOptionsStringValueBlue) +{ + std::string backgroundColorValue = "blue"; + std::string options = "{\"textBackgroundColor\":\"" + backgroundColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_COLOR_ARR_POSITION], mAttributes->COLOR_BLUE); +} + +/* + Test the getAttributes with background color yellow. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundColorExpectedJsonOptionsStringValueYellow) +{ + std::string backgroundColorValue = "yellow"; + std::string options = "{\"textBackgroundColor\":\"" + backgroundColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_COLOR_ARR_POSITION], mAttributes->COLOR_YELLOW); +} + +/* + Test the getAttributes with background color magenta. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundColorExpectedJsonOptionsStringValueMagenta) +{ + std::string backgroundColorValue = "magenta"; + std::string options = "{\"textBackgroundColor\":\"" + backgroundColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_COLOR_ARR_POSITION], mAttributes->COLOR_MAGENTA); +} + +/* + Test the getAttributes with background color cyan. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundColorExpectedJsonOptionsStringValueCyan) +{ + std::string backgroundColorValue = "cyan"; + std::string options = "{\"textBackgroundColor\":\"" + backgroundColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_COLOR_ARR_POSITION], mAttributes->COLOR_CYAN); +} + +/* + Test the getAttributes with background color auto. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundColor value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundColorExpectedJsonOptionsStringValueAuto) +{ + std::string backgroundColorValue = "auto"; + std::string options = "{\"textBackgroundColor\":\"" + backgroundColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_COLOR_ARR_POSITION], mAttributes->COLOR_EMBEDDED); +} + +/* + Test the getAttributes function supplying it with Right Key but invalid corresponding value. + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, EdgeTypeRightKeyInvalidValueJsonOptionsString) +{ + std::string edgeTypeValue = "curved"; + std::string options = "{\"textEdgeStyle\":\"" + edgeTypeValue + "\"}"; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeTypeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes with edge style none. + This will also test the output expected from the getEdgeType function. Edge type value in lower case + Expected values are: - a valid attributesMask and attributeValues as per textEdgeStyle value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeTypeExpectedJsonOptionsStringValueNoneLowerCase) +{ + std::string edgeTypeValue = "none"; + std::string options = "{\"textEdgeStyle\":\"" + edgeTypeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeTypeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_TYPE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_TYPE_ARR_POSITION], mAttributes->EDGE_TYPE_NONE); +} + +/* + Test the getAttributes with edge style none. + This will also test the output expected from the getEdgeType function. Edge type value in upper case. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeStyle value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeTypeExpectedJsonOptionsStringValueNoneUpperCase) +{ + std::string edgeTypeValue = "NONE"; + std::string options = "{\"textEdgeStyle\":\"" + edgeTypeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeTypeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_TYPE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_TYPE_ARR_POSITION], mAttributes->EDGE_TYPE_NONE); +} + +/* + Test the getAttributes with edge style raised. + This will also test the output expected from the getEdgeType function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeStyle value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeTypeExpectedJsonOptionsStringValueRaised) +{ + std::string edgeTypeValue = "raised"; + std::string options = "{\"textEdgeStyle\":\"" + edgeTypeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeTypeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_TYPE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_TYPE_ARR_POSITION], mAttributes->EDGE_TYPE_RAISED); +} + +/* + Test the getAttributes with edge style depressed. + This will also test the output expected from the getEdgeType function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeStyle value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeTypeExpectedJsonOptionsStringValueDepressed) +{ + std::string edgeTypeValue = "depressed"; + std::string options = "{\"textEdgeStyle\":\"" + edgeTypeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeTypeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_TYPE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_TYPE_ARR_POSITION], mAttributes->EDGE_TYPE_DEPRESSED); +} + +/* + Test the getAttributes with edge style uniform. + This will also test the output expected from the getEdgeType function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeStyle value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeTypeExpectedJsonOptionsStringValueUniform) +{ + std::string edgeTypeValue = "uniform"; + std::string options = "{\"textEdgeStyle\":\"" + edgeTypeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeTypeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_TYPE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_TYPE_ARR_POSITION], mAttributes->EDGE_TYPE_UNIFORM); +} + +/* + Test the getAttributes with edge style left drop shadow. + This will also test the output expected from the getEdgeType function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeStyle value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeTypeExpectedJsonOptionsStringValueLeftdropshadow) +{ + std::string edgeTypeValue = "Left drop shadow"; + std::string options = "{\"textEdgeStyle\":\"" + edgeTypeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeTypeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_TYPE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_TYPE_ARR_POSITION], mAttributes->EDGE_TYPE_SHADOW_LEFT); +} + +/* + Test the getAttributes with edge style right drop shadow. + This will also test the output expected from the getEdgeType function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeStyle value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeTypeExpectedJsonOptionsStringValueRightdropshadow) +{ + std::string edgeTypeValue = "Right drop shadow"; + std::string options = "{\"textEdgeStyle\":\"" + edgeTypeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeTypeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_TYPE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_TYPE_ARR_POSITION], mAttributes->EDGE_TYPE_SHADOW_RIGHT); +} + +/* + Test the getAttributes with edge style auto. + This will also test the output expected from the getEdgeType function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeStyle value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeTypeExpectedJsonOptionsStringValueAuto) +{ + std::string edgeTypeValue = "auto"; + std::string options = "{\"textEdgeStyle\":\"" + edgeTypeValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeTypeValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_TYPE_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_TYPE_ARR_POSITION], mAttributes->EDGE_TYPE_EMBEDDED); +} + +/* + Test the getAttributes function supplying it with Right Key but invalid corresponding value. + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, EdgeColorRightKeyInvalidValueJsonOptionsString) +{ + std::string edgeColorValue = "pink"; + std::string options = "{\"textEdgeColor\":\"" + edgeColorValue + "\"}"; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes with edge color black. + This will also test the output expected from the getColor function. Color value in lower case. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeColor value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeColorExpectedJsonOptionsStringValueBlackLowerCase) +{ + std::string edgeColorValue = "black"; + std::string options = "{\"textEdgeColor\":\"" + edgeColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_COLOR_ARR_POSITION], mAttributes->COLOR_BLACK); +} + +/* + Test the getAttributes with edge color black. + This will also test the output expected from the getColor function. Color value in upper case. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeColor value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeColorExpectedJsonOptionsStringValueBlackUpperCase) +{ + std::string edgeColorValue = "BLACK"; + std::string options = "{\"textEdgeColor\":\"" + edgeColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_COLOR_ARR_POSITION], mAttributes->COLOR_BLACK); +} + +/* + Test the getAttributes with edge color white. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeColor value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeColorExpectedJsonOptionsStringValueWhite) +{ + std::string edgeColorValue = "white"; + std::string options = "{\"textEdgeColor\":\"" + edgeColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_COLOR_ARR_POSITION], mAttributes->COLOR_WHITE); +} + +/* + Test the getAttributes with edge color red. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeColor value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeColorExpectedJsonOptionsStringValueRed) +{ + std::string edgeColorValue = "red"; + std::string options = "{\"textEdgeColor\":\"" + edgeColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_COLOR_ARR_POSITION], mAttributes->COLOR_RED); +} + +/* + Test the getAttributes with edge color green. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeColor value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeColorExpectedJsonOptionsStringValueGreen) +{ + std::string edgeColorValue = "green"; + std::string options = "{\"textEdgeColor\":\"" + edgeColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_COLOR_ARR_POSITION], mAttributes->COLOR_GREEN); +} + +/* + Test the getAttributes with edge color blue. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeColor value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeColorExpectedJsonOptionsStringValueBlue) +{ + std::string edgeColorValue = "blue"; + std::string options = "{\"textEdgeColor\":\"" + edgeColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_COLOR_ARR_POSITION], mAttributes->COLOR_BLUE); +} + +/* + Test the getAttributes with edge color yellow. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeColor value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeColorExpectedJsonOptionsStringValueYellow) +{ + std::string edgeColorValue = "yellow"; + std::string options = "{\"textEdgeColor\":\"" + edgeColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_COLOR_ARR_POSITION], mAttributes->COLOR_YELLOW); +} + +/* + Test the getAttributes with edge color mageta. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeColor value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeColorExpectedJsonOptionsStringValueMagenta) +{ + std::string edgeColorValue = "magenta"; + std::string options = "{\"textEdgeColor\":\"" + edgeColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_COLOR_ARR_POSITION], mAttributes->COLOR_MAGENTA); +} + +/* + Test the getAttributes with edge color cyan. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeColor value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeColorExpectedJsonOptionsStringValueCyan) +{ + std::string edgeColorValue = "cyan"; + std::string options = "{\"textEdgeColor\":\"" + edgeColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_COLOR_ARR_POSITION], mAttributes->COLOR_CYAN); +} + +/* + Test the getAttributes with edge color auto. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per textEdgeColor value +*/ +TEST_F(GetTextStyleAttributesTests, EdgeColorExpectedJsonOptionsStringValueAuto) +{ + std::string edgeColorValue = "auto"; + std::string options = "{\"textEdgeColor\":\"" + edgeColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(edgeColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<EDGE_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->EDGE_COLOR_ARR_POSITION], mAttributes->COLOR_EMBEDDED); +} + +/* + Test the getAttributes function supplying it with Right Key but invalid corresponding value. + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundOpacityRightKeyInvalidValueJsonOptionsString) +{ + std::string backgroundOpacityValue = "none"; + std::string options = "{\"textBackgroundOpacity\":\"" + backgroundOpacityValue + "\"}"; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes with background opacity solid. + This will also test the output expected from the getOpacity function. Opacity value in lower case. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundOpacityExpectedJsonOptionsStringValueSolidLowerCase) +{ + std::string backgroundOpacityValue = "solid"; + std::string options = "{\"textBackgroundOpacity\":\"" + backgroundOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_OPACITY_ARR_POSITION], mAttributes->OPACITY_SOLID); +} + +/* + Test the getAttributes with background opacity solid. + This will also test the output expected from the getOpacity function. Opacity value in upper case. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundOpacityExpectedJsonOptionsStringValueSolidUpperCase) +{ + std::string backgroundOpacityValue = "SOLID"; + std::string options = "{\"textBackgroundOpacity\":\"" + backgroundOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_OPACITY_ARR_POSITION], mAttributes->OPACITY_SOLID); +} + +/* + Test the getAttributes with background opacity flash. + This will also test the output expected from the getOpacity function. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundOpacityExpectedJsonOptionsStringValueFlash) +{ + std::string backgroundOpacityValue = "flash"; + std::string options = "{\"textBackgroundOpacity\":\"" + backgroundOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_OPACITY_ARR_POSITION], mAttributes->OPACITY_FLASHING); +} + +/* + Test the getAttributes with background opacity translucent. + This will also test the output expected from the getOpacity function. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundOpacityExpectedJsonOptionsStringValueTranslucent) +{ + std::string backgroundOpacityValue = "translucent"; + std::string options = "{\"textBackgroundOpacity\":\"" + backgroundOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_OPACITY_ARR_POSITION], mAttributes->OPACITY_TRANSLUCENT); +} + +/* + Test the getAttributes with background opacity transparent. + This will also test the output expected from the getOpacity function. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundOpacityExpectedJsonOptionsStringValueTransparent) +{ + std::string backgroundOpacityValue = "transparent"; + std::string options = "{\"textBackgroundOpacity\":\"" + backgroundOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_OPACITY_ARR_POSITION], mAttributes->OPACITY_TRANSPARENT); +} + +/* + Test the getAttributes with background opacity auto. + This will also test the output expected from the getOpacity function. + Expected values are: - a valid attributesMask and attributeValues as per textBackgroundOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, BackgroundOpacityExpectedJsonOptionsStringValueAuto) +{ + std::string backgroundOpacityValue = "auto"; + std::string options = "{\"textBackgroundOpacity\":\"" + backgroundOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(backgroundOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<BACKGROUND_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->BACKGROUND_OPACITY_ARR_POSITION], mAttributes->OPACITY_EMBEDDED); +} + +/* + Test the getAttributes function supplying it with Right Key but invalid corresponding value. + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, FontOpacityRightKeyInvalidValueJsonOptionsString) +{ + std::string fontOpacityValue = "none"; + std::string options = "{\"textForegroundOpacity\":\"" + fontOpacityValue + "\"}"; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes with font opacity solid. + This will also test the output expected from the getOpacity function. Opacity value in lower case. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, FontOpacityExpectedJsonOptionsStringValueSolidLowerCase) +{ + std::string fontOpacityValue = "solid"; + std::string options = "{\"textForegroundOpacity\":\"" + fontOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_OPACITY_ARR_POSITION], mAttributes->OPACITY_SOLID); +} + +/* + Test the getAttributes with font opacity solid. + This will also test the output expected from the getOpacity function. Opacity value in upper case. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, FontOpacityExpectedJsonOptionsStringValueSolidUpperCase) +{ + std::string fontOpacityValue = "SOLID"; + std::string options = "{\"textForegroundOpacity\":\"" + fontOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_OPACITY_ARR_POSITION], mAttributes->OPACITY_SOLID); +} + +/* + Test the getAttributes with font opacity flash. + This will also test the output expected from the getOpacity function. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, FontOpacityExpectedJsonOptionsStringValueFlash) +{ + std::string fontOpacityValue = "flash"; + std::string options = "{\"textForegroundOpacity\":\"" + fontOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_OPACITY_ARR_POSITION], mAttributes->OPACITY_FLASHING); +} + +/* + Test the getAttributes with font opacity translucent. + This will also test the output expected from the getOpacity function. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, FontOpacityExpectedJsonOptionsStringValueTranslucent) +{ + std::string fontOpacityValue = "translucent"; + std::string options = "{\"textForegroundOpacity\":\"" + fontOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_OPACITY_ARR_POSITION], mAttributes->OPACITY_TRANSLUCENT); +} + +/* + Test the getAttributes with font opacity transparent. + This will also test the output expected from the getOpacity function. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, FontOpacityExpectedJsonOptionsStringValueTransparent) +{ + std::string fontOpacityValue = "transparent"; + std::string options = "{\"textForegroundOpacity\":\"" + fontOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_OPACITY_ARR_POSITION], mAttributes->OPACITY_TRANSPARENT); +} + +/* + Test the getAttributes with font opacity auto. + This will also test the output expected from the getOpacity function. + Expected values are: - a valid attributesMask and attributeValues as per textForegroundOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, FontOpacityExpectedJsonOptionsStringValueAuto) +{ + std::string fontOpacityValue = "auto"; + std::string options = "{\"textForegroundOpacity\":\"" + fontOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(fontOpacityValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<FONT_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->FONT_OPACITY_ARR_POSITION], mAttributes->OPACITY_EMBEDDED); +} + +/* + Test the getAttributes function supplying it with Right Key but invalid corresponding value. + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, WindowColorRightKeyInvalidValueJsonOptionsString) +{ + std::string windowColorValue = "pink"; + std::string options = "{\"windowFillColor\":\"" + windowColorValue + "\"}"; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes with window color black. + This will also test the output expected from the getColor function. Color value in lower case. + Expected values are: - a valid attributesMask and attributeValues as per windowFillColor value +*/ +TEST_F(GetTextStyleAttributesTests, WindowColorExpectedJsonOptionsStringValueBlackLowerCase) +{ + std::string windowColorValue = "black"; + std::string options = "{\"windowFillColor\":\"" + windowColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_COLOR_ARR_POSITION], mAttributes->COLOR_BLACK); +} + +/* + Test the getAttributes with window color black. + This will also test the output expected from the getColor function. Color value in upper case. + Expected values are: - a valid attributesMask and attributeValues as per windowFillColor value +*/ +TEST_F(GetTextStyleAttributesTests, WindowColorExpectedJsonOptionsStringValueBlackUpperCase) +{ + std::string windowColorValue = "BLACK"; + std::string options = "{\"windowFillColor\":\"" + windowColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_COLOR_ARR_POSITION], mAttributes->COLOR_BLACK); +} + +/* + Test the getAttributes with window color white. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per windowFillColor value +*/ +TEST_F(GetTextStyleAttributesTests, WindowColorExpectedJsonOptionsStringValueWhite) +{ + std::string windowColorValue = "white"; + std::string options = "{\"windowFillColor\":\"" + windowColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_COLOR_ARR_POSITION], mAttributes->COLOR_WHITE); +} + +/* + Test the getAttributes with window color red. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per windowFillColor value +*/ +TEST_F(GetTextStyleAttributesTests, WindowColorExpectedJsonOptionsStringValueRed) +{ + std::string windowColorValue = "red"; + std::string options = "{\"windowFillColor\":\"" + windowColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_COLOR_ARR_POSITION], mAttributes->COLOR_RED); +} + +/* + Test the getAttributes with window color green. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per windowFillColor value +*/ +TEST_F(GetTextStyleAttributesTests, WindowColorExpectedJsonOptionsStringValueGreen) +{ + std::string windowColorValue = "green"; + std::string options = "{\"windowFillColor\":\"" + windowColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_COLOR_ARR_POSITION], mAttributes->COLOR_GREEN); +} + +/* + Test the getAttributes with window color blue. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per windowFillColor value +*/ +TEST_F(GetTextStyleAttributesTests, WindowColorExpectedJsonOptionsStringValueBlue) +{ + std::string windowColorValue = "blue"; + std::string options = "{\"windowFillColor\":\"" + windowColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_COLOR_ARR_POSITION], mAttributes->COLOR_BLUE); +} + +/* + Test the getAttributes with window color yellow. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per windowFillColor value +*/ +TEST_F(GetTextStyleAttributesTests, WindowColorExpectedJsonOptionsStringValueYellow) +{ + std::string windowColorValue = "yellow"; + std::string options = "{\"windowFillColor\":\"" + windowColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_COLOR_ARR_POSITION], mAttributes->COLOR_YELLOW); +} + +/* + Test the getAttributes with window color magenta. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per windowFillColor value +*/ +TEST_F(GetTextStyleAttributesTests, WindowColorExpectedJsonOptionsStringValueMagenta) +{ + std::string windowColorValue = "Magenta"; + std::string options = "{\"windowFillColor\":\"" + windowColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_COLOR_ARR_POSITION], mAttributes->COLOR_MAGENTA); +} + +/* + Test the getAttributes with window color cyan. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per windowFillColor value +*/ +TEST_F(GetTextStyleAttributesTests, WindowColorExpectedJsonOptionsStringValueCyan) +{ + std::string windowColorValue = "cyan"; + std::string options = "{\"windowFillColor\":\"" + windowColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_COLOR_ARR_POSITION], mAttributes->COLOR_CYAN); +} + +/* + Test the getAttributes with window color auto. + This will also test the output expected from the getColor function. + Expected values are: - a valid attributesMask and attributeValues as per windowFillColor value +*/ +TEST_F(GetTextStyleAttributesTests, WindowColorExpectedJsonOptionsStringValueAuto) +{ + std::string windowColorValue = "auto"; + std::string options = "{\"windowFillColor\":\"" + windowColorValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowColorValue), Return(true))); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())).WillOnce(Return(false)); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_COLOR_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_COLOR_ARR_POSITION], mAttributes->COLOR_EMBEDDED); +} + +/* + Test the getAttributes function supplying it with Right Key but invalid corresponding value. + In this case getAttributes must set the attributeMask to 0; informing caller nothing to proceed +*/ +TEST_F(GetTextStyleAttributesTests, WindowOpacityRightKeyInvalidValueJsonOptionsString) +{ + std::string windowOpacityValue = "none"; + std::string options = "{\"windowFillOpacity\":\"" + windowOpacityValue + "\"}"; + std::uint32_t attributesMask = 0x1234; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowOpacityValue), Return(true))); + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, 0); +} + +/* + Test the getAttributes with font opacity solid. + This will also test the output expected from the getOpacity function. Opacity value in lower case. + Expected values are: - a valid attributesMask and attributeValues as per windowFillOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, WindowOpacityExpectedJsonOptionsStringValueSolidLowerCase) +{ + std::string windowOpacityValue = "solid"; + std::string options = "{\"windowFillOpacity\":\"" + windowOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowOpacityValue), Return(true))); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_OPACITY_ARR_POSITION], mAttributes->OPACITY_SOLID); +} + +/* + Test the getAttributes with font opacity solid. + This will also test the output expected from the getOpacity function. Opacity value in upper case. + Expected values are: - a valid attributesMask and attributeValues as per windowFillOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, WindowOpacityExpectedJsonOptionsStringValueSolidUpperCase) +{ + std::string windowOpacityValue = "SOLID"; + std::string options = "{\"windowFillOpacity\":\"" + windowOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowOpacityValue), Return(true))); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_OPACITY_ARR_POSITION], mAttributes->OPACITY_SOLID); +} + +/* + Test the getAttributes with font opacity flash. + This will also test the output expected from the getOpacity function. + Expected values are: - a valid attributesMask and attributeValues as per windowFillOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, WindowOpacityExpectedJsonOptionsStringValueFlash) +{ + std::string windowOpacityValue = "flash"; + std::string options = "{\"windowFillOpacity\":\"" + windowOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowOpacityValue), Return(true))); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_OPACITY_ARR_POSITION], mAttributes->OPACITY_FLASHING); +} + +/* + Test the getAttributes with font opacity translucent. + This will also test the output expected from the getOpacity function. + Expected values are: - a valid attributesMask and attributeValues as per windowFillOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, WindowOpacityExpectedJsonOptionsStringValueTranslucent) +{ + std::string windowOpacityValue = "translucent"; + std::string options = "{\"windowFillOpacity\":\"" + windowOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowOpacityValue), Return(true))); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_OPACITY_ARR_POSITION], mAttributes->OPACITY_TRANSLUCENT); +} + +/* + Test the getAttributes with font opacity transparent. + This will also test the output expected from the getOpacity function. + Expected values are: - a valid attributesMask and attributeValues as per windowFillOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, WindowOpacityExpectedJsonOptionsStringValueTransparent) +{ + std::string windowOpacityValue = "transparent"; + std::string options = "{\"windowFillOpacity\":\"" + windowOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowOpacityValue), Return(true))); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_OPACITY_ARR_POSITION], mAttributes->OPACITY_TRANSPARENT); +} + +/* + Test the getAttributes with font opacity auto. + This will also test the output expected from the getOpacity function. + Expected values are: - a valid attributesMask and attributeValues as per windowFillOpacity value +*/ +TEST_F(GetTextStyleAttributesTests, WindowOpacityExpectedJsonOptionsStringValueAuto) +{ + std::string windowOpacityValue = "auto"; + std::string options = "{\"windowFillOpacity\":\"" + windowOpacityValue + "\"}"; + std::uint32_t attributesMask = 0; + attributesType attributesValues = {0}; + + EXPECT_CALL(*g_mockPlayerJsonObject, get("penSize", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("fontStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeStyle", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textEdgeColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textBackgroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("textForegroundOpacity", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillColor", An())).WillOnce(Return(false)); + EXPECT_CALL(*g_mockPlayerJsonObject, get("windowFillOpacity", An())) + .WillOnce(DoAll(SetArgReferee<1>(windowOpacityValue), Return(true))); + + EXPECT_EQ(0, mAttributes->getAttributes(options, attributesValues, attributesMask)); + EXPECT_EQ(attributesMask, (1<WIN_OPACITY_ARR_POSITION)); + EXPECT_EQ(attributesValues[mAttributes->WIN_OPACITY_ARR_POSITION], mAttributes->OPACITY_EMBEDDED); +} diff --git a/test/utests/tests/TextStyleAttributes/TextStyleAttributesTests.cpp b/test/utests/tests/TextStyleAttributes/TextStyleAttributesTests.cpp new file mode 100644 index 00000000..f51285d1 --- /dev/null +++ b/test/utests/tests/TextStyleAttributes/TextStyleAttributesTests.cpp @@ -0,0 +1,26 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2022 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 + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/utests/tests/base16Tests/CMakeLists.txt b/test/utests/tests/base16Tests/CMakeLists.txt new file mode 100644 index 00000000..a868a307 --- /dev/null +++ b/test/utests/tests/base16Tests/CMakeLists.txt @@ -0,0 +1,65 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2022 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(GoogleTest) + +set(PLAYER_ROOT "../../../../") +set(UTESTS_ROOT "../../") +set(EXEC_NAME base16Tests) + +include_directories(${PLAYER_ROOT} ${PLAYER_ROOT}/isobmff ${PLAYER_ROOT}/drm ${PLAYER_ROOT}/downloader ${PLAYER_ROOT}/drm/helper ${PLAYER_ROOT}/drm/ave ${PLAYER_ROOT}/subtitle ${PLAYER_ROOT}/middleware/subtitle) +include_directories(${PLAYER_ROOT}/subtec/libsubtec) +include_directories(${PLAYER_ROOT}/subtec/subtecparser) +include_directories(${PLAYER_ROOT}/playerjsonobject) +include_directories(${PLAYER_ROOT}/baseConversion) + +include_directories(${GTEST_INCLUDE_DIRS}) +include_directories(${GMOCK_INCLUDE_DIRS}) +include_directories(${GLIB_INCLUDE_DIRS}) +include_directories(${GSTREAMER_INCLUDE_DIRS}) +include_directories(${LibXml2_INCLUDE_DIRS}) +include_directories(${LIBCJSON_INCLUDE_DIRS}) +include_directories(SYSTEM ${UTESTS_ROOT}/mocks) +include_directories(${PLAYER_ROOT}/tsb/api) +include_directories(${PLAYER_ROOT}/../) + + +set(TEST_SOURCES base16Tests.cpp + base16playerTests.cpp) + + +set(PLAYER_SOURCES ${PLAYER_ROOT}/baseConversion/base16.cpp) + +add_executable(${EXEC_NAME} + ${TEST_SOURCES} + ${PLAYER_SOURCES}) + +set_target_properties(${EXEC_NAME} PROPERTIES FOLDER "utests") + +if (CMAKE_XCODE_BUILD_SYSTEM) + # XCode schema target + xcode_define_schema(${EXEC_NAME}) +endif() + +if (COVERAGE_ENABLED) + include(CodeCoverage) + APPEND_COVERAGE_COMPILER_FLAGS() +endif() + +target_link_libraries(${EXEC_NAME} fakes -pthread ${GLIB_LINK_LIBRARIES} ${OS_LD_FLAGS} ${GMOCK_LINK_LIBRARIES} ${GTEST_LINK_LIBRARIES}) + +player_utest_run_add(${EXEC_NAME}) diff --git a/test/utests/tests/base16Tests/base16Tests.cpp b/test/utests/tests/base16Tests/base16Tests.cpp new file mode 100644 index 00000000..2b0f772e --- /dev/null +++ b/test/utests/tests/base16Tests/base16Tests.cpp @@ -0,0 +1,153 @@ +/* +* If not stated otherwise in this file or this component's license file the +* following copyright and licenses apply: +* +* Copyright 2023 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 "base16.h" +#include +using namespace testing; + +class Base16EncodeDecodeTest : public ::testing::Test { +protected: + char *encoded; + + void SetUp() override { + const unsigned char *inputData = (const unsigned char *)"hello"; + encoded = base16_Encode(inputData, 5); + ASSERT_NE(encoded, nullptr); + } + + void TearDown() override { + if (encoded != nullptr) { + free(encoded); + } + } +}; +TEST_F(Base16EncodeDecodeTest, EncodeValidData1) +{ + const unsigned char inputData[]={'H','e','l','l','o'}; + size_t inputLength = sizeof(inputData); + const char* expectedOutput = "48656c6c6f"; + char* encodedData = base16_Encode(inputData, inputLength); + EXPECT_STREQ(encodedData, expectedOutput); + +} +TEST_F(Base16EncodeDecodeTest, EncodeValidData2) +{ + const unsigned char inputData[]={'r','a','j','a','j','j','a','a','m'}; + size_t inputLength = sizeof(inputData); + const char* expectedOutput = "72616a616a6a61616d"; + char* encodedData = base16_Encode(inputData, inputLength); + EXPECT_STREQ(encodedData, expectedOutput); + +} +TEST_F(Base16EncodeDecodeTest, EncodeValidData3) +{ + const unsigned char inputData[]={'H','e','l','l','o','1','2','3','W','o','r','l','d'}; + size_t inputLength = sizeof(inputData); + const char* expectedOutput = "48656c6c6f313233576f726c64"; + char* encodedData = base16_Encode(inputData, inputLength); + EXPECT_STREQ(encodedData, expectedOutput); + +} +TEST_F(Base16EncodeDecodeTest, EncodeValidData4) +{ + const unsigned char inputData[]={'1','2','3','4','5','6','7','8'}; + size_t inputLength = sizeof(inputData); + const char* expectedOutput = "3132333435363738"; + char* encodedData = base16_Encode(inputData, inputLength); + EXPECT_STREQ(encodedData, expectedOutput); + +} + +TEST_F(Base16EncodeDecodeTest, EncodeValidData5) +{ + const unsigned char inputData[]={'@','#','$',' ','%','&'}; + size_t inputLength = sizeof(inputData); + const char* expectedOutput = "402324202526"; + char* encodedData = base16_Encode(inputData, inputLength); + EXPECT_STREQ(encodedData, expectedOutput); + +} +TEST_F(Base16EncodeDecodeTest, EncodeValidData6) +{ + const unsigned char inputData[]={' ',' ',' ',' ',' ','H'}; + size_t inputLength = sizeof(inputData); + const char* expectedOutput = "202020202048"; + char* encodedData = base16_Encode(inputData, inputLength); + EXPECT_STREQ(encodedData, expectedOutput); + +} + +TEST_F(Base16EncodeDecodeTest, DecodeEmptyString) { + size_t decodedLength = 0; + + const char *emptyData=""; + base16_Decode(emptyData, 0, &decodedLength); + EXPECT_EQ(decodedLength, 0); +} + +TEST_F(Base16EncodeDecodeTest, DecodeValidData1) +{ + size_t decodedLength = 0; + + const char inputData[]= {'4','8','6','5','6','c','6','c','6','f'}; + size_t inputLength = sizeof(inputData); + unsigned char outputData[]="Hello"; + unsigned char *decodeData= base16_Decode(inputData, inputLength, &decodedLength); + for(size_t i=0;i +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/vendor/SocInterface.cpp b/vendor/SocInterface.cpp index 897fbfb4..bae44572 100644 --- a/vendor/SocInterface.cpp +++ b/vendor/SocInterface.cpp @@ -49,8 +49,9 @@ bool SocInterface::StartsWith( const char *inputStr, const char *prefix ) /** * @brief To enable certain player configs based upon platform check */ -SocPlatformType InferPlatformsFromPluginScan() +SocPlatformType InferPlatformFromPluginScan() { + SocPlatformType platform = SOC_PLATFORM_DEFAULT; // Ensure GST is initialized if (!gst_init_check(nullptr, nullptr, nullptr)) { MW_LOG_ERR("gst_init_check() failed"); @@ -60,9 +61,9 @@ SocPlatformType InferPlatformsFromPluginScan() {"omxeac3dec", SOC_PLATFORM_REALTEK}, {"brcmaudiodecoder", SOC_PLATFORM_BROADCOM}, }; - + GstRegistry* registry = gst_registry_get(); - + for (const auto& plugin : plugins) { GstPluginFeature* pluginFeature = gst_registry_lookup_feature(registry, plugin.first); @@ -70,19 +71,23 @@ SocPlatformType InferPlatformsFromPluginScan() { gst_object_unref(pluginFeature); MW_LOG_MIL("InterfacePlayerRDK: %s plugin found in registry", plugin.first); - return plugin.second; + platform = plugin.second; + break; } } - - MW_LOG_WARN("InterfacePlayerRDK: None of the plugins found in registry"); - return SOC_PLATFORM_DEFAULT; + + if( platform == SOC_PLATFORM_DEFAULT ) + { + MW_LOG_WARN("InterfacePlayerRDK: None of the plugins found in registry"); + } + return platform; } /** * @brief Infers SoC platform type from device.properties. * @return Inferred SoC platform type. */ -SocPlatformType SocInterface::InferPlatformsFromDeviceProperties( void ) +SocPlatformType SocInterface::InferPlatformFromDeviceProperties( void ) { SocPlatformType platform = SOC_PLATFORM_DEFAULT; FILE* fp = fopen("/etc/device.properties", "rb"); @@ -145,35 +150,30 @@ SocPlatformType SocInterface::InferPlatformsFromDeviceProperties( void ) */ std::shared_ptr SocInterface::CreateSocInterface() { - SocPlatformType platformType = InferPlatformsFromDeviceProperties(); - - if(platformType == SOC_PLATFORM_DEFAULT) - { - platformType = InferPlatformsFromPluginScan(); - } static std::shared_ptr socInterface; - if(socInterface) + if( !socInterface) { - return socInterface; - } - switch (platformType) - { - case SOC_PLATFORM_AMLOGIC: - socInterface = std::make_shared(); - break; - case SOC_PLATFORM_BROADCOM: - socInterface = std::make_shared(); - break; - case SOC_PLATFORM_REALTEK: - socInterface = std::make_shared(); - break; - default: - socInterface = std::make_shared(); - break; + SocPlatformType platformType = InferPlatformFromDeviceProperties(); + if(platformType == SOC_PLATFORM_DEFAULT) + { + platformType = InferPlatformFromPluginScan(); + } + switch (platformType) + { + case SOC_PLATFORM_AMLOGIC: + socInterface = std::make_shared(); + break; + case SOC_PLATFORM_BROADCOM: + socInterface = std::make_shared(); + break; + case SOC_PLATFORM_REALTEK: + socInterface = std::make_shared(); + break; + default: + socInterface = std::make_shared(); + break; + } } - if(!socInterface) - MW_LOG_ERR("failed to create soc interface"); - return socInterface; } @@ -231,28 +231,3 @@ void SocInterface::SetWesterosSinkState(bool status) { mUsingWesterosSink = status; } -/** - * @brief Dump a file to log - */ -void SocInterface::DumpFile(const char* fileName) -{ - int c; - FILE *fp = fopen(fileName, "r"); - if (fp) - { - printf("\n************************Dump %s **************************\n", fileName); - c = getc(fp); - while (c != EOF) - { - printf("%c", c); - c = getc(fp); - } - fclose(fp); - printf("\n**********************Dump %s end *************************\n", fileName); - } - else - { - MW_LOG_WARN("Could not open %s", fileName); - } -} - diff --git a/vendor/SocInterface.h b/vendor/SocInterface.h index 3906e775..f2a56b98 100644 --- a/vendor/SocInterface.h +++ b/vendor/SocInterface.h @@ -27,7 +27,7 @@ #include #include "PlayerLogManager.h" -#define REQUIRED_QUEUED_FRAMES_DEFAULT (5+1) +#define REQUIRED_QUEUED_FRAMES_DEFAULT (5+1) /** * @brief Enumeration for play flags. * @@ -54,7 +54,7 @@ typedef enum */ enum SocPlatformType { - SOC_PLATFORM_DEFAULT, /**< Ubuntu */ + SOC_PLATFORM_DEFAULT, /**< Ubuntu/OSX */ SOC_PLATFORM_AMLOGIC, /**< Amlogic */ SOC_PLATFORM_REALTEK, /**< Realtek */ SOC_PLATFORM_BROADCOM, /**< Broadcom */ @@ -66,419 +66,411 @@ enum SocPlatformType */ class SocInterface { - private: - - protected: - - /** - * @brief Infers the SoC type from device.properties. - * @return The SoC platform type. - */ - static SocPlatformType InferPlatformsFromDeviceProperties( void ); - - static void DumpFile(const char* fileName); - - public: - SocInterface() {} - - /*config to indicate platforms using westeros sink*/ - bool mUsingWesterosSink = false; - - /** - * @brief Checks if the input string starts with the given prefix. - * - * @param inputStr The input string to check. - * @param prefix The prefix to check for. - * - * @return True if the input string starts with the prefix, false otherwise. - */ - bool StartsWith( const char *inputStr, const char *prefix ); - /** - * @brief Sets the state of Westeros Sink usage. - * - * This function updates the internal flag to indicate whether - * Westeros Sink is being used. It does not enable or disable - * Westeros Sink itself, but merely informs the SocInterface - * about its status. - * - * @param status Set to `true` if Westeros Sink is enabled, `false` otherwise. - */ - void SetWesterosSinkState(bool status); - - /*@brief returns true if video stats required from sink otherwise false*/ - virtual bool IsPlaybackQualityFromSink(){return false;} - - /** - * Sets buffer size and duration for the given GstElement. - * - * @param sink The GstElement to configure. - * @param size The desired buffer size. - */ - virtual void SetVideoBufferSize(GstElement *sink, int size){}; - - /** - * Sets asynchronous mode for the given Sink. - * - * @param sink element. - * @param status Enable (TRUE) or disable (FALSE) asynchronous mode. - */ - virtual void SetSinkAsync(GstElement *sink, gboolean status){} - - /** - * @brief Creates an instance of the SoC-specific interface. - * @return A pointer to the created SocInterface object. - */ - static std::shared_ptr CreateSocInterface(); - - /** - * @brief Check if AppSrc should be used. - * - * Determines whether the AppSrc element should be used in the current context. - * - * @return True if AppSrc should be used, false otherwise. - */ - virtual bool UseAppSrc(){return false;} - - /** - * @brief Check if AC4 should be disabled. - * - * Determines whether AC4 support should be disabled. - * - * @return True if AC4 should be disabled, false otherwise. - */ - virtual bool IsSupportedAC4(){return false;} - - /** - * @brief Check if Westeros sink should be used. - * - * Determines whether the Westeros sink should be used in the current context. - * - * @return True if platform uses Westeros sink, false otherwise. - */ - virtual bool UseWesterosSink(){return true;} - - /** - * @brief Check if audio fragments should be synchronized. - * - * Determines whether audio fragments should be synchronized. - * - * @return True if audio fragments should be synchronized, false otherwise. - */ - virtual bool IsAudioFragmentSyncSupported(){return false;} - - /** - * @brief Check if live latency correction should be enabled. - * - * Determines whether live latency correction should be enabled. - * - * @return True if live latency correction should be enabled, false otherwise. - */ - virtual bool EnableLiveLatencyCorrection(){return false;} - - /** - * @brief Get the required number of queued frames. - * - * Returns the total number of frames that should be queued. - * - * @return The required number of queued frames. - */ - virtual int RequiredQueuedFrames(){return REQUIRED_QUEUED_FRAMES_DEFAULT;} - - /** - * @brief Check if PTS restamping is supported by the platform. - * - * Determines whether the platform supports PTS restamping. - * - * @return True if PTS restamping is supported, false otherwise. - */ - virtual bool EnablePTSRestamp(){return false;} - - /** - * Checks if this is the first tune with Westeros disabled. - * - * @return True if this is the first tune with Westeros disabled for the current platform, false otherwise. - */ - virtual bool IsFirstTuneWithWesteros(){return false;} - - /** - * @brief Set SoC volume property name. - */ - virtual void SetAudioProperty(const char **volume, const char **mute, bool& isSinkBinVolume)=0; - - /** - * @brief enables the seamless switch property - * @param object The GStreamer element to configure. - * @param value True to enable seamless switching, false to disable. - */ - virtual void SetSeamlessSwitch(GstElement* object, gboolean value){} - - /** - * @brief Sets the sinkbin to audio-only mode. - * - * This is a pure virtual function that must be implemented by derived classes. - * - * @param sinkbin The GStreamer sinkbin to configure. - * @param property The name of the property to set for audio-only mode. - */ - virtual bool AudioOnlyMode(GstElement *sinkbin){return false;} - - /** - * @brief Sets the playback rate for the given GStreamer elements. - * - * @param sources A vector of GStreamer source elements. - * @param pipeline The main GStreamer pipeline. - * @param rate The desired playback rate. - * @param video_dec The video decoder element. - * @param audio_dec The audio decoder element. - * @return True if the playback rate was set successfully, false otherwise. - */ - virtual bool SetPlaybackRate(const std::vector& sources, GstElement *pipeline, double rate, GstElement *video_dec, GstElement *audio_dec) = 0; - - /** - * @brief Retrieves the source pad of the given GStreamer element. - * - * This is a pure virtual function that must be implemented by derived classes. - * - * @param element The GStreamer element to retrieve the source pad from. - * @return A pointer to the source pad of the element, or NULL if not found. - */ - virtual GstPad* GetSourcePad(GstElement* element){return NULL;} - - /** - * @brief Get video sink from sinkbin. - * @param sinkbin The GStreamer sinkbin. - */ - virtual GstElement* GetVideoSink(GstElement* sinkbin){return nullptr;} - - /** - * @brief Set AC4 tracks. - * @param src Source element. - * @param trackId Track ID. - */ - virtual void SetAC4Tracks(GstElement *src, int trackId) = 0; - - /** - * @brief Set platform playback rate. - * @return True on success, false otherwise. - */ - virtual bool SetPlatformPlaybackRate(){return false;} - - /** - * @brief Set rate correction. - * @return True on success, false otherwise. - */ - virtual bool SetRateCorrection() = 0; - - /** - * @brief Check if the given name is a video sink. - * @param name Element name. - * @param isRialto Rialto flag. - * @return True if it's a video sink, false otherwise. - */ - virtual bool IsVideoSink(const char* name, bool isRialto) = 0; - - /** - * @brief Check if the given name is an audio sink or audio decoder. - * @param name Element name. - * @param isRialto Rialto flag. - * @return True if it's an audio sink or audio decoder, false otherwise. - */ - virtual bool IsAudioSinkOrAudioDecoder(const char* name, bool isRialto) = 0; - - /** - * @brief Check if the given name is a video decoder. - * @param name Element name. - * @param isRialto Rialto flag. - * @param isWesteros Westeros flag. - * @return True if it's a video decoder, false otherwise. - */ - virtual bool IsVideoDecoder(const char* name, bool isRialto) = 0; - - /** - * @brief Configure the audio sink. - * @param audio_sink Pointer to the audio sink element. - * @param src Source object. - * @param decStreamSync Decoder stream synchronization flag. - * @return True on success, false otherwise. - */ - virtual bool ConfigureAudioSink(GstElement **audio_sink, GstObject *src, bool decStreamSync) = 0; - - /** - * @brief Check if the given name is an audio or video decoder. - * @param name Element name. - * @param IsWesteros Westeros flag. - * @return True if it's an audio or video decoder, false otherwise. - */ - virtual bool IsAudioOrVideoDecoder(const char* name, bool isRialto) = 0; - - /** - * @brief Disable asynchronous audio. - * @param audio_sink Audio sink element. - * @param rate Playback rate. - * @param isSeeking True if seeking is in progress, false otherwise. - * @return True if async changed from enabled to disabled, false otherwise. - */ - virtual bool DisableAsyncAudio(GstElement *audio_sink, int rate, bool isSeeking){return false;}; - - /** - * Gets the decoder handle from the video decoder element. - * - * @param dec_handle Pointer to store the decoder handle. - * @param video_dec The video decoder element. - */ - virtual void GetCCDecoderHandle(gpointer *dec_handle, GstElement *video_dec) = 0; - - /** - * @brief Resets the trick play UTC. - * - * @return True if the reset is required, false otherwise. - */ - virtual bool ResetTrickUTC(){return false;} - - /** - * @brief Get video PTS. - * - * Retrieves the current video presentation timestamp (PTS). - * - * @param video_sink The video sink element. - * @param video_dec The video decoder element. - * @param isWesteros A flag for Westeros logic. - * - * @return Video PTS in nanoseconds, or -1 on error. - */ - virtual long long GetVideoPts(GstElement *video_sink, GstElement *video_dec, bool isWesteros); - - /** - * @brief Notify first video frame. - */ - virtual bool NotifyVideoFirstFrame(){return false;} - - /** - * @brief Set decode error on source. - * - * Sets a decode error flag on the given source object. - * - * @param src The source object. - */ - virtual void SetDecodeError(GstObject* src); - - /** - * @brief Set freerun threshold on source. - * - * Sets the freerun threshold on the given source object. - * - * @param src The source object. - */ - virtual void SetFreerunThreshold(GstObject* src){}; - - /** - * @brief Check if element setup is required. - * - * Determines if the element requires setup before it can be used. - * - * @return True if setup is required, false otherwise. - */ - virtual bool RequiredElementSetup(){return false;} - - /** - * @brief Set audio routing properties on source. - * - * Sets audio routing properties on the given source element. - * - * @param source The source element. - */ - virtual void SetAudioRoutingProperties(GstElement *source){} - - /** - * @brief Check if first audio frame callback is set. - * - * Determines if a callback function has been set for the first audio frame. - * - * @return True if a callback is set, false otherwise. - */ - - virtual bool HasFirstAudioFrameCallback(){return true;} - - /** - * @brief Check if video sink errors are handled. - * - * Determines if the platform handles errors from the video sink. - * - * @return True if video sink errors are handled, false otherwise. - */ - virtual bool IsVideoSinkHandleErrors(){return false;} - - /** - * @brief Set playback flags. - * - * Sets the playback flags based on the given parameters. - * - * @param flags Reference to the flags integer. - * @param isSub Flag indicating whether the content is a subtitle. - */ - virtual void SetPlaybackFlags(gint &flags, bool isSub)=0; - - /** - * @brief checks if the firstFrame is received from the simulator - */ - virtual bool IsSimulatorFirstFrame(){return false;} - - /** - * @brief checks if the sink is from the simulator - */ - virtual bool IsSimulatorSink(){return false;} - - /** - * @brief Configure the plugin priority for PulseAudio. - */ - virtual void ConfigurePluginPriority(){}; - - /** - * @brief checks if the teardown is required for simulator - */ - virtual bool ShouldTearDownForTrickplay(){return false;} - - /** - * @brief checks if the video sample is from the simulator - */ - virtual bool IsSimulatorVideoSample(){return false;} - - /** - *@brief Sets the platform specific H264 caps - */ - virtual void SetH264Caps(GstCaps *caps){} - - /** - *@brief Sets the HEVC caps for simulator - */ - virtual void SetHevcCaps(GstCaps *caps){} - - virtual void DumpDiagnosis(){}; - - /** - * @brief Resets segment event flags during trickplay transitions. - * - * Manages segment event tracking for trickplay scenarios without disrupting seekplay or advertisements. - */ - virtual bool ResetNewSegmentEvent(){return false;} - /** - * @brief Checks if the platform segment is ready for processing new segment. - * - * This function returns a boolean value indicating whether the platform segment - * is ready. If the function returns `true`, it means the segment is ready; - * otherwise, it is not. - * - * @return `true` if the platform segment is ready, `false` otherwise. - */ - virtual bool IsPlatformSegmentReady(){return false;} - - /** - *@brief Checks if the platform is video master. - *@return 'true' if video master otherwise false. - */ - virtual bool IsVideoMaster(){return true;} - - - +protected: + /** + * @brief Infers the SoC type from device.properties. + * @return The SoC platform type. + */ + static SocPlatformType InferPlatformFromDeviceProperties( void ); + + /** + * @brief Checks if the input string starts with the given prefix. + * + * @param inputStr The input string to check. + * @param prefix The prefix to check for. + * + * @return True if the input string starts with the prefix, false otherwise. + */ + bool StartsWith( const char *inputStr, const char *prefix ); + + /*config to indicate platforms using westeros sink*/ + bool mUsingWesterosSink = false; + +public: + SocInterface() {} + + /** + * @brief Sets the state of Westeros Sink usage. + * + * This function updates the internal flag to indicate whether + * Westeros Sink is being used. It does not enable or disable + * Westeros Sink itself, but merely informs the SocInterface + * about its status. + * + * @param status Set to `true` if Westeros Sink is enabled, `false` otherwise. + */ + void SetWesterosSinkState(bool status); + + /*@brief returns true if video stats required from sink otherwise false*/ + virtual bool IsPlaybackQualityFromSink(){return false;} + + /** + * Sets buffer size and duration for the given GstElement. + * + * @param sink The GstElement to configure. + * @param size The desired buffer size. + */ + virtual void SetVideoBufferSize(GstElement *sink, int size){}; + + /** + * Sets asynchronous mode for the given Sink. + * + * @param sink element. + * @param status Enable (TRUE) or disable (FALSE) asynchronous mode. + */ + virtual void SetSinkAsync(GstElement *sink, gboolean status){} + + /** + * @brief Creates an instance of the SoC-specific interface. + * @return A pointer to the created SocInterface object. + */ + static std::shared_ptr CreateSocInterface(); + + /** + * @brief Check if AppSrc should be used. + * + * Determines whether the AppSrc element should be used in the current context. + * + * @return True if AppSrc should be used, false otherwise. + */ + virtual bool UseAppSrc(){return false;} + + /** + * @brief Check if AC4 should be disabled. + * + * Determines whether AC4 support should be disabled. + * + * @return True if AC4 should be disabled, false otherwise. + */ + virtual bool IsSupportedAC4(){return false;} + + /** + * @brief Check if Westeros sink should be used. + * + * Determines whether the Westeros sink should be used in the current context. + * + * @return True if platform uses Westeros sink, false otherwise. + */ + virtual bool UseWesterosSink(){return true;} + + /** + * @brief Check if audio fragments should be synchronized. + * + * Determines whether audio fragments should be synchronized. + * + * @return True if audio fragments should be synchronized, false otherwise. + */ + virtual bool IsAudioFragmentSyncSupported(){return false;} + + /** + * @brief Check if live latency correction should be enabled. + * + * Determines whether live latency correction should be enabled. + * + * @return True if live latency correction should be enabled, false otherwise. + */ + virtual bool EnableLiveLatencyCorrection(){return false;} + + /** + * @brief Get the required number of queued frames. + * + * Returns the total number of frames that should be queued. + * + * @return The required number of queued frames. + */ + virtual int RequiredQueuedFrames(){return REQUIRED_QUEUED_FRAMES_DEFAULT;} + + /** + * @brief Check if PTS restamping is supported by the platform. + * + * Determines whether the platform supports PTS restamping. + * + * @return True if PTS restamping is supported, false otherwise. + */ + virtual bool EnablePTSRestamp(){return false;} + + /** + * Checks if this is the first tune with Westeros disabled. + * + * @return True if this is the first tune with Westeros disabled for the current platform, false otherwise. + */ + virtual bool IsFirstTuneWithWesteros(){return false;} + + /** + * @brief Set SoC volume property name. + */ + virtual void SetAudioProperty(const char * &volume, const char * &mute, bool& isSinkBinVolume)=0; + + /** + * @brief enables the seamless switch property + * @param object The GStreamer element to configure. + * @param value True to enable seamless switching, false to disable. + */ + virtual void SetSeamlessSwitch(GstElement* object, gboolean value){} + + /** + * @brief Sets the sinkbin to audio-only mode. + * + * This is a pure virtual function that must be implemented by derived classes. + * + * @param sinkbin The GStreamer sinkbin to configure. + * @param property The name of the property to set for audio-only mode. + */ + virtual bool AudioOnlyMode(GstElement *sinkbin){return false;} + + /** + * @brief Sets the playback rate for the given GStreamer elements. + * + * @param sources A vector of GStreamer source elements. + * @param pipeline The main GStreamer pipeline. + * @param rate The desired playback rate. + * @param video_dec The video decoder element. + * @param audio_dec The audio decoder element. + * @return True if the playback rate was set successfully, false otherwise. + */ + virtual bool SetPlaybackRate(const std::vector& sources, GstElement *pipeline, double rate, GstElement *video_dec, GstElement *audio_dec) = 0; + + /** + * @brief Retrieves the source pad of the given GStreamer element. + * + * This is a pure virtual function that must be implemented by derived classes. + * + * @param element The GStreamer element to retrieve the source pad from. + * @return A pointer to the source pad of the element, or NULL if not found. + */ + virtual GstPad* GetSourcePad(GstElement* element){return NULL;} + + /** + * @brief Get video sink from sinkbin. + * @param sinkbin The GStreamer sinkbin. + */ + virtual GstElement* GetVideoSink(GstElement* sinkbin){return nullptr;} + + /** + * @brief Set AC4 tracks. + * @param src Source element. + * @param trackId Track ID. + */ + virtual void SetAC4Tracks(GstElement *src, int trackId) = 0; + + /** + * @brief Set platform playback rate. + * @return True on success, false otherwise. + */ + virtual bool SetPlatformPlaybackRate(){return false;} + + /** + * @brief Set rate correction. + * @return True on success, false otherwise. + */ + virtual bool SetRateCorrection() = 0; + + /** + * @brief Check if the given name is a video sink. + * @param name Element name. + * @param isRialto Rialto flag. + * @return True if it's a video sink, false otherwise. + */ + virtual bool IsVideoSink(const char* name, bool isRialto) = 0; + + /** + * @brief Check if the given name is an audio sink or audio decoder. + * @param name Element name. + * @param isRialto Rialto flag. + * @return True if it's an audio sink or audio decoder, false otherwise. + */ + virtual bool IsAudioSinkOrAudioDecoder(const char* name, bool isRialto) = 0; + + /** + * @brief Check if the given name is a video decoder. + * @param name Element name. + * @param isRialto Rialto flag. + * @param isWesteros Westeros flag. + * @return True if it's a video decoder, false otherwise. + */ + virtual bool IsVideoDecoder(const char* name, bool isRialto) = 0; + + /** + * @brief Configure the audio sink. + * @param audio_sink Pointer to the audio sink element. + * @param src Source object. + * @param decStreamSync Decoder stream synchronization flag. + * @return True on success, false otherwise. + */ + virtual bool ConfigureAudioSink(GstElement **audio_sink, GstObject *src, bool decStreamSync) = 0; + + /** + * @brief Check if the given name is an audio or video decoder. + * @param name Element name. + * @param IsWesteros Westeros flag. + * @return True if it's an audio or video decoder, false otherwise. + */ + virtual bool IsAudioOrVideoDecoder(const char* name, bool isRialto) = 0; + + /** + * @brief Disable asynchronous audio. + * @param audio_sink Audio sink element. + * @param rate Playback rate. + * @param isSeeking True if seeking is in progress, false otherwise. + * @return True if async changed from enabled to disabled, false otherwise. + */ + virtual bool DisableAsyncAudio(GstElement *audio_sink, int rate, bool isSeeking){return false;}; + + /** + * Gets the decoder handle from the video decoder element. + * + * @param dec_handle Pointer to store the decoder handle. + * @param video_dec The video decoder element. + */ + virtual void GetCCDecoderHandle(gpointer *dec_handle, GstElement *video_dec) = 0; + + /** + * @brief Resets the trick play UTC. + * + * @return True if the reset is required, false otherwise. + */ + virtual bool ResetTrickUTC(){return false;} + + /** + * @brief Get video PTS. + * + * Retrieves the current video presentation timestamp (PTS). + * + * @param video_sink The video sink element. + * @param video_dec The video decoder element. + * @param isWesteros A flag for Westeros logic. + * + * @return Video PTS in nanoseconds, or -1 on error. + */ + virtual long long GetVideoPts(GstElement *video_sink, GstElement *video_dec, bool isWesteros); + + /** + * @brief Notify first video frame. + */ + virtual bool NotifyVideoFirstFrame(){return false;} + + /** + * @brief Set decode error on source. + * + * Sets a decode error flag on the given source object. + * + * @param src The source object. + */ + virtual void SetDecodeError(GstObject* src); + + /** + * @brief Set freerun threshold on source. + * + * Sets the freerun threshold on the given source object. + * + * @param src The source object. + */ + virtual void SetFreerunThreshold(GstObject* src){}; + + /** + * @brief Check if element setup is required. + * + * Determines if the element requires setup before it can be used. + * + * @return True if setup is required, false otherwise. + */ + virtual bool RequiredElementSetup(){return false;} + + /** + * @brief Set audio routing properties on source. + * + * Sets audio routing properties on the given source element. + * + * @param source The source element. + */ + virtual void SetAudioRoutingProperties(GstElement *source){} + + /** + * @brief Check if first audio frame callback is set. + * + * Determines if a callback function has been set for the first audio frame. + * + * @return True if a callback is set, false otherwise. + */ + + virtual bool HasFirstAudioFrameCallback(){return true;} + + /** + * @brief Check if video sink errors are handled. + * + * Determines if the platform handles errors from the video sink. + * + * @return True if video sink errors are handled, false otherwise. + */ + virtual bool IsVideoSinkHandleErrors(){return false;} + + /** + * @brief Set playback flags. + * + * Sets the playback flags based on the given parameters. + * + * @param flags Reference to the flags integer. + * @param isSub Flag indicating whether the content is a subtitle. + */ + virtual void SetPlaybackFlags(gint &flags, bool isSub)=0; + + /** + * @brief checks if the firstFrame is received from the simulator + */ + virtual bool IsSimulatorFirstFrame(){return false;} + + /** + * @brief checks if the sink is from the simulator + */ + virtual bool IsSimulatorSink(){return false;} + + /** + * @brief Configure the plugin priority for PulseAudio. + */ + virtual void ConfigurePluginPriority(){}; + + /** + * @brief checks if the teardown is required for simulator + */ + virtual bool ShouldTearDownForTrickplay(){return false;} + + /** + * @brief checks if the video sample is from the simulator + */ + virtual bool IsSimulatorVideoSample(){return false;} + + /** + *@brief Sets the platform specific H264 caps + */ + virtual void SetH264Caps(GstCaps *caps){} + + /** + *@brief Sets the HEVC caps for simulator + */ + virtual void SetHevcCaps(GstCaps *caps){} + + /** + * @brief Resets segment event flags during trickplay transitions. + * + * Manages segment event tracking for trickplay scenarios without disrupting seekplay or advertisements. + */ + virtual bool ResetNewSegmentEvent(){return false;} + + /** + * @brief Checks if the platform segment is ready for processing new segment. + * + * This function returns a boolean value indicating whether the platform segment + * is ready. If the function returns `true`, it means the segment is ready; + * otherwise, it is not. + * + * @return `true` if the platform segment is ready, `false` otherwise. + */ + virtual bool IsPlatformSegmentReady(){return false;} + + /** + *@brief Checks if the platform is video master. + *@return 'true' if video master otherwise false. + */ + virtual bool IsVideoMaster(){return true;} }; #endif diff --git a/vendor/amlogic/AmlogicSocInterface.cpp b/vendor/amlogic/AmlogicSocInterface.cpp index 2335c69b..5e78dc30 100644 --- a/vendor/amlogic/AmlogicSocInterface.cpp +++ b/vendor/amlogic/AmlogicSocInterface.cpp @@ -30,11 +30,11 @@ AmlogicSocInterface::AmlogicSocInterface() * @brief Get SoC volume property name. * @return Volume property name. */ -void AmlogicSocInterface::SetAudioProperty(const char **volume, const char **mute, bool& isSinkBinVolume) +void AmlogicSocInterface::SetAudioProperty(const char * &volume, const char * &mute, bool& isSinkBinVolume) { /* Avoid mute property setting for AMLOGIC as use of "mute" property on pipeline is impacting all other players */ /* Using "stream-volume" property of audio-sink for setting volume and mute for AMLOGIC platform */ - *volume = "stream-volume"; + volume = "stream-volume"; isSinkBinVolume = false; } diff --git a/vendor/amlogic/AmlogicSocInterface.h b/vendor/amlogic/AmlogicSocInterface.h index d416bd61..f9d2fcc4 100644 --- a/vendor/amlogic/AmlogicSocInterface.h +++ b/vendor/amlogic/AmlogicSocInterface.h @@ -21,9 +21,7 @@ #define AMLOGIC_SOC_INTERFACE_H #include "SocInterface.h" -#if defined(AMLOGIC) -#include "gst_svp_meta.h" -#endif + /** * @brief Amlogic SoC interface class. * @@ -45,7 +43,7 @@ class AmlogicSocInterface : public SocInterface * @brief Get SoC volume property name. * @return Volume property name. */ - void SetAudioProperty(const char **volume, const char **mute, bool& isSinkBinVolume)override; + void SetAudioProperty(const char * &volume, const char * &mute, bool& isSinkBinVolume)override; /** * @brief enables the seamless switch property @@ -98,7 +96,7 @@ class AmlogicSocInterface : public SocInterface * @return True on success, false otherwise. */ bool SetRateCorrection() override {return false;} - + /** * @brief Check if the given name is a video sink. * @param name Element name. diff --git a/vendor/brcm/BrcmSocInterface.cpp b/vendor/brcm/BrcmSocInterface.cpp index fc6e92ba..8c2feb43 100644 --- a/vendor/brcm/BrcmSocInterface.cpp +++ b/vendor/brcm/BrcmSocInterface.cpp @@ -27,10 +27,10 @@ BrcmSocInterface::BrcmSocInterface() * @brief Get SoC volume property name. * @return Volume property name. */ -void BrcmSocInterface::SetAudioProperty(const char **volume, const char **mute, bool& isSinkBinVolume) +void BrcmSocInterface::SetAudioProperty(const char * &volume, const char * &mute, bool& isSinkBinVolume) { - *volume = "volume"; - *mute = "mute"; + volume = "volume"; + mute = "mute"; isSinkBinVolume = false; /*volume/mute property should be applied on audio_sink*/ } @@ -255,10 +255,3 @@ void BrcmSocInterface::SetPlaybackFlags(gint &flags, bool isSub) flags = PLAY_FLAG_TEXT; } } - -void BrcmSocInterface::DumpDiagnosis() -{ - DumpFile("/proc/brcm/transport"); - DumpFile("/proc/brcm/video_decoder"); - DumpFile("/proc/brcm/audio"); -} diff --git a/vendor/brcm/BrcmSocInterface.h b/vendor/brcm/BrcmSocInterface.h index 1cbcfbda..91ae124a 100644 --- a/vendor/brcm/BrcmSocInterface.h +++ b/vendor/brcm/BrcmSocInterface.h @@ -40,7 +40,7 @@ class BrcmSocInterface : public SocInterface * @return True if AC4 should be disabled, false otherwise. */ bool IsSupportedAC4()override{return true;} - + /** * @brief Check if PTS restamping is supported by the platform. * @@ -54,7 +54,7 @@ class BrcmSocInterface : public SocInterface * @brief Get SoC volume property name. * @return Volume property name. */ - void SetAudioProperty(const char **volume, const char **mute, bool& isSinkBinVolume)override; + void SetAudioProperty(const char * &volume, const char * &mute, bool& isSinkBinVolume)override; /** * @brief Sets the playback rate for the given GStreamer elements. @@ -143,9 +143,6 @@ class BrcmSocInterface : public SocInterface * @param isSub Flag indicating whether the content is a subtitle. */ void SetPlaybackFlags(gint &flags, bool isSub)override; - - void DumpDiagnosis()override; - }; diff --git a/vendor/default/DefaultSocInterface.cpp b/vendor/default/DefaultSocInterface.cpp index 11a654a5..d99a5365 100644 --- a/vendor/default/DefaultSocInterface.cpp +++ b/vendor/default/DefaultSocInterface.cpp @@ -42,11 +42,11 @@ bool DefaultSocInterface::UseAppSrc() * @brief Get SoC volume property name. * @return Volume property name. */ -void DefaultSocInterface::SetAudioProperty(const char **volume, const char **mute, bool& isSinkBinVolume) +void DefaultSocInterface::SetAudioProperty(const char * &volume, const char * &mute, bool& isSinkBinVolume) { isSinkBinVolume = false; - *volume = "volume"; - *mute = "mute"; + volume = "volume"; + mute = "mute"; #if defined(__APPLE__) isSinkBinVolume = true; #endif diff --git a/vendor/default/DefaultSocInterface.h b/vendor/default/DefaultSocInterface.h index 96c4ddb9..8338eca1 100644 --- a/vendor/default/DefaultSocInterface.h +++ b/vendor/default/DefaultSocInterface.h @@ -55,7 +55,7 @@ class DefaultSocInterface : public SocInterface * @brief Get volume property name. * @return Volume property name. */ - void SetAudioProperty(const char **volume, const char **mute, bool& isSinkBinVolume)override; + void SetAudioProperty(const char * &volume, const char * &mute, bool& isSinkBinVolume)override; /** * @brief Sets the playback rate for the given GStreamer elements. diff --git a/vendor/realtek/RealtekSocInterface.cpp b/vendor/realtek/RealtekSocInterface.cpp index b4735ad0..cb57a10c 100644 --- a/vendor/realtek/RealtekSocInterface.cpp +++ b/vendor/realtek/RealtekSocInterface.cpp @@ -52,10 +52,10 @@ void RealtekSocInterface::SetSinkAsync(GstElement *sink, gboolean status) * @brief Get SoC volume property name. * @return Volume property name. */ -void RealtekSocInterface::SetAudioProperty(const char **volume, const char **mute, bool& isSinkBinVolume) +void RealtekSocInterface::SetAudioProperty(const char * &volume, const char * &mute, bool& isSinkBinVolume) { - *volume = "volume"; - *mute = "mute"; + volume = "volume"; + mute = "mute"; isSinkBinVolume = true; /*volume/mute property should be applied on sinkbin*/ } @@ -355,6 +355,7 @@ void RealtekSocInterface::SetH264Caps(GstCaps *caps) gst_caps_set_simple (caps, "enable-fastplayback", G_TYPE_STRING, "true", NULL); } + /** * @brief Get video sink from sinkbin. * @param sinkbin The GStreamer sinkbin. diff --git a/vendor/realtek/RealtekSocInterface.h b/vendor/realtek/RealtekSocInterface.h index 8521b3c4..50ff2957 100644 --- a/vendor/realtek/RealtekSocInterface.h +++ b/vendor/realtek/RealtekSocInterface.h @@ -43,7 +43,7 @@ class RealtekSocInterface : public SocInterface * @return True if audio fragments should be synchronized, false otherwise. */ bool IsAudioFragmentSyncSupported()override{return true;} - + /*@brief returns true if video stats required from sink otherwise false*/ bool IsPlaybackQualityFromSink() override {return true;} @@ -100,7 +100,7 @@ class RealtekSocInterface : public SocInterface * @brief Get SoC volume property name. * @return Volume property name. */ - void SetAudioProperty(const char **volume, const char **mute, bool& isSinkBinVolume)override; + void SetAudioProperty(const char * &volume, const char * &mute, bool& isSinkBinVolume)override; /** * @brief Sets the playback rate for the given GStreamer elements.