Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,12 @@ endif()
if (CMAKE_PLAYER_TELEMETRY_SUPPORT)
message("CMAKE_PLAYER_TELEMETRY_SUPPORT set")
set(LIBPLAYERGSTINTERFACE_DEFINES "${LIBPLAYERGSTINTERFACE_DEFINES} -DPLAYER_TELEMETRY_SUPPORT")
set(LIBPLAYERGSTINTERFACE_SOURCES ${LIBPLAYERGSTINTERFACE_SOURCES} PlayerTelemetry.cpp)
find_path(TELEMETRY2_INCDIR telemetry2_marker.h)
if(TELEMETRY2_INCDIR)
include_directories(${TELEMETRY2_INCDIR})
endif()
set(LIBPLAYERGSTINTERFACE_DEPENDS "${LIBPLAYERGSTINTERFACE_DEPENDS} -ltelemetry2")
endif()

if (CMAKE_SUBTITLE_SUPPORT)
Expand Down
2 changes: 2 additions & 0 deletions GstHandlerControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,12 @@ bool GstHandlerControl::waitForDone(int MaximumDelayMilliseconds, std::string na
MW_LOG_ERR("GstPlayer: %d instance%s of %s running",
mInstanceCount, mInstanceCount?"s":"", name.c_str());
{
#ifdef PLAYER_TELEMETRY_SUPPORT
TelemetryPayload handlerPayload;
handlerPayload.add("handler", name);
handlerPayload.add("count", mInstanceCount);
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_HANDLER_TIMEOUT, handlerPayload);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
return false;
}
Expand Down
40 changes: 40 additions & 0 deletions InterfacePlayerRDK.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,17 @@ mSourceSetupCV(), mScheduler(), callbackMap(), setupStreamCallbackMap(), mDrmSys
pthread_mutex_init(&interfacePlayerPriv->gstPrivateContext->stream[i].sourceLock, NULL);
// start Scheduler Worker for task handling
mScheduler.StartScheduler();
#ifdef PLAYER_TELEMETRY_SUPPORT
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_INITIALIZED);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}

/* InterfacePlayerRDK destructor*/
InterfacePlayerRDK::~InterfacePlayerRDK()
{
#ifdef PLAYER_TELEMETRY_SUPPORT
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_SHUTDOWN);
#endif /* PLAYER_TELEMETRY_SUPPORT */
DestroyPipeline();
if (mDrmSystem)
{
Expand Down Expand Up @@ -414,10 +418,12 @@ void InterfacePlayerRDK::ConfigurePipeline(int format, int audioFormat, int subF
{
MW_LOG_MIL("AudioType Changed. Force configure pipeline");
{
#ifdef PLAYER_TELEMETRY_SUPPORT
TelemetryPayload trackSwitchedPayload;
trackSwitchedPayload.add("trackType", "audio");
trackSwitchedPayload.add("trackId", trackId);
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_TRACK_SWITCHED, trackSwitchedPayload);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
configureStream[i] = true;
}
Expand Down Expand Up @@ -489,11 +495,13 @@ void InterfacePlayerRDK::ConfigurePipeline(int format, int audioFormat, int subF
{
MW_LOG_ERR("InterfacePlayerRDK: GST_STATE_PAUSED failed");
{
#ifdef PLAYER_TELEMETRY_SUPPORT
TelemetryPayload pauseOnStartPayload;
pauseOnStartPayload.add("fromState", "NULL");
pauseOnStartPayload.add("toState", "PAUSED");
pauseOnStartPayload.add("context", "ConfigurePipeline_pauseOnStart");
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_PIPELINE_STATE_CHANGE_FAILURE, pauseOnStartPayload);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
}
}
Expand All @@ -509,16 +517,20 @@ void InterfacePlayerRDK::ConfigurePipeline(int format, int audioFormat, int subF
{
MW_LOG_ERR("InterfacePlayerRDK_Configure GST_STATE_PAUSED failed");
{
#ifdef PLAYER_TELEMETRY_SUPPORT
TelemetryPayload bufferingPausePayload;
bufferingPausePayload.add("fromState", "NULL");
bufferingPausePayload.add("toState", "PAUSED");
bufferingPausePayload.add("context", "ConfigurePipeline_buffering");
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_PIPELINE_STATE_CHANGE_FAILURE, bufferingPausePayload);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
}
else
{
#ifdef PLAYER_TELEMETRY_SUPPORT
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_BUFFERING_STARTED);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
interfacePlayerPriv->gstPrivateContext->pendingPlayState = false;
interfacePlayerPriv->gstPrivateContext->paused = false;
Expand All @@ -530,16 +542,20 @@ void InterfacePlayerRDK::ConfigurePipeline(int format, int audioFormat, int subF
{
MW_LOG_ERR("InterfacePlayerRDK: GST_STATE_PLAYING failed");
{
#ifdef PLAYER_TELEMETRY_SUPPORT
TelemetryPayload playingFailPayload;
playingFailPayload.add("fromState", "PAUSED");
playingFailPayload.add("toState", "PLAYING");
playingFailPayload.add("context", "ConfigurePipeline");
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_PIPELINE_STATE_CHANGE_FAILURE, playingFailPayload);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
}
else
{
#ifdef PLAYER_TELEMETRY_SUPPORT
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_PLAYBACK_STARTED);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
interfacePlayerPriv->gstPrivateContext->pendingPlayState = false;
interfacePlayerPriv->gstPrivateContext->paused = false;
Expand Down Expand Up @@ -1429,7 +1445,9 @@ void InterfacePlayerRDK::TearDownStream(int type)
void InterfacePlayerRDK::Stop(bool keepLastFrame)
{
std::lock_guard<std::mutex> lock(mMutex);
#ifdef PLAYER_TELEMETRY_SUPPORT
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_PLAYBACK_STOPPED);
#endif /* PLAYER_TELEMETRY_SUPPORT */
/* make the execution of this function more deterministic and
* reduce scope for potential pipeline lockups*/

Expand Down Expand Up @@ -1697,10 +1715,12 @@ bool InterfacePlayerRDK::Flush(double position, int rate, bool shouldTearDown, b
ResetGstEvents();
MW_LOG_INFO("InterfacePlayerRDK: Pipeline flush seek - start = %f rate = %d", position, rate);
{
#ifdef PLAYER_TELEMETRY_SUPPORT
TelemetryPayload seekStartedPayload;
seekStartedPayload.add("position", position);
seekStartedPayload.add("rate", rate);
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_SEEK_STARTED, seekStartedPayload);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
double playRate = 1.0;
if (eGST_MEDIAFORMAT_PROGRESSIVE == static_cast<GstMediaFormat>(m_gstConfigParam->media))
Expand All @@ -1726,10 +1746,12 @@ bool InterfacePlayerRDK::Flush(double position, int rate, bool shouldTearDown, b
}
else
{
#ifdef PLAYER_TELEMETRY_SUPPORT
TelemetryPayload seekCompletedPayload;
seekCompletedPayload.add("position", position);
seekCompletedPayload.add("rate", rate);
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_SEEK_COMPLETED, seekCompletedPayload);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}

if ((interfacePlayerPriv->gstPrivateContext->usingRialtoSink) &&
Expand Down Expand Up @@ -2944,7 +2966,9 @@ bool InterfacePlayerRDK::StopBuffering(bool forceStop, bool &isPlaying)
if (current == GST_STATE_PLAYING)
{
sendEndEvent = true;
#ifdef PLAYER_TELEMETRY_SUPPORT
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_BUFFERING_ENDED);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
}
}
Expand Down Expand Up @@ -3397,30 +3421,38 @@ bool InterfacePlayerRDK::Pause(bool pause , bool forceStopGstreamerPreBuffering)
{
MW_LOG_ERR("InterfacePlayerRDK_Pause - validateStateWithMsTimeout - FAILED GstState %d", nextState);
{
#ifdef PLAYER_TELEMETRY_SUPPORT
TelemetryPayload pauseTimeoutPayload;
pauseTimeoutPayload.add("toState", pause ? "PAUSED" : "PLAYING");
pauseTimeoutPayload.add("context", "Pause_timeout");
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_PIPELINE_STATE_CHANGE_FAILURE, pauseTimeoutPayload);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
}
else
{
#ifdef PLAYER_TELEMETRY_SUPPORT
PlayerTelemetry::sendEvent(pause ? TELEMETRY_EVENT_PLAYBACK_PAUSED : TELEMETRY_EVENT_PLAYBACK_RESUMED);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
}
else if (GST_STATE_CHANGE_SUCCESS != rc)
{
MW_LOG_ERR("InterfacePlayerRDK_Pause - gst_element_set_state - FAILED rc %d", rc);
{
#ifdef PLAYER_TELEMETRY_SUPPORT
TelemetryPayload pauseFailPayload;
pauseFailPayload.add("toState", pause ? "PAUSED" : "PLAYING");
pauseFailPayload.add("context", "Pause_failure");
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_PIPELINE_STATE_CHANGE_FAILURE, pauseFailPayload);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
}
else
{
#ifdef PLAYER_TELEMETRY_SUPPORT
PlayerTelemetry::sendEvent(pause ? TELEMETRY_EVENT_PLAYBACK_PAUSED : TELEMETRY_EVENT_PLAYBACK_RESUMED);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}

interfacePlayerPriv->gstPrivateContext->buffering_target_state = nextState;
Expand Down Expand Up @@ -4182,10 +4214,12 @@ static void GstPlayer_OnGstDecodeErrorCb(GstElement* object, guint arg0, gpointe
privatePlayer->gstPrivateContext->decodeErrorMsgTimeMS = NOW_STEADY_TS_MS;
MW_LOG_ERR("Got Decode Error message from %s total_cb=%d timeMs=%d", GST_ELEMENT_NAME(object), privatePlayer->gstPrivateContext->decodeErrorCBCount, GST_MIN_DECODE_ERROR_INTERVAL);
{
#ifdef PLAYER_TELEMETRY_SUPPORT
TelemetryPayload decodeErrPayload;
decodeErrPayload.add("element", GST_ELEMENT_NAME(object) ? GST_ELEMENT_NAME(object) : "unknown");
decodeErrPayload.add("count", privatePlayer->gstPrivateContext->decodeErrorCBCount);
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_DECODE_ERROR, decodeErrPayload);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
privatePlayer->gstPrivateContext->decodeErrorCBCount = 0;
#ifdef USE_EXTERNAL_STATS
Expand Down Expand Up @@ -4231,6 +4265,7 @@ static gboolean bus_message(GstBus * bus, GstMessage * msg, InterfacePlayerRDK *
}
pInterfacePlayerRDK->busMessageCallback(std::move(busEvent));
MW_LOG_ERR("Debug Info: %s\n", (dbg_info) ? dbg_info : "none");
#ifdef PLAYER_TELEMETRY_SUPPORT
if (error->domain == GST_RESOURCE_ERROR)
{
TelemetryPayload networkErrPayload;
Expand All @@ -4247,6 +4282,7 @@ static gboolean bus_message(GstBus * bus, GstMessage * msg, InterfacePlayerRDK *
errPayload.add("debugInfo", dbg_info ? dbg_info : "none");
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_ERROR, errPayload);
}
#endif /* PLAYER_TELEMETRY_SUPPORT */
g_clear_error(&error);
g_free(dbg_info);
break;
Expand Down Expand Up @@ -4451,9 +4487,11 @@ static gboolean bus_message(GstBus * bus, GstMessage * msg, InterfacePlayerRDK *
pInterfacePlayerRDK->busMessageCallback(std::move(busEvent));
MW_LOG_MIL("GST_MESSAGE_EOS");
{
#ifdef PLAYER_TELEMETRY_SUPPORT
TelemetryPayload eosPayload;
eosPayload.add("element", GST_OBJECT_NAME(msg->src) ? GST_OBJECT_NAME(msg->src) : "unknown");
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_EOS_DETECTED, eosPayload);
#endif /* PLAYER_TELEMETRY_SUPPORT */
}
pInterfacePlayerRDK->NotifyEOS();
break;
Expand Down Expand Up @@ -5037,7 +5075,9 @@ void InterfacePlayerRDK::NotifyEOS()
interfacePlayerPriv->gstPrivateContext->eosCallbackIdleTaskPending = true;
// eosSignalled is reset once the async task is completed either in Configure/Flush/ResetEOSSignalled, so set the flag before scheduling the task
interfacePlayerPriv->gstPrivateContext->eosSignalled = true;
#ifdef PLAYER_TELEMETRY_SUPPORT
PlayerTelemetry::sendEvent(TELEMETRY_EVENT_PLAYBACK_COMPLETED);
#endif /* PLAYER_TELEMETRY_SUPPORT */
interfacePlayerPriv->gstPrivateContext->eosCallbackIdleTaskId = mScheduler.ScheduleTask(PlayerAsyncTaskObj(IdleCallbackOnEOS, (void *)this, "IdleCallbackOnEOS"));
if (interfacePlayerPriv->gstPrivateContext->eosCallbackIdleTaskId == PLAYER_TASK_ID_INVALID && true == interfacePlayerPriv->gstPrivateContext->eosCallbackIdleTaskPending)
{
Expand Down
66 changes: 66 additions & 0 deletions PlayerTelemetry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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.
*/

/**
* @file PlayerTelemetry.cpp
* @brief Implementation of PlayerTelemetry::sendEvent() using the Telemetry 2.0 framework.
*
* Compiled only when PLAYER_TELEMETRY_SUPPORT is defined. Each event is
* forwarded to t2_event_s() so that it is picked up by the platform telemetry
* back-end.
*/

#ifdef PLAYER_TELEMETRY_SUPPORT

#include "PlayerTelemetry2.hpp"
#include <telemetry2_marker.h>

#include "PlayerTelemetry.h"

/**
* @brief Emit a telemetry event with no additional payload.
*/
void PlayerTelemetry::sendEvent(const std::string& eventName)
{
/* t2_event_s() is a C API that takes char* but does not modify the string. */
t2_event_s(const_cast<char*>(eventName.c_str()), const_cast<char*>("1"));
}

/**
* @brief Emit a telemetry event with a structured key/value payload.
*
* The payload fields are serialised as a single space-separated
* "key=value" string and forwarded as the t2_event_s value argument.
*/
void PlayerTelemetry::sendEvent(const std::string& eventName, const TelemetryPayload& payload)
{
std::string fields;
for (const auto& kv : payload.fields())
{
if (!fields.empty())
{
fields += ' ';
}
fields += kv.first + '=' + kv.second;
}
/* t2_event_s() is a C API that takes char* but does not modify the strings. */
t2_event_s(const_cast<char*>(eventName.c_str()), const_cast<char*>(fields.c_str()));
}

#endif /* PLAYER_TELEMETRY_SUPPORT */
22 changes: 4 additions & 18 deletions PlayerTelemetry.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@

#include <string>
#include <map>
#include "PlayerLogManager.h"

/**
* @class TelemetryPayload
Expand Down Expand Up @@ -106,6 +105,8 @@ class TelemetryPayload
* @brief Static helper for emitting named telemetry events with optional payload data.
*
* Active implementation compiled when PLAYER_TELEMETRY_SUPPORT is defined.
* The method bodies are provided in PlayerTelemetry.cpp which uses the
* Telemetry 2.0 framework (t2_event_s).
*/
class PlayerTelemetry
{
Expand All @@ -114,29 +115,14 @@ class PlayerTelemetry
* @brief Emit a telemetry event with no additional payload.
* @param[in] eventName One of the TELEMETRY_EVENT_* markers from TelemetryMarkers.h.
*/
static void sendEvent(const std::string& eventName)
{
MW_LOG_MIL("[TELEMETRY] event=%s", eventName.c_str());
}
static void sendEvent(const std::string& eventName);

/**
* @brief Emit a telemetry event with a structured key/value payload.
* @param[in] eventName One of the TELEMETRY_EVENT_* markers from TelemetryMarkers.h.
* @param[in] payload Additional context data built with TelemetryPayload::add().
*/
static void sendEvent(const std::string& eventName, const TelemetryPayload& payload)
{
std::string fields;
for (const auto& kv : payload.fields())
{
if (!fields.empty())
{
fields += ' ';
}
fields += kv.first + '=' + kv.second;
}
MW_LOG_MIL("[TELEMETRY] event=%s %s", eventName.c_str(), fields.c_str());
}
static void sendEvent(const std::string& eventName, const TelemetryPayload& payload);

private:
PlayerTelemetry() = delete;
Expand Down
Loading