Skip to content
Open
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
7 changes: 6 additions & 1 deletion media/client/ipc/source/MediaKeysIpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ const char *toString(const firebolt::rialto::MediaKeyErrorStatus &errorStatus)
{
return "FAIL";
}
case firebolt::rialto::MediaKeyErrorStatus::OUTPUT_RESTRICTED:
{
return "OUTPUT_RESTRICTED";
}
}
return "UNKNOWN";
}
Expand Down Expand Up @@ -334,7 +338,7 @@ bool MediaKeysIpc::containsKey(int32_t keySessionId, const std::vector<uint8_t>
}

MediaKeyErrorStatus MediaKeysIpc::createKeySession(KeySessionType sessionType, std::weak_ptr<IMediaKeysClient> client,
bool isLDL, int32_t &keySessionId)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the indentation

bool isLDL, int32_t &keySessionId)
{
if (!reattachChannelIfRequired())
{
Expand Down Expand Up @@ -415,6 +419,7 @@ MediaKeyErrorStatus MediaKeysIpc::generateRequest(int32_t keySessionId, InitData
break;
}


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this line

firebolt::rialto::GenerateRequestRequest request;
request.set_media_keys_handle(m_mediaKeysHandle);
request.set_key_session_id(keySessionId);
Expand Down
4 changes: 3 additions & 1 deletion media/public/include/MediaCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,8 @@ enum class MediaKeyErrorStatus
NOT_SUPPORTED, /**< The request parameters are not supported. */
INVALID_STATE, /**< The object is in an invalid state for the operation. */
INTERFACE_NOT_IMPLEMENTED, /**< The interface is not implemented. */
BUFFER_TOO_SMALL /**< The size of the buffer is too small. */
BUFFER_TOO_SMALL, /**< The size of the buffer is too small. */
OUTPUT_RESTRICTED
Comment on lines +295 to +296
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First note: Please add the Doxygen comment, as it was requested by the Copilot.
Second note: You changed the public interface here, I believe new status needs to be handled in rialto-ocdm to forward this information to the client app

};

/**
Expand Down Expand Up @@ -473,6 +474,7 @@ struct PlaybackInfo
int64_t currentPosition{-1}; /**< The current playback position */
double volume{1.0}; /**< The current volume */
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this extra line

} // namespace firebolt::rialto

#endif // FIREBOLT_RIALTO_MEDIA_COMMON_H_
8 changes: 7 additions & 1 deletion media/server/ipc/source/MediaKeysModuleService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ convertMediaKeyErrorStatus(const firebolt::rialto::MediaKeyErrorStatus &errorSta
{
return firebolt::rialto::ProtoMediaKeyErrorStatus::FAIL;
}
case firebolt::rialto::MediaKeyErrorStatus::OUTPUT_RESTRICTED:
{
// TODO
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implement this

}
}
Comment on lines +69 to 73
return firebolt::rialto::ProtoMediaKeyErrorStatus::FAIL;
Comment on lines 67 to 74
Comment on lines 66 to 74
Comment on lines +69 to 74
Comment on lines 66 to 74
}
Expand Down Expand Up @@ -100,6 +104,7 @@ firebolt::rialto::InitDataType covertInitDataType(firebolt::rialto::GenerateRequ
return firebolt::rialto::InitDataType::UNKNOWN;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this line

} // namespace

namespace firebolt::rialto::server::ipc
Expand Down Expand Up @@ -277,11 +282,12 @@ void MediaKeysModuleService::generateRequest(::google::protobuf::RpcController *
::google::protobuf::Closure *done)
{
RIALTO_SERVER_LOG_DEBUG("entry:");

MediaKeyErrorStatus status = m_cdmService.generateRequest(request->media_keys_handle(), request->key_session_id(),
covertInitDataType(request->init_data_type()),
std::vector<std::uint8_t>{request->init_data().begin(),
request->init_data().end()});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove those empty lines


response->set_error_status(convertMediaKeyErrorStatus(status));
done->Run();
}
Expand Down
12 changes: 12 additions & 0 deletions media/server/main/include/MediaKeysServerInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include <memory>
#include <string>
#include <vector>
#include <atomic>
#include <mutex>
#include <condition_variable>

namespace firebolt::rialto::server
{
Expand Down Expand Up @@ -149,6 +152,15 @@ class MediaKeysServerInternal : public IMediaKeysServerInternal
*/
uint32_t m_mainThreadClientId;


std::atomic_bool m_isShuttingDown{false};

std::atomic_bool m_outputWasRestricted{false};

std::atomic<GstClockTime> m_currentPositionPts{0};

std::atomic_bool m_hasCurrentPositionPts{false};

/**
* @brief Creates a session internally, only to be called on the main thread.
*
Expand Down
2 changes: 2 additions & 0 deletions media/server/main/source/MediaKeysCapabilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ const char *toString(const firebolt::rialto::MediaKeyErrorStatus &status)
return "NOT_SUPPORTED";
case firebolt::rialto::MediaKeyErrorStatus::INVALID_STATE:
return "INVALID_STATE";
case firebolt::rialto::MediaKeyErrorStatus::OUTPUT_RESTRICTED:
return "OUTPUT_RESTRICTED";
}
return "Unknown";
}
Expand Down
123 changes: 116 additions & 7 deletions media/server/main/source/MediaKeysServerInternal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,40 @@
*/

#include <stdexcept>
#include <chrono>
#include <thread>

#include "MediaKeysServerInternal.h"
#include "RialtoServerLogging.h"

/*namespace
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented out code

{
const char *toString(const firebolt::rialto::MediaKeyErrorStatus &status)
{
switch (status)
{
case firebolt::rialto::MediaKeyErrorStatus::OK:
return "OK";
case firebolt::rialto::MediaKeyErrorStatus::FAIL:
return "FAIL";
case firebolt::rialto::MediaKeyErrorStatus::BAD_SESSION_ID:
return "BAD_SESSION_ID";
case firebolt::rialto::MediaKeyErrorStatus::INTERFACE_NOT_IMPLEMENTED:
return "INTERFACE_NOT_IMPLEMENTED";
case firebolt::rialto::MediaKeyErrorStatus::BUFFER_TOO_SMALL:
return "BUFFER_TOO_SMALL";
case firebolt::rialto::MediaKeyErrorStatus::NOT_SUPPORTED:
return "NOT_SUPPORTED";
case firebolt::rialto::MediaKeyErrorStatus::INVALID_STATE:
return "INVALID_STATE";
case firebolt::rialto::MediaKeyErrorStatus::OUTPUT_RESTRICTED:
return "OUTPUT_RESTRICTED";
}
return "Unknown";
}
} */// namespace

Comment on lines +27 to +53
Comment on lines +27 to +53

namespace firebolt::rialto
{
const char *mediaKeyErrorStatusToString(const MediaKeyErrorStatus &status)
Expand Down Expand Up @@ -51,6 +81,10 @@ std::shared_ptr<IMediaKeysFactory> IMediaKeysFactory::createFactory()

namespace firebolt::rialto::server
{
constexpr std::chrono::milliseconds kOutputRestrictedRetryInterval{250};
constexpr std::chrono::seconds kOutputRestrictedRetryTimeout{6};
constexpr GstClockTime kStaleThreshold{4 * GST_SECOND};

Comment on lines +84 to +87
int32_t generateSessionId()
{
Comment on lines +84 to 89
static int32_t keySessionId{0};
Expand Down Expand Up @@ -140,12 +174,14 @@ MediaKeysServerInternal::MediaKeysServerInternal(
{
throw std::runtime_error("MediaKeys construction failed");
}

m_outputWasRestricted = false;
}

MediaKeysServerInternal::~MediaKeysServerInternal()
{
RIALTO_SERVER_LOG_DEBUG("entry:");

m_isShuttingDown = true;
auto task = [&]()
{
m_ocdmSystem.reset();
Expand Down Expand Up @@ -569,12 +605,83 @@ MediaKeyErrorStatus MediaKeysServerInternal::getCdmKeySessionIdInternal(int32_t

MediaKeyErrorStatus MediaKeysServerInternal::decrypt(int32_t keySessionId, GstBuffer *encrypted, GstCaps *caps)
{
RIALTO_SERVER_LOG_DEBUG("entry:");
RIALTO_SERVER_LOG_ERROR("DEBUG PURPOSE: entry:decrypt");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert this


MediaKeyErrorStatus status;
auto task = [&]() { status = decryptInternal(keySessionId, encrypted, caps); };
MediaKeyErrorStatus status{MediaKeyErrorStatus::FAIL};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation should be moved to the decryptInternal, in such case you won't need atomics in MediaPipelineServerInternal.h and we will keep the right call order


if (GST_BUFFER_PTS_IS_VALID(encrypted))
{
GstClockTime bufferPts = GST_BUFFER_PTS(encrypted);

if (!m_hasCurrentPositionPts.load() || bufferPts > m_currentPositionPts.load())
{
m_currentPositionPts = bufferPts;
m_hasCurrentPositionPts = true;
}

// After OUTPUT_RESTRICTED recovery, drop buffered segments that are behind live playback.
const GstClockTime currentPos = m_currentPositionPts.load();
if (m_outputWasRestricted.load() && m_hasCurrentPositionPts.load() && currentPos > bufferPts &&
(currentPos - bufferPts) > kStaleThreshold)
{
const double lagSeconds = static_cast<double>(currentPos - bufferPts) / GST_SECOND;
RIALTO_SERVER_LOG_WARN("Dropping stale segment (%.3fs behind) after HDCP recovery", lagSeconds);
return MediaKeyErrorStatus::OK; // Drop silently, pretend decrypt succeeded
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we seek backwards? Decryption won't work :)

}
}

const auto deadline = std::chrono::steady_clock::now() + kOutputRestrictedRetryTimeout;
do
{
auto task = [&]() { status = decryptInternal(keySessionId, encrypted, caps); };
m_mainThread->enqueueTaskAndWait(m_mainThreadClientId, task);
RIALTO_SERVER_LOG_DEBUG("DEBUG PURPOSE : Key session id :%d", keySessionId);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change the print

/* switch (status)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove commented out code

{
case firebolt::rialto::MediaKeyErrorStatus::OK:
RIALTO_SERVER_LOG_ERROR("DEBUG PURPOSE : Key session status : OK");
break;
case firebolt::rialto::MediaKeyErrorStatus::FAIL:
RIALTO_SERVER_LOG_ERROR("DEBUG PURPOSE : Key session status : FAIL");
break;
case firebolt::rialto::MediaKeyErrorStatus::BAD_SESSION_ID:
RIALTO_SERVER_LOG_ERROR("DEBUG PURPOSE : Key session status : BAD_SESSION_ID");
break;
case firebolt::rialto::MediaKeyErrorStatus::INTERFACE_NOT_IMPLEMENTED:
RIALTO_SERVER_LOG_ERROR("DEBUG PURPOSE : Key session status : INTERFACE_NOT_IMPLEMENTED");
break;
case firebolt::rialto::MediaKeyErrorStatus::BUFFER_TOO_SMALL:
RIALTO_SERVER_LOG_ERROR("DEBUG PURPOSE : Key session status : BUFFER_TOO_SMALL");
break;
case firebolt::rialto::MediaKeyErrorStatus::NOT_SUPPORTED:
RIALTO_SERVER_LOG_ERROR("DEBUG PURPOSE : Key session status : NOT_SUPPORTED");
break;
case firebolt::rialto::MediaKeyErrorStatus::INVALID_STATE:
RIALTO_SERVER_LOG_ERROR("DEBUG PURPOSE : Key session status : INVALID_STATE");
break;
case firebolt::rialto::MediaKeyErrorStatus::OUTPUT_RESTRICTED:
RIALTO_SERVER_LOG_ERROR("DEBUG PURPOSE : Key session status : OUTPUT_RESTRICTED");
break;
}*/

if (status != MediaKeyErrorStatus::OUTPUT_RESTRICTED)
{
m_outputWasRestricted = false;
break;
}
m_outputWasRestricted = true;
if (m_isShuttingDown.load())
{
RIALTO_SERVER_LOG_ERROR("Decrypt retry aborted — shutdown in progress");
break;
}

RIALTO_SERVER_LOG_WARN("Decrypt returned OUTPUT_RESTRICTED, retrying after delay");

std::this_thread::sleep_for(kOutputRestrictedRetryInterval);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use sleeps in Rialto Server's production code.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use the Timer class for example


} while (std::chrono::steady_clock::now() < deadline);
Comment on lines +610 to +683
Comment on lines 606 to +683
Comment on lines 606 to +683
Comment on lines +610 to +683

m_mainThread->enqueueTaskAndWait(m_mainThreadClientId, task);
return status;
}

Expand Down Expand Up @@ -604,12 +711,14 @@ bool MediaKeysServerInternal::isNetflixPlayreadyKeySystem() const
return m_kKeySystem.find("netflix") != std::string::npos;
}


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this line

void MediaKeysServerInternal::ping(std::unique_ptr<IHeartbeatHandler> &&heartbeatHandler)
{
RIALTO_SERVER_LOG_DEBUG("entry:");
RIALTO_SERVER_LOG_ERROR("entry:");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert this

auto task = [&]() { heartbeatHandler.reset(); };

m_mainThread->enqueueTaskAndWait(m_mainThreadClientId, task);
m_mainThread->enqueuePriorityTaskAndWait(m_mainThreadClientId, task);
RIALTO_SERVER_LOG_ERROR("exit:");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this print

}

MediaKeyErrorStatus MediaKeysServerInternal::getMetricSystemData(std::vector<uint8_t> &buffer)
Expand Down
37 changes: 34 additions & 3 deletions media/server/service/source/CdmService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -492,16 +492,31 @@ bool CdmService::isServerCertificateSupported(const std::string &keySystem)

MediaKeyErrorStatus CdmService::decrypt(int32_t keySessionId, GstBuffer *encrypted, GstCaps *caps)
{
RIALTO_SERVER_LOG_DEBUG("CdmService requested to decrypt, key session id: %d", keySessionId);

IMediaKeysServerInternal *mediaKeys{nullptr};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is not needed, revert it

{
std::lock_guard<std::mutex> lock{m_mediaKeysMutex};
auto iter = m_sessionInfo.find(keySessionId);
if (iter == m_sessionInfo.end()) return MediaKeyErrorStatus::FAIL;
mediaKeys = m_mediaKeys[iter->second.mediaKeysHandle].get();
// Increment ref counter to prevent destruction while in use
++iter->second.refCounter;
}
auto status = mediaKeys->decrypt(keySessionId, encrypted, caps);
decrementSessionIdUsageCounter(keySessionId); // May trigger deferred release
Comment on lines +496 to +506
return status;

/* RIALTO_SERVER_LOG_DEBUG("CdmService requested to decrypt, key session id: %d", keySessionId);

RIALTO_SERVER_LOG_ERROR("DEBUG PURPOSE : CdmService : decrypt entry");
std::lock_guard<std::mutex> lock{m_mediaKeysMutex};
auto mediaKeysHandleIter{m_sessionInfo.find(keySessionId)};
if (mediaKeysHandleIter == m_sessionInfo.end())
{
RIALTO_SERVER_LOG_ERROR("Media keys handle for mksId: %d does not exists", keySessionId);
return MediaKeyErrorStatus::FAIL;
}
return m_mediaKeys[mediaKeysHandleIter->second.mediaKeysHandle]->decrypt(keySessionId, encrypted, caps);
return m_mediaKeys[mediaKeysHandleIter->second.mediaKeysHandle]->decrypt(keySessionId, encrypted, caps);*/
}

bool CdmService::isNetflixPlayreadyKeySystem(int32_t keySessionId)
Expand Down Expand Up @@ -580,12 +595,28 @@ void CdmService::decrementSessionIdUsageCounter(int32_t keySessionId)

void CdmService::ping(const std::shared_ptr<IHeartbeatProcedure> &heartbeatProcedure)
{
std::lock_guard<std::mutex> lock{m_mediaKeysMutex};

std::unique_lock<std::mutex> lock{m_mediaKeysMutex, std::try_to_lock};
if (!lock.owns_lock())
{
// Server is alive but busy in decrypt retry — acknowledge ping
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact, that the mutex is locked, doesn't mean that the decryption is ongoing, we can be blocked on something else as well. This change breaks the whole healthcheck mechanism in CdmService

RIALTO_SERVER_LOG_WARN("CdmService::ping - mutex busy (decrypt in progress), skipping CDM ping");
return; // HeartbeatProcedure destructor sends success ack
}
for (const auto &mediaKeyPair : m_mediaKeys)
{
auto &mediaKeys = mediaKeyPair.second;
mediaKeys->ping(heartbeatProcedure->createHandler());
}

/*std::lock_guard<std::mutex> lock{m_mediaKeysMutex};
RIALTO_SERVER_LOG_ERROR("DEBUG PURPOSE: ping entry");
for (const auto &mediaKeyPair : m_mediaKeys)
{
auto &mediaKeys = mediaKeyPair.second;
mediaKeys->ping(heartbeatProcedure->createHandler());
}
RIALTO_SERVER_LOG_ERROR("DEBUG PURPOSE: ping exit");*/
}

MediaKeyErrorStatus CdmService::getMetricSystemData(int mediaKeysHandle, std::vector<uint8_t> &buffer)
Expand Down
2 changes: 2 additions & 0 deletions wrappers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ target_include_directories(

PRIVATE
include
../common/interface/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please look how directories are included in other CMake files and make the code consistent.

../logging/include/
${GStreamerApp_INCLUDE_DIRS}
$<TARGET_PROPERTY:RialtoPlayerPublic,INTERFACE_INCLUDE_DIRECTORIES>
${WRAPPER_INCLUDES}
Expand Down
2 changes: 2 additions & 0 deletions wrappers/include/OcdmSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class OcdmSession : public IOcdmSession
private:
using OcdmGstSessionDecryptExFn = OpenCDMError (*)(struct OpenCDMSession *, GstBuffer *, GstBuffer *,
const uint32_t, GstBuffer *, GstBuffer *, uint32_t, GstCaps *);
using OcdmGstSessionDecryptBufferOnceFn = OpenCDMError (*)(struct OpenCDMSession *, GstBuffer *, GstCaps *);
/**
* @brief The System handle.
*/
Expand All @@ -115,6 +116,7 @@ class OcdmSession : public IOcdmSession
struct OpenCDMSession *m_session;

static OcdmGstSessionDecryptExFn m_ocdmGstSessionDecryptEx;
static OcdmGstSessionDecryptBufferOnceFn m_ocdmGstSessionDecryptBufferOnce;

/**
* @brief Requests the processing of the challenge data.
Expand Down
Loading
Loading