Files
BPI-CM9-Linux/aml-comp/multimedia/aml_mp_sdk/cas/AmlDvbCasHal.cpp
T

427 lines
11 KiB
C++
Raw Normal View History

2026-08-13 11:28:40 +08:00
/*
* Copyright (c) 2020 Amlogic, Inc. All rights reserved.
*
* This source code is subject to the terms and conditions defined in the
* file 'LICENSE' which is part of this source code package.
*
* Description:
*/
#define LOG_TAG "AmlDvbCasHal"
#include "AmlDvbCasHal.h"
#include <pthread.h>
#include <utils/AmlMpUtils.h>
#include <utils/AmlMpLog.h>
static const char* mName = LOG_TAG;
///////////////////////////////////////////////////////////////////////////////
#ifdef HAVE_CAS_HAL
extern CasHandle g_casHandle;
static CA_SERVICE_TYPE_t convertToCAServiceType(Aml_MP_CASServiceType casServiceType)
{
switch (casServiceType) {
case AML_MP_CAS_SERVICE_LIVE_PLAY:
return SERVICE_LIVE_PLAY;
case AML_MP_CAS_SERVICE_PVR_PLAY:
return SERVICE_PVR_PLAY;
case AML_MP_CAS_SERVICE_PVR_RECORDING:
return SERVICE_PVR_RECORDING;
case AML_MP_CAS_SERVICE_PVR_TIMESHIFT_PLAY:
return SERVICE_PVR_TIMESHIFT_PLAY;
case AML_MP_CAS_SERVICE_PVR_TIMESHIFT_RECORDING:
return SERVICE_PVR_TIMESHIFT_RECORDING;
default:
break;
}
return SERVICE_TYPE_INVALID;
}
static CA_SERVICE_MODE_t convertToCAServiceMode(Aml_MP_CASServiceMode serviceMode)
{
switch (serviceMode) {
case AML_MP_CAS_SERVICE_DVB:
return SERVICE_DVB;
case AML_MP_CAS_SERVICE_IPTV:
return SERVICE_IPTV;
default:
break;
}
return SERVICE_DVB;
}
static void convertToCAServiceInfo(AM_CA_ServiceInfo_t* caServiceInfo, Aml_MP_CASServiceInfo* mpServiceInfo)
{
caServiceInfo->service_id = mpServiceInfo->service_id;
caServiceInfo->fend_dev = mpServiceInfo->fend_dev;
caServiceInfo->dmx_dev = mpServiceInfo->dmx_dev;
caServiceInfo->dsc_dev = mpServiceInfo->dsc_dev;
caServiceInfo->dvr_dev = mpServiceInfo->dvr_dev;
caServiceInfo->service_mode = convertToCAServiceMode(mpServiceInfo->serviceMode);
caServiceInfo->service_type = convertToCAServiceType(mpServiceInfo->serviceType);
caServiceInfo->ecm_pid = mpServiceInfo->ecm_pid;
memcpy(caServiceInfo->stream_pids, mpServiceInfo->stream_pids, sizeof(caServiceInfo->stream_pids));
caServiceInfo->stream_num = mpServiceInfo->stream_num;
memcpy(caServiceInfo->ca_private_data, mpServiceInfo->ca_private_data, sizeof(caServiceInfo->ca_private_data));
caServiceInfo->ca_private_data_len = mpServiceInfo->ca_private_data_len;
}
static int convertToAmlMPErrorCode(AM_RESULT CasResult) {
switch (CasResult) {
case AM_ERROR_SUCCESS:
return AML_MP_OK;
case AM_ERROR_NOT_LOAD:
return AML_MP_ERROR_NO_INIT;
case AM_ERROR_NOT_SUPPORTED:
return AML_MP_ERROR_INVALID_OPERATION;
case AM_ERROR_OVERFLOW:
return AML_MP_ERROR_BAD_INDEX;
default:
return AML_MP_ERROR;
}
}
#endif
///////////////////////////////////////////////////////////////////////////////
namespace aml_mp {
#ifdef HAVE_CAS_HAL
std::mutex AmlDvbCasHal::sCasHalSessionLock;
std::map<CasSession, wptr<AmlDvbCasHal>> AmlDvbCasHal::sCasHalSessionMap;
#endif
AmlDvbCasHal::AmlDvbCasHal(Aml_MP_CASServiceType serviceType)
: AmlCasBase(serviceType)
{
#ifdef HAVE_CAS_HAL
AM_RESULT ret = AM_ERROR_GENERAL_ERROR;
CA_SERVICE_TYPE_t caServiceType = convertToCAServiceType(mServiceType);
//coverity[value_overwrite]
ret = AM_CA_OpenSession(g_casHandle, &mCasSession, caServiceType);
if (ret != AM_ERROR_SUCCESS) {
MLOGE("AM_CA_OpenSession failed!");
return;
}
MLOG("openSession:%#zx, MAX_CHAN_COUNT=%d", mCasSession, MAX_CHAN_COUNT);
std::unique_lock<std::mutex> _l(sCasHalSessionLock);
auto result = sCasHalSessionMap.emplace(mCasSession, this);
if (!result.second) {
MLOGE("save CasSession failed! (%#zx, %p)", mCasSession, this);
}
#endif
}
AmlDvbCasHal::~AmlDvbCasHal()
{
MLOG();
#ifdef HAVE_CAS_HAL
AM_RESULT ret = AM_ERROR_GENERAL_ERROR;
//coverity[value_overwrite]
ret = AM_CA_CloseSession(mCasSession);
if (ret != AM_ERROR_SUCCESS) {
MLOGE("AM_CA_CloseSession failed!");
}
std::unique_lock<std::mutex> _l(sCasHalSessionLock);
auto result = sCasHalSessionMap.erase(mCasSession);
if (result == 0) {
MLOGE("remove CasSession failed! (%#zx, %p)", mCasSession, this);
}
#endif
}
int AmlDvbCasHal::registerEventCallback(Aml_MP_CAS_EventCallback cb, void* userData)
{
MLOG();
int ret = AML_MP_ERROR;
mCb = cb;
mUserData = userData;
#ifdef HAVE_CAS_HAL
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_RegisterEventCallback(mCasSession, sCasHalCb));
#else
AML_MP_UNUSED(cb);
#endif
return ret;
}
int AmlDvbCasHal::startDescrambling(Aml_MP_CASServiceInfo* serviceInfo)
{
MLOG();
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
AM_CA_ServiceInfo_t caServiceInfo;
convertToCAServiceInfo(&caServiceInfo, serviceInfo);
MLOG("startDescrambling: caServiceInfo->stream_num=%d", caServiceInfo.stream_num);
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_StartDescrambling(mCasSession, &caServiceInfo));
#else
AML_MP_UNUSED(serviceInfo);
#endif
return ret;
}
int AmlDvbCasHal::stopDescrambling()
{
MLOG();
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_StopDescrambling(mCasSession));
#endif
return ret;
}
int AmlDvbCasHal::updateDescramblingPid(int oldStreamPid, int newStreamPid)
{
MLOG("oldStreamPid:%d, newStreamPid:%d", oldStreamPid, newStreamPid);
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_UpdateDescramblingPid(mCasSession, oldStreamPid, newStreamPid));
#endif
return ret;
}
int AmlDvbCasHal::startDVRRecord(Aml_MP_CASServiceInfo* serviceInfo)
{
MLOG();
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
AM_CA_ServiceInfo_t caServiceInfo;
convertToCAServiceInfo(&caServiceInfo, serviceInfo);
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_DVRStart(mCasSession, &caServiceInfo));
#else
AML_MP_UNUSED(serviceInfo);
#endif
return ret;
}
int AmlDvbCasHal::stopDVRRecord()
{
MLOG();
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_DVRStop(mCasSession));
#endif
return ret;
}
int AmlDvbCasHal::startDVRReplay(Aml_MP_CASDVRReplayParams* dvrReplayParams)
{
MLOG();
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
AM_CA_PreParam_t caParams;
caParams.dmx_dev = dvrReplayParams->dmxDev;
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_DVRSetPreParam(mCasSession, &caParams));
#else
AML_MP_UNUSED(dvrReplayParams);
#endif
return ret;
}
int AmlDvbCasHal::stopDVRReplay()
{
MLOG();
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_DVRStopReplay(mCasSession));
#endif
return ret;
}
int AmlDvbCasHal::dvrReplay(Aml_MP_CASCryptoParams* cryptoParams)
{
MLOG();
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
AM_CA_CryptoPara_t* amCryptoParams = reinterpret_cast<AM_CA_CryptoPara_t*>(cryptoParams);
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_DVRReplay(mCasSession, amCryptoParams));
#else
AML_MP_UNUSED(cryptoParams);
#endif
return ret;
}
int AmlDvbCasHal::DVREncrypt(Aml_MP_CASCryptoParams* cryptoParams)
{
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
static_assert(sizeof(Aml_MP_CASCryptoParams) == sizeof(AM_CA_CryptoPara_t), "Incompatible with AM_CA_CryptoPara_t!");
static_assert(sizeof(loff_t) == sizeof(int64_t), "Incompatible loff_t vs int64_t");
AM_CA_CryptoPara_t* amCryptoParams = reinterpret_cast<AM_CA_CryptoPara_t*>(cryptoParams);
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_DVREncrypt(mCasSession, amCryptoParams));
#else
AML_MP_UNUSED(cryptoParams);
#endif
return ret;
}
int AmlDvbCasHal::DVRDecrypt(Aml_MP_CASCryptoParams* cryptoParams)
{
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
static_assert(sizeof(Aml_MP_CASCryptoParams) == sizeof(AM_CA_CryptoPara_t), "Incompatible with AM_CA_CryptoPara_t!");
static_assert(sizeof(loff_t) == sizeof(int64_t), "Incompatible loff_t vs int64_t");
AM_CA_CryptoPara_t* amCryptoParams = reinterpret_cast<AM_CA_CryptoPara_t*>(cryptoParams);
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_DVRDecrypt(mCasSession, amCryptoParams));
#else
AML_MP_UNUSED(cryptoParams);
#endif
return ret;
}
AML_MP_SECMEM AmlDvbCasHal::createSecmem(Aml_MP_CASServiceType type, void** pSecbuf, uint32_t* size)
{
#ifdef HAVE_CAS_HAL
SecMemHandle secMem = 0;
CA_SERVICE_TYPE_t caServiceType = convertToCAServiceType(type);
secMem = AM_CA_CreateSecmem(mCasSession, caServiceType, pSecbuf, size);
MLOG("service type:%d, secMem:%#zx", type, secMem);
return (AML_MP_SECMEM)secMem;
#else
AML_MP_UNUSED(type);
AML_MP_UNUSED(pSecbuf);
AML_MP_UNUSED(size);
return nullptr;
#endif
}
int AmlDvbCasHal::destroySecmem(AML_MP_SECMEM secMem)
{
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
MLOG("secMem:%#zx", (SecMemHandle)secMem);
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_DestroySecmem(mCasSession, (SecMemHandle)secMem));
#else
AML_MP_UNUSED(secMem);
#endif
return ret;
}
int AmlDvbCasHal::ioctl(const char* inJson, char* outJson, uint32_t outLen)
{
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_Ioctl(mCasSession, inJson, outJson, outLen));
#else
AML_MP_UNUSED(inJson);
AML_MP_UNUSED(outJson);
AML_MP_UNUSED(outLen);
#endif
return ret;
}
int AmlDvbCasHal::getStoreRegion(Aml_MP_CASStoreRegion* region, uint8_t* regionCount)
{
int ret = AML_MP_ERROR;
#ifdef HAVE_CAS_HAL
static_assert(sizeof(Aml_MP_CASStoreRegion) == sizeof(AM_CA_StoreRegion_t), "Incompatible with AM_CA_StoreRegion_t!");
//coverity[value_overwrite]
ret = convertToAmlMPErrorCode(AM_CA_GetStoreRegion(mCasSession, reinterpret_cast<AM_CA_StoreRegion_t*>(region), regionCount));
#else
AML_MP_UNUSED(region);
AML_MP_UNUSED(regionCount);
#endif
return ret;
}
#ifdef HAVE_CAS_HAL
AM_RESULT AmlDvbCasHal::sCasHalCb(CasSession session, char* json)
{
sptr<AmlDvbCasHal> dvbCasCal;
{
std::unique_lock<std::mutex> _l(sCasHalSessionLock);
auto ret = sCasHalSessionMap.find(session);
if (ret != sCasHalSessionMap.end()) {
dvbCasCal = ret->second.promote();
}
}
if (dvbCasCal != nullptr) {
dvbCasCal->notifyListener(json);
} else {
MLOGE("dvbCasCal is NULL, session:%#zx", session);
}
return AM_ERROR_SUCCESS;
}
#endif
void AmlDvbCasHal::notifyListener(char* json)
{
if (mCb) {
mCb(this, json);
} else {
MLOGW("mCb is NULL, json:%s", json);
}
}
}