/**
* Copyright(c) 2011 Sunmedia Technologies - All Rights Reserved.
*
* @file al_psi_monitor.c
*
* @brief this file defines psi monitor interface for app layer.
*
* The file supports the psi monitor functions by used for app layer.
* The psi monitor check all psi and si table changed,
* if table change parse and update information to database and notify application dispose.
*
*/

/**<header files*/
#include <ctype.h>
#include "gl_mutex.h"
#include "ai_debug_config.h"
#include "mid_playback.h"
#include "mid_siutil_13818.h"
#include "mid_siutil_dvb.h"
#ifdef CONFIG_SUPPORT_OTA_UPGRADE
#include "mid_ota.h"
#include "mid_otamon.h"
#endif
#include "mid_psimon.h"
#include "dvb_dr_13818.h"
#include "app_area_info.h" //Gahu:D0506
#ifdef CONFIG_SUPPORT_MHEG5
#include "mid_mheg5.h"
#endif
#include "ai_psi_monitor.h"
#include "ai_database.h"
#include "ai_time.h"
#ifdef CONFIG_SUPPORT_SUBTITLE
#include "ai_subtitle.h"
#endif
#ifdef CONFIG_SUPPORT_TTX
#include "ai_teletext.h"
#endif
#include "ai_tp_list.h"
#include "ai_dvb_monitor.h"
#include "al_fw.h"
#include "dvb_dr_dvb.h"
#ifdef CONFIG_SUPPORT_ISDB_SUBTITLE
#include "al_sbtvd_subtitle.h"
#include "ai_sbtvd_subtitle.h"
#endif
#include "al_area_info.h"
#ifdef CONFIG_CI_SUPPORT
#include "mid_dtvci.h"
#include "app_dvb_ci_mmi.h"
#endif
#include "mid_pmtother_mon.h"
#ifdef CONFIG_SUPPORT_EWS
#include "ai_ews_monitor.h"
#endif
#ifdef SUPPORT_ASTRA_LCN_MONITOR
#include "ai_astralcn_monitor.h"
#endif
#include "unicode.h"
#ifdef CONFIG_SUPPORT_HBBTV
#include "hbbtv_si_query.h"
#include "hbbtv_application_manager.h"
#include "rb_download.h"
#endif
#ifdef __cplusplus
	extern "C"{
#endif

/**<Macro define*/

#if AL_PSI_MONITOR_DEBUG_FLAG
	#define PSI_MONITOR_DEBUG_MSG(fmt, arg...) \
	do { \
		UMFDBG(0,"[Debug]%s: %d Line \n", __FUNCTION__, __LINE__); \
		UMFDBG(0,fmt, ##arg); \
	} while(0)
#else
	#define PSI_MONITOR_DEBUG_MSG(fmt, arg...);
#endif

#if AL_PSI_MONITOR_ERROR_FLAG
	#define PSI_MONITOR_ERROR_MSG(fmt, arg...) \
	do { \
		UMFDBG(0,"[Error]%s: %d Line \n", __FUNCTION__, __LINE__); \
		UMFDBG(0,fmt, ##arg); \
	} while(0)
#else
	#define PSI_MONITOR_ERROR_MSG(fmt, arg...);
#endif

#define ABSMETHOD(n) ({							\
	register int _n = n, _t = _n;					\
	_t >>= sizeof (_t) * 8 - 1;					\
	_n ^= _t;							\
	_n -= _t;							\
})

#define min(x,y) ((x)>(y) ? (y) : (x))

#define PSIMON_MUTEX_LOCK(Mutex)\
{\
	if(Mutex)\
	{\
		GL_MutexLock(Mutex);\
	}\
}

#define PSIMON_MUTEX_UNLOCK(Mutex)\
{\
	if(Mutex)\
	{\
		GL_MutexUnlock(Mutex);\
	}\
}

#define PSIMON_SEND_MSG(CallBk, Msg, Parm)		\
{\
	if(CallBk != al_null) \
	{\
		CallBk(Msg, Parm);\
	}\
}

#define PSIMON_SERVICE_ADD_DURATION		(10*10) /* 10*10*100ms = 10s */
#define PSIMON_SERVICE_RMV_DURATION		(15*10) /* 15*10*100ms = 15s */
#define PSIMON_SERVICE_ADD_DURATION_NORWAY		(10*10) /* 10*10*100ms = 10s */
#define PSIMON_SERVICE_RMV_DURATION_NORWAY		(10*10) /* 10*10*100ms = 10s */
#define PSIMON_SERVICE_UPDATE_DURATION		(5*10) /* 5*10*100ms = 5s */
#define PSIMON_INDONESIA_EWS_STOP		(5*10) /* 5*10*100ms = 5s */

#define PSIMON_SIZE_OF_TMP_TP_LIST		20

#define PSIMON_CHANGETIMEINSEC          30

#define REGION_ID_NO_USED       (0)

#ifdef CONFIG_SUPPORT_OTA_UPGRADE
	#define OUI_LINKAGE_TYPE	0X09
	#ifdef CONFIG_SUPPORT_OAD_UPGRADE
		#define OAD_OUI_LINKAGE_TYPE	0X81
	#endif
#endif

#define NORDIG_RIKS_ONID	(0x2242)

#define THAI_ONID			(0x22fc)


/**< Replacement type */
typedef enum
{
	AI_PSIMONITOR_REPLACEMENT_TYPE_NOT_RUNNING = 0, /**< service replacement service */
	AI_PSIMONITOR_REPLACEMENT_TYPE_SCRAMBLE,	/**< CA replacement service */
	AI_PSIMONITOR_REPLACEMENT_TYPE_SIMLCASE, /**< Simulcase replacement service */
#ifdef EPG_REPLACE
	AI_PSIMONITOR_REPLACEMENT_TYPE_EPG,	/**< EPG replacement service */
#endif
	AI_PSIMONITOR_REPLACEMENT_TYPE_MAX,
}AI_PsiMon_ReplacementType_t;

/**< Current tp service list type */
typedef enum
{
	AL_PSIMONITOR_CURRTP_SRVLIST_SDT = 0,
	AL_PSIMONITOR_CURRTP_SRVLIST_NIT,
	AL_PSIMONITOR_CURRTP_SRVLIST_PAT,
	AL_PSIMONITOR_CURRTP_SRVLIST_MAX,
}AI_PsiMon_CurrTp_SrvList_t;

/**< Other tp service list type */
typedef enum
{
	AL_PSIMONITOR_OTHERTP_SRVLIST_SDT,
	AL_PSIMONITOR_OTHERTP_SRVLIST_NIT,
	AL_PSIMONITOR_OTHERTP_SRVLIST_MAX,
} AI_PsiMon_OtherTp_SrvList_t;

typedef struct _PSIMon_SimplePmt
{
	al_uint16 usProgNum; /**< program number */
	al_uint8 bHasVideo;
	al_uint8 bHasAudio;
	struct _PSIMon_SimplePmt *pstNext;
} AL_PSIMon_SimplePmt_t;

/**<Global Variables*/
static AL_PsiMon_AudioComp_t *g_pstCurrAudioCompList = al_null;
static al_uint16 g_u16MinAudioPid = DB_DVB_INVALID_PID;
static al_uint8 g_u8VideoPidCount = 0xff;
static al_uint8 g_u8AudioPidCount = 0xff;
static AL_PSIMon_SimpleSrv_t *g_pstCurrSdtSrvList = al_null; /**< current sdt service list, used to dynamic add or remove database */
static AL_PSIMon_SimpleSrv_t *g_pstCurrNitSrvList = al_null; /**< current nit service list, used to dynamic add or remove database */
static AL_PSIMon_SimpleSrv_t *g_pstCurrPatSrvList = al_null; /**< pat service list, used to dynamic add or remove database */
static AL_PSIMon_SimplePmt_t *g_pstCurrPmtSrvList = al_null; /**< pat service list, used to dynamic add or remove database */
static AL_PSIMon_SimpleSrv_t *g_pstOtherSdtSrvList = al_null; /**< other sdt service list, used to dynamic add or remove database */
static AL_PSIMon_SimpleSrv_t *g_pstOtherNitSrvList = al_null; /**< other nit service list, used to dynamic add or remove database */
static al_uint16 g_u16OrgTsId = 0xffff;
static al_uint16 g_u16OrgNetId = 0xffff;
static al_uint16 g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_MAX] = {0xffff,0xffff,0xffff};
static al_uint16 g_u16NumberOfOtherTpSrv = 0; /**< Number of need add to database for other tp service, from nit got */
static al_bool g_bOtherSDTNeedToDecode = al_false; /**< Need tp decode other sdt table flag */
static al_uint32 g_u32TpListCnt[PSIMON_SIZE_OF_TMP_TP_LIST]; /**< Other tp list(low 16bits:ts id) and other tp dispose cont(high 16bits:tp dispose count) */
#ifdef SUPPORT_NETWORK_UPDATE_RESCAN
static al_uint32 g_u32TpListFreq[TDB_MAX_TSNUM_WITHIN_NETWORK];
static al_uint8 g_u8CurrNitVersion = 0;
static al_uint8 g_u8CurrNitTSIDNum = 0;
static al_uint16 g_u16CurrNitTSIDList[TDB_MAX_TSNUM_WITHIN_NETWORK];
#endif
static AL_PSIMon_SpecialSpec_t g_ePsiFollowSpec = AL_PSIMON_SPECIAL_SPEC_NONE; /**< used to setup psi dispose spec*/
static AL_PsiMon_DynamicUpdate_Type_t g_ePsiUpdateOptions = 0; /**< used to setup psi dispose spec */
static GL_Mutex_t g_PsiMonMutex = al_null; /**< used to protect static resource, for example g_pstCurrSdtSrvList/g_pstCurrNitSrvList/g_pstCurrPatSrvList */
static al_uint32 g_u32PsiTimer[AI_PSIMONITOR_TIMER_NUMBER_MAX]; /**< add or remove service timer, used to dynamic add or remove database */
static AI_PsiMon_Timer_Type_t g_ePsiTimerEventArrange = AI_PSIMONITOR_TIMER_NUMBER_MAX; /**<add or  remove service, used to dynamic add or remove database */
static al_int g_iPsiTimerAddDiff = 0;
static al_int g_iPsiTimerRemoveDiff = 0;
static al_int g_iPsiTimerUpdateDiff = 0;
static AL_PsiMon_NewSrvPosition_t g_stNewServiceLocation; /**< used to service move dispose */
static al_uint32 g_u32SipsiInfoState;
static AL_RecHandle_t g_hReplacement[AI_PSIMONITOR_REPLACEMENT_TYPE_MAX];
static AL_RecHandle_t g_hReplaced[AI_PSIMONITOR_REPLACEMENT_TYPE_MAX];
static AI_pfPsiMonCallback g_pfPsiMonCallbks = al_null;
static AL_pfPsiMonCheckSrvType g_pfPsiMonCheckSrvType = al_null;
static AL_pfPsiMonCheckNotVisible g_pfPsiMonCheckNotVisible = al_null;
static al_bool g_bPsiMonInited = al_false;
static al_bool g_bPsiMonStarted = al_false;
static al_uint8 g_u8FTADataTblParsed = DTGCMG_TBL_NONE ;
static al_uint8 g_u8FTADataData = 0x00 ;/**<(EIT)(SDT)(NIT2ndLoop)(NIT1stLoop)_0000 */
static al_uint8 g_u8FTADataDataStored = 0x00 ;/**<(EIT)(SDT)(NIT2ndLoop)(NIT1stLoop)_0000 */
static TpListHdl_st g_hTPList = 0;
static al_uint32 g_uiTuneFreqNum = 0;
#ifdef CONFIG_SUPPORT_SSU_ENHANCE_UPGRADE
al_bool gfTotHasUpdate = al_false, gfTdtHasUpdate = al_false;
#endif
static al_bool g_bChanlScanLock = al_false;
static al_uint16 g_u16TSID = INVALID_TSID;
static al_uint16 g_uOrigNetId = INVALID_ORGNETID;
static al_uint16 g_CA_SYS_ID = 0xffff;
#ifdef CONFIG_SUPPORT_INDONESIA_EWS
static AL_PsiMon_EwsList_t g_ewsList = {0};
static al_int g_iPsiTimerEWSUpdateDiff = 0;
static al_bool g_bIsEwsActive = al_false;
#endif

static AL_Return_t _AI_PSI_Monitor_FTADataReset(al_void)
{
	g_u8FTADataTblParsed = 0;
	g_u8FTADataData = 0x00;
	g_u8FTADataDataStored = 0x00 ;

	return AL_SUCCESS;
}

static al_void _AI_PSI_Monitor_ResetState(al_bool ClearReplaceData)
{
	al_int i;

	if (ClearReplaceData)
	{
		g_u32SipsiInfoState = 0;

		for(i=0;i<AI_PSIMONITOR_REPLACEMENT_TYPE_MAX;i++)
		{
			g_hReplacement[i] = AL_DB_INVALIDHDL;
			g_hReplaced[i] = AL_DB_INVALIDHDL;
		}
	}

	g_u16MinAudioPid = DB_DVB_INVALID_PID;
	g_u8VideoPidCount = 0xff;
	g_u8AudioPidCount = 0xff;
	g_CA_SYS_ID = 0xffff;
	g_u16TSID = INVALID_TSID;
	g_uOrigNetId = INVALID_ORGNETID;
}
#ifdef CONFIG_DVB_SYSTEM
static void _AI_PSI_Monitor_CheckStreamSpec(al_uint8 *pu8CountryCode, AL_PSIMon_SpecialSpec_t *eTempSpec)
{
    UINT8 u8Area = 0;
    int equal = 0;
    char *TempCountryCode = al_null;
    int Temp;

    extern char* APP_Area_GetCountryCode(al_uint8 u8Area);
    for(Temp = 0; Temp < MAX_AREA; Temp++)
    {
        TempCountryCode = APP_Area_GetCountryCode(Temp);
		equal = memcmp(pu8CountryCode, TempCountryCode, 3 );
        if( equal == 0)
        {
            u8Area = Temp;
            break;
        }
    }

    switch (u8Area)
    {
// for DVB system, BRAZIL not necessary to support any spec
#ifndef CONFIG_ISDB_SYSTEM

        case AREA_ENGLAND:
            *eTempSpec = AL_PSIMON_SPECIAL_SPEC_DTG;
            break;
        case AREA_ITALY:

            *eTempSpec = AL_PSIMON_SPECIAL_SPEC_ZBOOK;
            break;

        case AREA_FRANCE:
            *eTempSpec = AL_PSIMON_SPECIAL_SPEC_EBOOK;
            break;

        case AREA_FINLAND:
        case AREA_SWEDEN:
        case AREA_DENMARK:
        case AREA_NORWAY:
#ifdef SUPPORT_GHANA_LCN
        case AREA_GHANA:
#endif
        case AREA_SINGAPORE:
        case AREA_THAILAND:

       // case AREA_GERMANY:
		case AREA_IRELAND:
#ifdef CONFIG_SUPPORT_MALAYSIA_CERTIFICATION
        case AREA_MALAYSIA:
#endif
			*eTempSpec = AL_PSIMON_SPECIAL_SPEC_NORDIG;
            break;

        case AREA_NETHERLANDS:
        case AREA_SPAIN:
#endif
        default:
			 *eTempSpec = AL_PSIMON_SPECIAL_SPEC_NONE;
            break;
    }
}
#endif
static al_bool _AI_PSI_Monitor_CheckCountry(al_uint8 *pu8CountryCode)
{
	al_uint8 u8TempCotryCode[3] = {0};
	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
	AL_FW_GetContextCb(&pfPSIMonGetContext);
#ifdef CONFIG_DVB_SYSTEM
    AL_PSIMon_SpecialSpec_t eTempSpec = AL_PSIMON_SPECIAL_SPEC_NONE;
	//extern Boolean APP_Area_SupportNorDig(void);
#endif
	if (pfPSIMonGetContext != al_null)
	{
		pfPSIMonGetContext(FW_CONTEXT_TYPE_COUNTRY_CODE , FW_CONTEXT_OP_TYPE_READ,
			(al_void *)u8TempCotryCode, 0);
	}
	if ((toupper(pu8CountryCode[0]) == toupper(u8TempCotryCode[0]))
		&& (toupper(pu8CountryCode[1]) == toupper(u8TempCotryCode[1]))
		&& (toupper(pu8CountryCode[2]) == toupper(u8TempCotryCode[2])))
	{
		return al_true;
	}
#ifdef CONFIG_DVB_SYSTEM
    else if(APP_Area_SupportNorDig())
    {
        _AI_PSI_Monitor_CheckStreamSpec(pu8CountryCode, &eTempSpec);
        if (g_ePsiFollowSpec == eTempSpec)
    	{
	        return al_true;
    	}
    }
#endif
	return al_false;
}

static al_void _AI_PSI_Monitor_TimerEventChange(AI_PsiMon_Timer_Type_t eType, al_bool bEnable)
{
	if ((g_ePsiTimerEventArrange & (1<<AI_PSIMONITOR_TIMER_SERVICE_ADD))
		&& (eType == AI_PSIMONITOR_TIMER_SERVICE_ADD) && bEnable)
	{
		return;
	}
	else if ((g_ePsiTimerEventArrange & (1<<AI_PSIMONITOR_TIMER_SERVICE_REMOVE))
		&& (eType == AI_PSIMONITOR_TIMER_SERVICE_REMOVE) && bEnable)
	{
		return;
	}
	else if ((g_ePsiTimerEventArrange & (1<<AI_PSIMONITOR_TIMER_SERVICE_UPDATE))
		&& (eType == AI_PSIMONITOR_TIMER_SERVICE_UPDATE) && bEnable)
	{
		return;
	}
#ifdef CONFIG_SUPPORT_INDONESIA_EWS
	else if ((g_ePsiTimerEventArrange & (1<<AI_PSIMONITOR_TIMER_INDONESIA_EWS_STOP))
		&& (eType == AI_PSIMONITOR_TIMER_INDONESIA_EWS_STOP) && bEnable)
	{
		return;
	}
#endif

	if (bEnable)
	{
		g_ePsiTimerEventArrange|=1<<eType;
	}
	else
	{
		g_ePsiTimerEventArrange&=~(1<<eType);
	}

	g_u32PsiTimer[eType] = 0;
}

static AL_Return_t _AI_PSI_Monitor_CurrProgAudioStack(MID_SiutilPmtStreamInfoDescr_t * pComp)
{
	AL_PsiMon_AudioComp_t *pTempAudoComp = al_null;
	AL_PsiMon_AudioComp_t *pList = al_null;
	AL_PsiMon_AudioComp_t *pNext = al_null;
	AL_PsiMon_AudioComp_t *pCurrent = al_null;

	if ((pComp != al_null) && (pComp->elementary_pid != 0x1fff) && (pComp->elementary_pid != 0))
	{
		PSIMON_MUTEX_LOCK(g_PsiMonMutex);

		pList = g_pstCurrAudioCompList;

		pTempAudoComp = (AL_PsiMon_AudioComp_t *) zero_malloc(sizeof(AL_PsiMon_AudioComp_t));

		if (pTempAudoComp == al_null)
		{
			PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
			return AL_FAILURE;
		}

		pTempAudoComp->u8StreamType = pComp->stream_type;
		pTempAudoComp->u16ElementaryPid = pComp->elementary_pid;
		pTempAudoComp->u16DescLen = pComp->descLen;
		if (pTempAudoComp->u16DescLen != 0)
		{
			pTempAudoComp->pu8Desc = zero_malloc(pTempAudoComp->u16DescLen);
			if (pTempAudoComp->pu8Desc == al_null)
			{
				PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
				free(pTempAudoComp);
				return AL_FAILURE;
			}
			memcpy(pTempAudoComp->pu8Desc, pComp->p_desc, pTempAudoComp->u16DescLen);
		}

		if (pList == al_null)
		{
			pList = pTempAudoComp;
			g_pstCurrAudioCompList = pList;
		}
		else
		{
			pCurrent = pList;

			pNext = pCurrent;
			while (pNext)
			{
				if (pNext->u16ElementaryPid == pTempAudoComp->u16ElementaryPid)
				{
					pNext->u8StreamType = pTempAudoComp->u8StreamType;
					pNext->u16DescLen = pTempAudoComp->u16DescLen;
					SAFE_FREE(pNext->pu8Desc);
					pNext->pu8Desc = al_null;
					pNext->pu8Desc = zero_malloc(pTempAudoComp->u16DescLen);
					if (pNext->pu8Desc)
					{
						memcpy(pNext->pu8Desc, pTempAudoComp->pu8Desc, pTempAudoComp->u16DescLen);
					}
					SAFE_FREE(pTempAudoComp->pu8Desc);
					pTempAudoComp->pu8Desc = al_null;
					SAFE_FREE(pTempAudoComp);
					pTempAudoComp = al_null;
					break;
				}
				pCurrent = pNext;
				pNext = pNext->pstNext;
			}

			if (pTempAudoComp)
			{
				pCurrent->pstNext = pTempAudoComp;
			}
		}

		PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);

		return AL_SUCCESS;
	}
	else
	{
		return AL_FAILURE;
	}
}

static AL_Return_t _AI_PSI_Monitor_CurrProgAudioStackReset(al_void)
{
	AL_PsiMon_AudioComp_t *pCurrent = al_null;
	AL_PsiMon_AudioComp_t *pNext = al_null;

	PSIMON_MUTEX_LOCK(g_PsiMonMutex);

	pCurrent = g_pstCurrAudioCompList;

	while (pCurrent)
	{
		pNext = pCurrent->pstNext;
		SAFE_FREE(pCurrent->pu8Desc);
		pCurrent->pu8Desc = al_null;
		SAFE_FREE(pCurrent);
		pCurrent = al_null;
		pCurrent = pNext;
	}

	g_pstCurrAudioCompList = al_null;

	PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);

	return AL_SUCCESS;
}

static AL_Return_t _AI_PSI_Monitor_CurTpServicesReset(void)
{
	al_int16 iCount = 0;
	AL_PSIMon_SimpleSrv_t *pCurrent = al_null;
	AL_PSIMon_SimpleSrv_t *pNext = al_null;

	PSIMON_MUTEX_LOCK(g_PsiMonMutex);

	for (iCount = 0; iCount < AL_PSIMONITOR_CURRTP_SRVLIST_MAX; iCount++)
	{
		if (iCount == AL_PSIMONITOR_CURRTP_SRVLIST_SDT)
		{
			pCurrent = g_pstCurrSdtSrvList;
		}
		else if (iCount == AL_PSIMONITOR_CURRTP_SRVLIST_NIT)
		{
			pCurrent = g_pstCurrNitSrvList;
		}
		else if (iCount == AL_PSIMONITOR_CURRTP_SRVLIST_PAT)
		{
			pCurrent = g_pstCurrPatSrvList;
		}

		if(pCurrent)
		{
			while(pCurrent)
			{
				pNext = pCurrent->pstNext;

				if(pCurrent->pucname)
				{
					SAFE_FREE(pCurrent->pucname);
					pCurrent->pucname = al_null;
				}

				SAFE_FREE(pCurrent);
				pCurrent = al_null;
				pCurrent = pNext;
			}
		}

		AI_PSI_Monitor_TimerEventClear((1<<AI_PSIMONITOR_TIMER_SERVICE_ADD)|(1<<AI_PSIMONITOR_TIMER_SERVICE_REMOVE));
	}

	g_u16OrgTsId = 0xffff;
	g_u16OrgNetId = 0xffff;
	g_pstCurrSdtSrvList = al_null;
	g_pstCurrNitSrvList = al_null;
	g_pstCurrPatSrvList = al_null;
	g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_SDT] = 0xffff;
	g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_NIT] = 0xffff;
	g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_PAT] = 0xffff;
	PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
	return AL_SUCCESS;
}


static AL_Return_t _AI_PSI_Monitor_CurTPServicesStack(al_uint8 u8TablId,
	al_uint16 u16Version, AL_PSIMon_SimpleSrv_t stProg)
{
	AL_RecHandle_t hCurProg = AL_DB_INVALIDHDL;
	al_uint16 u16TsId = 0;
	al_uint16 u16OrgNetId = 0;
	al_bool bVersionChange = 0;
	AL_PSIMon_SimpleSrv_t *pList = al_null;
	AL_PSIMon_SimpleSrv_t *pNext = al_null;
	AL_PSIMon_SimpleSrv_t *pCurrent = al_null;
	AL_PSIMon_SimpleSrv_t *pTmpservice = al_null;
	AL_DB_EDBType_t eDBType = AL_DBTYPE_MAX;
	al_int16 iCount = 0;


	if ((MID_SUCCESS != MID_PlaybackGetCurProgHandle(al_null, &hCurProg))
			|| (hCurProg == AL_DB_INVALIDHDL))
	{
		PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
		return AL_FAILURE;
	}

	if (AL_SUCCESS != AL_DB_GetRecordType(hCurProg, &eDBType, al_null))
	{
		PSI_MONITOR_ERROR_MSG("Get current active db type error.\n");
		return AL_FAILURE;
	}

	PSIMON_MUTEX_LOCK(g_PsiMonMutex);

	u16TsId = stProg.usTsId;
	u16OrgNetId = stProg.usOrgNetId;

	if (u8TablId != TABLE_ID_NIT_ACT && ((u16TsId != g_u16OrgTsId) || (g_u16OrgNetId != u16OrgNetId)))
	{
		PSI_MONITOR_DEBUG_MSG("[%s:%d] s_u16OrgTsId: %d, u16TsId: %d, s_u16OrgNetId: %d, u16OrgNetId: %d\n",
				__FUNCTION__,__LINE__,g_u16OrgTsId,u16TsId, g_u16OrgNetId, u16OrgNetId);
		for (iCount = 0; iCount < AL_PSIMONITOR_CURRTP_SRVLIST_MAX; iCount++)
		{
			if (iCount == AL_PSIMONITOR_CURRTP_SRVLIST_SDT)
			{
				pCurrent = g_pstCurrSdtSrvList;
			}
			else if (iCount == AL_PSIMONITOR_CURRTP_SRVLIST_NIT)
			{
				pCurrent = g_pstCurrNitSrvList;
			}
			else if (iCount == AL_PSIMONITOR_CURRTP_SRVLIST_PAT)
			{
				pCurrent = g_pstCurrPatSrvList;
			}

			if(pCurrent)
			{
				while(pCurrent)
				{
					pNext = pCurrent->pstNext;

					if(pCurrent->pucname)
					{
						SAFE_FREE(pCurrent->pucname);
						pCurrent->pucname = al_null;
					}

					SAFE_FREE(pCurrent);
					pCurrent = al_null;
					pCurrent = pNext;
				}
			}

			AI_PSI_Monitor_TimerEventClear((1<<AI_PSIMONITOR_TIMER_SERVICE_ADD)|(1<<AI_PSIMONITOR_TIMER_SERVICE_REMOVE));
		}

		g_u16OrgTsId = u16TsId;
		g_u16OrgNetId = u16OrgNetId;
		pList = al_null;
		g_pstCurrSdtSrvList = al_null;
		g_pstCurrNitSrvList = al_null;
		g_pstCurrPatSrvList = al_null;
		g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_SDT] = 0xffff;
		g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_NIT] = 0xffff;
		g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_PAT] = 0xffff;
	}

	if (u8TablId == TABLE_ID_SDT_ACT)
	{
		pList = g_pstCurrSdtSrvList;

		if (g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_SDT] != u16Version)
		{
			bVersionChange = al_true;
			g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_SDT] = u16Version;
			g_pstCurrSdtSrvList = al_null;
		}
	}
	else if (u8TablId == TABLE_ID_NIT_ACT)
	{
		pList = g_pstCurrNitSrvList;

		if (g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_NIT] != u16Version)
		{
			bVersionChange = al_true;
			g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_NIT] = u16Version;
			g_pstCurrNitSrvList = al_null;
		}
	}
	else if (u8TablId == TABLE_ID_PAT)
	{
		pList = g_pstCurrPatSrvList;

		if (g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_PAT] != u16Version)
		{
			bVersionChange = al_true;
			g_u16TableVersion[AL_PSIMONITOR_CURRTP_SRVLIST_PAT] = u16Version;
			g_pstCurrPatSrvList = al_null;
		}
	}
	else
	{
		PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
		return AL_FAILURE;
	}

	if (bVersionChange == al_true && pList != al_null)
	{
		pCurrent = pList;
		pList = al_null;

		while (pCurrent)
		{
			pNext = pCurrent->pstNext;

			if (pCurrent->pucname)
			{
				SAFE_FREE(pCurrent->pucname);
				pCurrent->pucname = al_null;
			}

			SAFE_FREE(pCurrent);
			pCurrent = al_null;
			pCurrent = pNext;
		}
	}

	pTmpservice = (AL_PSIMon_SimpleSrv_t *) zero_malloc(sizeof(AL_PSIMon_SimpleSrv_t));

	if (pTmpservice == al_null)
	{
		PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
		return AL_FAILURE;
	}

	memcpy(pTmpservice,&stProg,sizeof(AL_PSIMon_SimpleSrv_t));
	pTmpservice->pstNext = al_null;

	if (u8TablId == TABLE_ID_SDT_ACT)
	{
		pTmpservice->pucname = zero_malloc(DB_DVB_MAX_CHNAME_LEN);
		memcpy(pTmpservice->pucname,stProg.pucname,DB_DVB_MAX_CHNAME_LEN);

		if (g_ePsiUpdateOptions &( AL_PSIMONITOR_CURTP_SRVADD | AL_PSIMONITOR_CURTP_SRVADD2))
		{
			_AI_PSI_Monitor_TimerEventChange(AI_PSIMONITOR_TIMER_SERVICE_ADD,al_true);
		}

		if (g_ePsiUpdateOptions & (AL_PSIMONITOR_CURTP_SRV_REMOVE))
		{
			_AI_PSI_Monitor_TimerEventChange(AI_PSIMONITOR_TIMER_SERVICE_REMOVE,al_true);
		}
	}

	if (u8TablId == TABLE_ID_NIT_ACT)
	{
		if (g_ePsiUpdateOptions & (AL_PSIMONITOR_CURTP_SRVADD | AL_PSIMONITOR_CURTP_SRVADD2))
		{
			_AI_PSI_Monitor_TimerEventChange(AI_PSIMONITOR_TIMER_SERVICE_ADD,al_true);
		}

		if (g_ePsiUpdateOptions & (AL_PSIMONITOR_CURTP_SRV_REMOVE))
		{
			_AI_PSI_Monitor_TimerEventChange(AI_PSIMONITOR_TIMER_SERVICE_REMOVE,al_true);
		}
	}

	/* add the service to list */
	if (pList == al_null)
	{
		pList = pTmpservice;

		if (u8TablId == TABLE_ID_SDT_ACT)
		{
			g_pstCurrSdtSrvList = pList;
		}
		else if(u8TablId == TABLE_ID_NIT_ACT)
		{
			g_pstCurrNitSrvList = pList;
		}
		else if (u8TablId == TABLE_ID_PAT)
		{
			g_pstCurrPatSrvList = pList;
		}
	}
	else
	{
		pCurrent = pList;

		pNext = pCurrent;
		while (pNext)
		{
			/* the service is presented in list, no need to add */
			if (pNext->usServiceId == pTmpservice->usServiceId
				&& pNext->usOrgNetId == pTmpservice->usOrgNetId
				&& pNext->usTsId == pTmpservice->usTsId)
			{
				SAFE_FREE(pTmpservice->pucname);
				pTmpservice->pucname = al_null;
				SAFE_FREE(pTmpservice);
				pTmpservice = al_null;
				break;
			}
			pCurrent  =pNext;
			pNext = pNext->pstNext;
		}

		if (pTmpservice)
		{
			pCurrent->pstNext = pTmpservice;
		}
	}

	PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
	return AL_SUCCESS;
}

static AL_Return_t _AI_PSI_Monitor_OtherPmtStack(al_void *pData)
{
	AL_PSIMon_SimplePmt_t *pList = al_null;
	AL_PSIMon_SimplePmt_t *pNext = al_null;
	AL_PSIMon_SimplePmt_t *pCurrent = al_null;
	AL_PSIMon_SimplePmt_t *pTmpservice = al_null;
	AL_PSIMon_SimplePmt_t stProg;
	MID_SiutilPmtInfo_t *pPmt = (MID_SiutilPmtInfo_t *) pData;
	al_int iCount = 0;
    MID_SiutilPmtStreamInfoDescr_t *pComp = NULL;

	memset(&stProg, 0, sizeof(AL_PSIMon_SimplePmt_t));

	if (pPmt == NULL)
	{
		return AL_FAILURE;
	}
	//PSI_MONITOR_DEBUG_MSG("[%s:%d] program_number ============ %d\n",__FUNCTION__,__LINE__,pPmt->program_number);
	stProg.usProgNum = pPmt->program_number;

	for (iCount = 0; iCount < pPmt->comp_count; iCount++)
	{
	    pComp = &pPmt->p_comp[iCount];

	    switch (pComp->stream_type)
	    {
	        case STREAM_TYPE_VIDEO_MPEG1:
	        case STREAM_TYPE_VIDEO_MPEG2:
	        case STREAM_TYPE_VIDEO_MPEG4:
	        case STREAM_TYPE_VIDEO_AVC:	/*H.264*/
			#ifdef CONFIG_DTMB_SYSTEM
			case STREAM_TYPE_VIDEO_AVS:
			#endif
			case STREAM_TYPE_VIDEO_HEVC:
	            stProg.bHasVideo = TRUE;
				break;

			case STREAM_TYPE_AUDIO_MPEG1:
			case STREAM_TYPE_AUDIO_MPEG2:
			case STREAM_TYPE_AUDIO_AC3:
			case STREAM_TYPE_AUDIO_EAC3:
			case STREAM_TYPE_AUDIO_AAC:
			case STREAM_TYPE_AUDIO_MPEG2_AAC:
				stProg.bHasAudio = TRUE;
				break;

			case STREAM_TYPE_PRIVATE_DATA:
				break;
	   		default:
	        	break;
	    }
	}

	PSIMON_MUTEX_LOCK(g_PsiMonMutex);
	pList = g_pstCurrPmtSrvList;

	pTmpservice = (AL_PSIMon_SimplePmt_t *) zero_malloc(sizeof(AL_PSIMon_SimplePmt_t));

	if (pTmpservice == al_null)
	{
		PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
		return AL_FAILURE;
	}

	memcpy(pTmpservice,&stProg,sizeof(AL_PSIMon_SimplePmt_t));
	pTmpservice->pstNext = al_null;

	if (pList == al_null)
	{
		pList = pTmpservice;
		g_pstCurrPmtSrvList = pList;
	}
	else
	{
		pCurrent = pList;

		pNext = pCurrent;
		while (pNext)
		{
			/* the service is presented in list, no need to add */
			if (pNext->usProgNum == pTmpservice->usProgNum)
			{
				SAFE_FREE(pTmpservice);
				pTmpservice = al_null;
				break;
			}
			pCurrent  =pNext;
			pNext = pNext->pstNext;
		}

		if (pTmpservice)
		{
			pCurrent->pstNext = pTmpservice;
		}
	}

	PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
	return AL_SUCCESS;
}

static AL_Return_t _AI_PSI_Monitor_OtherPmtReset(al_void)
{
	AL_PSIMon_SimplePmt_t *pCurrent = al_null;
	AL_PSIMon_SimplePmt_t *pNext = al_null;

	PSIMON_MUTEX_LOCK(g_PsiMonMutex);
	pCurrent = g_pstCurrPmtSrvList;

	while(pCurrent)
	{
		pNext = pCurrent->pstNext;

		SAFE_FREE(pCurrent);
		pCurrent = al_null;
		pCurrent = pNext;
	}

	g_pstCurrPmtSrvList = al_null;
	PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
	return AL_SUCCESS;
}

static al_void _AI_PSI_Monitor_OtherTpSrvListReset(void)
{
	AL_PSIMon_SimpleSrv_t *pCurrent = al_null;
	AL_PSIMon_SimpleSrv_t *pNext = al_null;

	PSIMON_MUTEX_LOCK(g_PsiMonMutex);

	g_u16NumberOfOtherTpSrv = 0;
	g_bOtherSDTNeedToDecode = al_false;

	pCurrent = g_pstOtherNitSrvList;

	while (pCurrent)
	{
		pNext = pCurrent->pstNext;
		SAFE_FREE(pCurrent);
		pCurrent = al_null;
		pCurrent = pNext;
	}

	g_pstOtherNitSrvList = al_null;

	pCurrent = g_pstOtherSdtSrvList;

	while (pCurrent)
	{
		pNext = pCurrent->pstNext;
		SAFE_FREE(pCurrent->pucname);
		pCurrent->pucname = al_null;
		SAFE_FREE(pCurrent);
		pCurrent = al_null;
		pCurrent = pNext;
	}

	g_pstOtherSdtSrvList = al_null;

	memset((al_uint8 *)g_u32TpListCnt,0,PSIMON_SIZE_OF_TMP_TP_LIST*sizeof(al_uint32));

	PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
}

static al_uint16 _AI_PSI_Monitor_OtherTpServiceFound(void)
{
	AL_PSIMon_SimpleSrv_t *pnit_srvlist = al_null;
	AL_PSIMon_SimpleSrv_t *psdt_srvlist = al_null;
	// AL_PSIMon_SimpleSrv_t *parentsrv = g_pstOtherNitSrvList;
	// AL_PSIMon_SimpleSrv_t *pcursrv = g_pstOtherNitSrvList;

	PSIMON_MUTEX_LOCK(g_PsiMonMutex);

	pnit_srvlist = g_pstOtherNitSrvList;

	/*sync. nit & sdt service list. if the service present in both service, it seems as a valid service.*/
	/* it can be added to database.*/
	while (pnit_srvlist)
	{
		psdt_srvlist = g_pstOtherSdtSrvList;

		while (psdt_srvlist)
		{
			if(pnit_srvlist->usServiceId == psdt_srvlist->usServiceId
				&& pnit_srvlist->usTsId == psdt_srvlist->usTsId )
			{
				pnit_srvlist->pucname = psdt_srvlist->pucname;
				pnit_srvlist->ucServiceType = psdt_srvlist->ucServiceType;
				break;
			}

			psdt_srvlist = psdt_srvlist->pstNext;
		}

		pnit_srvlist = pnit_srvlist->pstNext;
	}

	/*delet invalid service*/
#if 0
	while (pcursrv)
	{
		if (pcursrv->pucname == al_null)
		{
			PSI_MONITOR_DEBUG_MSG("service(%x) will be removed \n",pcursrv->usServiceId);
			/*the service doesn't presnet in SDT*/
			if (parentsrv == pcursrv)
			{
				g_pstOtherNitSrvList = parentsrv->pstNext;
				SAFE_FREE(parentsrv);
				parentsrv = al_null;
				parentsrv = g_pstOtherNitSrvList;
			}
			else
			{
				parentsrv->pstNext = pcursrv->pstNext;
				SAFE_FREE(pcursrv);
				pcursrv = al_null;
			}

			g_u16NumberOfOtherTpSrv--;
		}
		else
		{
			parentsrv = pcursrv;
		}

		if (parentsrv)
		{
			pcursrv = parentsrv->pstNext;
		}
	}
#endif

	PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);

	PSI_MONITOR_DEBUG_MSG("remind new srv = %d \n",g_u16NumberOfOtherTpSrv);

	return g_u16NumberOfOtherTpSrv;
}

static AL_PSIMon_SimpleSrv_t *_AI_PSI_Monitor_OtherTpGetAFreeSrvSlot(AI_PsiMon_OtherTp_SrvList_t eType)
{
	AL_PSIMon_SimpleSrv_t *pcurlist = al_null;
	AL_PSIMon_SimpleSrv_t *pnewslot = al_null;

	PSIMON_MUTEX_LOCK(g_PsiMonMutex);

	if (eType == AL_PSIMONITOR_OTHERTP_SRVLIST_SDT)
	{
		pcurlist = g_pstOtherSdtSrvList;
	}
	else
	{
		pcurlist = g_pstOtherNitSrvList;
	}

	if (pcurlist)
	{
		pnewslot = pcurlist->pstNext;

		while (pnewslot)
		{
			pcurlist = pnewslot;
			pnewslot = pcurlist->pstNext;
		}

		pnewslot = (AL_PSIMon_SimpleSrv_t *)zero_malloc(sizeof(AL_PSIMon_SimpleSrv_t));

		if (pnewslot == al_null)
		{
			PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
			PSI_MONITOR_ERROR_MSG("NO MEMORY!! for new service slot\n");
			return al_null;
		}

		pcurlist->pstNext = pnewslot;

		if (eType == AL_PSIMONITOR_OTHERTP_SRVLIST_SDT)
		{
			pnewslot->pucname = (al_uint8 *) zero_malloc(DB_DVB_MAX_CHNAME_LEN);

			if (pnewslot->pucname == al_null)
			{
				PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
				PSI_MONITOR_ERROR_MSG("NO MEMORY!! for new service name\n");
				return al_null;
			}
		}
	}
	else
	{
		pnewslot = (AL_PSIMon_SimpleSrv_t *)zero_malloc(sizeof(AL_PSIMon_SimpleSrv_t));

		if (pnewslot == al_null)
		{
			PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
			PSI_MONITOR_ERROR_MSG("NO MEMORY!! for new service slot\n");
			return al_null;
		}

		if (eType == AL_PSIMONITOR_OTHERTP_SRVLIST_SDT)
		{
			g_pstOtherSdtSrvList = pnewslot;

			pnewslot->pucname = (al_uint8 *) zero_malloc(DB_DVB_MAX_CHNAME_LEN);

			if (pnewslot->pucname == al_null)
			{
				PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
				PSI_MONITOR_ERROR_MSG("NO MEMORY!! for new service name\n");
				return al_null;
			}
		}
		else
		{
			g_pstOtherNitSrvList = pnewslot;
		}
	}

	pnewslot->pstNext = NULL;

	PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);

	return pnewslot;
}

static al_bool _AI_PSI_Monitor_IsTransStreamPresent(al_uint16 u16TsId, AL_DB_EDBType_t eDBType)
{
	al_uint32 u32TotalTpNum = 0;
	AL_RecHandle_t hTPHdl = AL_DB_INVALIDHDL;
	al_uint16 u16QueryTsId = 0;
	AL_MultiplexDetail_t stTSInfo;

	memset(&stTSInfo, 0, sizeof(AL_MultiplexDetail_t));

	if (AL_SUCCESS != AL_DB_GetRecordsTotalNum(eDBType, AL_RECTYPE_DVBMULTIPLEX, &u32TotalTpNum))
	{
		return al_false;
	}

	if (u32TotalTpNum == 0)
	{
		return al_false;
	}

	if (u16TsId == 0)
	{
		return al_true;
	}

	if (AL_SUCCESS == AL_DB_GetRecord(AL_DB_REQ_GETFIRST, eDBType, AL_RECTYPE_DVBMULTIPLEX, &hTPHdl))
	{
		do
		{
			if (AL_SUCCESS == AL_DB_QueryDetail(hTPHdl, &stTSInfo))
			{
				if (eDBType == AL_DBTYPE_DVB_C)
				{
					u16QueryTsId = stTSInfo.stDVBCMultiplex.usTsId;
				}
				else if (eDBType == AL_DBTYPE_DVB_T)
				{
					u16QueryTsId = stTSInfo.stDVBTMultiplex.usTsId;
				}
				else if (eDBType == AL_DBTYPE_DVB_S)
				{
					u16QueryTsId = stTSInfo.stDVBSMultiplex.usTsId;
				}
                #ifdef CONFIG_ISDB_SYSTEM
				else if (eDBType == AL_DBTYPE_DVB_SBTVD)
				{
					u16QueryTsId = stTSInfo.stSBTVDMultiplex.usTsId;
				}
                #endif

				if(u16QueryTsId == u16TsId)
				{
					return al_true;
				}
			}
		} while(AL_DB_GetRecord(AL_DB_REQ_GETNEXT, eDBType, AL_RECTYPE_DVBMULTIPLEX, &hTPHdl) == AL_SUCCESS);
	}

	return al_false;
}

static al_void _AI_PSI_Monitor_PmtCallbkBeforeParseInit(AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrProg)
{
	al_int iCount = 0;
	DBPIDInfo_t		stPrvPid[DB_DVB_MAX_PRV_COMP_NUM];
	memset(&stPrvPid, 0, sizeof(DBPIDInfo_t)*DB_DVB_MAX_PRV_COMP_NUM);

	/* Reset provid data */
	AL_DB_QueryDetailFieldByName(hCurrProg, (al_uint8 *)"stPrvPid", (al_void *)&stPrvPid);

	for (iCount = 0; iCount < DB_DVB_MAX_PRV_COMP_NUM; iCount++)
	{
		stPrvPid[iCount].usCodec = (al_uint16)DB_DVB_INVALID_PID;
		stPrvPid[iCount].usDataPID = (al_uint16)0;
		stPrvPid[iCount].usCompTag = (al_uint16)0;
	}

	if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProg, (al_uint8*)"stPrvPid", &stPrvPid))
	{
		PSI_MONITOR_ERROR_MSG("update stPrvPid failed !!!\n");
	}
#ifdef CONFIG_SUPPORT_SUBTITLE
	AL_Subtitle_Reset();
#endif
#ifdef CONFIG_SUPPORT_ISDB_SUBTITLE
	AL_SBSUB_Reset();
#endif
#ifdef CONFIG_SUPPORT_TTX
//#ifdef CONFIG_SUPPORT_ANTENNA_READY_HD_CERTIFICATION
	AL_TTX_Reset();
//#endif
#endif
}

static al_uint32 _AI_PSI_Monitor_VideoStreamUpdate(AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrProg,
	MID_SiutilPmtStreamInfoDescr_t * pComp, al_bool IsVideoFound)
{
	al_uint32 u32UpdateFlag = 0;
	al_uint16 u16CompTag = 0;
	dvbpsi_strmid_dr_t si_strmid;
	dvbpsi_ca_dr_t *pCaDest = al_null;
	al_int iProcessLen = 0;
	al_int iDescLen = 0;
	DBPIDInfo_t		stVideoPid;

	if (pComp == al_null)
	{
		return 0;
	}

    al_int iRemainLen = pComp->descLen;

	memset(&stVideoPid, 0, sizeof(DBPIDInfo_t));

	 AL_DB_QueryDetailFieldByName(hCurrProg, (al_uint8 *)"stVideoPid", (al_void *)&stVideoPid);

	/* current playback video pid dispose */
	if (IsVideoFound == 0)
	{
		/*  TODO: video pid changed?, scrambled?*/
		/* 1. Check video changed */
		/* 1.1 check video pid*/
		if (pComp->elementary_pid != ((stVideoPid.usDataPID)&0x1fff))
		{
			if (dvbpsi_DecodeStrmIdDr(pComp->p_desc, pComp->descLen,&si_strmid) >= 0)
			{
				u16CompTag = si_strmid.i_comp_data;
			}

			/* video pid changed.*/
			u32UpdateFlag |= COMP_CHG_VID;
			stVideoPid.usDataPID =
				(stVideoPid.usDataPID & 0xe000)
				| (al_uint16)(pComp->elementary_pid & 0x1fff);
			stVideoPid.usCompTag = u16CompTag;

			if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProg, (al_uint8*)"stVideoPid", &stVideoPid))
			{
				PSI_MONITOR_ERROR_MSG("update stVideoPid failed !!!\n");
			}
		}

		/*1.2 Check video codec changes or not */
		AL_DB_QueryDetailFieldByName(hCurrProg, (al_uint8 *)"stVideoPid", (al_void *)&stVideoPid);
		if (pComp->stream_type != stVideoPid.usCodec)
		{
			u32UpdateFlag |= COMP_CHG_VID_CODEC;
			stVideoPid.usCodec = pComp->stream_type;

			if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProg, (al_uint8*)"stVideoPid", &stVideoPid))
			{
				PSI_MONITOR_ERROR_MSG("update stVideoPid failed !!!\n");
			}
		}

		/* 2. check scrambled*/
		while (iRemainLen > 0)
		{
			iDescLen = *(pComp->p_desc+iProcessLen+1)+2;
			if (*(pComp->p_desc+iProcessLen) == DESCR_CA)
			{
				pCaDest = dvbpsi_DecodeCADr((pComp->p_desc+iProcessLen), iDescLen);
				if (pCaDest)
				{
					u32UpdateFlag |= COMP_CHG_CA;
					g_CA_SYS_ID = pCaDest->i_ca_system_id;
					SAFE_FREE(pCaDest);
					pCaDest = al_null;
				}
			}
			iRemainLen -= iDescLen;
			iProcessLen += iDescLen;
		}
	}
	/* other video pid store prv pid info, for mheg5 */
#ifdef CONFIG_SUPPORT_MHEG5 //Gahu:D0506
	else if( g_ePsiFollowSpec==AL_PSIMON_SPECIAL_SPEC_DTG
		|| ( g_ePsiFollowSpec==AL_PSIMON_SPECIAL_SPEC_NORDIG && APP_Area_SupportMHEG5() ) )
#else
	else if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_DTG)
#endif
	{
		if (pComp->elementary_pid != ((stVideoPid.usDataPID)&0x1fff))
		{
			if (dvbpsi_DecodeStrmIdDr(pComp->p_desc, pComp->descLen,&si_strmid) >= 0)
			{
				u16CompTag = si_strmid.i_comp_data;
			}

			DBPIDInfo_t		stPrvPid[DB_DVB_MAX_PRV_COMP_NUM];
			memset(&stPrvPid, 0, sizeof(DBPIDInfo_t)*DB_DVB_MAX_PRV_COMP_NUM);
			al_uint16 iCount = 0;
			al_uint16 TmpPid = 0;

			 AL_DB_QueryDetailFieldByName(hCurrProg, (al_uint8 *)"stPrvPid", (al_void *)&stPrvPid);
			/* in the case, it's not primary video & not in private space */
			for (iCount = 0; iCount < DB_DVB_MAX_PRV_COMP_NUM; iCount++)
			{
				TmpPid = stPrvPid[iCount].usDataPID;

				if (TmpPid == 0 || TmpPid == DB_DVB_INVALID_PID)
				{
					stPrvPid[iCount].usCodec = (al_uint16)pComp->stream_type;
					stPrvPid[iCount].usDataPID = (al_uint16)pComp->elementary_pid;
					stPrvPid[iCount].usCompTag = (al_uint16)u16CompTag;

					if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProg, (al_uint8*)"stPrvPid", &stPrvPid))
					{
						PSI_MONITOR_ERROR_MSG("update stPrvPid failed !!!\n");
					}

					return 0;
				}
			}
		}
	}

	return u32UpdateFlag;

}

static al_void _AI_PSI_Monitor_AudioStreamUpdate(MID_SiutilPmtStreamInfoDescr_t * pComp)
{
	_AI_PSI_Monitor_CurrProgAudioStack(pComp);
}

static al_uint32 _AI_PSI_Monitor_PrivateStreamUpate(AL_DB_EDBType_t eDBType,
	AL_RecHandle_t hCurrProg, MID_SiutilPmtStreamInfoDescr_t * pComp)
{
	al_uint32 u32Ret = 0;
	al_bool bSpecifiedComponent = al_false;

	if (pComp == al_null)
	{
		return 0;
	}
#ifdef CONFIG_SUPPORT_TTX
	/* 1. teletext checking */
	UINT8 teletext_tags[3];

	teletext_tags[0] = DESCR_VBI_DATA;
	teletext_tags[1] = DESCR_VBI_TELETEXT;
	teletext_tags[2] = DESCR_TELETEXT;

	if (MID_SIUTIL_TagsInDescriptorArray(teletext_tags, 3, pComp->p_desc, pComp->descLen) > 0)
	{
		bSpecifiedComponent = al_true;
		AI_TTX_ParseDesc(pComp->p_desc, pComp->descLen, pComp->elementary_pid);

		//PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_TELETECT_UPDATE, 0);
		u32Ret |= COMP_CHG_TTX_FOUND;
	}
#endif
#ifdef CONFIG_SUPPORT_SUBTITLE
	/* 2. subtitle checking */
	UINT8 subtitle_tags[1];

	subtitle_tags[0] = DESCR_SUBTITLING;

	if (MID_SIUTIL_TagsInDescriptorArray(subtitle_tags, 1, pComp->p_desc, pComp->descLen) > 0)
	{
		bSpecifiedComponent=TRUE;

		AL_Subtitle_ParseDesc(pComp->p_desc, pComp->descLen, pComp->elementary_pid);

		//PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SUBTITLE_UPDATE, 0);
		u32Ret |= COMP_CHG_SUB_FOUND;
	}
#endif
#ifdef CONFIG_SUPPORT_ISDB_SUBTITLE
// 2. sbtvd subtitle checking
	UINT8 sbsub_tags[1];
	sbsub_tags[0] = DESCR_STREAM_ID;

	if (MID_SIUTIL_TagsInDescriptorArray(sbsub_tags, 1, pComp->p_desc, pComp->descLen) > 0)
	{
		//bSpecifiedComponent=TRUE;
		// got subtitle related descriptors, the component is subtitle
		//	TODO:
		bSpecifiedComponent = TRUE;
		printf("%s %d :got sb subtitle component!\n", __FUNCTION__,__LINE__);
		AI_SBSUB_ParseDesc(pComp->p_desc, pComp->descLen, pComp->elementary_pid);
		//PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_CLOSECAPTION_UPDATE, 0);
		u32Ret |= COMP_CHG_CC_FOUND;
	}
#endif
#ifdef SUPPORT_AUDIO_AC3
	/* 3. AC3 checking*/
	al_uint8 audiodr_tags[3];

	audiodr_tags[0] = DESCR_AC3;
	audiodr_tags[1] = DESCR_EAC3;
	audiodr_tags[2] = DESCR_EXTENSION;

	if (MID_SIUTIL_TagsInDescriptorArray(audiodr_tags, 3, pComp->p_desc, pComp->descLen) > 0)
	{
		bSpecifiedComponent = al_true;

		_AI_PSI_Monitor_CurrProgAudioStack(pComp);
		u32Ret |= COMP_CHG_AUD_FOUND;
	}
#endif
#ifdef CONFIG_DTMB_SYSTEM
	/* 4. DRA checking*/
	al_uint8 draaudiodr_tags[1];
	al_uint8 RDA_Regist_audiodr_tags[1];
	draaudiodr_tags[0] = DESCR_DRA_AUDIO_STREAM;
	RDA_Regist_audiodr_tags[0] = DESCR_DRA_REGISTRATION;
	if (MID_SIUTIL_TagsInDescriptorArray(draaudiodr_tags, 1, pComp->p_desc, pComp->descLen) > 0)
	{
		bSpecifiedComponent = al_true;

		_AI_PSI_Monitor_CurrProgAudioStack(pComp);
		u32Ret |= COMP_CHG_AUD_FOUND;
	}
	else if((MID_SIUTIL_TagsInDescriptorArray(RDA_Regist_audiodr_tags, 1, pComp->p_desc, pComp->descLen) > 0)
		&& (dvbpsi_DecodeDRARegistrationDr(pComp->p_desc, pComp->descLen) == 0x44524131))
	{
		bSpecifiedComponent = al_true;

		_AI_PSI_Monitor_CurrProgAudioStack(pComp);
		u32Ret |= COMP_CHG_AUD_FOUND;
	}
#endif
	/* 4. component is unknow, it should add to private stock for MHEG-5 access */
    /* also DTG and Soarview need to add*/
	if (((g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_DTG)||(g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG))
		&& (bSpecifiedComponent == al_false))
	{
		al_uint16 iCount = 0;
		al_uint16 u16pid = 0;
		al_uint16 u16comp_tag = 0;
		DBPIDInfo_t stPrvPid[DB_DVB_MAX_PRV_COMP_NUM];

		memset(&stPrvPid, 0, sizeof(DBPIDInfo_t)*DB_DVB_MAX_PRV_COMP_NUM);

		AL_DB_QueryDetailFieldByName(hCurrProg, (al_uint8 *)"stPrvPid", (al_void *)&stPrvPid);

		for (iCount = 0; iCount < DB_DVB_MAX_PRV_COMP_NUM; iCount++)
		{
			u16pid = stPrvPid[iCount].usDataPID;
			u16pid = u16pid & 0x1fff;

			/* invalid pid value */
			if (u16pid == 0 || u16pid == 0x1fff)
			{
				break;
			}
		}

		if (iCount < DB_DVB_MAX_PRV_COMP_NUM)
		{
			dvbpsi_strmid_dr_t si_strmid;

			if (dvbpsi_DecodeStrmIdDr(pComp->p_desc, pComp->descLen,&si_strmid) >= 0)
			{
				u16comp_tag = si_strmid.i_comp_data;
			}

			u16pid = pComp->elementary_pid;

			stPrvPid[iCount].usDataPID = (al_uint16)u16pid;
			stPrvPid[iCount].usCompTag = (al_uint16)u16comp_tag;

			if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProg, (al_uint8*)"stPrvPid", &stPrvPid))
			{
				PSI_MONITOR_ERROR_MSG("update stPrvPid failed !!!\n");
			}
		}
	}
	return u32Ret;
}

#ifdef CONFIG_SUPPORT_OTA_UPGRADE
static AL_Return_t _AI_PSI_Monitor_InNitOtaProcess(al_void *pData, AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrTpHdl)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *) pData;
	dvbpsi_linkage_dr_t  *pstLinkage = al_null;
    al_uint8 *pu8Data=NULL;
#ifdef CONFIG_SUPPORT_OAD_UPGRADE
	al_uint16 u16OADHwModel = 0xffff;
	al_uint16 u16OADHwVersion = 0xffff;
#endif
	al_int i = 0;

	if (pNit == al_null || hCurrTpHdl == AL_DB_INVALIDHDL)
	{
		return AL_INVALID_PARAM;
	}

	for (i = 0; i< pNit->descLen; )
	{
        if (DESCR_LINKAGE != *(pNit->p_descr+i))
        {
            i += *(pNit->p_descr+i+1) +2;
            continue;
        }

        pstLinkage = dvbpsi_DecodeLinkDr((pNit->p_descr+i), pNit->descLen - i);

        if (pstLinkage == NULL)
        {
            break;
        }

        i += pstLinkage->length + 9;

        al_uint8 u8OtaType = 0xff;

#ifdef CONFIG_SUPPORT_SSU_UPGRADE
        al_uint8 Flash_OUI[3];
        al_int8 i8OuiLen = 0;
        al_uint8 u8OuiIndex = 0;
		memset(Flash_OUI, 0, sizeof(al_uint8)*3);
        if (pstLinkage->i_linkage_type == OUI_LINKAGE_TYPE)
        {
            MID_OTA_GetOtaMonThreadData(OTA_DATA_F_OUI,Flash_OUI);
            i8OuiLen= *(pstLinkage->data) - 1;
            pu8Data = pstLinkage->data + 1;

            while (i8OuiLen > 0)
            {
                if ((Flash_OUI[0] == pu8Data[0]) && (Flash_OUI[1] == pu8Data[1]) && (Flash_OUI[2] == pu8Data[2]))
                {
                    MID_OTA_SetOtaMonThreadData(OTA_DATA_TS_OUI,pu8Data);
                    u8OtaType = OTA_TYPE_SSU;
                }
#ifdef CONFIG_SUPPORT_SSU_ENHANCE_UPGRADE
				if (pu8Data[0]==0x00 && pu8Data[1]==0x01 && pu8Data[2]==0x5a)
				{
					MID_OTA_SetOtaMonThreadData(OTA_DATA_TS_OUI,pu8Data);
					u8OtaType = OTA_TYPE_SSU;
				}
#endif
                i8OuiLen = i8OuiLen - 3;
                pu8Data = pu8Data + 3 + pu8Data[3] + 1;
                u8OuiIndex++;
            }

            if (u8OtaType == OTA_TYPE_SSU)
            {
                MID_OTA_SetOtaMonThreadData(OTA_DATA_TS_SERVICE_ID,&pstLinkage->i_service_id);
                MID_OTA_SetOtaMonThreadData(OTA_DATA_TS_ONID,&pstLinkage->i_original_network_id);
                MID_OTA_SetOtaMonThreadData(OTA_DATA_TS_TSID,&pstLinkage->i_transport_stream_id);
            }
            else
            {
                if (pstLinkage != NULL)
                {
                    GL_MemFree(pstLinkage);
                    pstLinkage = NULL;
                }
                continue;
            }
		}
#endif

#ifdef CONFIG_SUPPORT_OAD_UPGRADE
        if (pstLinkage != NULL && pstLinkage->i_linkage_type == OAD_OUI_LINKAGE_TYPE)
        {
            u8OtaType = OTA_TYPE_OAD;
            MID_OTA_SetOtaMonThreadData(OTA_DATA_TS_SERVICE_ID,&pstLinkage->i_service_id);
			MID_OTA_SetOtaMonThreadData(OTA_DATA_TS_ONID,&pstLinkage->i_original_network_id);
			MID_OTA_SetOtaMonThreadData(OTA_DATA_TS_TSID,&pstLinkage->i_transport_stream_id);
         //   MID_OTA_SetOtaMonThreadData(OTA_DATA_TS_OTA_TYPE,&u8OtaType);
            pu8Data = pstLinkage->data;
            MID_OTA_SetOtaMonThreadData(OTA_DATA_TS_OUI,pu8Data);
            pu8Data += 3;
			u16OADHwModel = pu8Data[0]*256 + pu8Data[1];
            MID_OTA_SetOtaMonThreadData(OTA_DATA_TS_HW_MODEL,&u16OADHwModel);
            pu8Data += 2;
			u16OADHwVersion= pu8Data[0]*256 + pu8Data[1];
            MID_OTA_SetOtaMonThreadData(OTA_DATA_TS_HW_VERSION,&u16OADHwVersion);

            GL_MemFree(pstLinkage);
            pstLinkage = NULL;
        }
#endif
        if (pstLinkage != NULL)
        {
            GL_MemFree(pstLinkage);
            pstLinkage = NULL;
        }

        if (u8OtaType == OTA_TYPE_SSU || u8OtaType == OTA_TYPE_OAD)
        {
            MID_OtaMonNotifyDetectUpgrade();
            break;
        }
    }

	return AL_SUCCESS;
}

static AL_Return_t _AI_PSI_Monitor_InPatOtaProcess(al_void *pData)
{
	if (pData == al_null)
	{
		return AL_INVALID_PARAM;
	}

	MID_OtaMonNotifyUpdate(pData);

	return AL_SUCCESS;
}
#endif

static AL_Return_t _AI_PSI_Monitor_OtherPmtMon_Start()
{
	_AI_PSI_Monitor_OtherPmtReset();
	MID_PmtOtherStop(al_false);
	if (MID_SUCCESS != MID_PmtOtherStart())
	{
		return AL_FAILURE;
	}

	return AL_SUCCESS;
}

#ifdef CONFIG_SUPPORT_INDONESIA_EWS
static al_void _AI_PSI_Monitor_IndonesiaEWS_PmtCallback(al_void *pData)
{
	if (pData == al_null)
	{
		return;
	}

	MID_SiutilPmtInfo_t *pPmt = (MID_SiutilPmtInfo_t *) pData;
	al_int iCount = 0;
	MID_SiutilPmtStreamInfoDescr_t *pComp = NULL;

	for (iCount = 0; iCount < pPmt->comp_count; iCount++)
	{
		pComp = &pPmt->p_comp[iCount];
		if (pComp->stream_type == 0x80) // EWS stream
		{
			PSI_MONITOR_DEBUG_MSG("[%s:%d] EWS PID = 0x%04x\n", __func__, __LINE__, pComp->elementary_pid);
			MID_PsiMonSetEwsPid(pComp->elementary_pid);
			break;
		}
	}

}

#endif

#ifdef CONFIG_CIPLUS_SUPPORT
static BOOLEAN app_ciplus_find_desc(
    U8BIT tag,
    U8BIT *desc_loop, U16BIT desc_loop_len,
    U8BIT **desc )
{
    U8BIT *ptr = NULL, *end = NULL;
    U16BIT len = 0;

    if (desc_loop == NULL || desc_loop_len < 2)
    {
        return FALSE;
    }

    ptr = desc_loop;
    end = desc_loop + desc_loop_len;

    while (ptr + 2 < end)
    {
        len = ptr[1];

        if (ptr[0] == tag)
        {
            if (desc)
            {
                *desc = ptr;
            }
            return TRUE;
        }

        ptr += 2;

        if (ptr + len >= end)
        {
            break;
        }

        ptr += len;
    }

    return FALSE;
}

void app_ciplus_parse_ci_protection_desc(AL_RecHandle_t hCurrProgHdl,MID_SiutilSdtServiceDescr_t *pSdtDescr)
{
    U8BIT *ci_protection_desc = NULL;
#ifndef CONFIG_CIPLUS_CACHE_DATA_NOT_SAVE
    BOOLEAN bNeedResetProtectData = FALSE;
 	DBCIProtection_t usCIShunningData = {CI_SHUNNING_INVALID,0,0,0,{0,0}};
#endif
 	S_CI_PROTECTION	usCIProtectData = {0,0,0,{0,0}};
 	al_uint8 bFindCIplusDesc = CI_SHUNNING_INVALID;

    if( app_ciplus_find_desc(DESCR_CI_PROTECTION_DESC,pSdtDescr->p_descr,pSdtDescr->descLen,&ci_protection_desc) )
    {
        MID_DTVCI_PassCIProtectionDesc(ci_protection_desc,&usCIProtectData);
		bFindCIplusDesc = CI_SHUNNING_PRESENT;
    }
    else
    {
        MID_DTVCI_PassCIProtectionDesc(NULL,&usCIProtectData);
		bFindCIplusDesc = CI_SHUNNING_ABSENT;
    }
	bFindCIplusDesc = bFindCIplusDesc;//compiler error

#ifndef CONFIG_CIPLUS_CACHE_DATA_NOT_SAVE
	if (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usCIShunningData", (al_void *)&usCIShunningData))
	{
		if(usCIShunningData.u8hasShunningData != bFindCIplusDesc
			||usCIShunningData.u8freeCiModeFlag != usCIProtectData.free_ci_mode_flag
			||usCIShunningData.u8matchBrandFlag != usCIProtectData.match_brand_flag
			||usCIShunningData.u8numberOfEntries != usCIProtectData.number_of_entries)
		{
			usCIShunningData.u8hasShunningData = bFindCIplusDesc;
			if(bFindCIplusDesc == CI_SHUNNING_ABSENT)
			{
				memset(&usCIProtectData,0x0,sizeof(S_CI_PROTECTION));
				bNeedResetProtectData = TRUE;
			}
			usCIShunningData.u8freeCiModeFlag = usCIProtectData.free_ci_mode_flag;
			usCIShunningData.u8matchBrandFlag = usCIProtectData.match_brand_flag;
			usCIShunningData.u8numberOfEntries = usCIProtectData.number_of_entries;
			usCIShunningData.u16entries[0] = usCIProtectData.entries[0];
			usCIShunningData.u16entries[1] = usCIProtectData.entries[1];
			AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"usCIShunningData", &usCIShunningData);
			MID_DTVCI_SetPSIUpdateFlag(TRUE,bNeedResetProtectData);
			MID_DTVCI_PassCIProtectionDesc(NULL,NULL);//update
		}
	}
#endif
}

static al_void _AI_PSI_Monitor_InSdtCIPlusDispose(al_void *pData,
	AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrProgHdl)
{
	MID_SiutilSdtInfo_t *pSdt = (MID_SiutilSdtInfo_t *) pData;
	MID_SiutilSdtServiceDescr_t *pSdtDescr = al_null;
 	al_uint16	usServiceId = 0xffff;
 	al_int iCount = 0;

	if (pSdt == al_null)
	{
		return;
	}

	if (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usServiceId", (al_void *)&usServiceId))
	{
		for (iCount = 0; iCount < pSdt->services_count; iCount++)
		{
			pSdtDescr = &pSdt->p_sdt_descr_t[iCount];

			if (usServiceId == HILO(pSdtDescr->sdt_service.service_id))
			{
	            app_ciplus_parse_ci_protection_desc(hCurrProgHdl,pSdtDescr);
				break;
			}
		}
	}
	else
	{
		PSI_MONITOR_ERROR_MSG("query service id failed!\n");
	}
}
#endif

static al_bool _AI_PSI_Monitor_CheckFreqPresent(AL_DB_EDBType_t eDBType, al_uint16 TSID, al_uint32 Freq)
{
	AL_RecHandle_t hRec = AL_DB_INVALIDHDL;
	al_uint32 uiIter = 0;

	al_bool _InnerMatchMultiplex(al_void *param, al_void const*pRec)
	{
		if (eDBType == AL_DBTYPE_DVB_T)
		{
			STDBMultiplexInfo_t *pTDBMultiplex = (STDBMultiplexInfo_t*)pRec;
			if (TSID == pTDBMultiplex->usTsId)
			{
				for (uiIter = 0; uiIter < DB_DVB_MAX_MULTIP_FREQ_NUM && pTDBMultiplex->uiFreqList[uiIter] != 0; uiIter++)
				{
					if (pTDBMultiplex->uiFreqList[uiIter] == Freq)
					{
						return al_true;
					}
				}
			}
			return al_false;
		}
		else if (eDBType == AL_DBTYPE_DVB_C)
		{
			return al_true;
		}
		else if (eDBType == AL_DBTYPE_DVB_S)
		{
			return al_true;
		}
		else
		{
			return al_false;
		}
	}

	if (DB_SUCCESS == CDBIFindRecord(eDBType, AL_RECTYPE_DVBMULTIPLEX, (fpCDBIRecMatch)_InnerMatchMultiplex,
		al_null, TRUE, &hRec) && (hRec != AL_DB_INVALIDHDL))
	{
		return al_true;
	}
	else
	{
		return al_false;
	}
}

// thailand evora
static al_void _AI_PSI_Monitor_InNitOtherTpFreqUpdate(al_void *pData, AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrTpHdl)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *)pData;
	al_uint32 uiIter1 = 0;
	AL_RecHandle_t hCurrNetHdl = AL_DB_INVALIDHDL;
	AL_RecHandle_t hTpHdl = AL_DB_INVALIDHDL;
	al_uint16 usTsId = 0xffff;
	al_uint16 usOrigNetId = 0xffff;
	al_uint32 uiFreqK = 0;
	dvbpsi_terrestrial_system_dr_t *pTerrSysDr = al_null;
	dvbpsi_cable_system_dr_t *pstCableSysDr = al_null;
	dvbpsi_satellite_system_dr_t *pstSateSysDr = al_null;

	if (pData == al_null || hCurrTpHdl == AL_DB_INVALIDHDL)
	{
		return;
	}

	if (g_ePsiUpdateOptions & AL_PSIMONITOR_FREQ_UPDATE)
	{

		if ((AL_SUCCESS == AL_DB_GetRecord(AL_DB_REQ_GETFIRST, eDBType, AL_RECTYPE_DVBMULTIPLEX, &hTpHdl)) && hTpHdl != AL_DB_INVALIDHDL)
		{
			do
			{
				hCurrNetHdl = hCurrTpHdl;

				if (AL_SUCCESS != AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBNETWORK, &hCurrNetHdl))
				{
					PSI_MONITOR_ERROR_MSG("Get tp handle failed !!!\n");
					continue;
				}
				else
				{
					al_uint16 usNetId = 0;
					if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hTpHdl, (al_uint8 *)"usNetId", (al_void *)&usNetId))
					{
						PSI_MONITOR_ERROR_MSG("query usTsId failed!\n");
						continue;
					}
					else
					{
						printf("usNetId =============================== %d\n",usNetId);
					}
				}

				if (hTpHdl == hCurrTpHdl)
				{
					continue;
				}
				if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hTpHdl, (al_uint8 *)"usTsId", (al_void *)&usTsId))
				{
					PSI_MONITOR_ERROR_MSG("query usTsId failed!\n");
					continue;
				}
				if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hTpHdl, (al_uint8 *)"usOrigNetId", (al_void *)&usOrigNetId))
				{
					PSI_MONITOR_ERROR_MSG("query usOrigNetId failed!\n");
					continue;
				}
				if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hTpHdl, (al_uint8 *)"uiFreqK", (al_void *)&uiFreqK))
				{
					PSI_MONITOR_ERROR_MSG("query uiFreqK failed!\n");
					continue;
				}

				for (uiIter1 = 0; uiIter1 < pNit->trans_count; uiIter1++)
				{
					MID_SiutilNitTsDescr_t *pNitTsDescr = &pNit->p_trans[uiIter1];
					/* delivery information check */
					if (AL_DBTYPE_DVB_T == eDBType)
					{
						pTerrSysDr = dvbpsi_DecodeDVBTerrestrialSystemDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen);

						/* no delivery information, no need to check service */
						if (pTerrSysDr == al_null)
						{
							continue;
						}
						printf("[%s:%d] usTsId: %d, %d, usOrigNetId: %d, %d, uiFreqK: %d, %d\n",__FUNCTION__,__LINE__, usTsId, pNitTsDescr->trans_id,usOrigNetId,pNitTsDescr->original_network_id,uiFreqK,pTerrSysDr->u32freq);
						if (usTsId == pNitTsDescr->trans_id && usOrigNetId == pNitTsDescr->original_network_id && uiFreqK != pTerrSysDr->u32freq)
						{
							printf("[%s:%d] uiFreqK ========================== %d, %d\n",__FUNCTION__,__LINE__,uiFreqK,pTerrSysDr->u32freq);
							uiFreqK = pTerrSysDr->u32freq;
							if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hTpHdl, (al_uint8 *)"uiFreqK", (al_void *)&uiFreqK))
							{
								PSI_MONITOR_ERROR_MSG("update uiFreqK failed!\n");
							}
						}
						SAFE_FREE(pTerrSysDr);
						pTerrSysDr = al_null;
					}
					else if (AL_DBTYPE_DVB_C == eDBType)
					{
						pstCableSysDr = dvbpsi_DecodeCableSystemDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen);

						/* no delivery information, no need to check service */
						if (pstCableSysDr == al_null)
						{
							continue;
						}

						if (usTsId == pNitTsDescr->trans_id && usOrigNetId == pNitTsDescr->original_network_id && uiFreqK != pstCableSysDr->freq)
						{
							uiFreqK = pstCableSysDr->freq;
							if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hTpHdl, (al_uint8 *)"uiFreqK", (al_void *)&uiFreqK))
							{
								PSI_MONITOR_ERROR_MSG("update uiFreqK failed!\n");
							}
						}

						SAFE_FREE(pstCableSysDr);
						pstCableSysDr = al_null;
					}
					else if (AL_DBTYPE_DVB_S == eDBType)
					{
						pstSateSysDr = dvbpsi_DecodeSatelliteSystemDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen);

						/* no delivery information, no need to check service */
						if (pstSateSysDr == al_null)
						{
							continue;
						}

						SAFE_FREE(pstSateSysDr);
						pstSateSysDr = al_null;
					}
				}
			} while(AL_DB_GetRecord(AL_DB_REQ_GETNEXT, eDBType, AL_RECTYPE_DVBMULTIPLEX, &hTpHdl) == AL_SUCCESS);
		}
	}
}

static al_void _AI_PSI_Monitor_InNitOtherTpFound(al_void *pData, AL_DB_EDBType_t eDBType, al_int iCurrentTS)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *)pData;
	MID_SiutilNitTsDescr_t *pNitTsDescr = al_null;
	dvbpsi_frequency_list_dr_t *pstFreqListDr = al_null;
	al_uint32 uTPNumber = 0;
	al_int i = 0;
	al_uint32 k = 0;
	bool bNewFreqFound = al_false;
	bool bTuneNewFreq = al_false;

	if (pNit == al_null)
	{
		return;
	}

	if (g_ePsiUpdateOptions & AL_PSIMONITOR_OTHTP_FOND)
	{
		if (g_hTPList != 0 && g_uiTuneFreqNum != 0)
		{
			AI_TpListFree(g_hTPList);
			g_uiTuneFreqNum = 0;
			AI_TpListInit(&g_hTPList);
		}

#if 0 /* temp mask by jun.luo on 2013/1/27, only check freq list desc of current TS */
		for (i = 0; i < pNit->trans_count; i++)
#else
		for (i = iCurrentTS; i <= iCurrentTS; i++)
#endif
		{
			pNitTsDescr = &pNit->p_trans[i];

			if (pNitTsDescr->original_network_id != NORDIG_RIKS_ONID)
			{
				/* Discard none NORDIG_RIKS_ONID */
				continue;
			}

			/* delivery information check */
			pstFreqListDr = dvbpsi_DecodeFrequencyListDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen, &uTPNumber);

			if (pstFreqListDr == al_null)
			{
				continue;
			}

			/* check current db type is same with nit transmit */
			if (((AL_DBTYPE_DVB_T == eDBType) && (pstFreqListDr->coding_type == DVBPSI_FREQLIST_CODINGTYPE_TERRESTRIAL))
				|| ((AL_DBTYPE_DVB_C == eDBType) && (pstFreqListDr->coding_type == DVBPSI_FREQLIST_CODINGTYPE_CABLE))
				|| ((AL_DBTYPE_DVB_S == eDBType) && (pstFreqListDr->coding_type == DVBPSI_FREQLIST_CODINGTYPE_SATELLITE))
			)
			{
				bNewFreqFound = al_false;

				for (k = 0; k < uTPNumber; k++)
				{
					if (_AI_PSI_Monitor_CheckFreqPresent(eDBType, pNit->p_trans[i].trans_id, *(al_uint32*)&pstFreqListDr->p_centre_freq[k]) == al_false)
					{
						bNewFreqFound = al_true;
						break;
					}
				}

				if (bNewFreqFound)
				{
					for (k = 0; k < uTPNumber; k++)
					{
						AI_TpListAddNode(g_hTPList, &pstFreqListDr->p_centre_freq[k].Cfrequency, sizeof(dvbpsi_frequency_t));
						g_uiTuneFreqNum++;
					}
					bTuneNewFreq = al_true;
				}
			}

			dvbpsi_FreeFrequencyListDr(pstFreqListDr);
		}

		if (bTuneNewFreq)
		{
			PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_FIND_NEW_TPLIST, g_hTPList);
		}
	}
}

#ifdef SUPPORT_NETWORK_UPDATE_RESCAN
static AL_RecHandle_t _AI_PSI_Monitor_CheckTpPresent(AL_DB_EDBType_t eDBType, al_uint16 NID, al_uint16 ONID , al_uint16 TSID)
{
	AL_RecHandle_t hRec = AL_DB_INVALIDHDL;

	al_bool _InnerMatchMultiplex(al_void *param, al_void const*pRec)
	{
		if( eDBType == AL_DBTYPE_DVB_T )
		{
			STDBMultiplexInfo_t *pTDBMultiplex = (STDBMultiplexInfo_t*)pRec;
			if( NID==pTDBMultiplex->usNetId && ONID==pTDBMultiplex->usOrigNetId && TSID==pTDBMultiplex->usTsId )
				return al_true;
		}
		else if( eDBType == AL_DBTYPE_DVB_C )
		{
			SCDBMultiplexInfo_t *pCDBMultiplex = (SCDBMultiplexInfo_t*)pRec;
			if( NID==pCDBMultiplex->usNetId && ONID==pCDBMultiplex->usOrigNetId && TSID==pCDBMultiplex->usTsId )
				return al_true;
		}
		return al_false;
	}

	CDBIFindRecord(eDBType, AL_RECTYPE_DVBMULTIPLEX, (fpCDBIRecMatch)_InnerMatchMultiplex, al_null, TRUE, &hRec);
	return hRec;
}

static al_void _AI_PSI_Monitor_InNitCurrNwkTpRescan(al_void *pData, AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrTPHdl)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *)pData;
	al_uint16 usOrigNetId = 0xffff;
	al_uint16 usNetId = 0xffff;
	al_uint32 uiFreqK = 0;
	al_uint32 uiFreq = 0;
	al_uint8 ucNitVersion = 0xff;
	al_uint8 ucTSIDNum = 0;
	al_uint16 usTSIDList[TDB_MAX_TSNUM_WITHIN_NETWORK];
	al_int i = 0;
	al_int j = 0;
	BOOLEAN bTSIDListChanged = al_false;

	if( pNit == al_null )
		return;

	if( (g_ePsiUpdateOptions & AL_PSIMONITOR_CURNWK_TP_RESCAN) &&
		(eDBType==AL_DBTYPE_DVB_T || eDBType==AL_DBTYPE_DVB_C) )
	{
		if( AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrTPHdl, (al_uint8 *)"usOrigNetId", (al_void *)&usOrigNetId) )
		{
			PSI_MONITOR_ERROR_MSG("Warning! query hCurrTPHdl's usOrigNetId failed!\n");
			return;
		}

		if( AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrTPHdl, (al_uint8 *)"usNetId", (al_void *)&usNetId) )
		{
			PSI_MONITOR_ERROR_MSG("Warning! query hCurrTPHdl's usNetId failed!\n");
			return;
		}

		if( AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrTPHdl, (al_uint8 *)"ucNitVersion", (al_void *)&ucNitVersion) )
		{
			PSI_MONITOR_ERROR_MSG("Warning! query hCurrTPHdl's ucNitVersion failed!\n");
			return;
		}

		if( AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrTPHdl, (al_uint8 *)"ucTSIDNum", (al_void *)&ucTSIDNum) )
		{
			PSI_MONITOR_ERROR_MSG("Warning! query hCurrTPHdl's ucTSIDNum failed!\n");
			return;
		}

		if( AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrTPHdl, (al_uint8 *)"usTSIDList", (al_void *)&usTSIDList) )
		{
			PSI_MONITOR_ERROR_MSG("Warning! query hCurrTPHdl's usTSIDList failed!\n");
			return;
		}

		memset( (al_uint8 *)g_u32TpListFreq, 0, TDB_MAX_TSNUM_WITHIN_NETWORK*sizeof(al_uint32) );
	#if 1
		if( g_hTPList!=0 && g_uiTuneFreqNum!=0 )
		{
			AI_TpListFree(g_hTPList);
			g_uiTuneFreqNum = 0;
			AI_TpListInit(&g_hTPList);
		}
	#endif

		if( pNit->network_id!=usNetId || pNit->p_trans[0].original_network_id!=usOrigNetId )
			return;

		if( pNit->version_number != ucNitVersion )
		{
			for( i=0 ; i<pNit->trans_count ; i++ )
			{
				MID_SiutilNitTsDescr_t *pNitTsDescr = &pNit->p_trans[i];

				for( j=0 ; j<ucTSIDNum ; j++ )
				{
					if( pNitTsDescr->trans_id == usTSIDList[j] )
						break;
				}

				if( j == ucTSIDNum )
				{
					bTSIDListChanged = al_true;

					dvbpsi_terrestrial_system_dr_t *pTerrSysDr = al_null;
					dvbpsi_cable_system_dr_t *pstCableSysDr = al_null;
					if( AL_DBTYPE_DVB_T == eDBType )
					{
						pTerrSysDr = dvbpsi_DecodeDVBTerrestrialSystemDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen);
						if( pTerrSysDr == al_null )
						{
							memset( (al_uint8 *)g_u32TpListFreq, 0, TDB_MAX_TSNUM_WITHIN_NETWORK*sizeof(al_uint32) );
						#if 1
							if( g_hTPList!=0 && g_uiTuneFreqNum!=0 )
							{
								AI_TpListFree(g_hTPList);
								g_uiTuneFreqNum = 0;
								AI_TpListInit(&g_hTPList);
							}
						#endif
							break;
						}
						g_u32TpListFreq[0] ++;
						g_u32TpListFreq[g_u32TpListFreq[0]] = pTerrSysDr->u32freq;
					#if 1
						uiFreq = pTerrSysDr->u32freq * 100;
						AI_TpListAddNode( g_hTPList, &uiFreq, sizeof(al_uint32) );
						g_uiTuneFreqNum++;
					#endif

						SAFE_FREE(pTerrSysDr);
						pTerrSysDr = al_null;
					}
					else if( AL_DBTYPE_DVB_C == eDBType )
					{
						pstCableSysDr = dvbpsi_DecodeCableSystemDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen);
						if( pstCableSysDr == al_null )
						{
							memset( (al_uint8 *)g_u32TpListFreq, 0, TDB_MAX_TSNUM_WITHIN_NETWORK*sizeof(al_uint32) );
						#if 1
							if( g_hTPList!=0 && g_uiTuneFreqNum!=0 )
							{
								AI_TpListFree(g_hTPList);
								g_uiTuneFreqNum = 0;
								AI_TpListInit(&g_hTPList);
							}
						#endif
							break;
						}
						g_u32TpListFreq[0] ++;
						g_u32TpListFreq[g_u32TpListFreq[0]] = pstCableSysDr->freq;
					#if 1
						uiFreq = pstCableSysDr->freq * 100;
						AI_TpListAddNode( g_hTPList, &uiFreq, sizeof(al_uint32) );
						g_uiTuneFreqNum++;
					#endif

						SAFE_FREE(pstCableSysDr);
						pstCableSysDr = al_null;
					}
				}
			}

			for( j=0 ; j<ucTSIDNum ; j++ )
			{
				for( i=0 ; i<pNit->trans_count ; i++ )
				{
					if( usTSIDList[j] == pNit->p_trans[i].trans_id )
						break;
				}

				if( i == pNit->trans_count )
				{
					AL_RecHandle_t hOtherTPHdl = _AI_PSI_Monitor_CheckTpPresent( eDBType, usNetId, usOrigNetId, usTSIDList[j] );
					if( hOtherTPHdl == AL_DB_INVALIDHDL )
						continue;

					if( AL_SUCCESS != AL_DB_QueryDetailFieldByName(hOtherTPHdl, (al_uint8 *)"uiFreqK", (al_void *)&uiFreqK) )
					{
						PSI_MONITOR_ERROR_MSG("Warning! query hOtherTPHdl's uiFreqK failed!\n");
						continue;
					}

					bTSIDListChanged = al_true;

					g_u32TpListFreq[0] ++;
					g_u32TpListFreq[g_u32TpListFreq[0]] = uiFreqK;
				#if 1
					uiFreq = uiFreqK * 100;
					AI_TpListAddNode( g_hTPList, &uiFreq, sizeof(al_uint32) );
					g_uiTuneFreqNum++;
				#endif
				}
			}

			g_u8CurrNitVersion = pNit->version_number;
			g_u8CurrNitTSIDNum = pNit->trans_count;
			if( g_u8CurrNitTSIDNum > TDB_MAX_TSNUM_WITHIN_NETWORK )
			{
				g_u8CurrNitTSIDNum = TDB_MAX_TSNUM_WITHIN_NETWORK;
				PSI_MONITOR_ERROR_MSG("Warning! g_u8CurrNitTSIDNum(%d) bigger than TDB_MAX_TSNUM_WITHIN_NETWORK(%d)!\n",pNit->trans_count,TDB_MAX_TSNUM_WITHIN_NETWORK);
			}
			memset( (al_uint8 *)g_u16CurrNitTSIDList, 0, TDB_MAX_TSNUM_WITHIN_NETWORK*sizeof(al_uint16) );
			for( i=0 ; i<g_u8CurrNitTSIDNum ; i++ )
				g_u16CurrNitTSIDList[i] = pNit->p_trans[i].trans_id;

			if( bTSIDListChanged == al_false )
				AI_PSI_Monitor_UpdateCurrTpTSIDList();
			else
			{
				if( g_u32TpListFreq[0] == 0 )
				{
					PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_NWK_UPDATE_RESCAN, 0);
				}
				else
				{
					PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_NWK_UPDATE_STATIC, g_hTPList);
				}
			}
		}
	}
}
#endif

static al_void _AI_PSI_Monitor_InNitOtherTpSrvAdd(al_void *pData,
	AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrProgHdl)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *) pData;
	al_uint16	usTsId = 0xffff;
	dvbpsi_srvlist_dr_t *pstServiceList = al_null;
	dvbpsi_terrestrial_system_dr_t *pTerrSysDr = al_null;
	dvbpsi_cable_system_dr_t *pstCableSysDr = al_null;
	dvbpsi_satellite_system_dr_t *pstSateSysDr = al_null;
    #ifdef CONFIG_ISDB_SYSTEM
	dvbpsi_isdbterrestrial_system_dr_t *pISDBTerrSysDr = al_null;
    #endif
	al_int i = 0;
	al_int k = 0;

	if (pNit == al_null)
	{
		return;
	}

	if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usTsId", (al_void *)&usTsId))
	{
		PSI_MONITOR_ERROR_MSG("query usTsId failed!\n");
		return;
	}

	if (g_ePsiUpdateOptions & AL_PSIMONITOR_OTHTP_SR_ADD)
	{
		_AI_PSI_Monitor_OtherTpSrvListReset();

		for (i = 0; i < pNit->trans_count; i++)
		{
			MID_SiutilNitTsDescr_t *pNitTsDescr = &pNit->p_trans[i];
			/* delivery information check */
			if (AL_DBTYPE_DVB_T == eDBType)
			{
				pTerrSysDr = dvbpsi_DecodeDVBTerrestrialSystemDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen);

				/* no delivery information, no need to check service */
				if (pTerrSysDr == al_null)
				{
					continue;
				}
			}
			else if (AL_DBTYPE_DVB_C == eDBType)
			{
				pstCableSysDr = dvbpsi_DecodeCableSystemDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen);

				/* no delivery information, no need to check service */
				if (pstCableSysDr == al_null)
				{
					continue;
				}
			}
			else if (AL_DBTYPE_DVB_S == eDBType)
			{
				pstSateSysDr = dvbpsi_DecodeSatelliteSystemDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen);

				/* no delivery information, no need to check service */
				if (pstSateSysDr == al_null)
				{
					continue;
				}
			}
            #ifdef CONFIG_ISDB_SYSTEM
			else if (AL_DBTYPE_DVB_SBTVD== eDBType)
			{
				pISDBTerrSysDr = dvbpsi_DecodeISDBTerrestrialSystemDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen);

				/* no delivery information, no need to check service */
				if (pISDBTerrSysDr == al_null)
				{
					continue;
				}
			}
			#endif
			/* add service to temp service list */
			if (pNit->p_trans[i].trans_id != usTsId)
			{
				pstServiceList = dvbpsi_DecodeServiceListDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen);

				if (pstServiceList != al_null)
				{
					/* check if the services present in database or not */
					if (!_AI_PSI_Monitor_IsTransStreamPresent(pNit->p_trans[i].trans_id, eDBType))
					{
						al_uint16 u16NumOfSrv = 0;

						u16NumOfSrv = pstServiceList[0].service_id;

						for (k = 1; k <= u16NumOfSrv; k++)
						{
							AL_PSIMon_SimpleSrv_t *pSrv = al_null;
							al_uint16 u16ProgNo = 0;

							pSrv = _AI_PSI_Monitor_OtherTpGetAFreeSrvSlot(AL_PSIMONITOR_OTHERTP_SRVLIST_NIT);

							if (pSrv)
							{
								u16ProgNo = dvbpsi_DecodeLCNDr(pNitTsDescr->p_transDescr,
									pNitTsDescr->trans_descLen,pstServiceList[k].service_id, (dvbsi_special_spec)g_ePsiFollowSpec);

								if (u16ProgNo != 0xFFFF)
								{
									u16ProgNo &= 0x7FFF;
								}

								pSrv->usOrgNetId = pNit->p_trans[i].original_network_id;
								pSrv->usTsId = pNit->p_trans[i].trans_id;
								pSrv->usServiceId = pstServiceList[k].service_id;
								pSrv->u8SDTSrvType = pstServiceList[k].service_type;
								pSrv->usNetWorkId= pNit->network_id; //zhongbaoxing added for NorDig Test @20120806
								if (u16ProgNo != 0xffff && u16ProgNo != 0)
								{
									/* when the highest bit is 1,usProgNo is LCN,if 0,usProgNo is Number. */
									pSrv->usProgNum = (u16ProgNo | DB_DVB_LCN_INDICATOR);
								}
								else
								{
									pSrv->usProgNum = 0;
								}

								if (AL_DBTYPE_DVB_T == eDBType)
								{
									pSrv->uiFreq = (al_int)pTerrSysDr->u32freq;
								}
								else if (AL_DBTYPE_DVB_C == eDBType)
								{
									pSrv->uiFreq = (al_int)pstCableSysDr->freq;
								}
                                #ifdef CONFIG_ISDB_SYSTEM
                                else if (AL_DBTYPE_DVB_SBTVD == eDBType)
                                {
                                	/*In factly, I don't know how to use the frequency of ISDB-T*/
									/*To be checked how to use the frequency list ...*/
                                }
                                #endif
								g_u16NumberOfOtherTpSrv++;
							}
						}
					}
					SAFE_FREE(pstServiceList);
					pstServiceList = al_null;
				}

				if (AL_DBTYPE_DVB_T == eDBType)
				{
					SAFE_FREE(pTerrSysDr);
					pTerrSysDr = al_null;
				}
				else if (AL_DBTYPE_DVB_C == eDBType)
				{
					SAFE_FREE(pstCableSysDr);
					pstCableSysDr = al_null;
				}
				else if (AL_DBTYPE_DVB_S == eDBType)
				{
					SAFE_FREE(pstSateSysDr);
					pstSateSysDr = al_null;
				}
				#ifdef CONFIG_ISDB_SYSTEM
				else if (AL_DBTYPE_DVB_SBTVD == eDBType)
				{
				    /* To be modified for sbtvd zhongbaoxing @20120323*/
					SAFE_FREE(pISDBTerrSysDr);
					pISDBTerrSysDr = al_null;
				}
				#endif
			}
		}

		if (g_u16NumberOfOtherTpSrv)
		{
			// g_bOtherSDTNeedToDecode = al_true; // we add services without collecting any SDT-other since PSI monitor will update service info later
			if (_AI_PSI_Monitor_OtherTpServiceFound())
			{
				PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_OTHERTP_SRV_FOUND, 0);
			}

		}
	}
}

static al_void _AI_PSI_Monitor_InNitParseFTAData(al_void *pData, al_int iCurrentTS)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *) pData;
	MID_SiutilNitTsDescr_t *pNitTsDescr = NULL;
	al_uint8 u8FtaContentMgr = 0;

	if (pNit == al_null)
	{
		return;
	}
	pNitTsDescr = &pNit->p_trans[iCurrentTS];

	if(g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_DTG)
    {
        AI_PSI_Monitor_SetFTADataTbl(DTGCMG_TBL_NIT_1ST_LOOP);
        if(pNit->descLen)
        {
            if(dvbpsi_FtaContentMgrDr(pNit->p_descr,pNit->descLen,&u8FtaContentMgr))
            {
                AI_PSI_Monitor_FTADataParse(u8FtaContentMgr,DTGCMG_TBL_NIT_1ST_LOOP);
            }
        }
    }

	u8FtaContentMgr = 0;

	if(g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_DTG)
	{
		AI_PSI_Monitor_SetFTADataTbl(DTGCMG_TBL_NIT_2ND_LOOP);
		if(pNit->descLen)
		{
			if(dvbpsi_FtaContentMgrDr(pNitTsDescr->p_transDescr,pNitTsDescr->trans_descLen,&u8FtaContentMgr))
			{
				AI_PSI_Monitor_FTADataParse(u8FtaContentMgr,DTGCMG_TBL_NIT_2ND_LOOP);
			}
			else
			{
				AI_PSI_Monitor_FTADataParse(0,DTGCMG_TBL_NONE);
			}
		}
		else
		{
			AI_PSI_Monitor_FTADataParse(0,DTGCMG_TBL_NONE);
		}
	}
}

static al_void _AI_PSI_Monitor_InNitUpdateNetworkInfo(al_void *pData,
	AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrTPHdl)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *) pData;
	AL_RecHandle_t hNWHdl = AL_DB_INVALIDHDL;
	dvbpsi_network_name_dr_t *pstNetwork = NULL;
	al_uint8 szNetName[DB_DVB_MAX_NETNAME_LEN];
	al_uint8 NetName[DB_DVB_MAX_NETNAME_LEN];

	if (pNit == al_null)
	{
		return;
	}

	hNWHdl = hCurrTPHdl;

	if (AL_SUCCESS != AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBNETWORK, &hNWHdl))
	{
		PSI_MONITOR_ERROR_MSG("Get tp handle failed !!!\n");
		return;
	}

	/*
	* If NIT has not been received previously during channel search, then 'usNetId' is still 0 in DB and we should update it now
	*/
#ifndef CONFIG_DTMB_SYSTEM
	al_uint16 net_id = 0;
	if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hNWHdl, (al_uint8 *)"usNetId", &net_id))
	{
		PSI_MONITOR_ERROR_MSG("query network id failed!\n");
		return;
	}
	if (net_id == 0)
	{
		net_id = pNit->network_id;
		if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hNWHdl, (UINT8*)"usNetId", &net_id))
		{
			PSI_MONITOR_ERROR_MSG("update network_id failed !!!\n");
		}

		AL_RecHandle_t hTpHdl = CDBI_INVALID_HDL;
		while (AL_SUCCESS == AL_DB_GetChildRecord(hNWHdl, &hTpHdl))
		{
			if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hTpHdl, (UINT8*)"usNetId", &net_id))
			{
				PSI_MONITOR_ERROR_MSG("update network_id for TP failed !!!\n");
			}
		}
	}
#endif

	memset(szNetName, 0, sizeof(szNetName));
	memset(NetName, 0, sizeof(NetName));
	pstNetwork = dvbpsi_DecodeNetworkNameDr(pNit->p_descr, pNit->descLen);
	if (pstNetwork)
	{
		if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hNWHdl, (al_uint8 *)"szNetName", (al_void *)&szNetName))
		{
			PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
			SAFE_FREE(pstNetwork);
			return;
		}

		if(pstNetwork->i_network_name_length > 0)
		{
			int len = MID_CmnDecompressString(pstNetwork->network_name,
				pstNetwork->i_network_name_length);

			if(len > pstNetwork->i_network_name_length && len < DB_DVB_MAX_CHNAME_LEN)
			{
				pstNetwork->i_network_name_length=len;
			}

			MID_CmnTransStrWithSpeciChar(pstNetwork->network_name,
				pstNetwork->i_network_name_length);
			MID_CmnTransStrWithoutControlChar(pstNetwork->network_name,
				pstNetwork->i_network_name_length);

			if(pstNetwork->i_network_name_length > 0)
			{
				MID_CmnTransStrWith00(pstNetwork->network_name,
					pstNetwork->i_network_name_length);
			}

			if(pstNetwork->i_network_name_length > 0)
			{
				MID_CmnTransStrWithoutSpeciChar(pstNetwork->network_name,
					pstNetwork->i_network_name_length);
			}

			if(pstNetwork->i_network_name_length > 0)
			{
				MID_CmnTransStrWithoutNewline(pstNetwork->network_name,
					pstNetwork->i_network_name_length);
			}

			memcpy(NetName,pstNetwork->network_name, DB_DVB_MAX_NETNAME_LEN - 1);
		}

		if (eDBType != AL_DBTYPE_DVB_S)
		{
#ifdef NEW_FONT
				al_uint32 u32CodePage = 0xff;
				al_uint8 *pExtText = al_null;
				al_int32 i32Len = 0;

				i32Len = DB_DVB_MAX_NETNAME_LEN;
				AL_Event_GetCodePage(&u32CodePage, NetName, &i32Len);
				if (u32CodePage == 0xff)
				{
					AL_Event_GetDefaultCodePage(&u32CodePage);
				}
				pExtText = UNI_StringToUtf8(u32CodePage, NetName, &i32Len, al_false);
				memset(NetName, 0, DB_DVB_MAX_NETNAME_LEN);
				i32Len = i32Len <  DB_DVB_MAX_NETNAME_LEN ? i32Len : (DB_DVB_MAX_NETNAME_LEN -1);
				memcpy(NetName, pExtText, i32Len);//event name
				//printf("[%s:%d] u32CodePage : %d, u32Len: %d\n",__FUNCTION__,__LINE__, u32CodePage, i32Len);
				free(pExtText);
				pExtText = al_null;
#endif
			if (strcmp((char *)NetName, (char *)(szNetName)))
			{
				memcpy(szNetName, NetName, DB_DVB_MAX_NETNAME_LEN);
				if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hNWHdl, (UINT8*)"szNetName", &szNetName))
				{
					PSI_MONITOR_ERROR_MSG("update name failed !!!\n");
				}
				PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_NETWORK_UPDATE, 0);
			}
		}
		SAFE_FREE(pstNetwork);
	}
}

static al_void _AI_PSI_Monitor_InNitCheckHiddenSrv(al_void *pData,
	AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrProgHdl, al_int iCurrentTS)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *) pData;
	MID_SiutilNitTsDescr_t *pNitTsDescr = NULL;
	al_uint16	usServiceId = 0xffff;
	DBServAttrib_t stProgAttrib;
	al_uint8 u8RetVal = 0;
	al_bool bNotVisible = al_false;
	al_bool bNotSelectable = al_false;

	if (pNit == al_null)
	{
		return;
	}
	pNitTsDescr = &pNit->p_trans[iCurrentTS];

	memset(&stProgAttrib, 0, sizeof(DBServAttrib_t));

	if ((AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usServiceId", (al_void *)&usServiceId))
		|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stProgAttrib)))
	{
		PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
		return;
	}

	if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_DTG)
	{
		u8RetVal = dvbpsi_DecodeServiceAttributeDr(
				pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen, usServiceId);

		if ((u8RetVal & 0x01) == 0)
		{
			bNotVisible = al_true;

			if ((u8RetVal & 0x02) == 0)
			{
				bNotSelectable = al_true;
			}
		}

		if (((bNotVisible != stProgAttrib.notvisible)
				|| (bNotSelectable != stProgAttrib.notselectable)))
		{
			/* program handle should be got even when playback is stop */
			if(stProgAttrib.bInvalidService == 0) //richiechang 20130604, for CI+ v1.3 HostTune no SI service (Test 2.3.1 - Step.14)
			{
				stProgAttrib.notvisible = bNotVisible;
			}
			stProgAttrib.notselectable = bNotSelectable;

			if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (al_uint8*)"stProgAttrib", &stProgAttrib))
			{
				PSI_MONITOR_ERROR_MSG("update stProgAttrib failed !!!\n");
			}
		}
	}
}

//#ifdef SUPPORT_GHANA_LCN
//ghana & thailand test logo
#ifdef CONFIG_DVB_SYSTEM
static al_bool _AI_PSI_Monitor_InNitChnListLcnDispose( dvbpsi_lcn_v2_dr_t *pstSrcLcnV2Data, AL_RecHandle_t hCurrProgHdl, al_uint16	*lcn, al_uint16	*visible_service_flag )
{
	dvbpsi_lcn_v2_dr_t *pstLcnV2Data = al_null;
	al_uint16 u16ChnListId = 0xffff;
	al_uint8 channel_list_id_matched = 0;
	al_uint8 num_valid_chn_list = 0;
	al_uint8 idx = 0;
	AL_RecHandle_t hTpHdl = AL_DB_INVALIDHDL;
	AL_DB_EDBType_t eDBType = AL_DBTYPE_MAX;

	if( pstSrcLcnV2Data==al_null || lcn==al_null || visible_service_flag==al_null )
		return al_false;

	if( hCurrProgHdl == AL_DB_INVALIDHDL )
	{
		if( MID_SUCCESS!=MID_PlaybackGetCurProgHandle(al_null, &hCurrProgHdl) || hCurrProgHdl==AL_DB_INVALIDHDL )
			return al_false;
	}

	hTpHdl = hCurrProgHdl;
	if( AL_SUCCESS != AL_DB_GetRecordType(hCurrProgHdl, &eDBType, al_null) || eDBType!=AL_DBTYPE_DVB_T )
		return al_false;
	if( AL_SUCCESS != AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBMULTIPLEX, &hTpHdl) )
		return al_false;
	if( AL_SUCCESS != AL_DB_QueryDetailFieldByName(hTpHdl, (UINT8*)"usChnListId", &u16ChnListId) )
		return al_false;

	*lcn = 0xFFFF;
	*visible_service_flag = 1;

	pstLcnV2Data = pstSrcLcnV2Data;
	while( pstLcnV2Data && idx<MAX_CHNLIST_NUM )
	{
		if( _AI_PSI_Monitor_CheckCountry(pstLcnV2Data->country_code) )
		{
			if( pstLcnV2Data->channel_list_id == u16ChnListId )
				channel_list_id_matched = 1;
			num_valid_chn_list++;
		}

		idx++;
		pstLcnV2Data = pstLcnV2Data->p_next;
	}

	if( num_valid_chn_list<2 || channel_list_id_matched==0 )
		return al_false;

	pstLcnV2Data = pstSrcLcnV2Data;
	while( pstLcnV2Data )
	{
		if( _AI_PSI_Monitor_CheckCountry(pstLcnV2Data->country_code) && pstLcnV2Data->channel_list_id==u16ChnListId )
		{
			*lcn = pstLcnV2Data->lcn;
			*visible_service_flag = pstLcnV2Data->visible_service_flag;
		}

		pstLcnV2Data = pstLcnV2Data->p_next;
	}

	return al_true;
}
#endif

static al_void _AI_PSI_Monitor_InNitCurrTpSrvCheck(al_void *pData, AL_DB_EDBType_t eDBType, al_int iCurrentTS)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *) pData;
	MID_SiutilNitTsDescr_t *pNitTsDescr = al_null;
	AL_PSIMon_SimpleSrv_t stProg;
	dvbpsi_lcn_v2_dr_t *pstLcnV2Data = al_null;
	dvbpsi_srvlist_dr_t *pstServiceList = al_null;
	al_uint16 u16NumOfSrv = 0;
	al_int k = 0;
	al_int j = 0;
	al_uint16 u16ProgNo = 0;
	al_uint8	min_channel_list_id = 0xFF;
	al_uint16	visible_service_flag = 1;
	al_uint16	lcn = 0xFFFF;
	al_uint8	country_matched = 0;

#ifdef CONFIG_DVB_SYSTEM//SUPPORT_GHANA_LCN
	al_uint8 u8LocalRegionId = 0x3f;
	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
	AL_FW_GetContextCb(&pfPSIMonGetContext);
#endif

	if (pNit == al_null)
	{
		return;
	}

#ifdef CONFIG_DVB_SYSTEM
	if( pfPSIMonGetContext != al_null )
	{
		pfPSIMonGetContext( FW_CONTEXT_TYPE_COUNTRY_ID , FW_CONTEXT_OP_TYPE_READ, (al_void *)&u8LocalRegionId, 0 );
	}
#endif

	if (g_ePsiUpdateOptions
		& (AL_PSIMONITOR_CURTP_SRVADD|AL_PSIMONITOR_CURTP_SRVADD2|AL_PSIMONITOR_CURTP_SRV_REMOVE))
	{
		memset(&stProg, 0, sizeof(AL_PSIMon_SimpleSrv_t));

		for(k = 0; k < pNit->trans_count; k++)
		{
			pNitTsDescr = &pNit->p_trans[k];
			pstServiceList = dvbpsi_DecodeServiceListDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen);

			if (pstServiceList != NULL)
			{
				j = 0;
				u16ProgNo = 0;

				u16NumOfSrv = pstServiceList[0].service_id;

				for (j = 1; j <= u16NumOfSrv; j++)
				{
					memset(&stProg, 0, sizeof(AL_PSIMon_SimpleSrv_t));

#ifdef CONFIG_DVB_SYSTEM
					if (u8LocalRegionId == AREA_THAILAND)
					{
						if (pNitTsDescr->original_network_id == THAI_ONID)
							u16ProgNo = dvbpsi_DecodeLCNDr(pNitTsDescr->p_transDescr,
								pNitTsDescr->trans_descLen,pstServiceList[j].service_id, DVB_SPECIAL_SPEC_NONE);
					}
					else
#endif
#ifdef SUPPORT_GHANA_LCN
					if( u8LocalRegionId == AREA_GHANA )
                    {
						u16ProgNo = dvbpsi_DecodeLCNDr( pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen, pstServiceList[j].service_id, DVB_SPECIAL_SPEC_NONE );
                    }
                    else
#endif
#ifdef CONFIG_SUPPORT_MALAYSIA_CERTIFICATION
                    if(u8LocalRegionId == AREA_MALAYSIA)
                    {
                        u16ProgNo = dvbpsi_DecodeLCNDr( pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen, pstServiceList[j].service_id, DVB_SPECIAL_SPEC_NONE );
                    }
                    else
#endif
#ifdef CONFIG_AUS_DVB_SYSTEM
					if (u8LocalRegionId == AREA_SINGAPORE)
					{
						u16ProgNo = dvbpsi_DecodeLCNDr(pNitTsDescr->p_transDescr,
							pNitTsDescr->trans_descLen, pstServiceList[j].service_id, DVB_SPECIAL_SPEC_NONE);// don't check singapore's PDSD
					}
					else
#endif

					{
						u16ProgNo = dvbpsi_DecodeLCNDr(pNitTsDescr->p_transDescr,
							pNitTsDescr->trans_descLen,pstServiceList[j].service_id, (dvbsi_special_spec)g_ePsiFollowSpec);
					}

					if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG)
					{
#ifdef CONFIG_DVB_SYSTEM
					#ifdef SUPPORT_GHANA_LCN
						if( u8LocalRegionId == AREA_GHANA )
                        {
							pstLcnV2Data = dvbpsi_DecodeLCNV2Dr( pNitTsDescr->p_transDescr,
								pNitTsDescr->trans_descLen, pstServiceList[j].service_id, DVB_SPECIAL_SPEC_NONE );
                        }
                        else
					#endif
                    #ifdef CONFIG_SUPPORT_MALAYSIA_CERTIFICATION
                        if(u8LocalRegionId == AREA_MALAYSIA)
                        {
                            pstLcnV2Data = dvbpsi_DecodeLCNV2Dr( pNitTsDescr->p_transDescr, 
								pNitTsDescr->trans_descLen, pstServiceList[j].service_id, DVB_SPECIAL_SPEC_NONE );
                        }
                        else
                    #endif

						if (u8LocalRegionId == AREA_THAILAND)
						{
							pstLcnV2Data = dvbpsi_DecodeLCNV2Dr(pNitTsDescr->p_transDescr,
								pNitTsDescr->trans_descLen,  pstServiceList[j].service_id, DVB_SPECIAL_SPEC_THAI);
						}
						else
#endif
						{
							pstLcnV2Data = dvbpsi_DecodeLCNV2Dr(pNitTsDescr->p_transDescr,
								pNitTsDescr->trans_descLen, pstServiceList[j].service_id, (dvbsi_special_spec)g_ePsiFollowSpec);
						}

#ifdef CONFIG_DVB_SYSTEM
					//#ifdef SUPPORT_GHANA_LCN
						if((u8LocalRegionId==AREA_GHANA || u8LocalRegionId == AREA_THAILAND || u8LocalRegionId == AREA_SINGAPORE 
							#ifdef CONFIG_SUPPORT_MALAYSIA_CERTIFICATION
							|| u8LocalRegionId == AREA_MALAYSIA
							#endif
							)
							&& _AI_PSI_Monitor_InNitChnListLcnDispose(pstLcnV2Data, AL_DB_INVALIDHDL, &lcn, &visible_service_flag)==al_true )
						{
							dvbpsi_FreeLCNV2Dr();
							pstLcnV2Data = al_null;
						}
					//#endif
#endif

						if (pstLcnV2Data)
						{
							// 1.Lcn V2 has higher priority than Lcn V1
							// 2.lcn with matched country code has higher priority
							// 3.lcn with lowest channel list id  has higher priority
							/*
							* 1.The list with same country code as the IRD¡¯s user preference setting¡¯s country code. If
							* several list available with same matching country code, the IRD shall choose the one
							* with lowest list_id value OR let the viewer choose from a list, (typically using the
							* channel_list_name)
							*
							* 2.If no Channel list has a country code that matches the user preference setting¡¯s country
							* code, theNorDig IRD shall let the viewer choose from a list (recommended) OR choose
							* the one with lowest list_id value.
							*/

							min_channel_list_id = 0xFF;
							while (pstLcnV2Data)
							{
								if (_AI_PSI_Monitor_CheckCountry(pstLcnV2Data->country_code))
								{
									if (country_matched == 0)
									{
										min_channel_list_id = 0xFF;
									}

									if (pstLcnV2Data->channel_list_id < min_channel_list_id)
									{
										lcn = pstLcnV2Data->lcn;
										visible_service_flag = pstLcnV2Data->visible_service_flag;
										min_channel_list_id = pstLcnV2Data->channel_list_id;
									}
									country_matched = 1;
								}

								if (country_matched == 0)
								{
									if (pstLcnV2Data->channel_list_id < min_channel_list_id)
									{
										lcn = pstLcnV2Data->lcn;
										visible_service_flag = pstLcnV2Data->visible_service_flag;
										min_channel_list_id = pstLcnV2Data->channel_list_id;
									}
								}

								pstLcnV2Data = pstLcnV2Data->p_next;
							}
						}

						dvbpsi_FreeLCNV2Dr();
					}

					if (lcn != 0xFFFF) /* if has got LCN2 */
					{
						u16ProgNo = lcn | DB_DVB_LCN2_INDICATOR;
						stProg.stProgAttrib.notvisible = !visible_service_flag;
						stProg.usProgNum = u16ProgNo;
					}
					else
					{
						if ((u16ProgNo & 0x8000) == 0)
						{
							stProg.stProgAttrib.notvisible = 1;
#ifdef CONFIG_DVB_SYSTEM
							// junluo 2017.05.27,  refer to CSA-Signalling-Profilev3.4.pdf, france need ignore visible flag in lcd
							if (u8LocalRegionId == AREA_FRANCE && eDBType == AL_DBTYPE_DVB_T)
							{
								stProg.stProgAttrib.notvisible = 0;
							}
#endif
						}
						if (u16ProgNo != 0xFFFF)
						{
							u16ProgNo &= 0x7FFF;
						}

						if (u16ProgNo != 0xffff && u16ProgNo != 0)
						{
							/*when the highest bit is 1,usProgNo is LCN,if 0,usProgNo is Number.*/
							stProg.usProgNum = (u16ProgNo | DB_DVB_LCN_INDICATOR);
						}
						else
						{
							stProg.usProgNum = 0;
						}
					}

					stProg.usOrgNetId = pNit->p_trans[iCurrentTS].original_network_id;
					stProg.usTsId = pNit->p_trans[iCurrentTS].trans_id;
					stProg.usServiceId = pstServiceList[j].service_id;
					stProg.u8SDTSrvType = pstServiceList[j].service_type;
					stProg.usNetWorkId= pNit->network_id; //zhongbaoxing added for NorDig Test @20120806

					_AI_PSI_Monitor_CurTPServicesStack(TABLE_ID_NIT_ACT,pNit->version_number,stProg);
				}
				SAFE_FREE(pstServiceList);
				pstServiceList = al_null;
			}
		}
	}
}

static al_void _AI_PSI_Monitor_InNitLCNDynamicUpdate(al_void *pData,
	AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrProgHdl, al_int iCurrentTS)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *) pData;
	MID_SiutilNitTsDescr_t *pNitTsDescr = NULL;
	al_uint16 u16ProgNo = 0xffff;
	al_uint16 u16OrgLCN = 0xffff;
	AL_ServiceDetail_t stSrvInfo;
	al_uint16 u16CurServiceID = 0xffff;
	dvbpsi_lcn_v2_dr_t *pstLcnV2Data = al_null;
	al_uint8	min_channel_list_id = 0xFF;
	al_uint16	visible_service_flag = 1;
	al_uint16 select_flag = 1;
	DBServAttrib_t stProgAttrib;
	al_uint16	lcn = 0xFFFF;
	al_uint8	country_matched = 0;
	AL_RecHandle_t hRecHdl;
	bool bLCNChanged = FALSE;
	bool bServVisibleChanged = FALSE;
	bool bGotServValue = FALSE;
	al_uint8  eSDTSrvType;
	al_uint32 u32SerFlag = 0;
	dvbpsi_srvlist_dr_t *pstServiceList = al_null;
	al_uint32 iter = 0;

#if (defined CONFIG_DVB_SYSTEM || defined CONFIG_AUS_DVB_SYSTEM)//SUPPORT_GHANA_LCN
	al_uint8 u8LocalRegionId = 0x3f;
	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
	AL_FW_GetContextCb( &pfPSIMonGetContext );
#endif

    #ifdef CONFIG_CIPLUS_SUPPORT
    if (APP_CIPLUS_IsProfileSource())
    {
        return ;
    }
    if( APP_CIPLUS_IsProfileService(hCurrProgHdl) )
    	return;
    #endif

	if (pNit == al_null || !(g_ePsiUpdateOptions & AL_PSIMONITOR_LCN_DYNAMIC_UPDATE))
	{
		return;
	}
	pNitTsDescr = &pNit->p_trans[iCurrentTS];
#if (defined CONFIG_DVB_SYSTEM || defined CONFIG_AUS_DVB_SYSTEM)//SUPPORT_GHANA_LCN
	if( pfPSIMonGetContext != al_null )
	{
		pfPSIMonGetContext( FW_CONTEXT_TYPE_COUNTRY_ID , FW_CONTEXT_OP_TYPE_READ, (al_void *)&u8LocalRegionId, 0 );
	}
	else
	{
		return;
	}
#endif

#ifdef SUPPORT_LCN_UPDATE_ON_ALL_MUX
	hRecHdl = AL_DB_INVALIDHDL;
	hCurrProgHdl = AL_DB_INVALIDHDL;
	AL_Serv_SearchKey_t stSearchKey;
	memset(&stSearchKey, 0, sizeof(stSearchKey));
	stSearchKey.eDBType = eDBType;
	stSearchKey.eRecType = AL_RECTYPE_DVBMULTIPLEX;
	stSearchKey.u16OrigNetId = pNitTsDescr->original_network_id;
	stSearchKey.u16TsId = pNitTsDescr->trans_id;
	stSearchKey.eSearchField = AL_SRV_SEARCHFIELD_ORIGNETID
							| AL_SRV_SEARCHFIELD_TSID;
	if (AL_SUCCESS != AL_DB_GetMatchedRecord((AL_DB_RecordMatchFunc)AL_Serv_MatchRecBySearchKey,
			(al_void *)&stSearchKey, eDBType, AL_RECTYPE_DVBMULTIPLEX, AL_DB_REQ_GETFIRST, &hRecHdl))
	{
		PSI_MONITOR_DEBUG_MSG("cannot find multiplex with ONID 0x%x TSID 0x%x\n", pNitTsDescr->original_network_id, pNitTsDescr->trans_id);
		return;
	}
#else
	hRecHdl = hCurrProgHdl;
	hCurrProgHdl = AL_DB_INVALIDHDL;
	/* get Multiplex handle */
	if (AL_SUCCESS != AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBTV, &hRecHdl))
	{
		PSI_MONITOR_ERROR_MSG("query multiplex handle failed!\n");
		return;
	}
#endif

	pstServiceList = dvbpsi_DecodeServiceListDr(pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen);
	if (pstServiceList == NULL)
	{
		return;
	}

	while (AL_SUCCESS == AL_DB_GetChildRecord(hRecHdl, &hCurrProgHdl))
	{
	#ifdef CONFIG_CIPLUS_SUPPORT
		if( APP_CIPLUS_IsProfileService(hCurrProgHdl) )
			continue;
    #endif

		bGotServValue = FALSE;
		memset(&stProgAttrib, 0, sizeof stProgAttrib);

		/* query service Original LCN number */
		if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (UINT8*)"usOrgLcn", &u16OrgLCN))
		{
			PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
			goto FAIL;
		}

		/* query service attrib */
		if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
		{
			PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
			goto FAIL;
		}

		/* query service ID */
		if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (UINT8*)"usServiceId", &u16CurServiceID))
		{
			PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
			goto FAIL;
		}
		
		if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (UINT8*)"eSDTSrvType", &eSDTSrvType))
		{
			goto FAIL;
		}
		
		/* check this service whether exist in the service list desc */
		for (iter = 1; iter <= pstServiceList[0].service_id; iter++)
		{
			if (u16CurServiceID == pstServiceList[iter].service_id)
			{
				break;
			}
		}
		if (iter > pstServiceList[0].service_id)
		{
			continue;
		}

		u16ProgNo = 0xffff;
		visible_service_flag = 1;
		select_flag = 1;

#ifdef CONFIG_DVB_SYSTEM
		if (u8LocalRegionId == AREA_THAILAND)
		{
			if (pNitTsDescr->original_network_id == THAI_ONID)
				u16ProgNo = dvbpsi_DecodeLCNDr(pNitTsDescr->p_transDescr,
					pNitTsDescr->trans_descLen, u16CurServiceID, DVB_SPECIAL_SPEC_NONE);// we found some thailand TS don't have PDSD
		}
		else
#endif
#ifdef CONFIG_AUS_DVB_SYSTEM
		if (u8LocalRegionId == AREA_SINGAPORE)
		{
			u16ProgNo = dvbpsi_DecodeLCNDr(pNitTsDescr->p_transDescr,
				pNitTsDescr->trans_descLen, u16CurServiceID, DVB_SPECIAL_SPEC_NONE);// don't check singapore's PDSD
		}
		else
#endif
#ifdef SUPPORT_GHANA_LCN
		if( u8LocalRegionId == AREA_GHANA )
        {
			u16ProgNo = dvbpsi_DecodeLCNDr( pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen, u16CurServiceID, DVB_SPECIAL_SPEC_NONE );
        }
        else
#endif
#ifdef CONFIG_SUPPORT_MALAYSIA_CERTIFICATION
		if(u8LocalRegionId == AREA_MALAYSIA)
		{
			u16ProgNo = dvbpsi_DecodeLCNDr( pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen, u16CurServiceID, DVB_SPECIAL_SPEC_NONE );
		}
		else
#endif
        {
			u16ProgNo = dvbpsi_DecodeLCNDr(pNitTsDescr->p_transDescr,
				pNitTsDescr->trans_descLen, u16CurServiceID, (dvbsi_special_spec)g_ePsiFollowSpec);
		}

		if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG)
		{
#ifdef CONFIG_DVB_SYSTEM
		#ifdef SUPPORT_GHANA_LCN
			if( u8LocalRegionId == AREA_GHANA)
            {
				pstLcnV2Data = dvbpsi_DecodeLCNV2Dr( pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen, u16CurServiceID, DVB_SPECIAL_SPEC_NONE );
            }
            else
		#endif
#ifdef CONFIG_SUPPORT_MALAYSIA_CERTIFICATION
            if(u8LocalRegionId == AREA_MALAYSIA)
            {
				pstLcnV2Data = dvbpsi_DecodeLCNV2Dr( pNitTsDescr->p_transDescr, pNitTsDescr->trans_descLen, u16CurServiceID, DVB_SPECIAL_SPEC_NONE );
            }
            else
#endif
#ifdef SUPPORT_THAILAND_EVORA
			if (u8LocalRegionId == AREA_THAILAND)
			{
				pstLcnV2Data = dvbpsi_DecodeLCNV2Dr(pNitTsDescr->p_transDescr,
					pNitTsDescr->trans_descLen, u16CurServiceID, DVB_SPECIAL_SPEC_THAI);
			}
			else
#endif
#endif
			{
				pstLcnV2Data = dvbpsi_DecodeLCNV2Dr(pNitTsDescr->p_transDescr,
					pNitTsDescr->trans_descLen, u16CurServiceID, (dvbsi_special_spec)g_ePsiFollowSpec);
			}

#ifdef CONFIG_DVB_SYSTEM
		//#ifdef SUPPORT_GHANA_LCN
			if((u8LocalRegionId==AREA_GHANA || u8LocalRegionId == AREA_THAILAND || u8LocalRegionId == AREA_SINGAPORE 
	#ifdef CONFIG_SUPPORT_MALAYSIA_CERTIFICATION
				||u8LocalRegionId == AREA_MALAYSIA
	#endif
				)
				&& _AI_PSI_Monitor_InNitChnListLcnDispose(pstLcnV2Data, hCurrProgHdl, &lcn, &visible_service_flag)==al_true )
			{
				if( lcn != 0xFFFF )
				{
					u16ProgNo = lcn | DB_DVB_LCN2_INDICATOR;
					bGotServValue = TRUE;
				}

				dvbpsi_FreeLCNV2Dr();
				pstLcnV2Data = al_null;
			}
		//#endif
#endif

			if (pstLcnV2Data)
			{
				// 1.Lcn V2 has higher priority than Lcn V1
				// 2.lcn with matched country code has higher priority
				// 3.lcn with lowest channel list id  has higher priority
				/*
				* 1.The list with same country code as the IRD¡¯s user preference setting¡¯s country code. If
				* several list available with same matching country code, the IRD shall choose the one
				* with lowest list_id value OR let the viewer choose from a list, (typically using the
				* channel_list_name)
				*
				* 2.If no Channel list has a country code that matches the user preference setting¡¯s country
				* code, theNorDig IRD shall let the viewer choose from a list (recommended) OR choose
				* the one with lowest list_id value.
				*/

				min_channel_list_id = 0xFF;
				while (pstLcnV2Data)
				{
					if (_AI_PSI_Monitor_CheckCountry(pstLcnV2Data->country_code))
					{
						if (country_matched == 0)
						{
							min_channel_list_id = 0xFF;
						}

						if (pstLcnV2Data->channel_list_id < min_channel_list_id)
						{
							lcn = pstLcnV2Data->lcn;
							visible_service_flag = pstLcnV2Data->visible_service_flag;
							min_channel_list_id = pstLcnV2Data->channel_list_id;
						}
						country_matched = 1;
					}

					if (country_matched == 0)
					{
						if (pstLcnV2Data->channel_list_id < min_channel_list_id)
						{
							lcn = pstLcnV2Data->lcn;
							visible_service_flag = pstLcnV2Data->visible_service_flag;
							min_channel_list_id = pstLcnV2Data->channel_list_id;
						}
					}

					pstLcnV2Data = pstLcnV2Data->p_next;
				}

				if (lcn != 0xFFFF) /* if has got LCN2 */
				{
					u16ProgNo = lcn | DB_DVB_LCN2_INDICATOR;
					bGotServValue = TRUE;
					if (lcn == 0x3fff)//means LCN = 0  => unvisible & unselectable,it trans by dr_lcn & _scan_parser.inc
						select_flag = 0;
				}
			}

			dvbpsi_FreeLCNV2Dr();
		}

#ifdef CONFIG_DVB_SYSTEM
		if (u8LocalRegionId == AREA_THAILAND && pNitTsDescr->original_network_id != THAI_ONID)
		{
			u16OrgLCN = 0;
		}
#endif

		if (lcn == 0xFFFF || (g_ePsiFollowSpec != AL_PSIMON_SPECIAL_SPEC_NORDIG)) /* hasn't got LCN2 */
		{
			if (u16ProgNo != 0xFFFF) /* if has got LCN */
			{
				visible_service_flag = u16ProgNo & 0x8000;
#ifdef CONFIG_DVB_SYSTEM//SUPPORT_GHANA_LCN
				 // junluo 2017.05.27,  refer to CSA-Signalling-Profilev3.4.pdf, france dvb-t need ignore visible flag in lcd
				if (u8LocalRegionId == AREA_FRANCE && eDBType == AL_DBTYPE_DVB_T)
				{
					visible_service_flag |= 0x8000;
				}
#endif
				u16ProgNo &= ~(DB_DVB_LCN_INDICATOR | DB_DVB_LCN2_INDICATOR);
				u16ProgNo = u16ProgNo | DB_DVB_LCN_INDICATOR;
				bGotServValue = TRUE;
				if ((u16ProgNo & ~0x8000)== 0)
					select_flag = 0;
			}
		}

		if (g_pfPsiMonCheckNotVisible != al_null)
		{
			al_uint8 bTempSrv = FALSE;
			al_uint8 bNotVisible = FALSE;
			al_uint8 bNotNeedSave = FALSE;
			bTempSrv = stProgAttrib.svrtmp;
			g_pfPsiMonCheckNotVisible(eSDTSrvType, bTempSrv, &bNotVisible, &bNotNeedSave);

			if (bNotVisible)
			{
				u32SerFlag |= SERVICE_NOT_ENABLE;
			}
		}

		if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG && bGotServValue && stProgAttrib.notselectable != !select_flag)
		{
			stProgAttrib.notselectable = !select_flag;
			if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
			{
				PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
				goto FAIL;
			}
		}
		/* Notice here don't need concern the service visible attribute for D-Book, it load by service attribute descriptor */
		if ((g_ePsiFollowSpec != AL_PSIMON_SPECIAL_SPEC_DTG) && bGotServValue && (stProgAttrib.notvisible != !visible_service_flag))
		{
			if ((!visible_service_flag == al_false) && !(u32SerFlag & SERVICE_NOT_ENABLE))
			{
				stProgAttrib.notvisible = !visible_service_flag;

				if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
				{
					PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
					goto FAIL;
				}
				bServVisibleChanged = TRUE;
			}
			else if (((!visible_service_flag) == al_true) || (u32SerFlag & SERVICE_NOT_ENABLE))
			{
				if (stProgAttrib.notvisible != al_true)
				{
					stProgAttrib.notvisible = al_true;//!visible_service_flag;

					if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
					{
						PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
						goto FAIL;
					}
					bServVisibleChanged = TRUE;
				}
			}
		}

		if (bGotServValue && (u16ProgNo & ~(DB_DVB_LCN_INDICATOR | DB_DVB_LCN2_INDICATOR)) != u16OrgLCN)
		{
			u16OrgLCN = u16ProgNo & ~(DB_DVB_LCN_INDICATOR | DB_DVB_LCN2_INDICATOR);
#if 0
			AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"usOrgLcn", &u16OrgLCN);
			/* call a LCN update API to update the program's LCN */
			AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"usProgNo", &u16ProgNo);

			//LCN_UpdateLCN(hCurrProgHdl, u16ProgNo);
#else //lcn procdure(db_lcn.c) required, enforce update usOrgLcn and usProgNo atomicity and consistency
			AL_DB_QueryDetail(hCurrProgHdl, &stSrvInfo);
			if( eDBType == AL_DBTYPE_DVB_T )
			{
				stSrvInfo.stDVBTServ.usOrgLcn = u16OrgLCN;
				stSrvInfo.stDVBTServ.usProgNo = u16ProgNo;
			}
			else if( eDBType == AL_DBTYPE_DVB_C )
			{
				stSrvInfo.stDVBCServ.usOrgLcn = u16OrgLCN;
				stSrvInfo.stDVBCServ.usProgNo = u16ProgNo;
			}
			else if( eDBType == AL_DBTYPE_DVB_S )
			{
				stSrvInfo.stDVBSServ.usOrgLcn = u16OrgLCN;
				stSrvInfo.stDVBSServ.usProgNo = u16ProgNo;
			}
			AL_DB_UpdateDetail(hCurrProgHdl, &stSrvInfo);
#endif
			bLCNChanged = TRUE;
		}
		/* this program, that was allocated LCN previously, loses its LCN now */
		else if (u16ProgNo == 0xFFFF && u16OrgLCN != 0)
		{
			u16OrgLCN = 0;
			u16ProgNo = 0;
#if 0
			AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"usOrgLcn", &u16OrgLCN);
			AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"usProgNo", &u16ProgNo);
#else //lcn procdure(db_lcn.c) required, enforce update usOrgLcn and usProgNo atomicity and consistency
			AL_DB_QueryDetail(hCurrProgHdl, &stSrvInfo);
			if( eDBType == AL_DBTYPE_DVB_T )
			{
				stSrvInfo.stDVBTServ.usOrgLcn = u16OrgLCN;
				stSrvInfo.stDVBTServ.usProgNo = u16ProgNo;
			}
			else if( eDBType == AL_DBTYPE_DVB_C )
			{
				stSrvInfo.stDVBCServ.usOrgLcn = u16OrgLCN;
				stSrvInfo.stDVBCServ.usProgNo = u16ProgNo;
			}
			else if( eDBType == AL_DBTYPE_DVB_S )
			{
				stSrvInfo.stDVBSServ.usOrgLcn = u16OrgLCN;
				stSrvInfo.stDVBSServ.usProgNo = u16ProgNo;
			}
			AL_DB_UpdateDetail(hCurrProgHdl, &stSrvInfo);
#endif

			bLCNChanged = TRUE;
		}
	}

	if (bServVisibleChanged || bLCNChanged)
	{
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_UPDATE_LCN, 0);
		/* if service list has open, those data of channel list need refresh */
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SRV_UPDATE, 0);
	}

FAIL:
	SAFE_FREE(pstServiceList);
	pstServiceList = al_null;
}

/* For checking if new TS_id is received */
static al_bool _AI_PSI_Monitor_InNitCheckTSid(al_void *pData, AL_DB_EDBType_t eDBType)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *) pData;
	al_uint32 uiIter1 = 0;
	al_uint32 uiIter2 = 0;

	AL_RecHandle_t Rechdl = CDBI_INVALID_HDL;
	al_bool bFound = al_false;
	UINT16 usTSID[TDB_MAX_TSNUM_WITHIN_NETWORK];
#ifdef CONFIG_DVB_SYSTEM
	al_bool bAddTp = al_false;
	al_bool bDeleteTp = al_false;
	al_bool bOrgIdMatch = al_false;
	al_uint8 u8LocalRegionId = 0x3f;
	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
	AL_FW_GetContextCb( &pfPSIMonGetContext );
#endif

	if (pNit == al_null)
	{
		return al_false;
	}

#ifdef CONFIG_DVB_SYSTEM
	if( pfPSIMonGetContext != al_null )
	{
		pfPSIMonGetContext( FW_CONTEXT_TYPE_COUNTRY_ID , FW_CONTEXT_OP_TYPE_READ, (al_void *)&u8LocalRegionId, 0 );
	}
#endif

	al_bool _innerNetworkMatch(al_void *param, al_void const*pRec)
	{
		if (eDBType == AL_DBTYPE_DVB_T)
		{
			STDBNetworkInfo_t *pTDBNet = (STDBNetworkInfo_t *)pRec;

			if (pNit->network_id == pTDBNet->usNetId)
			{
				return al_true;
			}
			return al_false;
		}
		else if (eDBType == AL_DBTYPE_DVB_C)
		{
			return al_true;
		}
		else if (eDBType == AL_DBTYPE_DVB_S)
		{
			return al_true;
		}
		else
		{
			return al_false;
		}
	}

	if (DB_SUCCESS == CDBIFindRecord(eDBType, CDBI_RECTYPE_DVBNETWORK, (fpCDBIRecMatch)_innerNetworkMatch,
		al_null, TRUE, &Rechdl))
	{
		if (DB_SUCCESS == CDBIGetRecBySymbol(Rechdl, usTSID, (UINT8 *)"usTSID"))
		{
#ifdef CONFIG_DVB_SYSTEM
			if (u8LocalRegionId == AREA_THAILAND)
			{
				bAddTp = al_false;
				for (uiIter2 = 0; uiIter2 < pNit->trans_count; uiIter2++)
				{
					if (pNit->p_trans[uiIter2].original_network_id != NORDIG_RIKS_ONID && pNit->p_trans[uiIter2].original_network_id != THAI_ONID)
					{
						continue;
					}

					for (uiIter1 = 0; uiIter1 < TDB_MAX_TSNUM_WITHIN_NETWORK && usTSID[uiIter1] != 0; uiIter1++)
					{
						if (pNit->p_trans[uiIter2].trans_id == usTSID[uiIter1])
						{
							break;
						}
					}

					if (uiIter1 >= TDB_MAX_TSNUM_WITHIN_NETWORK)
					{
						bAddTp = al_true;
						break;
					}
				}

				bDeleteTp = al_false;
				for (uiIter1 = 0; uiIter1 < TDB_MAX_TSNUM_WITHIN_NETWORK && usTSID[uiIter1] != 0; uiIter1++)
				{
					for (uiIter2 = 0; uiIter2 < pNit->trans_count; uiIter2++)
					{
						if (pNit->p_trans[uiIter2].original_network_id != NORDIG_RIKS_ONID && pNit->p_trans[uiIter2].original_network_id != THAI_ONID)
						{
							continue;
						}
						if (usTSID[uiIter1] == pNit->p_trans[uiIter2].trans_id)
						{
							break;
						}
						bOrgIdMatch = al_true;
					}

					if ((uiIter2 >= pNit->trans_count) && bOrgIdMatch)
					{
						bDeleteTp = al_true;
						break;
					}
				}

				if (bAddTp || bDeleteTp)
				{
					/* new TS ID is found */
					PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_NEW_TSID, 0);
					return al_true;
				}

			}
			else
#endif
			{
				for (uiIter2 = 0; uiIter2 < pNit->trans_count; uiIter2++)
				{
					if (pNit->p_trans[uiIter2].original_network_id != NORDIG_RIKS_ONID)
					{
						continue;
					}

					bFound = al_false;
					for (uiIter1 = 0; uiIter1 < TDB_MAX_TSNUM_WITHIN_NETWORK && usTSID[uiIter1] != 0; uiIter1++)
					{
						if (pNit->p_trans[uiIter2].trans_id == usTSID[uiIter1])
						{
							bFound = TRUE;
							break;
						}
					}

					if (!bFound)
					{
						/* new TS ID is found */
						PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_NEW_TSID, 0);
						return al_true;
					}
				}
			}
		}
		else
		{
			/* do nothing if get content fail, maybe this structure don't have this member names "usTSID" */
		}
	}

	return al_false;
}

#ifdef EPG_REPLACE
static al_void _AI_PSI_Monitor_InNitReplaceDispose(al_void *pData, AL_DB_EDBType_t eDBType)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *) pData;
	dvbpsi_linkage_dr_t  *pLinkageDescr = al_null;
	al_int i = 0;
	AL_PsiMon_State_Type_t ePsiMinState = AL_PSIMONITOR_STATE_MAX;
	AL_RecHandle_t hProgHdl = AL_DB_INVALIDHDL;

	for (i = 0; i< pNit->descLen; )
	{
        if (DESCR_LINKAGE != *(pNit->p_descr+i))
        {
            i += *(pNit->p_descr+i+1) +2;
            continue;
        }

        pLinkageDescr = dvbpsi_DecodeLinkDr((pNit->p_descr+i), pNit->descLen - i);

        if (pLinkageDescr == NULL)
        {
            break;
        }

        i += pLinkageDescr->length + 9;

        if (pLinkageDescr->i_linkage_type == 0x04)
        {
			ePsiMinState = AL_PSIMONITOR_STATE_EPG_REPLACEMENT_EXIST;
			AL_Serv_SearchKey_t stSearchKey;
			memset(&stSearchKey, 0, sizeof(stSearchKey));

			stSearchKey.eDBType = eDBType;
			stSearchKey.eRecType = AL_RECTYPE_DVBSERVICE;
			stSearchKey.u16OrigNetId = pLinkageDescr->i_original_network_id;
			stSearchKey.u16TsId = pLinkageDescr->i_transport_stream_id;
#if 0
			stSearchKey.u16ServId = pLinkageDescr->i_service_id;
			stSearchKey.eSearchField = AL_SRV_SEARCHFIELD_ORIGNETID
										| AL_SRV_SEARCHFIELD_TSID
										| AL_SRV_SEARCHFIELD_SRVID;
#else
			stSearchKey.eSearchField = AL_SRV_SEARCHFIELD_ORIGNETID
										| AL_SRV_SEARCHFIELD_TSID;
#endif
			if (AL_SUCCESS == AL_DB_GetMatchedRecord((AL_DB_RecordMatchFunc)AL_Serv_MatchRecBySearchKey,
					(al_void *)&stSearchKey, eDBType, AL_RECTYPE_DVBSERVICE, AL_DB_REQ_GETFIRST, &hProgHdl))
			{
				AI_PSI_Monitor_SetState(ePsiMinState, &hProgHdl);
			}

			SAFE_FREE(pLinkageDescr);
			pLinkageDescr = al_null;
			return;
        }

		SAFE_FREE(pLinkageDescr);
		pLinkageDescr = al_null;
    }
}
#endif

#ifdef CONFIG_SUPPORT_KDG_CERTIFICATION
static al_void _AI_PSI_Monitor_InBatLCNDynamicUpdate(al_void *pData,
	AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrProgHdl, al_int iCurrentTS)
{
	MID_SiutilNitInfo_t *pBat = (MID_SiutilNitInfo_t *) pData;
	al_uint16 u16ProgNo = 0xffff;
	al_uint16 u16OrgLCN = 0xffff;
	AL_ServiceDetail_t stSrvInfo;
	al_uint16 u16CurServiceID = 0xffff;
	DBServAttrib_t stProgAttrib;
	AL_RecHandle_t hRecHdl;
	bool bLCNChanged = FALSE;
	// bool bServVisibleChanged = FALSE;
	bool bGotServValue = FALSE;

    #ifdef CONFIG_CIPLUS_SUPPORT
    if (APP_CIPLUS_IsProfileSource())
    {
        return AL_FAILURE;
    }
    if( APP_CIPLUS_IsProfileService(hCurrProgHdl) )
    	return;
    #endif

	if (pBat == al_null || !(g_ePsiUpdateOptions & AL_PSIMONITOR_KDG_LCN_DYNAMIC_UPDATE))
	{
		return;
	}

	hRecHdl = hCurrProgHdl;
	hCurrProgHdl = AL_DB_INVALIDHDL;
	/* get Multiplex handle */
	if (AL_SUCCESS != AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBTV, &hRecHdl))
	{
		PSI_MONITOR_ERROR_MSG("query multiplex handle failed!\n");
		return;
	}

	while (AL_SUCCESS == AL_DB_GetChildRecord(hRecHdl, &hCurrProgHdl))
	{
	#ifdef CONFIG_CIPLUS_SUPPORT
		if( APP_CIPLUS_IsProfileService(hCurrProgHdl) )
			continue;
	#endif

		bGotServValue = FALSE;
		memset(&stProgAttrib, 0, sizeof stProgAttrib);

		/* query service Original LCN number */
		if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (UINT8*)"usOrgLcn", &u16OrgLCN))
		{
			PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
			return;
		}

		/* query service attrib */
		if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
		{
			PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
			return;
		}

		/* query service ID */
		if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (UINT8*)"usServiceId", &u16CurServiceID))
		{
			PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
			return;
		}

		u16ProgNo = 0xffff;
		u16ProgNo = dvbpsi_DecodeLCNDr_9C(pBat->p_descr, pBat->descLen, u16CurServiceID);
		if (u16ProgNo != 0xFFFF) /* if has got LCN */
		{
			u16ProgNo &= ~(DB_DVB_LCN_INDICATOR | DB_DVB_LCN2_INDICATOR);
			u16ProgNo = u16ProgNo | DB_DVB_LCN_INDICATOR;
			bGotServValue = TRUE;
		}
		else
		{
			u16ProgNo = 0;
		}

		if (bGotServValue && (u16ProgNo & ~(DB_DVB_LCN_INDICATOR | DB_DVB_LCN2_INDICATOR)) != u16OrgLCN)
		{
			u16OrgLCN = u16ProgNo & ~(DB_DVB_LCN_INDICATOR | DB_DVB_LCN2_INDICATOR);
#if 0
			AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"usOrgLcn", &u16OrgLCN);
			/* call a LCN update API to update the program's LCN */
			AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"usProgNo", &u16ProgNo);

			//LCN_UpdateLCN(hCurrProgHdl, u16ProgNo);
#else //lcn procdure(db_lcn.c) required, enforce update usOrgLcn and usProgNo atomicity and consistency
			AL_DB_QueryDetail(hCurrProgHdl, &stSrvInfo);
			if( eDBType == AL_DBTYPE_DVB_T )
			{
				stSrvInfo.stDVBTServ.usOrgLcn = u16OrgLCN;
				stSrvInfo.stDVBTServ.usProgNo = u16ProgNo;
			}
			else if( eDBType == AL_DBTYPE_DVB_C )
			{
				stSrvInfo.stDVBCServ.usOrgLcn = u16OrgLCN;
				stSrvInfo.stDVBCServ.usProgNo = u16ProgNo;
			}
			else if( eDBType == AL_DBTYPE_DVB_S )
			{
				stSrvInfo.stDVBSServ.usOrgLcn = u16OrgLCN;
				stSrvInfo.stDVBSServ.usProgNo = u16ProgNo;
			}
			AL_DB_UpdateDetail(hCurrProgHdl, &stSrvInfo);
#endif
			bLCNChanged = TRUE;
		}
		/* this program, that was allocated LCN previously, loses its LCN now */
		else if (u16ProgNo == 0xFFFF && u16OrgLCN != 0)
		{
			u16OrgLCN = 0;
			u16ProgNo = 0;
#if 0
			AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"usOrgLcn", &u16OrgLCN);
			AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"usProgNo", &u16ProgNo);
#else //lcn procdure(db_lcn.c) required, enforce update usOrgLcn and usProgNo atomicity and consistency
			AL_DB_QueryDetail(hCurrProgHdl, &stSrvInfo);
			if( eDBType == AL_DBTYPE_DVB_T )
			{
				stSrvInfo.stDVBTServ.usOrgLcn = u16OrgLCN;
				stSrvInfo.stDVBTServ.usProgNo = u16ProgNo;
			}
			else if( eDBType == AL_DBTYPE_DVB_C )
			{
				stSrvInfo.stDVBCServ.usOrgLcn = u16OrgLCN;
				stSrvInfo.stDVBCServ.usProgNo = u16ProgNo;
			}
			else if( eDBType == AL_DBTYPE_DVB_S )
			{
				stSrvInfo.stDVBSServ.usOrgLcn = u16OrgLCN;
				stSrvInfo.stDVBSServ.usProgNo = u16ProgNo;
			}
			AL_DB_UpdateDetail(hCurrProgHdl, &stSrvInfo);
#endif

			bLCNChanged = TRUE;
		}

	}

	if (bLCNChanged)
	{
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_UPDATE_LCN, 0);
		/* if service list has open, those data of channel list need refresh */
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SRV_UPDATE, 0);
	}

}
#endif

static al_void _AI_PSI_Monitor_InSdtOtherSrvListDispose(al_void *pData,
	AL_DB_EDBType_t eDBType)
{
	MID_SiutilSdtInfo_t *pSdt = (MID_SiutilSdtInfo_t *) pData;
	MID_SiutilSdtServiceDescr_t *pSdtDescr = al_null;
	dvbpsi_service_dr_t *pServiceDr = al_null;
	dvbpsi_ml_service_dr_t *pMlServiceDr = al_null;
	al_int iCount = 0;
	al_uint8 u8Name[DB_DVB_MAX_CHNAME_LEN];
	al_uint8 szProgName[DB_DVB_MAX_CHNAME_LEN];
	al_uint8 u8Iso639Lang1[3] = {0};
	al_uint8 u8Iso639Lang2[3] = {0};
	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
	AL_RecHandle_t hProgHdl = AL_DB_INVALIDHDL;
	DBServAttrib_t 	stProgAttrib;
	al_uint8  eSDTSrvType;
	al_uint32 u32SerFlag = 0;
	AL_Serv_SearchKey_t stSearchKey;
	al_uint8 NeedUpdat = FALSE;

	if (pSdt == al_null)
	{
		return;
	}

	//zhongbaoxing added according to NorDig 2.2.1 Section 13.2.2 @20120806 +++
	if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG)
	{
		if(pSdt->original_network_id>= 0xFF00)
		{
			return;
		}
	}
	//zhongbaoxing added according to NorDig 2.2.1 Section 13.2.2 @20120806 ---

	if ((g_ePsiUpdateOptions & AL_PSIMONITOR_OTHTP_SR_UPDATE) == 0)
	{
		return;
	}

	memset(u8Name, 0, DB_DVB_MAX_CHNAME_LEN);

	for (iCount = 0; iCount < pSdt->services_count; iCount++)
	{
		pSdtDescr = &pSdt->p_sdt_descr_t[iCount];

		pServiceDr = dvbpsi_DecodeServiceDr(pSdtDescr->p_descr,pSdtDescr->descLen);

		if (pServiceDr)
		{
			if(pServiceDr->i_service_name_length > 0)
			{
				int len = MID_CmnDecompressString(pServiceDr->service_name,
					pServiceDr->i_service_name_length);

				if(len > pServiceDr->i_service_name_length && len < DB_DVB_MAX_CHNAME_LEN)
				{
					pServiceDr->i_service_name_length=len;
				}

				MID_CmnTransStrWithSpeciChar(pServiceDr->service_name,
					pServiceDr->i_service_name_length);
				MID_CmnTransStrWithoutControlChar(pServiceDr->service_name,
					pServiceDr->i_service_name_length);

				if(pServiceDr->i_service_name_length > 0)
				{
					MID_CmnTransStrWith00(pServiceDr->service_name,
						pServiceDr->i_service_name_length);
				}

				if(pServiceDr->i_service_name_length > 0)
				{
					MID_CmnTransStrWithoutSpeciChar(pServiceDr->service_name,
						pServiceDr->i_service_name_length);
				}

				if(pServiceDr->i_service_name_length > 0)
				{
					MID_CmnTransStrWithoutNewline(pServiceDr->service_name,
						pServiceDr->i_service_name_length);
				}
			}

			memset(u8Name, 0, DB_DVB_MAX_CHNAME_LEN);
			memcpy(u8Name,pServiceDr->service_name, DB_DVB_MAX_CHNAME_LEN - 1);

			/* Parse multi service descriptor in SDT service list every service and update service name to SDT service list */
			pMlServiceDr = dvbpsi_DecodeMlServiceDr(pSdtDescr->p_descr,pSdtDescr->descLen,(dvbsi_special_spec)g_ePsiFollowSpec);

			if (pMlServiceDr)
			{
				dvbpsi_ml_service_dr_t *pTmpmlService = pMlServiceDr;
				AL_FW_GetContextCb(&pfPSIMonGetContext);

				while (pTmpmlService)
				{
					if (pfPSIMonGetContext != al_null)
					{
						pfPSIMonGetContext(FW_CONTEXT_TYPE_ISO639LANGUAGE1 , FW_CONTEXT_OP_TYPE_READ,
							(al_void *)u8Iso639Lang1, 0);
						pfPSIMonGetContext(FW_CONTEXT_TYPE_ISO639LANGUAGE2 , FW_CONTEXT_OP_TYPE_READ,
							(al_void *)u8Iso639Lang2, 0);
					}

					if ((strncasecmp((const char*)u8Iso639Lang1,
						(const char*)pTmpmlService->i_iso6392_language_code,3) == 0)
						|| (strncasecmp((const char*)u8Iso639Lang2,
						(const char*)pTmpmlService->i_iso6392_language_code,3) == 0))
					{
						/* update the program name. */
						memset(u8Name, 0, DB_DVB_MAX_CHNAME_LEN);
						memcpy(u8Name,pTmpmlService->service_name, DB_DVB_MAX_CHNAME_LEN-1);
					}
					pTmpmlService = pTmpmlService->next;
				}

				dvbpsi_FreeMLServiceDr(pMlServiceDr);
				pMlServiceDr = al_null;
			}
#ifdef NEW_FONT
			al_uint32 u32CodePage = 0xff;
			al_uint8 *pExtText = al_null;
			al_int32 i32Len = 0;

			i32Len = DB_DVB_MAX_CHNAME_LEN;
			AL_Event_GetCodePage(&u32CodePage, u8Name, &i32Len);
			if (u32CodePage == 0xff)
			{
				AL_Event_GetDefaultCodePage(&u32CodePage);
			}
			pExtText = UNI_StringToUtf8(u32CodePage, u8Name, &i32Len, al_false);
			memset(u8Name, 0, DB_DVB_MAX_CHNAME_LEN);
			i32Len = i32Len < DB_DVB_MAX_CHNAME_LEN ? i32Len : DB_DVB_MAX_CHNAME_LEN -1;
			memcpy(u8Name, pExtText, i32Len);//service name
			free(pExtText);
#endif
		}

		memset(&stSearchKey, 0, sizeof(stSearchKey));

		stSearchKey.eDBType = eDBType;
		stSearchKey.eRecType = AL_RECTYPE_DVBSERVICE;
		stSearchKey.eSearchField = AL_SRV_SEARCHFIELD_ORIGNETID
								| AL_SRV_SEARCHFIELD_TSID
								| AL_SRV_SEARCHFIELD_SRVID;
		stSearchKey.u16OrigNetId = pSdt->original_network_id;
		stSearchKey.u16TsId = pSdt->transport_stream_id;
		stSearchKey.u16ServId = HILO(pSdtDescr->sdt_service.service_id);

		hProgHdl = AL_DB_INVALIDHDL;

		if ((AL_SUCCESS == AL_DB_GetMatchedRecord((AL_DB_RecordMatchFunc)AL_Serv_MatchRecBySearchKey,
			(al_void *)&stSearchKey, eDBType, AL_RECTYPE_DVBSERVICE, AL_DB_REQ_GETFIRST, &hProgHdl))
			&& (hProgHdl != AL_DB_INVALIDHDL))
		{
			memset(&stProgAttrib, 0, sizeof(DBServAttrib_t));
			memset(szProgName, 0, DB_DVB_MAX_CHNAME_LEN);
			eSDTSrvType = 0;
			u32SerFlag = 0;
			/* updata service name */
			if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
			{
				PSI_MONITOR_ERROR_MSG("get service info failed !!!\n");
			}
			if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hProgHdl, (UINT8*)"szProgName", &szProgName))
			{
				PSI_MONITOR_ERROR_MSG("get service info failed !!!\n");
			}
			if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hProgHdl, (UINT8*)"eSDTSrvType", &eSDTSrvType))
			{
				PSI_MONITOR_ERROR_MSG("get service info failed !!!\n");
			}

			if (g_ePsiUpdateOptions & AL_PSIMONITOR_OTHTP_SR_UPDATE)
			{
				if ((0 == stProgAttrib.nameModified))
				{
					if ((strlen((char *)u8Name) != 0) && (strcmp((char *)u8Name, (char *)(szProgName)))
#ifdef CONFIG_CIPLUS_SUPPORT
                     && !APP_CIPLUS_IsProfileSource()
                     && !APP_CIPLUS_IsProfileService(hProgHdl)
#endif
                    )
					{
						memcpy(szProgName, u8Name, DB_DVB_MAX_CHNAME_LEN);
						if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"szProgName", &szProgName))
						{
							PSI_MONITOR_ERROR_MSG("update name failed !!!\n");
						}

						NeedUpdat = TRUE;
					}
				}

				/* updata service attribute */
				//add by changhong@20121105
				if((stProgAttrib.svrtmp == al_true)
					&&(eSDTSrvType == SERVICE_DIGITAL_RADIO))
				{
					stProgAttrib.svrtmp = al_false;

					if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
					{
						PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
					}

				}

				if (pSdtDescr->sdt_service.free_ca_mode == al_true
					&& stProgAttrib.freeca == al_false)
				{
					stProgAttrib.freeca = al_true;

					if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
					{
						PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
					}
				}
				else if (pSdtDescr->sdt_service.free_ca_mode == al_false
					&& stProgAttrib.freeca == al_true)
				{
					stProgAttrib.freeca = al_false;

					if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
					{
						PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
					}
				}

				if (pServiceDr)
				{
					if (g_pfPsiMonCheckNotVisible != al_null)
					{
						al_uint8 bTempSrv = FALSE;
						al_uint8 bNotVisible = FALSE;
						al_uint8 bNotNeedSave = FALSE;
						bTempSrv = stProgAttrib.svrtmp;
						g_pfPsiMonCheckNotVisible(pServiceDr->i_service_type, bTempSrv, &bNotVisible, &bNotNeedSave);

						if (bNotVisible)
						{
							u32SerFlag |= SERVICE_NOT_ENABLE;
						}
					}

					if ((u32SerFlag & SERVICE_NOT_ENABLE) && (stProgAttrib.notvisible == al_false))
					{
						stProgAttrib.notvisible = al_true;

						if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
						{
							PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
						}
					}
				}
			}
		}
		SAFE_FREE(pServiceDr);
		pServiceDr = al_null;
	}

	if (NeedUpdat == TRUE)
	{
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SRV_UPDATE, 0);
	}
}


static al_void _AI_PSI_Monitor_InSdtSrvListDispose(al_void *pData,
	AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrTpHdl)
{
	MID_SiutilSdtInfo_t *pSdt = (MID_SiutilSdtInfo_t *) pData;
	MID_SiutilSdtServiceDescr_t *pSdtDescr = al_null;
	dvbpsi_service_dr_t *pServiceDr = al_null;
	dvbpsi_ml_service_dr_t *pMlServiceDr = al_null;
	dvbpsi_linkage_dr_t *pLinkageDescr = al_null;
	AL_PsiMon_State_Type_t ePsiMinState = AL_PSIMONITOR_STATE_MAX;
	AL_DB_ERecordType_t eServRecordType = AL_RECTYPE_DVBTV;
	AL_PSIMon_SimpleSrv_t stProg;
	al_int iCount = 0;
	al_uint8 u8Name[DB_DVB_MAX_CHNAME_LEN];
	AL_Serv_SearchKey_t stSearchKey;
	DBServAttrib_t 	stProgAttrib;
	al_uint8  szProgName[DB_DVB_MAX_CHNAME_LEN];
	al_uint8  eSDTSrvType;
	al_uint32 u32SerFlag = 0;
	AL_RecHandle_t hProgHdl = AL_DB_INVALIDHDL;
	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
	al_uint8 u8Iso639Lang1[3] = {0};
	al_uint8 u8Iso639Lang2[3] = {0};
	al_uint16 u16SerType = 0;
#ifdef SUPPORT_FREEVIEW_NZ
	al_uint32 u32Cellid = ~0;
	dvbpsi_ScanDvbSdtServiceCellIdInfo_t *pstCellInfo = al_null;
	al_bool CurrCellServ = al_false;
	al_uint32 cellIter = 0;
#endif

	if (pSdt == al_null)
	{
		return;
	}
	//zhongbaoxing added according to NorDig 2.2.1 Section 13.2.2 @20120806 +++
	if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG)
	{
		if(pSdt->original_network_id>= 0xFF00)
		{
			return;
		}
	}
	//zhongbaoxing added according to NorDig 2.2.1 Section 13.2.2 @20120806 ---

	memset(u8Name, 0, DB_DVB_MAX_CHNAME_LEN);
#ifdef SUPPORT_FREEVIEW_NZ
	AL_FW_GetContextCb(&pfPSIMonGetContext);
	if (pfPSIMonGetContext != al_null)
	{
		pfPSIMonGetContext(FW_CONTEXT_TYPE_CELLID ,  FW_CONTEXT_OP_TYPE_READ,
			(al_void *)&u32Cellid, 0);
	}
#endif

	for (iCount = 0; iCount < pSdt->services_count; iCount++)
	{
		pSdtDescr = &pSdt->p_sdt_descr_t[iCount];

#ifdef CONFIG_SUPPORT_EWS
		AI_EWS_Monitor_InSdtEWSDispose(pSdtDescr);
#endif

		/* 1. NorDig Simulcast replacement service dispose */
		if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG)
		{
			pLinkageDescr = dvbpsi_DecodeLinkDr(pSdtDescr->p_descr,pSdtDescr->descLen);

			if (pLinkageDescr != al_null)
			{
				if (pLinkageDescr->i_linkage_type == 0x82)
				{
					ePsiMinState = AL_PSIMONITOR_STATE_SIMULCAST_REPLACEMENT_EXIST;
				}

				if (ePsiMinState != AL_PSIMONITOR_STATE_MAX)
				{
					memset(&stSearchKey, 0, sizeof(stSearchKey));

					stSearchKey.eDBType = eDBType;
					stSearchKey.eRecType = AL_RECTYPE_DVBSERVICE;
					stSearchKey.eSearchField = AL_SRV_SEARCHFIELD_ORIGNETID
											| AL_SRV_SEARCHFIELD_TSID
											| AL_SRV_SEARCHFIELD_SRVID;
					stSearchKey.u16OrigNetId = pLinkageDescr->i_original_network_id;
					stSearchKey.u16TsId = pLinkageDescr->i_transport_stream_id;
					stSearchKey.u16ServId = pLinkageDescr->i_service_id;

					hProgHdl = AL_DB_INVALIDHDL;

					if ((AL_SUCCESS == AL_DB_GetMatchedRecord((AL_DB_RecordMatchFunc)AL_Serv_MatchRecBySearchKey,
						(al_void *)&stSearchKey, eDBType, AL_RECTYPE_DVBSERVICE, AL_DB_REQ_GETFIRST, &hProgHdl))
						&& (hProgHdl != AL_DB_INVALIDHDL))
					{
						AI_PSI_Monitor_SetState(ePsiMinState, &hProgHdl);
						AI_PSI_Monitor_ReplaceProcess(AL_PSIMONITOR_STATE_SIMULCAST_REPLACEMENT_EXIST);
					}
				}

				SAFE_FREE(pLinkageDescr);
				pLinkageDescr = al_null;
			}
		}

		/* 2. Parse service descriptor in SDT service list , Get service name*/
		pServiceDr = dvbpsi_DecodeServiceDr(pSdtDescr->p_descr,pSdtDescr->descLen);

		if (pServiceDr)
		{
			memset(&stProg, 0, sizeof(AL_PSIMon_SimpleSrv_t));
			stProg.pucname = u8Name;

			if(/*(g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_DTG)
				&& */pServiceDr->i_service_name_length > 0)
			{
				int len = MID_CmnDecompressString(pServiceDr->service_name,
					pServiceDr->i_service_name_length);

				if(len > pServiceDr->i_service_name_length && len < DB_DVB_MAX_CHNAME_LEN)
				{
					pServiceDr->i_service_name_length=len;
				}

				MID_CmnTransStrWithSpeciChar(pServiceDr->service_name,
					pServiceDr->i_service_name_length);
				MID_CmnTransStrWithoutControlChar(pServiceDr->service_name,
					pServiceDr->i_service_name_length);

				if(pServiceDr->i_service_name_length > 0)
				{
					MID_CmnTransStrWith00(pServiceDr->service_name,
						pServiceDr->i_service_name_length);
				}

				if(pServiceDr->i_service_name_length > 0)
				{
					MID_CmnTransStrWithoutSpeciChar(pServiceDr->service_name,
						pServiceDr->i_service_name_length);
				}

				if(pServiceDr->i_service_name_length > 0)
				{
					MID_CmnTransStrWithoutNewline(pServiceDr->service_name,
						pServiceDr->i_service_name_length);
				}
			}

			memset(stProg.pucname, 0, DB_DVB_MAX_CHNAME_LEN);
			memcpy(stProg.pucname,pServiceDr->service_name, DB_DVB_MAX_CHNAME_LEN - 1);

			/* Parse multi service descriptor in SDT service list every service and update service name to SDT service list */
			pMlServiceDr = dvbpsi_DecodeMlServiceDr(pSdtDescr->p_descr,pSdtDescr->descLen,(dvbsi_special_spec)g_ePsiFollowSpec);

			if (pMlServiceDr)
			{
				dvbpsi_ml_service_dr_t *pTmpmlService = pMlServiceDr;
				AL_FW_GetContextCb(&pfPSIMonGetContext);

				while (pTmpmlService)
				{
					if (pfPSIMonGetContext != al_null)
					{
#ifndef CONFIG_EPG_LANG_DEFAULT_BY_OSDLANG
						pfPSIMonGetContext(FW_CONTEXT_TYPE_ISO639LANGUAGE1 , FW_CONTEXT_OP_TYPE_READ,
							(al_void *)u8Iso639Lang1, 0);
						pfPSIMonGetContext(FW_CONTEXT_TYPE_ISO639LANGUAGE2 , FW_CONTEXT_OP_TYPE_READ,
							(al_void *)u8Iso639Lang2, 0);
#else
						pfPSIMonGetContext(FW_CONTEXT_TYPE_OSDISO639LANGUAGE1 , FW_CONTEXT_OP_TYPE_READ,
							(al_void *)u8Iso639Lang1, 0);
						pfPSIMonGetContext(FW_CONTEXT_TYPE_OSDISO639LANGUAGE2 , FW_CONTEXT_OP_TYPE_READ,
							(al_void *)u8Iso639Lang2, 0);
#endif
					}

					if ((strncasecmp((const char*)u8Iso639Lang1,
						(const char*)pTmpmlService->i_iso6392_language_code,3) == 0)
						|| (strncasecmp((const char*)u8Iso639Lang2,
						(const char*)pTmpmlService->i_iso6392_language_code,3) == 0))
					{
						/* update the program name. */
						memset(stProg.pucname, 0, DB_DVB_MAX_CHNAME_LEN);
						memcpy(stProg.pucname,pTmpmlService->service_name, DB_DVB_MAX_CHNAME_LEN-1);
					}
					pTmpmlService = pTmpmlService->next;
				}

				dvbpsi_FreeMLServiceDr(pMlServiceDr);
				pMlServiceDr = al_null;
			}
#ifdef NEW_FONT
			al_uint32 u32CodePage = 0xff;
			al_uint8 *pExtText = al_null;
			al_int32 i32Len = 0;

			i32Len = DB_DVB_MAX_CHNAME_LEN;
			AL_Event_GetCodePage(&u32CodePage, stProg.pucname, &i32Len);
			if (u32CodePage == 0xff)
			{
				AL_Event_GetDefaultCodePage(&u32CodePage);
			}
			pExtText = UNI_StringToUtf8(u32CodePage, stProg.pucname, &i32Len, al_false);
			memset(stProg.pucname, 0, DB_DVB_MAX_CHNAME_LEN);
			i32Len = i32Len < DB_DVB_MAX_CHNAME_LEN ? i32Len : DB_DVB_MAX_CHNAME_LEN -1;
			memcpy(stProg.pucname, pExtText, i32Len);//service name
			//printf("[%s:%d] u32CodePage : %d, u32Len: %d\n",__FUNCTION__,__LINE__, u32CodePage, i32Len);
			free(pExtText);
#endif
		}

		/* 3. Add, Remove Service */
		if (pServiceDr)
		{
			if (g_ePsiUpdateOptions &
				(AL_PSIMONITOR_CURTP_SRVADD | AL_PSIMONITOR_CURTP_SRVADD2 | AL_PSIMONITOR_CURTP_SRV_REMOVE
		 		| AL_PSIMONITOR_CURTP_SRV_ATR))
			{
				if (g_pfPsiMonCheckSrvType != al_null)
				{
					u16SerType = SERVICE_DIGITAL_TELEVISION;
					/*if (g_u8VideoPidCount != 0 && g_u8VideoPidCount != 0xff)
					{
						u16SerType = SERVICE_DIGITAL_TELEVISION;
					}
					else if (g_u8AudioPidCount != 0 && g_u8AudioPidCount != 0xff)
					{
						u16SerType = SERVICE_DIGITAL_RADIO;
					}
					else
					{
						u16SerType = SERVICE_DATABROADCAST;
					}*/

					g_pfPsiMonCheckSrvType(pServiceDr->i_service_type,  u16SerType, 0xff, 0xff, &eServRecordType);

					#ifdef CONFIG_ISDB_SYSTEM
					#ifndef SUPPORT_ONESEG_PROGRAM
					if(pServiceDr->i_service_type == SERVICE_DATA)
					{
						PSI_MONITOR_ERROR_MSG("not save oneseg program!\n");
						return;
					}
					#endif
					#endif
					stProg.usOrgNetId = pSdt->original_network_id;
					stProg.usServiceId = HILO(pSdtDescr->sdt_service.service_id);
					stProg.usTsId = pSdt->transport_stream_id;
					stProg.ucServiceType = eServRecordType;
					stProg.u8SDTSrvType = pServiceDr->i_service_type;
					stProg.usProgNum = 0;
					hProgHdl = AL_DB_INVALIDHDL;

					if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG)
					{
						if ((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SIMULCAST_REPLACEMENT_EXIST, &hProgHdl) == al_true)
							&& (hProgHdl != AL_DB_INVALIDHDL))
						{
							memset(&stSearchKey, 0, sizeof(stSearchKey));

							stSearchKey.eDBType = eDBType;
							stSearchKey.eRecType = AL_RECTYPE_DVBSERVICE;
							stSearchKey.eSearchField = AL_SRV_SEARCHFIELD_ORIGNETID
													| AL_SRV_SEARCHFIELD_TSID
													| AL_SRV_SEARCHFIELD_SRVID;
							stSearchKey.u16OrigNetId = pSdt->original_network_id;
							stSearchKey.u16TsId = pSdt->transport_stream_id;
							stSearchKey.u16ServId = HILO(pSdtDescr->sdt_service.service_id);

							hProgHdl = AL_DB_INVALIDHDL;

							if ((AL_SUCCESS == AL_DB_GetMatchedRecord((AL_DB_RecordMatchFunc)AL_Serv_MatchRecBySearchKey,
								(al_void *)&stSearchKey, eDBType, AL_RECTYPE_DVBSERVICE, AL_DB_REQ_GETFIRST, &hProgHdl))
								&& (hProgHdl != AL_DB_INVALIDHDL))
							{
								PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SERVICE_SIMULCASE_REPLACE, hProgHdl);
							}

							AI_PSI_Monitor_ReplaceProcess(AL_PSIMONITOR_STATE_SIMULCAST_REPLACED);
						}
						else if (g_ePsiUpdateOptions & (AL_PSIMONITOR_CURTP_SRVADD|AL_PSIMONITOR_CURTP_SRVADD2|
							AL_PSIMONITOR_CURTP_SRV_REMOVE))
						{
							_AI_PSI_Monitor_CurTPServicesStack(TABLE_ID_SDT_ACT,
								pSdt->version_number,stProg);
						}
					}
					else if(g_ePsiUpdateOptions & (AL_PSIMONITOR_CURTP_SRVADD|AL_PSIMONITOR_CURTP_SRVADD2|
						AL_PSIMONITOR_CURTP_SRV_REMOVE))
					{
#ifdef SUPPORT_FREEVIEW_NZ
						pstCellInfo = dvbpsi_DecodeServiceAvailabilityDr(pSdtDescr->p_descr, pSdtDescr->descLen);
						CurrCellServ = al_false;
						if (pstCellInfo != al_null && pstCellInfo->cellidCount != 0)
						{
							if (pstCellInfo->availability)
							{
								for (cellIter = 0; cellIter < pstCellInfo->cellidCount; cellIter++)
								{
									if(u32Cellid == pstCellInfo->cellid[cellIter])
									{
										CurrCellServ = al_true;
										break;
									}
								}
							}
							else
							{
								for (cellIter = 0; cellIter < pstCellInfo->cellidCount; cellIter++)
								{
									if(u32Cellid == pstCellInfo->cellid[cellIter])
									{
										break;
									}
								}
								if (cellIter >= pstCellInfo->cellidCount)
								{
									CurrCellServ = al_true;
								}
							}

							GL_MemFree(pstCellInfo);
							pstCellInfo = al_null;
						}
						else
						{
							CurrCellServ = al_true;
						}

						if (CurrCellServ)
						{
							_AI_PSI_Monitor_CurTPServicesStack(TABLE_ID_SDT_ACT,
								pSdt->version_number,stProg);
						}
#else
						_AI_PSI_Monitor_CurTPServicesStack(TABLE_ID_SDT_ACT,
							pSdt->version_number,stProg);
#endif
					}
				}
			}
		}

		/* 4. Update Service */
		hProgHdl = AL_DB_INVALIDHDL;
		al_uint16 u16OrigNetId = 0;
		al_uint16 u16TsId = 0;
		al_uint16 u16ServiceId = 0;
		AL_RecHandle_t hCurrProgHdl = AL_DB_INVALIDHDL;

		if ((MID_SUCCESS != MID_PlaybackGetCurProgHandle(al_null, &hCurrProgHdl))
			|| (hCurrProgHdl == AL_DB_INVALIDHDL))
		{
			PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
			return;
		}

		while (AL_SUCCESS == AL_DB_GetChildRecord(hCurrTpHdl, &hProgHdl)
			&& (hProgHdl != AL_DB_INVALIDHDL))
		{
			AL_DB_QueryDetailFieldByName(hProgHdl, (al_uint8 *)"usOrigNetId", (al_void *)&u16OrigNetId);
			AL_DB_QueryDetailFieldByName(hProgHdl, (al_uint8 *)"usTsId", (al_void *)&u16TsId);
			AL_DB_QueryDetailFieldByName(hProgHdl, (al_uint8 *)"usServiceId", (al_void *)&u16ServiceId);

			/* if scan not received sdt and nit, the original_network_id is 0, then ts is not change original_network_id, ts: \\Qin-he\share_bin\DVBT0958-128_LONDON_RF562000.ts */
			if (((u16OrigNetId == pSdt->original_network_id)
				&& (u16ServiceId == HILO(pSdtDescr->sdt_service.service_id))
				&& (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_DTG))
				|| ((u16OrigNetId == 0)
				&& (u16ServiceId == HILO(pSdtDescr->sdt_service.service_id))
				&& (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_DTG))
				|| (
#ifndef CONFIG_DTMB_SYSTEM
				(u16OrigNetId == pSdt->original_network_id)
				&& (u16TsId == pSdt->transport_stream_id)&& 
#endif
				(u16ServiceId == HILO(pSdtDescr->sdt_service.service_id)))
				|| ((u16OrigNetId == 0)
				&& (u16TsId == pSdt->transport_stream_id)
				&& (u16ServiceId == HILO(pSdtDescr->sdt_service.service_id))))
			{
				memset(&stProgAttrib, 0, sizeof(DBServAttrib_t));
				memset(szProgName, 0, DB_DVB_MAX_CHNAME_LEN);
				eSDTSrvType = 0;
				u32SerFlag = 0;
				/* updata service name */
				if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
				{
					break;
				}
				if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hProgHdl, (UINT8*)"szProgName", &szProgName))
				{
					break;
				}
				if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hProgHdl, (UINT8*)"eSDTSrvType", &eSDTSrvType))
				{
					break;
				}

				if (g_ePsiUpdateOptions & AL_PSIMONITOR_CURTP_SRV_ATR)
				{
					if ((0 == stProgAttrib.nameModified))
					{
					if ((strlen((char *)u8Name) != 0) && (strcmp((char *)u8Name, (char *)(szProgName)))
#ifdef CONFIG_CIPLUS_SUPPORT
                       && !APP_CIPLUS_IsProfileSource()
                       && !APP_CIPLUS_IsProfileService(hProgHdl)
#endif
                        )
						{
							memcpy(szProgName, u8Name, DB_DVB_MAX_CHNAME_LEN);
							if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"szProgName", &szProgName))
							{
								PSI_MONITOR_ERROR_MSG("update name failed !!!\n");
							}

							PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SRV_UPDATE, 0);
						}
					}
				}

				/* updata service attribute */
				//add by changhong@20121105
				if((stProgAttrib.svrtmp == al_true)
					&&(eSDTSrvType == SERVICE_DIGITAL_RADIO))
	                	{
	                    		stProgAttrib.svrtmp = al_false;

					if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
					{
						PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
					}

	                	}

				if (pSdtDescr->sdt_service.free_ca_mode == al_true
					&& stProgAttrib.freeca == al_false)
				{
					stProgAttrib.freeca = al_true;

					if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
					{
						PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
					}
				}
				else if (pSdtDescr->sdt_service.free_ca_mode == al_false
					&& stProgAttrib.freeca == al_true)
				{
					stProgAttrib.freeca = al_false;

					if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
					{
						PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
					}
				}

				if (pServiceDr)
				{
					if (g_pfPsiMonCheckNotVisible != al_null)
					{
						al_uint8 bTempSrv = FALSE;
						al_uint8 bNotVisible = FALSE;
						al_uint8 bNotNeedSave = FALSE;
						bTempSrv = stProgAttrib.svrtmp;
						g_pfPsiMonCheckNotVisible(pServiceDr->i_service_type, bTempSrv, &bNotVisible, &bNotNeedSave);

						if (bNotVisible)
						{
							u32SerFlag |= SERVICE_NOT_ENABLE;
						}
					}

					if ((u32SerFlag & SERVICE_NOT_ENABLE) && (stProgAttrib.notvisible == al_false))
					{
						stProgAttrib.notvisible = al_true;

						if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
						{
							PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
						}
					}

					if (eSDTSrvType != pServiceDr->i_service_type)
					{
						eSDTSrvType = pServiceDr->i_service_type;
						if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"eSDTSrvType", &eSDTSrvType))
						{
							PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
						}

						u16SerType = SERVICE_DIGITAL_TELEVISION;

						if (hCurrProgHdl == hProgHdl)
						{
							if (g_u8VideoPidCount != 0 && g_u8VideoPidCount != 0xff)
							{
								u16SerType = SERVICE_DIGITAL_TELEVISION;
							}
							else if (g_u8AudioPidCount != 0 && g_u8AudioPidCount != 0xff)
							{
								u16SerType = SERVICE_DIGITAL_RADIO;
							}
							else
							{
								u16SerType = SERVICE_DATABROADCAST;
							}
							if (g_pfPsiMonCheckSrvType != al_null)
							{
								g_pfPsiMonCheckSrvType(pServiceDr->i_service_type, u16SerType, g_u8VideoPidCount, g_u8AudioPidCount, &eServRecordType);
							}
						}
						else
						{
							DBPIDInfo_t		stVideoPid;
							DBPIDInfo_t		stAudioPid[DB_DVB_MAX_AUDIO_NUM];
							al_uint8 u8VideoPidCount = 0xff;
							al_uint8 u8AudioPidCount = 0xff;
							al_uint8 u8Count = 0;

							memset(&stVideoPid, 0, sizeof(DBPIDInfo_t));
							memset(&stAudioPid, 0, sizeof(DBPIDInfo_t)*DB_DVB_MAX_AUDIO_NUM);

							if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hProgHdl, (UINT8*)"stVideoPid", &stVideoPid))
							{
								break;
							}

							if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hProgHdl, (UINT8*)"stAudioPid", &stAudioPid))
							{
								break;
							}

							if ((((stVideoPid.usDataPID)&0x1fff) != 0x1fff) && (((stVideoPid.usDataPID)&0x1fff) != 0))
							{
								u8VideoPidCount = 1;
							}

							for (u8Count = 0; u8Count < DB_DVB_MAX_AUDIO_NUM; u8Count++)
							{
								if ((((stAudioPid[u8Count].usDataPID)&0x1fff) != 0x1fff) && (((stAudioPid[u8Count].usDataPID)&0x1fff) != 0))
								{
									u8AudioPidCount++;
								}
							}

							if (u8VideoPidCount != 0 && u8VideoPidCount != 0xff)
							{
								u16SerType = SERVICE_DIGITAL_TELEVISION;
							}
							else if (u8AudioPidCount != 0 && u8AudioPidCount != 0xff)
							{
								u16SerType = SERVICE_DIGITAL_RADIO;
							}
							else
							{
								u16SerType = SERVICE_DATABROADCAST;
							}
							if (g_pfPsiMonCheckSrvType != al_null)
							{
								g_pfPsiMonCheckSrvType(pServiceDr->i_service_type, u16SerType, u8VideoPidCount, u8AudioPidCount, &eServRecordType);
							}	
						}

						al_uint8 eTvRadioType = 0;
						if (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hProgHdl, (UINT8*)"eTvRadioType", &eTvRadioType))
						{
							if (eTvRadioType != eServRecordType
#ifdef CONFIG_CIPLUS_SUPPORT
									&& !APP_CIPLUS_IsProfileSource()
									&& !APP_CIPLUS_IsProfileService(hProgHdl)
#endif
								)
							{
								if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"eTvRadioType", &eServRecordType))
								{
									PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
								}
								else
								{
									PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_UPDATE_LCN, 0);
									PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SRV_UPDATE, 0);
									if (hCurrProgHdl == hProgHdl)
									{
										MID_PlaybackSetCurProgHandle(&eServRecordType, NULL);
										PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SERTYPE_CHANGED, eServRecordType);
									}
								}

								DBServAttrib_t 	stProgAttrib;
								memset(&stProgAttrib, 0, sizeof(DBServAttrib_t));
								if (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
								{
									if (stProgAttrib.svrtmp == al_true)
									{
										if (eServRecordType == AL_RECTYPE_DVBTV && g_u8VideoPidCount != 0 && g_u8VideoPidCount != 0xff)
										{
											stProgAttrib.svrtmp = al_false;

											if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
											{
												PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
											}
										}
										else if (eServRecordType == AL_RECTYPE_DVBRADIO && g_u8AudioPidCount != 0 && g_u8AudioPidCount != 0xff)
										{
											stProgAttrib.svrtmp = al_false;
											if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
											{
												PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
											}
										}
									}
									else
									{
										if (eServRecordType == AL_RECTYPE_DVBTV && g_u8VideoPidCount == 0 && g_u8VideoPidCount != 0xff)
										{
											stProgAttrib.svrtmp = al_true;
											if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
											{
												PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
											}
										}
										else if (eServRecordType == AL_RECTYPE_DVBRADIO && g_u8AudioPidCount == 0 && g_u8AudioPidCount != 0xff)
										{
											stProgAttrib.svrtmp = al_true;
											if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
											{
												PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
											}
										}
									}
								}
							}
						}
					}
				}

				break;
			}
		}

		SAFE_FREE(pServiceDr);
		pServiceDr = al_null;
	}
}

static al_void _AI_PSI_Monitor_InSdtReplaceDispose(al_bool bReplaced,
	al_void *pData, AL_DB_EDBType_t eDBType, al_int iCurrentSrv)
{
	MID_SiutilSdtInfo_t *pSdt = (MID_SiutilSdtInfo_t *) pData;
	MID_SiutilSdtServiceDescr_t *pSdtDescr = al_null;
	al_int iCount = 0;
	al_uint16 u16ONId = 0xffff;
	al_uint16 u16TsId = 0xffff;
	al_uint16 u16ServiceId = 0xffff;
	AL_RecHandle_t hReplacedProg = AL_DB_INVALIDHDL;
	AL_DB_EDBType_t eDBTypeTemp = AL_DBTYPE_MAX;
	AL_RecHandle_t hProgHdl = AL_DB_INVALIDHDL;
	dvbpsi_linkage_dr_t *pLinkageDescr = al_null;
	AL_PsiMon_State_Type_t ePsiMinState = AL_PSIMONITOR_STATE_MAX;

	if (bReplaced)
	{
		if (g_ePsiUpdateOptions & AL_PSIMONITOR_REPLACED_TO_ORIGNAL)
		{
			if (((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED, &hReplacedProg) == al_true)
				|| (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED, &hReplacedProg) == al_true))
				&& (AL_SUCCESS == AL_DB_GetRecordType(hReplacedProg, &eDBTypeTemp, al_null))
				&& (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hReplacedProg, (al_uint8 *)"usServiceId", (al_void *)&u16ServiceId))
				&& (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hReplacedProg, (al_uint8 *)"usOrigNetId", (al_void *)&u16ONId))
				&& (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hReplacedProg, (al_uint8 *)"usTsId", (al_void *)&u16TsId)))
			{
				if ((u16ONId == pSdt->original_network_id) && (u16TsId == pSdt->transport_stream_id))
				{
					for (iCount = 0; iCount < pSdt->services_count; iCount++)
					{
						pSdtDescr = &pSdt->p_sdt_descr_t[iCount];

						if ((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED, &hReplacedProg) == al_true)
							&&(u16ServiceId == HILO(pSdtDescr->sdt_service.service_id))
							&& (pSdtDescr->sdt_service.running_status == RS_RUNNING))
						{
							AI_PSI_Monitor_ReplaceProcess(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED);
							AI_PSI_Monitor_ClearState(AL_PSIMONITOR_STATE_NOT_RUNNING_FLAG);
							break;
						}
						else if ((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED, &hReplacedProg) == al_true)
							&&(u16ServiceId == HILO(pSdtDescr->sdt_service.service_id))
							&& (pSdtDescr->sdt_service.free_ca_mode == al_false))
						{
							AI_PSI_Monitor_ReplaceProcess(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED);
						}
					}
				}
			}
		}
	}
	else
	{
		/* modify by qinhe for current service is replaced other service discard current service replace infomation */
		if ((iCurrentSrv < 0) || (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED, &hReplacedProg) == al_true)
			|| (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED, &hReplacedProg) == al_true))
		{
			return;
		}

		pSdtDescr = &pSdt->p_sdt_descr_t[iCurrentSrv];

		if (pSdtDescr->sdt_service.running_status == RS_NOT_RUNNING)
		{
			AI_PSI_Monitor_SetState(AL_PSIMONITOR_STATE_NOT_RUNNING_FLAG, al_null);
#ifdef CHECK_NOTRUNNING_INSDT
			AI_PSI_Monitor_ReplaceProcess(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACEMENT_EXIST);
#endif
		}

		pLinkageDescr = dvbpsi_DecodeLinkDr(pSdtDescr->p_descr,pSdtDescr->descLen);

		if (pLinkageDescr != NULL)
		{
			if (pLinkageDescr->i_linkage_type == 0x05)
			{
				ePsiMinState = AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACEMENT_EXIST;
			}
			else if (pLinkageDescr->i_linkage_type == 0x03)
			{
				ePsiMinState = AL_PSIMONITOR_STATE_SCRAMBLED_REPLACEMENT_EXIST;
			}

			if (ePsiMinState != AL_PSIMONITOR_STATE_MAX)
			{
				AL_Serv_SearchKey_t stSearchKey;
				memset(&stSearchKey, 0, sizeof(stSearchKey));

				stSearchKey.eDBType = eDBType;
				stSearchKey.eRecType = AL_RECTYPE_DVBSERVICE;
				stSearchKey.eSearchField = AL_SRV_SEARCHFIELD_ORIGNETID
										| AL_SRV_SEARCHFIELD_TSID
										| AL_SRV_SEARCHFIELD_SRVID;
				stSearchKey.u16OrigNetId = pLinkageDescr->i_original_network_id;
				stSearchKey.u16TsId = pLinkageDescr->i_transport_stream_id;
				stSearchKey.u16ServId = pLinkageDescr->i_service_id;

				if (AL_SUCCESS == AL_DB_GetMatchedRecord((AL_DB_RecordMatchFunc)AL_Serv_MatchRecBySearchKey,
						(al_void *)&stSearchKey, eDBType, AL_RECTYPE_DVBSERVICE, AL_DB_REQ_GETFIRST, &hProgHdl))
				{
					AI_PSI_Monitor_SetState(ePsiMinState, &hProgHdl);
				}
			}

			SAFE_FREE(pLinkageDescr);
		}
	}
}


static al_void _AI_PSI_Monitor_InSdtParseFTAData(al_void *pData,  al_int iCurrentSrv)
{
	MID_SiutilSdtInfo_t *pSdt = (MID_SiutilSdtInfo_t *) pData;
	MID_SiutilSdtServiceDescr_t *pSdtDescr = NULL;
	al_uint8 u8FtaContentMgr;

	if (pSdt == al_null)
	{
		return;
	}
	pSdtDescr = &pSdt->p_sdt_descr_t[iCurrentSrv];

	if(g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_DTG)
	{
		AI_PSI_Monitor_SetFTADataTbl(DTGCMG_TBL_SDT);

		if(pSdtDescr->descLen)
		{
			if(dvbpsi_FtaContentMgrDr(pSdtDescr->p_descr,pSdtDescr->descLen,&u8FtaContentMgr))
			{
				AI_PSI_Monitor_FTADataParse(u8FtaContentMgr,DTGCMG_TBL_SDT);
			}
			else
			{
				AI_PSI_Monitor_FTADataParse(0,DTGCMG_TBL_NONE);
			}
		}
		else
		{
			AI_PSI_Monitor_FTADataParse(0,DTGCMG_TBL_NONE);
		}
	}
}

static al_void _AI_PSI_Monitor_TdtCallback(al_void *pData)
{
	MID_SiutilTdtTot_t *pTdt = (MID_SiutilTdtTot_t *) pData;
	al_uint32 u32NewMjd;
	al_uint32 u32OldTimeInSec = 0;
	AL_Time_t stTime;
	al_uint32 u32CurTimeInSec = 0;
	al_uint16 year = 0;
	al_uint8 month = 0;
	al_uint8 date = 0;

	//PSI_MONITOR_DEBUG_MSG("[%s:%d] \n",__FUNCTION__,__LINE__);
	if (AL_Time_GetSyncMode() == AL_TIME_SyncMode_Manual)
	{
		return;
	}

	if (pTdt == NULL)
	{
		return;
	}

	if (pTdt->table_id != TABLE_ID_TDT)
	{
		return;
	}
	/* Check the range of TDT in case of time is out of range */
	if (pTdt->asc_time.Year < 2000
		|| pTdt->asc_time.Month < 1 || pTdt->asc_time.Month > 12
		|| pTdt->asc_time.Day < 0 || pTdt->asc_time.Day > 31
		|| pTdt->asc_time.Hour < 0 || pTdt->asc_time.Hour > 23
		|| pTdt->asc_time.Min < 0 || pTdt->asc_time.Min > 59
		|| pTdt->asc_time.Second < 0 || pTdt->asc_time.Second > 59)
	{
		PSI_MONITOR_ERROR_MSG("TDT time is out of range !!!!!!\n");
		PSI_MONITOR_ERROR_MSG("TDT Year = %d\n", pTdt->asc_time.Year);
		PSI_MONITOR_ERROR_MSG("TDT Month = %d\n", pTdt->asc_time.Month);
		PSI_MONITOR_ERROR_MSG("TDT Day = %d\n", pTdt->asc_time.Day);
		PSI_MONITOR_ERROR_MSG("TDT Hour = %d\n", pTdt->asc_time.Hour);
		PSI_MONITOR_ERROR_MSG("TDT Min = %d\n", pTdt->asc_time.Min);
		PSI_MONITOR_ERROR_MSG("TDT Second = %d\n", pTdt->asc_time.Second);
		return;
	}
    AL_Time_GetDate(&year,&month,&date);
	/* 1. time update dispose */
	AL_Time_GetCurTimeInSecs(&u32OldTimeInSec);

	stTime.Year = pTdt->asc_time.Year;
	stTime.Month = pTdt->asc_time.Month;
	stTime.Day = pTdt->asc_time.Day;
	stTime.Hour = pTdt->asc_time.Hour;
	stTime.Min = pTdt->asc_time.Min;
	stTime.Sec = pTdt->asc_time.Second;

	AL_Time_DateToSecs(&stTime, &u32CurTimeInSec);
	u32NewMjd = AL_Time_YmdToMjd(pTdt->asc_time.Year, pTdt->asc_time.Month, pTdt->asc_time.Day);

	AI_Time_UpdateTime(u32NewMjd,pTdt->asc_time.Hour,pTdt->asc_time.Min,pTdt->asc_time.Second);

	//if((year == DEFAULT_YEAR)&&(month == DEFAULT_MONTH))
    {
        frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
        al_bool bForceDST = al_false;
        AL_FW_GetContextCb(&pfPSIMonGetContext);
        pfPSIMonGetContext(FW_CONTEXT_TYPE_CHECK_FORCE_DST , FW_CONTEXT_OP_TYPE_READ,
            (al_void *)&bForceDST, 0);
        if(bForceDST)
        {
            AL_Time_SetTimeDST(AL_TIME_DST_ON);

        }
        else
        {
            AL_Time_SetTimeDST(AL_TIME_DST_OFF);
        }
    }

	u32CurTimeInSec += AL_Time_GetGMTOffset();
	if (ABSMETHOD(u32CurTimeInSec - u32OldTimeInSec) >= PSIMON_CHANGETIMEINSEC)
	{
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_TIME_UPDATE, u32OldTimeInSec);
	}
#ifdef CONFIG_SUPPORT_SSU_ENHANCE_UPGRADE
	gfTdtHasUpdate = al_true;
#endif
}

static al_void _AI_PSI_Monitor_InPmtCheckComp(al_void *pData,
	AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrProgHdl, al_uint32 *pu32DBUpdateFlag)
{
	MID_SiutilPmtInfo_t *pPmt = (MID_SiutilPmtInfo_t *) pData;
	DBPIDInfo_t		stVideoPid;
	DBPIDInfo_t stAudioPid[DB_DVB_MAX_AUDIO_NUM];
	DBServAttrib_t 	stProgAttrib;
	al_int iCount = 0;
    MID_SiutilPmtStreamInfoDescr_t *pComp = NULL;
	al_uint16 u16MhegVideoPid = DB_DVB_INVALID_PID;
	al_uint16 u16AvcVideoPid = DB_DVB_INVALID_PID;
	al_uint16 u16PlayVideoPid = DB_DVB_INVALID_PID;
    al_uint16 u16MinAudioPid = DB_DVB_INVALID_PID;
    al_uint8  u8VideoPidCount = 0;
    al_uint8  u8AudioPidCount = 0;

	if (pPmt == al_null)
	{
		return;
	}

	memset(&stVideoPid, 0, sizeof(DBPIDInfo_t));
	memset(&stProgAttrib, 0, sizeof(DBServAttrib_t));
	memset(&stAudioPid, 0, sizeof(DBPIDInfo_t)*DB_DVB_MAX_AUDIO_NUM);

	if ((AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"stVideoPid", (al_void *)&stVideoPid))
		&& (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"stAudioPid", (al_void *)&stAudioPid)))
	{
		PSI_MONITOR_ERROR_MSG("Get service info failed!!!\n");
		return;
	}
	/* Get minimal pid, We choose the minimal PID as default in Italy*/
	for (iCount = 0; iCount < pPmt->comp_count; iCount++)
	{
	    pComp = &pPmt->p_comp[iCount];

	    switch (pComp->stream_type)
	    {
	        case STREAM_TYPE_VIDEO_MPEG1:
	        case STREAM_TYPE_VIDEO_MPEG2:
	        case STREAM_TYPE_VIDEO_MPEG4:
	        case STREAM_TYPE_VIDEO_AVC:	/*H.264*/
			#ifdef CONFIG_DTMB_SYSTEM
			case STREAM_TYPE_VIDEO_AVS:
			#endif
			case STREAM_TYPE_VIDEO_HEVC:
	            u8VideoPidCount++;
			/* ZBOOK : play min video pid */
			if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_ZBOOK)
			{
				if (u16PlayVideoPid >= pComp->elementary_pid)
				{
				    u16PlayVideoPid = pComp->elementary_pid;
				}
			}
			/* NORDIG : if has AVC, play first AVC video; else if has mpeg2, play first Mpeg2 video */
			else if ((g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG) &&
				((pComp->stream_type == STREAM_TYPE_VIDEO_MPEG2) || (pComp->stream_type == STREAM_TYPE_VIDEO_AVC)))
			{
				if ((pComp->stream_type == STREAM_TYPE_VIDEO_MPEG2) && (u16MhegVideoPid == DB_DVB_INVALID_PID))
				{
					u16MhegVideoPid = pComp->elementary_pid;
				}
				else if ((pComp->stream_type == STREAM_TYPE_VIDEO_AVC) && (u16AvcVideoPid == DB_DVB_INVALID_PID))
				{
					u16AvcVideoPid = pComp->elementary_pid;
				}
			}
			/* play first video */
			else if (u16PlayVideoPid == DB_DVB_INVALID_PID)
			{
				u16PlayVideoPid = pComp->elementary_pid;
			}
			break;

		case STREAM_TYPE_AUDIO_MPEG1:
		case STREAM_TYPE_AUDIO_MPEG2:
		case STREAM_TYPE_AUDIO_AC3:
		case STREAM_TYPE_AUDIO_EAC3:
		case STREAM_TYPE_AUDIO_AAC:
		case STREAM_TYPE_AUDIO_MPEG2_AAC:
			u8AudioPidCount++;
			if(u16MinAudioPid >= pComp->elementary_pid)
			{
				u16MinAudioPid = pComp->elementary_pid;
			}
			break;

		case STREAM_TYPE_PRIVATE_DATA:
			{
#ifdef SUPPORT_AUDIO_AC3
				/* 3. AC3 checking*/
				al_uint8 audiodr_tags[3];
				audiodr_tags[0] = DESCR_AC3;
				audiodr_tags[1] = DESCR_EAC3;
				audiodr_tags[2] = DESCR_EXTENSION;

				if (MID_SIUTIL_TagsInDescriptorArray(audiodr_tags, 3, pComp->p_desc, pComp->descLen) > 0)
				{
					u8AudioPidCount++;
					if(u16MinAudioPid >= pComp->elementary_pid)
					{
						u16MinAudioPid = pComp->elementary_pid;
					}
				}
#endif
#ifdef CONFIG_DTMB_SYSTEM
				al_uint8 draaudiodr_tags[1];
				al_uint8 RDA_Regist_audiodr_tags[1];
				draaudiodr_tags[0] = DESCR_DRA_AUDIO_STREAM;
				RDA_Regist_audiodr_tags[0] = DESCR_DRA_REGISTRATION;
				if (MID_SIUTIL_TagsInDescriptorArray(draaudiodr_tags, 1, pComp->p_desc, pComp->descLen) > 0)
				{
					u8AudioPidCount++;
					if(u16MinAudioPid >= pComp->elementary_pid)
					{
						u16MinAudioPid = pComp->elementary_pid;
					}
				}
				else if((MID_SIUTIL_TagsInDescriptorArray(RDA_Regist_audiodr_tags, 1, pComp->p_desc, pComp->descLen) > 0)
					&& (dvbpsi_DecodeDRARegistrationDr(pComp->p_desc, pComp->descLen) == 0x44524131))
				{
					u8AudioPidCount++;
					if(u16MinAudioPid >= pComp->elementary_pid)
					{
						u16MinAudioPid = pComp->elementary_pid;
					}
				}
#endif
			}
			break;
	        default:
	            break;
	    }
	}

	if (u16AvcVideoPid != DB_DVB_INVALID_PID)
	{
		u16PlayVideoPid = u16AvcVideoPid;
	}
	else if (u16MhegVideoPid != DB_DVB_INVALID_PID)
	{
		u16PlayVideoPid = u16MhegVideoPid;
	}

	g_u16MinAudioPid = u16MinAudioPid;
	g_u8VideoPidCount = u8VideoPidCount;
    g_u8AudioPidCount = u8AudioPidCount;

	UINT8 eSDTSrvType;
	UINT32 eTvRadioType = 0;
	UINT32 u32TvRadioType = 0;
	al_uint16 u16SerType = 0;
	AL_DB_ERecordType_t eServRecordType = AL_RECTYPE_DVBTV;

	if (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8*)"eSDTSrvType", &eSDTSrvType))
	{
		u16SerType = SERVICE_DIGITAL_TELEVISION;
		if (g_u8VideoPidCount != 0 && g_u8VideoPidCount != 0xff)
		{
			u16SerType = SERVICE_DIGITAL_TELEVISION;
		}
		else if (g_u8AudioPidCount != 0 && g_u8AudioPidCount != 0xff)
		{
			u16SerType = SERVICE_DIGITAL_RADIO;
		}
		else
		{
			u16SerType = SERVICE_DATABROADCAST;
		}

		g_pfPsiMonCheckSrvType(eSDTSrvType, u16SerType, g_u8VideoPidCount, g_u8AudioPidCount, &eServRecordType);

		if (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8*)"eTvRadioType", &eTvRadioType))
		{
			if (eTvRadioType != eServRecordType
#ifdef CONFIG_CIPLUS_SUPPORT
					&& !APP_CIPLUS_IsProfileSource()
					&& !APP_CIPLUS_IsProfileService(hCurrProgHdl)
#endif
				)
			{
				if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (al_uint8*)"eTvRadioType", &eServRecordType))
				{
					PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
				}
				else
				{
					PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_UPDATE_LCN, 0);
					PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SERTYPE_CHANGED, eServRecordType);
				}
			}
		}
	}

	if (MID_SUCCESS != MID_PlaybackGetCurProgHandle(&u32TvRadioType, NULL))
	{
		PSI_MONITOR_ERROR_MSG("MID_PlaybackGetCurProgHandle failed !!!\n");
	}

	/* update temp service attribute */
	if (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stProgAttrib))
	{
		if((((stVideoPid.usDataPID) & 0x1fff) == DB_DVB_INVALID_PID)
			&& (u16PlayVideoPid != DB_DVB_INVALID_PID))
		{
			if (stProgAttrib.svrtmp == al_true)
			{
				stProgAttrib.svrtmp = al_false;
			}
		}

		if (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8*)"eTvRadioType", &eTvRadioType))
		{
			if (eTvRadioType != u32TvRadioType)
			{
				PSI_MONITOR_DEBUG_MSG("[%s:%d] service type changed \n",__FUNCTION__,__LINE__);
			}
		}

		if ((eTvRadioType == AL_RECTYPE_DVBTV) && (g_u8VideoPidCount == 0))
		{
			stProgAttrib.svrtmp = al_true;
		}
		else if ((eTvRadioType == AL_RECTYPE_DVBRADIO) && (g_u8VideoPidCount == 0) && (g_u8AudioPidCount == 0))
		{
			stProgAttrib.svrtmp = al_true;
		}

		if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (al_uint8*)"stProgAttrib", &stProgAttrib))
		{
			PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
		}
	}
	else
	{
		PSI_MONITOR_ERROR_MSG("Get service info failed!!!\n");
	}
	/* update video pid */
	if (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"stVideoPid", (al_void *)&stVideoPid))
	{
		if (g_u8VideoPidCount == 0)
		{
			/* check prev video is not null, but now video is null */
			if( (((stVideoPid.usDataPID)&0x1fff) != 0) && (((stVideoPid.usDataPID)&0x1fff) != 0x1fff))
			{
				*pu32DBUpdateFlag |= COMP_CHG_VID;
			}
			stVideoPid.usDataPID = (stVideoPid.usDataPID & 0xe000) | (al_uint16)(DB_DVB_INVALID_PID);
			if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (al_uint8*)"stVideoPid", &stVideoPid))
			{
				PSI_MONITOR_ERROR_MSG("update stVideoPid failed !!!\n");
			}
		}
	}
	else
	{
		PSI_MONITOR_ERROR_MSG("Get service info failed!!!\n");
	}
	/* update video pid */
	if (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"stAudioPid", (al_void *)&stAudioPid))
	{
		if (g_u8AudioPidCount == 0)
		{
			/* check prev audio is not null, but now audio is null */
#if 0
			if (((((stAudioPid[0].usDataPID) >> 15) & 0x01 == 0) && ((stAudioPid[0].usDataPID & 0x1fff) != 0) && ((stAudioPid[0].usDataPID & 0x1fff) != 0x1fff))
				|| ((((stAudioPid[0].usDataPID) >> 15) & 0x01 == 1) && ((stAudioPid[1].usDataPID & 0x1fff) != 0) && ((stAudioPid[1].usDataPID & 0x1fff) != 0x1fff)))
			{
				*pu32DBUpdateFlag |= COMP_CHG_AUD;
			}
#else
			if ((((stAudioPid[0].usDataPID & 0x1fff) != 0) && ((stAudioPid[0].usDataPID & 0x1fff) != 0x1fff))
				||(((stAudioPid[1].usDataPID & 0x1fff) != 0) && ((stAudioPid[1].usDataPID & 0x1fff) != 0x1fff)))
			{
				*pu32DBUpdateFlag |= COMP_CHG_AUD;
			}
#endif
			stAudioPid[0].usDataPID = (stAudioPid[0].usDataPID & 0xe000) | DB_DVB_INVALID_PID;
			stAudioPid[1].usDataPID = (stAudioPid[1].usDataPID & 0xe000) | DB_DVB_INVALID_PID;

			//stAudioPid[0].usDataPID = stAudioPid[0].usDataPID;
			//stAudioPid[1].usDataPID = stAudioPid[1].usDataPID;

			if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (al_uint8*)"stAudioPid", &stAudioPid))
			{
				PSI_MONITOR_ERROR_MSG("update stAudioPid failed !!!\n");
			}
		}
	}
	else
	{
		PSI_MONITOR_ERROR_MSG("Get service info failed!!!\n");
	}
	/* component update check */
	for (iCount = 0; iCount < pPmt->comp_count; iCount++)
    {
        pComp = &pPmt->p_comp[iCount];

        switch (pComp->stream_type)
        {
            case STREAM_TYPE_VIDEO_MPEG1:
            case STREAM_TYPE_VIDEO_MPEG2:
            case STREAM_TYPE_VIDEO_MPEG4:
            case STREAM_TYPE_VIDEO_AVC:	/*H.264*/
			#ifdef CONFIG_DTMB_SYSTEM
			case STREAM_TYPE_VIDEO_AVS:
			#endif
			case STREAM_TYPE_VIDEO_HEVC:
                if (u16PlayVideoPid == pComp->elementary_pid)
                {
                    /* video elementary stream */
					*pu32DBUpdateFlag |= _AI_PSI_Monitor_VideoStreamUpdate(eDBType, hCurrProgHdl,
                    		pComp,0);
					*pu32DBUpdateFlag |= COMP_CHG_VID_FOUND;
                }
		 		else
				 {
					*pu32DBUpdateFlag |= _AI_PSI_Monitor_VideoStreamUpdate(eDBType, hCurrProgHdl,
		                    		pComp,1);
				 }
                break;

            case STREAM_TYPE_AUDIO_MPEG1:
            case STREAM_TYPE_AUDIO_MPEG2:
#ifdef SUPPORT_AUDIO_AC3
            case STREAM_TYPE_AUDIO_AC3:
#endif
            case STREAM_TYPE_AUDIO_AAC:
            case STREAM_TYPE_AUDIO_MPEG2_AAC:
			//case STREAM_TYPE_AUDIO_AVS:
                if ((u8VideoPidCount >= 2) && (u16MinAudioPid != pComp->elementary_pid)
                	&&(g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_ZBOOK ))
                {
                    break;
                }
                /* audio elementary stream */
                _AI_PSI_Monitor_AudioStreamUpdate(pComp);
                *pu32DBUpdateFlag |= COMP_CHG_AUD_FOUND;
                break;

            case STREAM_TYPE_PRIVATE_DATA:
                /* private elementary stream */
                /* check subtitle, teletext, AC3 or other elementary stream. */
                *pu32DBUpdateFlag |= _AI_PSI_Monitor_PrivateStreamUpate(eDBType, hCurrProgHdl, pComp);
                break;

			case STREAM_TYPE_OBJECT_DATA_CAROUSEL:
			case 0x80:
#ifdef CONFIG_SUPPORT_OTA_UPGRADE
#ifdef CONFIG_SUPPORT_OTAMON_DONOTPARSECURRENTPMT
				{
					PSI_MONITOR_DEBUG_MSG("psi monitor parsing current pmt\n\n\n");
					int hasFind;
					hasFind = Mid_OtaMon_FindUpgradeInfoInPMT(pComp);
					if (hasFind == 0)
					{
						PSI_MONITOR_DEBUG_MSG("current program have upgrade service.\n\n\n");
						MID_PsiMonSetCurtProgrameHaveOta(TRUE);

						MID_OtaMonNotifyDetectUpgrade();
					}
				}
#endif
#endif
				break;
		}
	}
}


static al_void _AI_PSI_Monitor_InPmtCheckPCR(al_void *pData,
	AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrProgHdl, al_uint32 *pu32DBUpdateFlag)
{
	MID_SiutilPmtInfo_t *pPmt = (MID_SiutilPmtInfo_t *) pData;
	al_uint16	usPcrPid = 0xffff;

	if (pPmt == al_null)
	{
		return;
	}

	if (AL_SUCCESS == AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usPcrPid", (al_void *)&usPcrPid))
	{
		if (usPcrPid != pPmt->pcr_pid)
		{
			*pu32DBUpdateFlag |= COMP_CHG_PCR;
			usPcrPid = pPmt->pcr_pid;

			if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (al_uint8*)"usPcrPid", &usPcrPid))
			{
				PSI_MONITOR_ERROR_MSG("update usPcrPid failed !!!\n");
			}
		}
	}

}
#ifdef CONFIG_ISDB_SYSTEM
static al_void _AI_PSI_Monitor_InPmtCheckLocked(al_void *pData,
	AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrProgHdl)
{
	MID_SiutilPmtInfo_t *pPmt = (MID_SiutilPmtInfo_t *) pData;
	al_int iRemainLen = 0;
	al_int iProcessLen = 0;
	al_int iDescLen = 0;
	al_uint8 u8ParentLock = 0;
	al_bool bPmtParentLock = al_false;
	al_bool bProgLocked = al_false;

	if (pPmt == al_null)
	{
		return;
	}

	iRemainLen = pPmt->info_len;

	while (iRemainLen > 0)
	{
		iDescLen = *(pPmt->p_info+iProcessLen+1)+2;
		if (*(pPmt->p_info+iProcessLen) == DESCR_PARENTAL_RATING)
		{
			u8ParentLock = dvbpsi_ParentalRatingDr((pPmt->p_info+iProcessLen), iDescLen);
			bPmtParentLock = al_true;

			if (u8ParentLock == 0)
			{
				u8ParentLock = 1;//a parent lock Dr in pmt
			}
		}

		iRemainLen -= iDescLen;
		iProcessLen += iDescLen;
	}

	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;

	AL_FW_GetContextCb(&pfPSIMonGetContext);
	if (pfPSIMonGetContext != al_null)
	{
		pfPSIMonGetContext(FW_CONTEXT_TYPE_LOCK_STATE , FW_CONTEXT_OP_TYPE_READ,
			(al_void *)&bProgLocked, 0);
	}

	/* a unlock prog changed to locked prog */
	if(bPmtParentLock == al_true && bProgLocked == al_false)
	{
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SRV_UPDATE, u8ParentLock);
	}
	/* a locked prog changed to unlock prog */
	else if(bPmtParentLock == al_false && bProgLocked == al_true)
	{
		u8ParentLock = 0;//no parent lock Dr in pmt
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SRV_UPDATE, u8ParentLock);
	}
	else
	{
	}
}
#endif

static al_void _AI_PSI_Monitor_InPmtCheckScramble(al_void *pData,
	AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrProgHdl, al_uint32 *pu32DBUpdateFlag)
{
	MID_SiutilPmtInfo_t *pPmt = (MID_SiutilPmtInfo_t *) pData;
	dvbpsi_ca_dr_t *pCaDest = al_null;
	al_int iRemainLen = 0;
	al_int iProcessLen = 0;
	al_int iDescLen = 0;
	al_int iCount = 0;
	MID_SiutilPmtStreamInfoDescr_t *p_comp = NULL;

	if (pPmt == al_null)
	{
		return;
	}

	iRemainLen = pPmt->info_len;

	while (iRemainLen > 0)
    {
        iDescLen = *(pPmt->p_info+iProcessLen+1)+2;
        if (*(pPmt->p_info+iProcessLen) == DESCR_CA)
        {
            pCaDest = dvbpsi_DecodeCADr((pPmt->p_info+iProcessLen), iDescLen);

            if (pCaDest)
            {
                *pu32DBUpdateFlag |= COMP_CHG_CA;
				g_CA_SYS_ID = pCaDest->i_ca_system_id;
                SAFE_FREE(pCaDest);
				pCaDest = al_null;
            }
        }

        iRemainLen -= iDescLen;
        iProcessLen += iDescLen;
    }

	p_comp = pPmt->p_comp;
	for (iCount = 0; iCount < pPmt->comp_count; iCount++)
	{
		iDescLen = 0;
		iRemainLen = p_comp[iCount].descLen;
		iProcessLen = 0;

		while (iRemainLen > 0)
		{
			iDescLen += *(p_comp[iCount].p_desc + iProcessLen + 1) + 2;
			if (*(p_comp[iCount].p_desc + iProcessLen) == DESCR_CA)
			{
				pCaDest = dvbpsi_DecodeCADr((p_comp[iCount].p_desc + iProcessLen), iDescLen);

				if (pCaDest)
				{
					*pu32DBUpdateFlag |= COMP_CHG_CA;
					g_CA_SYS_ID = pCaDest->i_ca_system_id;
					SAFE_FREE(pCaDest);
					pCaDest = al_null;
				}
			}

			iRemainLen -= iDescLen;
			iProcessLen += iDescLen;
		}
	}


	DBServAttrib_t stProgAttrib;
	memset(&stProgAttrib, 0, sizeof stProgAttrib);

	/* query service attrib */
	if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
	{
		PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
		return;
	}

	if ((*pu32DBUpdateFlag & COMP_CHG_CA) && (stProgAttrib.scramble != al_true))
	{
		stProgAttrib.scramble = al_true;

		if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
		{
			 PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
		}

		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SRV_UPDATE, 0);
	}
	else if (((*pu32DBUpdateFlag & COMP_CHG_CA) == 0) && (stProgAttrib.scramble == al_true))
	{
		stProgAttrib.scramble = al_false;

		if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (UINT8*)"stProgAttrib", &stProgAttrib))
		{
			 PSI_MONITOR_ERROR_MSG("update attribute failed !!!\n");
		}

		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SRV_UPDATE, 0);
	}
}

static al_void _AI_PSI_Monitor_InPmtUpdatePlayback(al_void *pData,
	AL_DB_EDBType_t eDBType, AL_RecHandle_t hCurrProgHdl, al_uint32 *pu32DBUpdateFlag)
{
	MID_SiutilPmtInfo_t *pPmt = (MID_SiutilPmtInfo_t *) pData;
	DBPIDInfo_t stAudioPid[DB_DVB_MAX_AUDIO_NUM];
	DBPIDInfo_t stVideoPid;
	al_uint16	usPcrPid = 0xffff;
	al_bool bProgLocked = al_false; //Gahu:D0903
	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
#if (defined(CONFIG_SUPPORT_MHEG5) /*|| defined(CONFIG_CIPLUS_SUPPORT)*/)
    al_uint32 u32PidCodec = 0;
#endif

	if (pPmt == al_null)
	{
		return;
	}

	memset(&stVideoPid, 0, sizeof(DBPIDInfo_t));
	memset(&stAudioPid, 0, sizeof(DBPIDInfo_t)*DB_DVB_MAX_AUDIO_NUM);

	if ((AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"stVideoPid", (al_void *)&stVideoPid))
		&& (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"stAudioPid", (al_void *)&stAudioPid)))
	{
		PSI_MONITOR_ERROR_MSG("Get service info failed!!!\n");
		return;
	}

	/* 1. pcr & video */
	AL_FW_GetContextCb(&pfPSIMonGetContext);

	if (pfPSIMonGetContext != al_null)
	{
		pfPSIMonGetContext(FW_CONTEXT_TYPE_LOCK_STATE , FW_CONTEXT_OP_TYPE_READ,
			(al_void *)&bProgLocked, 0);
	}

	AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usPcrPid", (al_void *)&usPcrPid);

    if ((*pu32DBUpdateFlag & (COMP_CHG_PCR | COMP_CHG_VID|COMP_CHG_VID_CODEC)) > 0)
    {
        /* video or pcr changed, stop video */
#if (defined(CONFIG_SUPPORT_MHEG5) /* || defined(CONFIG_CIPLUS_SUPPORT)*/)
        if (MHEG5APP_NotifyAVPIDChange(NULL,NULL,NULL) == 0)
#endif

        {
            MID_PlaybackStopVideo(TRUE);
        }

#if (defined(CONFIG_SUPPORT_MHEG5) /* || defined(CONFIG_CIPLUS_SUPPORT) */)
		u32PidCodec = MHEG5APP_PID_CODEC(((stVideoPid.usDataPID) & 0x1fff),stVideoPid.usCodec);
#endif
		if (!bProgLocked
#if (defined(CONFIG_SUPPORT_MHEG5) /* || defined(CONFIG_CIPLUS_SUPPORT)*/)
			&& (g_ePsiFollowSpec != AL_PSIMON_SPECIAL_SPEC_DTG ||
			MHEG5APP_NotifyAVPIDChange(&u32PidCodec, NULL,&usPcrPid) == 0)
#endif
		)
		{
			/* play video */
			if (((stVideoPid.usDataPID)&0x1fff) != 0
				&& ((stVideoPid.usDataPID)&0x1fff) != DB_DVB_INVALID_PID)
			{
				/* need to play vidoe when video pid/pcr pid/stream type Change */
				if (*pu32DBUpdateFlag & COMP_CHG_VID || *pu32DBUpdateFlag & COMP_CHG_PCR || *pu32DBUpdateFlag & COMP_CHG_VID_CODEC)
				{
					MID_PlaybackStartVideo(((stVideoPid.usDataPID)& 0x1fff), usPcrPid, stVideoPid.usCodec);
				}
			}
		}
    	}

	/* 2. audio */
	if (*pu32DBUpdateFlag & COMP_CHG_AUD_FOUND)
	{
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_AUDIO_UPDATE, 0);
	}
	else if (*pu32DBUpdateFlag & COMP_CHG_AUD)
	{
#if (defined(CONFIG_SUPPORT_MHEG5) /*|| defined(CONFIG_CIPLUS_SUPPORT)*/)
		stAudioPid[0].usDataPID = (stAudioPid[0].usDataPID & 0xe000) | DB_DVB_INVALID_PID;
		u32PidCodec = MHEG5APP_PID_CODEC(((stAudioPid[0].usDataPID)&0x1fff), stAudioPid[0].usCodec);
		if (g_ePsiFollowSpec != AL_PSIMON_SPECIAL_SPEC_DTG
			|| MHEG5APP_NotifyAVPIDChange(NULL,&u32PidCodec,&usPcrPid) == 0)
#endif
		MID_PlaybackStopAudio();
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_AUDIO_UPDATE, 0);
	}
#ifdef CONFIG_SUPPORT_TTX
	/* 3. teletext */
	if (*pu32DBUpdateFlag & COMP_CHG_TTX_FOUND)
	{
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_TELETECT_UPDATE, 0);
	}
#endif
#ifdef CONFIG_SUPPORT_SUBTITLE
	/* 4. subtitle */
	if (*pu32DBUpdateFlag & COMP_CHG_SUB_FOUND)
	{
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SUBTITLE_UPDATE, 0);
	}
#endif
#ifdef CONFIG_ISDB_SYSTEM
	/* 5. close caption */
	if (*pu32DBUpdateFlag & COMP_CHG_CC_FOUND)
	{
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_CLOSECAPTION_UPDATE, 0);
	}
#endif
}

static al_void _AI_PSI_Monitor_TotCallback(al_void *pData)
{
	if (pData == NULL)
	{
		return;
	}

	MID_SiutilTdtTot_t *pTot = (MID_SiutilTdtTot_t *) pData;
	if (pTot == NULL)
	{
		return;
	}

	al_uint32 u32NewMjd;
	al_uint32 u32OldTimeInSec = 0;
    al_uint32 u32B4OffsetTimeInSec = 0;
	AL_Time_t stTime;
	al_uint32 u32CurTimeInSec = 0;
	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
	al_uint8 u8TimeOffset = 0;
	al_uint8 u8LoopNum = 0;
	al_uint8 *pdescr = pTot->p_descr;
	al_int16 i16DesLen = (INT16)pTot->descLen;
	al_uint16 u16TempLen = 0;
	al_uint8 u8LocalRegionId = 0x3f;
	al_uint8 u8CountryRegionId;
	MID_SiutilTimeDate_t stTimeOfChange;
	al_uint8 u8CountryCode[3];
	al_uint8 u8LocalTimeOffsetPolarity;
	al_uint8 u8LocalTimeOffsetHour;
	al_uint8 u8LocalTimeOffsetMinute;
	al_uint8 u8NextTimeOffsetHour;
	al_uint8 u8NextTimeOffsetMinute;
	al_int32 i32TimeOffset = 0;
	al_int32 i32NextTimeOffset = 0;
	al_int32 i = 0;
	al_int32 j = 0;
	al_uint32 u32MjdOfChange = 0xffffffff;
	al_uint32 u32CurrentSec = 0;
	al_uint32 u32ChangeSec = 0;
	al_bool bTimeChanage = al_false;
	al_bool bHasTimeChange = al_false;
	al_int32 old_gmtoffset = AL_Time_GetGMTOffset();
	bool bForceDST = al_false;
	al_bool bIsAusArea = al_false;
	
	//PSI_MONITOR_DEBUG_MSG("[%s:%d] \n",__FUNCTION__,__LINE__);
	if (AL_Time_GetSyncMode() == AL_TIME_SyncMode_Manual)
	{
		return;
	}

	if (pTot->table_id != TABLE_ID_TOT)
	{
		return;
	}
	/* Check the range of TOT in case of time is out of range */
	if (pTot->asc_time.Year < 2000
		|| pTot->asc_time.Month <1 || pTot->asc_time.Month > 12
		|| pTot->asc_time.Day < 0 || pTot->asc_time.Day > 31
		|| pTot->asc_time.Hour < 0 || pTot->asc_time.Hour > 23
		|| pTot->asc_time.Min < 0 || pTot->asc_time.Min > 59
		|| pTot->asc_time.Second < 0 || pTot->asc_time.Second > 59)
	{
		PSI_MONITOR_ERROR_MSG("TOT time is out of range !!!!!!\n");
		PSI_MONITOR_ERROR_MSG("TOT Year = %d\n", pTot->asc_time.Year);
		PSI_MONITOR_ERROR_MSG("TOT Month = %d\n", pTot->asc_time.Month);
		PSI_MONITOR_ERROR_MSG("TOT Day = %d\n", pTot->asc_time.Day);
		PSI_MONITOR_ERROR_MSG("TOT Hour = %d\n", pTot->asc_time.Hour);
		PSI_MONITOR_ERROR_MSG("TOT Min = %d\n", pTot->asc_time.Min);
		PSI_MONITOR_ERROR_MSG("TOT Second = %d\n", pTot->asc_time.Second);
		return;
	}

	/* 1. time update dispose */
	AL_Time_GetCurTimeInSecs(&u32OldTimeInSec);

	stTime.Year = pTot->asc_time.Year;
	stTime.Month = pTot->asc_time.Month;
	stTime.Day = pTot->asc_time.Day;
	stTime.Hour = pTot->asc_time.Hour;
	stTime.Min = pTot->asc_time.Min;
	stTime.Sec = pTot->asc_time.Second;

	AL_Time_DateToSecs(&stTime, &u32CurTimeInSec);
	u32NewMjd = AL_Time_YmdToMjd(pTot->asc_time.Year, pTot->asc_time.Month, pTot->asc_time.Day);
	AI_Time_UpdateTime(u32NewMjd, pTot->asc_time.Hour,pTot->asc_time.Min, pTot->asc_time.Second);

	/* 2. time offset dispose for DESCR_LOCAL_TIME_OFF */
	AL_FW_GetContextCb(&pfPSIMonGetContext);

	if (pfPSIMonGetContext != al_null)
	{
        AL_FW_GetContextCb(&pfPSIMonGetContext);

		al_bool bForceDST = al_false;
        pfPSIMonGetContext(FW_CONTEXT_TYPE_CHECK_FORCE_DST , FW_CONTEXT_OP_TYPE_READ,
            (al_void *)&bForceDST, 0);
        if(bForceDST)
        {
            AL_Time_SetTimeDST(AL_TIME_DST_ON);

        }
        else
        {
            AL_Time_SetTimeDST(AL_TIME_DST_OFF);
        }

		/* get user setting time offset value */
		pfPSIMonGetContext(FW_CONTEXT_TYPE_TIME_ZONE , FW_CONTEXT_OP_TYPE_READ,
			(al_void *)&u8TimeOffset, 0);

		if (u8TimeOffset != AL_TIME_GMT_OFFSET_AUTO)
		{
			u32CurTimeInSec += AL_Time_GetGMTOffset();
			if (ABSMETHOD(u32CurTimeInSec - u32OldTimeInSec) >= PSIMON_CHANGETIMEINSEC)
			{
				PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_TIME_UPDATE, u32OldTimeInSec);
			}
			//return;
		}

		/* get user setting region id */
		pfPSIMonGetContext(FW_CONTEXT_TYPE_COUNTRY_REGION , FW_CONTEXT_OP_TYPE_READ,
			(al_void *)&u8LocalRegionId, 0);
		pfPSIMonGetContext(FW_CONTEXT_TYPE_CHECK_AUS_AREA , FW_CONTEXT_OP_TYPE_READ,
			(al_void *)&bIsAusArea, 0);
#ifndef CONFIG_AU_FOLLOW_TOT
        if (bIsAusArea == al_true)
        {
            return;
        }
#endif
	}
    AL_Time_GetCurTimeInSecs(&u32B4OffsetTimeInSec);

	while (i16DesLen > 0)
	{
		u16TempLen = (UINT16)pdescr[1];
		if (u16TempLen > i16DesLen)
		{
			break;
		}
		if(pdescr[0] == DESCR_LOCAL_TIME_OFF)
		{
			u8LoopNum = u16TempLen / 13;	// 13 = (24 + 6 + 1 + 1 + 16 + 40 + 16) / 8
			pdescr += 2;
			stTimeOfChange.Hour = 0;
			stTimeOfChange.Min = 0;
			stTimeOfChange.Second = 0;
			bTimeChanage = al_false;
			u32MjdOfChange = 0xffffffff;
			u32CurrentSec = 0;
			u32ChangeSec = 0;

			for (i = (u8LoopNum - 1); i >= 0; i--)
			{
				j = 13 * i;
				u8CountryCode[0] = pdescr[j + 0];
				u8CountryCode[1] = pdescr[j + 1];
				u8CountryCode[2] = pdescr[j + 2];

				if (!_AI_PSI_Monitor_CheckCountry(u8CountryCode))
				{
					continue;
				}

				u8CountryRegionId = pdescr[j + 3] >> 2;
				if((u8CountryRegionId != u8LocalRegionId) && (u8LocalRegionId != 0xff))
				{
					continue;
				}

				bTimeChanage = al_true;
				bHasTimeChange = al_true;

				u8LocalTimeOffsetPolarity = pdescr[j + 3] & 0x01;

				u8LocalTimeOffsetHour = (pdescr[j + 4] >> 4) * 10 + (pdescr[j + 4] & 0x0f);
				u8LocalTimeOffsetMinute = (pdescr[j + 5] >> 4) * 10 + (pdescr[j + 5] & 0x0f);

				u32MjdOfChange = (pdescr[j + 6] << 8) | pdescr[j + 7];
				stTimeOfChange.Hour = (pdescr[j + 8] >> 4) * 10 + (pdescr[j + 8] & 0x0f);
				stTimeOfChange.Min = (pdescr[j + 9] >> 4) * 10 + (pdescr[j + 9] & 0x0f);
				stTimeOfChange.Second = (pdescr[j + 10] >> 4) * 10 + (pdescr[j + 10] & 0x0f);

				u8NextTimeOffsetHour = (pdescr[j + 11] >> 4) * 10 + (pdescr[j + 11] & 0x0f);
				u8NextTimeOffsetMinute = (pdescr[j + 12] >> 4) * 10 + (pdescr[j + 12] & 0x0f);

				i32TimeOffset = 0;
				i32NextTimeOffset = 0;

				i32TimeOffset = u8LocalTimeOffsetHour * 3600 + u8LocalTimeOffsetMinute * 60;
				i32NextTimeOffset = u8NextTimeOffsetHour * 3600 + u8NextTimeOffsetMinute * 60;

				if (u8LocalTimeOffsetPolarity)
				{
					i32TimeOffset = -i32TimeOffset;
					i32NextTimeOffset = -i32NextTimeOffset;
				}
				/*if (i32TimeOffset != i32NextTimeOffset)
				{
					AL_Time_SetTimeDST(AL_TIME_DST_ON);
				}
				else
				{
					AL_Time_SetTimeDST(AL_TIME_DST_OFF);
				}*/
			}

			if (bTimeChanage)
			{
				//PSI_MONITOR_DEBUG_MSG("time channge ##############################\n");
				u32CurrentSec = pTot->asc_time.Hour * 3600 + pTot->asc_time.Min * 60 + pTot->asc_time.Second;
				u32ChangeSec = stTimeOfChange.Hour * 3600 + stTimeOfChange.Min * 60 + stTimeOfChange.Second;
				AI_Time_UpdateNextTime(u32MjdOfChange, stTimeOfChange.Hour,
					stTimeOfChange.Min, stTimeOfChange.Second);
				AI_Time_SetNextTimeOffset(i32NextTimeOffset);

				if ((u32NewMjd > u32MjdOfChange) || ((u32NewMjd == u32MjdOfChange)
					&& (u32CurrentSec >= u32ChangeSec)))
				{
					AL_Time_SetTimeOffset(i32NextTimeOffset);
					AI_Time_SetOldTimeOffset(i32TimeOffset);
				}
				else
				{
					AL_Time_SetTimeOffset(i32TimeOffset);
					AI_Time_SetOldTimeOffset(~0);
				}
				if (i32TimeOffset != 0)
				{
					break;
				}
			}
		}
		else
		{
			pdescr += 2;
		}

		i16DesLen -= (u16TempLen+ 2);
		pdescr += u16TempLen;
	}

	if (!bHasTimeChange)
	{
		AL_Time_Reset();
		if (pfPSIMonGetContext)
		{
			pfPSIMonGetContext(FW_CONTEXT_TYPE_CHECK_FORCE_DST , FW_CONTEXT_OP_TYPE_READ,
				(al_void *)&bForceDST, 0);
		}
		if(bForceDST)
        {
        	AL_Time_SetTimeDST(AL_TIME_DST_ON);
        }
    	else
        {
        	AL_Time_SetTimeDST(AL_TIME_DST_OFF);
        }
		if (g_ePsiUpdateOptions & AL_PSIMONITOR_USER_TOTOFFSET
#ifdef CONFIG_AU_FOLLOW_TOT
			|| (bIsAusArea == al_true)
#endif
		)
		{
			AI_Time_SetForceUpdateOffset(al_false);
		}
    }
	else
	{
		if (g_ePsiUpdateOptions & AL_PSIMONITOR_USER_TOTOFFSET
#ifdef CONFIG_AU_FOLLOW_TOT
			|| (bIsAusArea == al_true)
#endif
		)
		{
			AI_Time_SetForceUpdateOffset(al_true);
		}
	}


	AL_Time_DateToSecs(&stTime, &u32CurTimeInSec);

	u32CurTimeInSec += AL_Time_GetGMTOffset();

	if (ABSMETHOD(u32CurTimeInSec - u32OldTimeInSec) >= PSIMON_CHANGETIMEINSEC)
	{
		if (old_gmtoffset != AL_Time_GetGMTOffset())
		{
			PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_TIME_OFFSET_UPDATE,  u32B4OffsetTimeInSec);
		}
		else
		{
			PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_TIME_UPDATE,  u32OldTimeInSec);
		}
	}
#ifdef CONFIG_SUPPORT_SSU_ENHANCE_UPGRADE
	gfTotHasUpdate = al_true;
#endif

}

static al_void _AI_PSI_Monitor_CatCallback(al_void *pData)
{
	MID_SiutilCatInfo_t *pCat = (MID_SiutilCatInfo_t *) pData;

	if (pCat == NULL)
	{
		return;
	}
	PSI_MONITOR_DEBUG_MSG("[%s:%d] \n",__FUNCTION__,__LINE__);
	//  TODO:

}

static al_void _AI_PSI_Monitor_NitCallback(al_void *pData)
{
	MID_SiutilNitInfo_t *pNit = (MID_SiutilNitInfo_t *) pData;
	al_int i = 0;
	al_uint16	usTsId = 0xffff;
	al_uint16	usOrigNetId = 0xffff;
	AL_RecHandle_t hTp = AL_DB_INVALIDHDL;
	AL_RecHandle_t hCurrProgHdl = AL_DB_INVALIDHDL;
	AL_DB_EDBType_t eDBType = AL_DBTYPE_MAX;
	al_bool bFindNewTSid = al_false;
	PSI_MONITOR_DEBUG_MSG("[%s:%d] \n",__FUNCTION__,__LINE__);


	if (pNit == NULL)
	{
		return;
	}
#ifdef	CONFIG_CIPLUS_SUPPORT
	if (APP_DVB_CI_GetIsPlaybackPMT())
	{
		return;
	}
#endif

	if ((MID_SUCCESS != MID_PlaybackGetCurProgHandle(al_null, &hCurrProgHdl))
		|| (hCurrProgHdl == AL_DB_INVALIDHDL))
	{
		PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
		return;
	}

	if (AL_SUCCESS != AL_DB_GetRecordType(hCurrProgHdl, &eDBType, al_null))
	{
		PSI_MONITOR_ERROR_MSG("Get current active db type error.\n");
		return;
	}

	if ((AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usTsId", (al_void *)&usTsId))
		|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usOrigNetId", (al_void *)&usOrigNetId)))
	{
		PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
		return;
	}

	hTp = hCurrProgHdl;

	if (AL_SUCCESS != AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBMULTIPLEX, &hTp))
	{
		PSI_MONITOR_ERROR_MSG("Get tp handle failed !!!\n");
		return;
	}


#ifdef CONFIG_SUPPORT_OTA_UPGRADE
	_AI_PSI_Monitor_InNitOtaProcess(pData, eDBType, hTp);
#endif

#ifdef SUPPORT_ASTRA_LCN_MONITOR
	AI_AstraLcn_Monitor_InNitAstraLcnDispose(pData);
#endif
#ifdef EPG_REPLACE
	if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG)
	{
		_AI_PSI_Monitor_InNitReplaceDispose(pData, eDBType);
	}
#endif

	/* 0. network name update */
	_AI_PSI_Monitor_InNitUpdateNetworkInfo((al_void *)pNit, eDBType, hTp);

#ifdef SUPPORT_NETWORK_UPDATE_RESCAN
	_AI_PSI_Monitor_InNitCurrNwkTpRescan((al_void *)pNit, eDBType, hTp);
#endif

	/* 1. other tp service add */
	_AI_PSI_Monitor_InNitOtherTpSrvAdd((al_void *)pNit, eDBType, hCurrProgHdl);

	/* 2. Find current transponder */
	for (i = 0; i < pNit->trans_count; i++)
	{
		/* check transponder match with current?*/
		/* if scan not received sdt and nit, the original_network_id is 0, then ts is not change original_network_id, ts: \\Qin-he\share_bin\DVBT0958-128_LONDON_RF562000.ts */
		if (((pNit->p_trans[i].trans_id == usTsId) && (pNit->p_trans[i].original_network_id == usOrigNetId))
			|| ((pNit->p_trans[i].trans_id == usTsId) && (0 == usOrigNetId)))
		{
			g_uOrigNetId = pNit->p_trans[i].original_network_id;
			/* transponder match */
			break;
		}
	}

	if (i >= pNit->trans_count)
	{
		/* Not found the match transponder with current */
		return;
	}

	//thailand evora
	_AI_PSI_Monitor_InNitOtherTpFreqUpdate((al_void *)pNit, eDBType, hTp);

	/* check if there's new TS_id in NIT transport stream loop */
	bFindNewTSid = _AI_PSI_Monitor_InNitCheckTSid((al_void *)pNit,eDBType);

	/* check Freq list whether has changed */
	if (!bFindNewTSid)
	{
		_AI_PSI_Monitor_InNitOtherTpFound((al_void *)pNit, eDBType, i);
	}

	/* 3. Parse FTA data */
	_AI_PSI_Monitor_InNitParseFTAData((al_void *)pNit, i);

	/* 4. check hidden service attribute */
	_AI_PSI_Monitor_InNitCheckHiddenSrv((al_void *)pNit, eDBType, hCurrProgHdl, i);

	/* 5. current tp service list add and remove check */
	_AI_PSI_Monitor_InNitCurrTpSrvCheck((al_void *)pNit, eDBType, i);

	/* 6. handle LCN dynamic update */
	if (eDBType != AL_DBTYPE_DVB_S) //2017/08/16 note: channel star 6B, freq 3710Khz take lcn services
	{
#ifdef SUPPORT_LCN_UPDATE_ON_ALL_MUX
		for (i = 0; i < pNit->trans_count; i++)
		{
			_AI_PSI_Monitor_InNitLCNDynamicUpdate((al_void *)pNit, eDBType, hCurrProgHdl, i);
		}
#else
		_AI_PSI_Monitor_InNitLCNDynamicUpdate((al_void *)pNit, eDBType, hCurrProgHdl, i);
#endif
	}
}

#ifdef CONFIG_SUPPORT_KDG_CERTIFICATION
static al_void _AI_PSI_Monitor_BatCallback(al_void *pData)
{
	AL_RecHandle_t hCurrProgHdl = AL_DB_INVALIDHDL;
	AL_RecHandle_t hTp = AL_DB_INVALIDHDL;
	AL_DB_EDBType_t eDBType = AL_DBTYPE_MAX;
	al_int i = 0;
	al_uint16	usTsId = 0xffff;
	al_uint16	usOrigNetId = 0xffff;

	MID_SiutilBatInfo_t *pBat = (MID_SiutilBatInfo_t *) pData;
	PSI_MONITOR_DEBUG_MSG("[%s:%d] \n",__FUNCTION__,__LINE__);

	if (pBat == NULL)
	{
		return;
	}

	if ((MID_SUCCESS != MID_PlaybackGetCurProgHandle(al_null, &hCurrProgHdl))
		|| (hCurrProgHdl == AL_DB_INVALIDHDL))
	{
		PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
		return;
	}

	if (AL_SUCCESS != AL_DB_GetRecordType(hCurrProgHdl, &eDBType, al_null))
	{
		PSI_MONITOR_ERROR_MSG("Get current active db type error.\n");
		return;
	}

	if ((AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usTsId", (al_void *)&usTsId))
		|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usOrigNetId", (al_void *)&usOrigNetId)))
	{
		PSI_MONITOR_ERROR_MSG("query single service info failed!\n");
		return;
	}

	hTp = hCurrProgHdl;

	if (AL_SUCCESS != AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBMULTIPLEX, &hTp))
	{
		PSI_MONITOR_ERROR_MSG("Get tp handle failed !!!\n");
		return;
	}

	/* 2. Find current transponder */
	for (i = 0; i < pBat->trans_count; i++)
	{
		/* check transponder match with current?*/
		/* if scan not received sdt and nit, the original_network_id is 0, then ts is not change original_network_id, ts: \\Qin-he\share_bin\DVBT0958-128_LONDON_RF562000.ts */
		if (((pBat->p_trans[i].trans_id == usTsId) && (pBat->p_trans[i].original_network_id == usOrigNetId))
			|| ((pBat->p_trans[i].trans_id == usTsId) && (0 == usOrigNetId)))
		{
			/* transponder match */
			break;
		}
	}

	/* 6. handle LCN dynamic update */
	_AI_PSI_Monitor_InBatLCNDynamicUpdate((al_void *)pBat, eDBType, hCurrProgHdl, i);
}
#endif

static al_void _AI_PSI_Monitor_SdtCallback(al_void *pData)
{
	MID_SiutilSdtInfo_t *pSdt = (MID_SiutilSdtInfo_t *) pData;
	MID_SiutilSdtServiceDescr_t *pSdtDescr = al_null;
	al_int iCurrentServiceMatchIndex = -1;
	AL_RecHandle_t hCurrProgHdl = AL_DB_INVALIDHDL;
	AL_RecHandle_t hCurrTpHdl = AL_DB_INVALIDHDL;
	al_int iCount = 0;
	AL_DB_EDBType_t eDBType = AL_DBTYPE_MAX;
	al_uint16	usTsId = 0xffff;
	al_uint16	usTsId_pat = 0xffff;
	al_uint16	usOrigNetId = 0xffff;
	al_uint16	usServiceId = 0xffff;

	PSI_MONITOR_DEBUG_MSG("[%s:%d] \n",__FUNCTION__,__LINE__);

#ifdef	CONFIG_CIPLUS_SUPPORT
	if (APP_DVB_CI_GetIsPlaybackPMT())
	{
		return;
	}
#endif
	if (pSdt == al_null)
	{
		return;
	}

	if ((MID_SUCCESS != MID_PlaybackGetCurProgHandle(al_null, &hCurrProgHdl))
		|| (hCurrProgHdl == AL_DB_INVALIDHDL))
	{
		PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
		return;
	}

	if (AL_SUCCESS != AL_DB_GetRecordType(hCurrProgHdl, &eDBType, al_null))
	{
		PSI_MONITOR_ERROR_MSG("Get current active db type error.\n");
		return;
	}

	if ((AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usTsId", (al_void *)&usTsId))
		|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usTsId_pat", (al_void *)&usTsId_pat))
		|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usOrigNetId", (al_void *)&usOrigNetId))
		|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usServiceId", (al_void *)&usServiceId)))
	{
		PSI_MONITOR_ERROR_MSG("Get service info failed!!!\n");
		return;
	}

	hCurrTpHdl = hCurrProgHdl;
	if ((AL_SUCCESS != AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBMULTIPLEX, &hCurrTpHdl))
		|| (hCurrTpHdl == AL_DB_INVALIDHDL))
	{
		PSI_MONITOR_ERROR_MSG("Get current TP handle failed!!!\n");
		return;
	}

	al_bool bChnlock = al_false;
	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
	AL_FW_GetContextCb(&pfPSIMonGetContext);
	if (pfPSIMonGetContext != al_null)
	{
		pfPSIMonGetContext(FW_CONTEXT_TYPE_GET_CHANNEL_LOCK , FW_CONTEXT_OP_TYPE_READ,
		(al_void *)&bChnlock, 0);
	}
	if(bChnlock)
	{
		PSI_MONITOR_ERROR_MSG("\nNot update channel list.\n");
	}
	else
	{
		g_uOrigNetId = pSdt->original_network_id;
	//for DTMB SYSTEM, only dispose TSID same as PAT
#ifdef CONFIG_DTMB_SYSTEM//add by qinhe for mantis 0047382,  ts : \\10.49.208.200\ts\ÂëÁ÷\058_2011071531.ts
//and mantis 0047669 ts:\\10.49.208.200\ts\8506ÏÖ³¡²âÊÔÂëÁ÷\Î÷°²\xianyang_20180611_103630.ts
		//if (!(pSdt->original_network_id == 0 && pSdt->transport_stream_id == 0))
		PSI_MONITOR_DEBUG_MSG("[%s:%d] transport_stream_id : %d, g_u16TSID: %d, usTsId_pat: %d, g_uOrigNetId: %d\n", \
					 __FUNCTION__,__LINE__,pSdt->transport_stream_id, g_u16TSID, usTsId_pat, g_uOrigNetId);
		if (!((g_u16TSID != INVALID_TSID && pSdt->transport_stream_id != g_u16TSID) || (g_u16TSID == INVALID_TSID && pSdt->transport_stream_id != usTsId_pat)))
#endif
		{
			g_u16TSID = pSdt->transport_stream_id;
#ifdef SUPPORT_CHANGE_TS_DYNAMICALLY
			/* if scan not received sdt and nit, the original_network_id is 0, then ts is not change original_network_id, ts: \\Qin-he\share_bin\DVBT0958-128_LONDON_RF562000.ts */
			if (((usOrigNetId != INVALID_ORGNETID) && (pSdt->original_network_id != usOrigNetId || pSdt->transport_stream_id != usTsId))
				|| ((usOrigNetId == INVALID_ORGNETID) && (pSdt->transport_stream_id != usTsId))
				|| ((usOrigNetId == INVALID_ORGNETID) && (pSdt->original_network_id != INVALID_ORGNETID)))
			{
				AI_PSI_Monitor_TimerEventClear((1<<AI_PSIMONITOR_TIMER_SERVICE_UPDATE));
				PSI_MONITOR_DEBUG_MSG("[%s:%d] original_network_id : %d, %d, transport_stream_id : %d, %d\n", \
					 __FUNCTION__,__LINE__,pSdt->original_network_id,usOrigNetId, pSdt->transport_stream_id, usTsId);
	
				UINT32 Param;
				Param = (pSdt->transport_stream_id << 16) | pSdt->original_network_id;
				PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_TS_CHANGED, Param);
				return;
			}
#endif
		}
	}

	
	AI_PSI_Monitor_TimerEventClear((1<<AI_PSIMONITOR_TIMER_SERVICE_UPDATE));

	/* 1. service list dispose */
	_AI_PSI_Monitor_InSdtSrvListDispose((al_void *)pSdt, eDBType, hCurrTpHdl);

	/* 2. Replace service back to original service */
	_AI_PSI_Monitor_InSdtReplaceDispose(al_true, (al_void *)pSdt, eDBType, -1);

	/* 3. check service info match with current */
	for (iCount = 0; iCount < pSdt->services_count; iCount++)
	{
		pSdtDescr = &pSdt->p_sdt_descr_t[iCount];

		if ((pSdt->original_network_id == usOrigNetId)
			&& (pSdt->transport_stream_id == usTsId)
			&& (HILO(pSdtDescr->sdt_service.service_id) == usServiceId))
		{
			iCurrentServiceMatchIndex = iCount;
			break;
		}
	}

	if (iCurrentServiceMatchIndex < 0)
	{
		/* Not found the match service with current.*/
		return;
	}

	/* 4. Current service not running/scramble dispose */
	_AI_PSI_Monitor_InSdtReplaceDispose(al_false, (al_void *)pSdt, eDBType, iCurrentServiceMatchIndex);

	/* 5. FTA data parse */
	_AI_PSI_Monitor_InSdtParseFTAData((al_void *)pSdt, iCurrentServiceMatchIndex);

	/* 6. CIPLUS dispose */
#ifdef CONFIG_CIPLUS_SUPPORT
	_AI_PSI_Monitor_InSdtCIPlusDispose((al_void *)pSdt, eDBType, hCurrProgHdl);
#endif

	return;
}

static al_void _AI_PSI_Monitor_SdtOtherCallback(al_void *pData)
{
	MID_SiutilSdtInfo_t *pSdt = (MID_SiutilSdtInfo_t *) pData;
	MID_SiutilSdtServiceDescr_t *pSdtDescr = al_null;
	AL_DB_EDBType_t eDBType = AL_DBTYPE_MAX;
	AL_RecHandle_t hCurrProgHdl = AL_DB_INVALIDHDL;
	DBServAttrib_t 	stProgAttrib;
	al_uint16	usTsId = 0xffff;
	al_uint16	usOrigNetId = 0xffff;
	al_uint16	usServiceId = 0xffff;
	al_bool bScramble = al_false;
	al_int iCount = 0;
	al_uint16 u16SerType = SERVICE_DIGITAL_TELEVISION;

	if (pSdt == al_null)
	{
		return;
	}

#ifdef	CONFIG_CIPLUS_SUPPORT
	if (APP_DVB_CI_GetIsPlaybackPMT())
	{
		return;
	}
#endif

	if ((MID_SUCCESS != MID_PlaybackGetCurProgHandle(al_null, &hCurrProgHdl))
		|| (hCurrProgHdl == AL_DB_INVALIDHDL))
	{
		PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
		return;
	}

	if (AL_SUCCESS != AL_DB_GetRecordType(hCurrProgHdl, &eDBType, al_null))
	{
		PSI_MONITOR_ERROR_MSG("Get current active db type error.\n");
		return;
	}

	/* 1. Other TP service dispose */
	if (g_ePsiUpdateOptions & AL_PSIMONITOR_OTHTP_SR_ADD)
	{
		AL_DB_ERecordType_t eSrvType = AL_RECTYPE_DVBTV;

		if (g_bOtherSDTNeedToDecode && (pSdt->transport_stream_id > 0))
		{
			dvbpsi_service_dr_t *pServiceDr = al_null;

			/* to escape from loss of any SDT OTHER */
			for (iCount = 0; iCount < PSIMON_SIZE_OF_TMP_TP_LIST; iCount++)
			{
				if (pSdt->transport_stream_id == (al_uint16)g_u32TpListCnt[iCount])
				{
					/* the high 16bits is used to count how many of time the TP srv list is found. */
					g_u32TpListCnt[iCount] += 1<<16;

					break;
				}
			}

			if (iCount == PSIMON_SIZE_OF_TMP_TP_LIST)
			{
				for (iCount = 0; iCount < PSIMON_SIZE_OF_TMP_TP_LIST; iCount++)
				{
					if (g_u32TpListCnt[iCount] == 0)
					{
						g_u32TpListCnt[iCount] = (al_uint32)pSdt->transport_stream_id;
						g_u32TpListCnt[iCount] += 1<<16;
						break;
					}
				}

				for (iCount = 0; iCount < pSdt->services_count; iCount++)
				{
					pSdtDescr = &pSdt->p_sdt_descr_t[iCount];
					pServiceDr = dvbpsi_DecodeServiceDr(pSdtDescr->p_descr,pSdtDescr->descLen);

					if (pServiceDr)
					{
						if (g_pfPsiMonCheckSrvType != al_null)
						{
							u16SerType = SERVICE_DIGITAL_TELEVISION;
							/*if (g_u8VideoPidCount != 0 && g_u8VideoPidCount != 0xff)
							{
								u16SerType = SERVICE_DIGITAL_TELEVISION;
							}
							else if (g_u8AudioPidCount != 0 && g_u8AudioPidCount != 0xff)
							{
								u16SerType = SERVICE_DIGITAL_RADIO;
							}
							else
							{
								u16SerType = SERVICE_DATABROADCAST;
							}*/

							g_pfPsiMonCheckSrvType(pServiceDr->i_service_type, u16SerType,0xff, 0xff, &eSrvType);
                        			}
					}
					else
					{
						continue;
					}

					AL_PSIMon_SimpleSrv_t *psrvslot =
						_AI_PSI_Monitor_OtherTpGetAFreeSrvSlot(AL_PSIMONITOR_OTHERTP_SRVLIST_SDT);
					psrvslot->usServiceId = HILO(pSdtDescr->sdt_service.service_id);
					psrvslot->usTsId = pSdt->transport_stream_id;
					psrvslot->ucServiceType = eSrvType;
					psrvslot->u8SDTSrvType = pServiceDr->i_service_type;
					memcpy(psrvslot->pucname,pServiceDr->service_name,min(
						pServiceDr->i_service_name_length,DB_DVB_MAX_CHNAME_LEN-1));

					SAFE_FREE(pServiceDr);
					pServiceDr = al_null;
				}
			}

			/* check if each tp list has received twice, this is for error handle. */
			/* when system is busy, the table may receive discountine. */
			for (iCount = 0; iCount < PSIMON_SIZE_OF_TMP_TP_LIST; iCount++)
			{
				if (g_u32TpListCnt[iCount] > 0 && (g_u32TpListCnt[iCount]>>16) < 2)
				{
					break;
				}
			}

			if (iCount == PSIMON_SIZE_OF_TMP_TP_LIST)
			{
				g_bOtherSDTNeedToDecode = al_false;
				if (_AI_PSI_Monitor_OtherTpServiceFound())
				{
					PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_OTHERTP_SRV_FOUND, 0);
				}
			}
		}
	}

	/* 2. current program dispose */
	AL_RecHandle_t hReplacedProgHdl = AL_DB_INVALIDHDL;

	if ((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED, &hReplacedProgHdl) == al_true
		|| AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED, &hReplacedProgHdl) == al_true)
		&& (hReplacedProgHdl != AL_DB_INVALIDHDL))
	{
		memset(&stProgAttrib, 0, sizeof(DBServAttrib_t));

		if ((AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usTsId", (al_void *)&usTsId))
			|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usOrigNetId", (al_void *)&usOrigNetId))
			|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usServiceId", (al_void *)&usServiceId))
			|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stProgAttrib)))
		{
			bScramble = stProgAttrib.scramble;

			/* Check if it is current program */
			if ((pSdt->original_network_id == usOrigNetId) || (pSdt->transport_stream_id == usTsId))
			{
				for (iCount = 0; iCount < pSdt->services_count; iCount++)
				{
					pSdtDescr = &pSdt->p_sdt_descr_t[iCount];

					if (HILO(pSdtDescr->sdt_service.service_id) == usServiceId)
					{
						/* Scramble -> Free */
						if (pSdtDescr->sdt_service.free_ca_mode == al_false
							&& bScramble == al_true)
						{
							AI_PSI_Monitor_ReplaceProcess(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED);
						}

						/*Not Running -> Running*/
						if(pSdtDescr->sdt_service.running_status == RS_RUNNING)
						{
							AI_PSI_Monitor_ReplaceProcess(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED);
						}
					}
				}
			}
		}
		else
		{
			PSI_MONITOR_ERROR_MSG("Get service info failed!!!\n");
		}
	}

	_AI_PSI_Monitor_InSdtOtherSrvListDispose(pData, eDBType);
}


static al_void _AI_PSI_Monitor_PatCallback(al_void *pData)
{
	MID_SiutilPatInfo_t *pPat = (MID_SiutilPatInfo_t *) pData;
	al_bool bLoseCurPmt = al_true;
	DBServAttrib_t 	stProgAttrib;
	al_uint16	usTsId = 0xffff;
	al_uint16	usOrigNetId = 0xffff;
	al_uint16	usServiceId = 0xffff;
	AL_DB_EDBType_t eDBType = AL_DBTYPE_MAX;
	AL_RecHandle_t hCurrProgHdl = AL_DB_INVALIDHDL;
	AL_DB_ERecordType_t	eServiceType = AL_RECTYPE_MAX;
	AL_PSIMon_SimpleSrv_t stProg;
	al_int iCount = 0;
    frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
    al_bool bChnlock = al_false;
	al_uint16 pmt_pid = 0;
	al_uint16 usPMTPid = 0;
#ifdef CONFIG_SUPPORT_INDONESIA_EWS
	al_bool bEwsPmtFound = al_false;
#endif
	memset(&stProgAttrib, 0, sizeof(DBServAttrib_t));
	memset(&stProg, 0, sizeof(AL_PSIMon_SimpleSrv_t));

	PSI_MONITOR_DEBUG_MSG("[%s:%d] \n",__FUNCTION__,__LINE__);

	if (pPat == NULL)
	{
		return;
	}

#if defined(CONFIG_SUPPORT_EWS) || defined(SUPPORT_ASTRA_LCN_MONITOR) || defined(CONFIG_SUPPORT_INDONESIA_EWS)
	MID_PmtOtherAddPmt(pPat);
#else
	if (g_ePsiUpdateOptions & AL_PSIMONITOR_CURTP_SRVADDCHECKPMT)
	{
		MID_PmtOtherAddPmt(pPat);
	}
#endif

#ifdef	CONFIG_CIPLUS_SUPPORT
	if (APP_DVB_CI_GetIsPlaybackPMT())
	{
		return;
	}
#endif
	AL_FW_GetContextCb(&pfPSIMonGetContext);
	if (pfPSIMonGetContext != al_null)
	{
		pfPSIMonGetContext(FW_CONTEXT_TYPE_GET_CHANNEL_LOCK , FW_CONTEXT_OP_TYPE_READ,
		(al_void *)&bChnlock, 0);
	}

	if(bChnlock)
	{
		PSI_MONITOR_ERROR_MSG("Not update channel list.\n");
		return;
	}

	if ((MID_SUCCESS != MID_PlaybackGetCurProgHandle(&eServiceType, &hCurrProgHdl))
			|| (hCurrProgHdl == AL_DB_INVALIDHDL))
	{
		PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
		return;
	}

	if (AL_SUCCESS != AL_DB_GetRecordType(hCurrProgHdl, &eDBType, al_null))
	{
		PSI_MONITOR_ERROR_MSG("Get current active db type error.\n");
		return;
	}

	if ((AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usTsId_pat", (al_void *)&usTsId))
		|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usOrigNetId", (al_void *)&usOrigNetId))
		|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usServiceId", (al_void *)&usServiceId))
		|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stProgAttrib)))
	{
		PSI_MONITOR_ERROR_MSG("Query Single Prog Info failed!\n");
		return;
	}

	if (g_u16TSID == INVALID_TSID)//if not received SDT to need set timer
	{
		if (usTsId != pPat->transport_stream_id)
		{
			PSI_MONITOR_DEBUG_MSG("[%s:%d] transport_stream_id : %d, %d\n", \
				__FUNCTION__,__LINE__,pPat->transport_stream_id, usTsId);
			UINT32 Param;
			Param = (pPat->transport_stream_id << 16) | 0;
			PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_TS_CHANGED, Param);
		}
		else
		{
			g_u16TSID = pPat->transport_stream_id;
			_AI_PSI_Monitor_TimerEventChange(AI_PSIMONITOR_TIMER_SERVICE_UPDATE, al_true);
		}
	}
	else
	{
		g_u16TSID = pPat->transport_stream_id;
	}

	/* 1.service list dispose, service add and remove */
	for (iCount = 0; iCount < pPat->maps_count; iCount++)
	{
		if (pPat->pat_maps[iCount].program_number == 0)
		{
			/* network_PID */
			continue;
		}

		if (pPat->pat_maps[iCount].program_number == usServiceId)
		{
			pmt_pid = pPat->pat_maps[iCount].pid;
			bLoseCurPmt = al_false;
		}
#ifdef CONFIG_SUPPORT_INDONESIA_EWS
		if (pPat->pat_maps[iCount].pid == 0x038f)
		{
			bEwsPmtFound = al_true;
		}
#endif
		if (g_ePsiUpdateOptions
			& (AL_PSIMONITOR_CURTP_SRVADD | AL_PSIMONITOR_CURTP_SRVADD2 | AL_PSIMONITOR_CURTP_SRV_REMOVE))
		{
			stProg.usOrgNetId = usOrigNetId;
			stProg.usServiceId = pPat->pat_maps[iCount].program_number;
			stProg.usPMTPid = pPat->pat_maps[iCount].pid;
			stProg.usTsId = pPat->transport_stream_id;
			stProg.usProgNum = 0;
			_AI_PSI_Monitor_CurTPServicesStack(TABLE_ID_PAT,pPat->version_number,stProg);
		}
	}
#ifdef CONFIG_SUPPORT_INDONESIA_EWS
	if (bEwsPmtFound || (g_ePsiUpdateOptions & AL_PSIMONITOR_CURTP_SRVADDCHECKPMT))
	{
		_AI_PSI_Monitor_OtherPmtMon_Start();
	}
#else
	if (g_ePsiUpdateOptions & AL_PSIMONITOR_CURTP_SRVADDCHECKPMT)
	{
		_AI_PSI_Monitor_OtherPmtMon_Start();
	}
#endif
#ifdef CONFIG_SUPPORT_OTA_UPGRADE
	_AI_PSI_Monitor_InPatOtaProcess(pPat);
#endif

	/* 2. check state, lose pmt need to clean pid of audio and video */
	if (bLoseCurPmt)
	{
#if 0/* modify by qinhe  for mantis 29008 */
		MID_PlaybackStopVideo(TRUE);
		MID_PlaybackStopAudio();

		/* when PMT not found in PAT case */
		g_u16MinAudioPid = DB_DVB_INVALID_PID;
		g_u8VideoPidCount = 0xff;
		g_u8AudioPidCount= 0xff;

		if (0 == stProgAttrib.svrnotrun)
		{
			stProgAttrib.svrnotrun = 1;
			if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (al_uint8*)"stProgAttrib", &stProgAttrib))
			{
				PSI_MONITOR_ERROR_MSG("update stProgAttrib failed !!!\n");
			}
         }
#endif
	}
	else
	{
		AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usPMTPid", (al_void *)&usPMTPid);

		if ((pmt_pid != 0) && (pmt_pid != usPMTPid))
		{
#if 0		/* move to open new pmt demux channel update*/
			if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (al_uint8*)"usPMTPid", &pmt_pid))
			{
				PSI_MONITOR_ERROR_MSG("update stProgAttrib failed !!!\n");
			}
#endif
		}

		if((1 == stProgAttrib.svrnotrun) && (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED, al_null) == al_false))
		{
			stProgAttrib.svrnotrun = 0;
			if (AL_SUCCESS != AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (al_uint8*)"stProgAttrib", &stProgAttrib))
			{
				PSI_MONITOR_ERROR_MSG("update stProgAttrib failed !!!\n");
			}

			if (eServiceType == AL_RECTYPE_DVBRADIO)
			{
				if (MID_PlaybackGetActiveAudHandle(al_false) == INVALID_HANDLE)
				{
					MID_PlaybackStartAVOnly();
				}
			}
			else if (eServiceType == AL_RECTYPE_DVBTV)
			{
				if ((MID_PlaybackGetActiveVidHandle() == INVALID_HANDLE) || (MID_PlaybackGetActiveAudHandle(al_false) == INVALID_HANDLE))
				{
					MID_PlaybackStartAVOnly();
                    PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_PMT_UPDATE, 0);
				}
			}
		}
	}
}
#ifdef CONFIG_SUPPORT_INDONESIA_EWS

static al_void _AI_PSI_Monitor_FreeEwsTrdwList(AL_PsiMon_EwsList_t * list)
{
	int i, j;
	if(list && list->trdwEntries)
	{
		for(i = 0; i < list->u8NumTrdwEntries; ++i)
		{
			for(j = 0; j < list->trdwEntries[i].u8NumLocations; ++j)
			{
				SAFE_FREE(list->trdwEntries[i].locations[j].location_name);
			}
			SAFE_FREE(list->trdwEntries[i].locations);
		}
		free(list->trdwEntries);
		list->trdwEntries = 0;
		list->u8NumTrdwEntries = 0;
		list->u32TrdwCrc32 = 0;
	}
}

static al_void _AI_PSI_Monitor_FreeEwsTcdwList(AL_PsiMon_EwsList_t * list)
{
	int i;
	if(list && list->tcdwEntries)
	{
		for(i = 0; i < list->u8NumTcdwEntries; ++i)
		{
			SAFE_FREE(list->tcdwEntries[i].disaster_name);
			SAFE_FREE(list->tcdwEntries[i].disaster_position);
			SAFE_FREE(list->tcdwEntries[i].disaster_date);
			SAFE_FREE(list->tcdwEntries[i].disaster_characteristic);
		}
		free(list->tcdwEntries);
		list->tcdwEntries = 0;
		list->u8NumTcdwEntries = 0;
		list->u32TcdwCrc32 = 0;
	}
}

static al_void _AI_PSI_Monitor_FreeEwsTmdwList(AL_PsiMon_EwsList_t * list)
{
	int i, j;
	if(list && list->tmdwEntries)
	{
		for(i = 0; i < list->u8NumTmdwEntries; ++i)
		{
			for(j = 0; j < list->tmdwEntries[i].u8NumMessages; ++j)
			{
				SAFE_FREE(list->tmdwEntries[i].messages[j]);
			}
			SAFE_FREE(list->tmdwEntries[i].messages);
		}
		free(list->tmdwEntries);
		list->tmdwEntries = 0;
		list->u8NumTmdwEntries = 0;
		list->u32TmdwCrc32 = 0;
	}
}

static al_void _AI_PSI_Monitor_FreeEwsList(AL_PsiMon_EwsList_t * list)
{
	_AI_PSI_Monitor_FreeEwsTrdwList(list);
	_AI_PSI_Monitor_FreeEwsTcdwList(list);
	_AI_PSI_Monitor_FreeEwsTmdwList(list);
}

static SI_STRING_DESC* _AI_PSI_Monitor_DupString(SI_STRING_DESC *src)
{
	SI_STRING_DESC* dst = NULL;

	if(src && src->str_ptr)
	{
		dst = (SI_STRING_DESC*) zero_malloc(sizeof(SI_STRING_DESC) + src->nbytes);
		if(dst != NULL)
		{
			dst->nbytes = src->nbytes;
			dst->str_ptr = ((UINT8*)dst) + sizeof(SI_STRING_DESC);
			memcpy(dst->str_ptr, src->str_ptr, src->nbytes);
		}
	}

	return(dst);
}

static al_void _AI_PSI_Monitor_TxDWCallback(al_void *pData)
{
	MID_SiutilTxdwInfo_t *pTxdw = (MID_SiutilTxdwInfo_t *) pData;
	int i, j;

	if (pTxdw == NULL)
	{
		return;
	}

	if(pTxdw->table_type == SI_EWS_TABLE_TRDW && pTxdw->crc32 != g_ewsList.u32TrdwCrc32)
	{
		_AI_PSI_Monitor_FreeEwsTrdwList(&g_ewsList);

		g_ewsList.u8NumTrdwEntries = pTxdw->num_entries;
		g_ewsList.u32TrdwCrc32 = pTxdw->crc32;
		g_ewsList.trdwEntries = (AL_PsiMon_EwsTrdwInfo_t*) zero_malloc(sizeof(AL_PsiMon_EwsTrdwInfo_t) * g_ewsList.u8NumTrdwEntries);

		for(i = 0; i < g_ewsList.u8NumTrdwEntries; ++i)
		{
			g_ewsList.trdwEntries[i].usDisaster = pTxdw->trdw_entry[i].disaster_code;
			g_ewsList.trdwEntries[i].usLocationType = pTxdw->trdw_entry[i].location_type_code;
			g_ewsList.trdwEntries[i].u8PackageId = pTxdw->trdw_entry[i].package_id;
			g_ewsList.trdwEntries[i].u8NumLocations = pTxdw->trdw_entry[i].number_locations;
			if(g_ewsList.trdwEntries[i].u8NumLocations)
				g_ewsList.trdwEntries[i].locations = (SI_EWS_TRDW_LOCATION*) zero_malloc(sizeof(SI_EWS_TRDW_LOCATION) * g_ewsList.trdwEntries[i].u8NumLocations);
			for(j = 0; j < g_ewsList.trdwEntries[i].u8NumLocations; ++j)
			{
				g_ewsList.trdwEntries[i].locations[j].location_code = pTxdw->trdw_entry[i].locations[j].location_code;
				g_ewsList.trdwEntries[i].locations[j].location_name = _AI_PSI_Monitor_DupString(pTxdw->trdw_entry[i].locations[j].location_name);
			}
		}
	}
	else if(pTxdw->table_type == SI_EWS_TABLE_TCDW && pTxdw->crc32 != g_ewsList.u32TcdwCrc32)
	{
		_AI_PSI_Monitor_FreeEwsTcdwList(&g_ewsList);

		g_ewsList.u8NumTcdwEntries = pTxdw->num_entries;
		g_ewsList.u32TcdwCrc32 = pTxdw->crc32;
		g_ewsList.tcdwEntries = (AL_PsiMon_EwsTcdwInfo_t*) zero_malloc(sizeof(AL_PsiMon_EwsTcdwInfo_t) * g_ewsList.u8NumTcdwEntries);

		for(i = 0; i < g_ewsList.u8NumTcdwEntries; ++i)
		{
			g_ewsList.tcdwEntries[i].u8PackageId = pTxdw->tcdw_entry[i].package_id;
			g_ewsList.tcdwEntries[i].u8Authority = pTxdw->tcdw_entry[i].authority;
			g_ewsList.tcdwEntries[i].usDisaster = pTxdw->tcdw_entry[i].disaster_code;
			g_ewsList.tcdwEntries[i].disaster_name = _AI_PSI_Monitor_DupString(pTxdw->tcdw_entry[i].disaster_name);
			g_ewsList.tcdwEntries[i].disaster_position = _AI_PSI_Monitor_DupString(pTxdw->tcdw_entry[i].disaster_position);
			g_ewsList.tcdwEntries[i].disaster_date = _AI_PSI_Monitor_DupString(pTxdw->tcdw_entry[i].disaster_date);
			g_ewsList.tcdwEntries[i].disaster_characteristic = _AI_PSI_Monitor_DupString(pTxdw->tcdw_entry[i].disaster_characteristic);
		}
	}
	else if(pTxdw->table_type == SI_EWS_TABLE_TMDW && pTxdw->crc32 != g_ewsList.u32TmdwCrc32)
	{
		_AI_PSI_Monitor_FreeEwsTmdwList(&g_ewsList);

		g_ewsList.u8NumTmdwEntries = pTxdw->num_entries;
		g_ewsList.u32TmdwCrc32 = pTxdw->crc32;
		g_ewsList.tmdwEntries = (AL_PsiMon_EwsTmdwInfo_t*) zero_malloc(sizeof(AL_PsiMon_EwsTmdwInfo_t) * g_ewsList.u8NumTmdwEntries);

		for(i = 0; i < g_ewsList.u8NumTmdwEntries; ++i)
		{
			g_ewsList.tmdwEntries[i].usLocationType = pTxdw->tmdw_entry[i].location_type_code;
			g_ewsList.tmdwEntries[i].u8PackageId = pTxdw->tmdw_entry[i].package_id;
			g_ewsList.tmdwEntries[i].u8NumMessages = pTxdw->tmdw_entry[i].num_messages;
			if(g_ewsList.tmdwEntries[i].u8NumMessages)
				g_ewsList.tmdwEntries[i].messages = (SI_STRING_DESC**) zero_malloc(sizeof(SI_STRING_DESC*) * g_ewsList.tmdwEntries[i].u8NumMessages);
			for(j = 0; j < g_ewsList.tmdwEntries[i].u8NumMessages; ++j)
			{
				g_ewsList.tmdwEntries[i].messages[j] = _AI_PSI_Monitor_DupString(pTxdw->tmdw_entry[i].messages[j]);
			}
		}
	}
	else
	{
		//PSI_MONITOR_DEBUG_MSG("TxDW already received - table_type %d, CRC32 0x%x\n", pTxdw->table_type, pTxdw->crc32);
		// Received TxDW tables, so we reset the EWS timer
		g_u32PsiTimer[AI_PSIMONITOR_TIMER_INDONESIA_EWS_STOP] = 0;
		return;
	}

	// Received TxDW tables, so we reset the EWS timer
	g_u32PsiTimer[AI_PSIMONITOR_TIMER_INDONESIA_EWS_STOP] = 0;

	/* Check if all 3 tables have been collected */
	if(g_ewsList.trdwEntries && g_ewsList.tcdwEntries && g_ewsList.tmdwEntries)
	{
#if 0 //AL_PSI_MONITOR_DEBUG_FLAG
		UMFDBG(0, "%s: %d: ALL tables collected!!!\n", __func__, __LINE__);
		for(i = 0; i < g_ewsList.u8NumTrdwEntries; ++i)
		{
			UMFDBG(0, "TRDW   disaster %u, location type %u, package %u, \n", g_ewsList.trdwEntries[i].usDisaster, g_ewsList.trdwEntries[i].usLocationType, g_ewsList.trdwEntries[i].u8PackageId);
			for(j = 0; j < g_ewsList.trdwEntries[i].u8NumLocations; ++j)
			{
				UMFDBG(0, "      location 0x%x, name {%.*s}\n", g_ewsList.trdwEntries[i].locations[j].location_code,
					g_ewsList.trdwEntries[i].locations[j].location_name->nbytes, g_ewsList.trdwEntries[i].locations[j].location_name->str_ptr);
			}
		}

		for(i = 0; i < g_ewsList.u8NumTcdwEntries; ++i)
		{
			UMFDBG(0, "TCDW package %u, disaster %u, name {%.*s}\n", g_ewsList.tcdwEntries[i].u8PackageId, g_ewsList.tcdwEntries[i].usDisaster,
				g_ewsList.tcdwEntries[i].disaster_name->nbytes, g_ewsList.tcdwEntries[i].disaster_name->str_ptr);

		}

		for(i = 0; i < g_ewsList.u8NumTmdwEntries; ++i)
		{
			UMFDBG(0, "TMDW package %u, location %u, numMsg %u, msg[0]={%.*s}\n", g_ewsList.tmdwEntries[i].u8PackageId, g_ewsList.tmdwEntries[i].usLocationType, g_ewsList.tmdwEntries[i].u8NumMessages,
				g_ewsList.tmdwEntries[i].messages[0]->nbytes, g_ewsList.tmdwEntries[i].messages[0]->str_ptr);
		}
#endif
		if( g_ewsList.u32TrdwCrc32==0 || g_ewsList.u32TcdwCrc32==0 || g_ewsList.u32TmdwCrc32==0 )
			return;
		g_bIsEwsActive = 1;
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_INDONESIA_EWS_UPDATE, 0);
		_AI_PSI_Monitor_TimerEventChange(AI_PSIMONITOR_TIMER_INDONESIA_EWS_STOP, al_true);
	}

}

static void ews_ConvertLocationCodeToAreaCode(al_uint32 location_code, al_uint32* max_code, al_uint32* min_code)
{
	al_int8 i;
	al_uint8 c;

	location_code >>= 4;

	for (i=4; i>=0; i--)
	{
		*(max_code) *= 10;
		*(min_code) *= 10;

		c = (location_code >> (i*4))&0xf;

		if (c == 0xf)
		{
			*(max_code) += 9;
			*(min_code) += 0;
		}
		else
		{
			*(max_code) += c;
			*(min_code) += c;
		}
	}
}

static al_bool _AI_PSI_Monitor_MatchEwsAreaCode(al_uint32 location_code, al_uint32 area_code)
{
	al_uint32 max_code = 0;
	al_uint32 min_code = 0;
	printf("[%s,%d]:location_code = %d\n",__FUNCTION__,__LINE__,location_code);
	ews_ConvertLocationCodeToAreaCode(location_code, &max_code, &min_code);

	return (max_code >= area_code && area_code >= min_code);
}

AL_Return_t AL_PSI_Monitor_GetEwsDetail(al_uint32 u32AreaCode, AL_PsiMon_EwsDetail_t *ewsDetail)
{
	if(!ewsDetail)
	{
		return AL_FAILURE;
	}
	al_uint8 i, j, k;
	al_bool is_tcdw_found = al_false;
	al_bool is_tmdw_found = al_false;
	
	for(i = 0; i < g_ewsList.u8NumTrdwEntries; ++i)
	{
		for(j = 0; j < g_ewsList.trdwEntries[i].u8NumLocations; ++j)
		{
			if(_AI_PSI_Monitor_MatchEwsAreaCode(g_ewsList.trdwEntries[i].locations[j].location_code, u32AreaCode))
			{
				if(g_ewsList.trdwEntries[i].u8PackageId == 0xff)
				{
					/* end the display of EWS */
					PSI_MONITOR_DEBUG_MSG("end the display of EWS for location_code %x\n", g_ewsList.trdwEntries[i].locations[j].location_code);
					return AL_FAILURE;
				}
				memset(ewsDetail, 0, sizeof(AL_PsiMon_EwsDetail_t));

				/* fill in ewsDetail with data from TRDW */
				ewsDetail->usDisaster = g_ewsList.trdwEntries[i].usDisaster;
				ewsDetail->usLocationType = g_ewsList.trdwEntries[i].usLocationType;
				ewsDetail->u8PackageId = g_ewsList.trdwEntries[i].u8PackageId;
				if (PSIMON_MAX_EWSDETAIL_LEN >= g_ewsList.trdwEntries[i].locations[j].location_name->nbytes)
				{
					memcpy(ewsDetail->location_name, g_ewsList.trdwEntries[i].locations[j].location_name->str_ptr, g_ewsList.trdwEntries[i].locations[j].location_name->nbytes);
				}
				else
				{
					memcpy(ewsDetail->location_name, g_ewsList.trdwEntries[i].locations[j].location_name->str_ptr, PSIMON_MAX_EWSDETAIL_LEN);
				}
				/* look for matching TCDW entry and fill in ewsDetail */
				for(k = 0; k < g_ewsList.u8NumTcdwEntries; ++k)
				{
					if(g_ewsList.tcdwEntries[k].u8PackageId == ewsDetail->u8PackageId && 
						g_ewsList.tcdwEntries[k].usDisaster == ewsDetail->usDisaster)
					{
						is_tcdw_found = al_true;
						ewsDetail->u8Authority = g_ewsList.tcdwEntries[k].u8Authority;
						if (PSIMON_MAX_EWSDETAIL_LEN >= g_ewsList.tcdwEntries[k].disaster_name->nbytes)
						{
							memcpy(ewsDetail->disaster_name, g_ewsList.tcdwEntries[k].disaster_name->str_ptr, g_ewsList.tcdwEntries[k].disaster_name->nbytes);
						}
						else
						{
							memcpy(ewsDetail->disaster_name, g_ewsList.tcdwEntries[k].disaster_name->str_ptr, PSIMON_MAX_EWSDETAIL_LEN);
						}
						if (PSIMON_MAX_EWSDETAIL_LEN >= g_ewsList.tcdwEntries[k].disaster_position->nbytes)
						{
							memcpy(ewsDetail->disaster_position, g_ewsList.tcdwEntries[k].disaster_position->str_ptr, g_ewsList.tcdwEntries[k].disaster_position->nbytes);
						}
						else
						{
							memcpy(ewsDetail->disaster_position, g_ewsList.tcdwEntries[k].disaster_position->str_ptr, PSIMON_MAX_EWSDETAIL_LEN);
						}
						if (PSIMON_MAX_EWSDETAIL_LEN >= g_ewsList.tcdwEntries[k].disaster_date->nbytes)
						{
							memcpy(ewsDetail->disaster_date, g_ewsList.tcdwEntries[k].disaster_date->str_ptr, g_ewsList.tcdwEntries[k].disaster_date->nbytes);
						}
						else
						{
							memcpy(ewsDetail->disaster_date, g_ewsList.tcdwEntries[k].disaster_date->str_ptr, PSIMON_MAX_EWSDETAIL_LEN);
						}
						if (PSIMON_MAX_EWSDETAIL_LEN >= g_ewsList.tcdwEntries[k].disaster_characteristic->nbytes)
						{
							memcpy(ewsDetail->disaster_characteristic, g_ewsList.tcdwEntries[k].disaster_characteristic->str_ptr, g_ewsList.tcdwEntries[k].disaster_characteristic->nbytes);
						}
						else
						{
							memcpy(ewsDetail->disaster_characteristic, g_ewsList.tcdwEntries[k].disaster_characteristic->str_ptr, PSIMON_MAX_EWSDETAIL_LEN);
						}
						break;
					}
				}
				
				/* look for matching TMDW entry and fill in ewsDetail */
				for(k = 0; k < g_ewsList.u8NumTmdwEntries; ++k)
				{
					if(g_ewsList.tmdwEntries[k].u8PackageId == ewsDetail->u8PackageId
						&& g_ewsList.tmdwEntries[k].usLocationType == ewsDetail->usLocationType
						&& g_ewsList.tmdwEntries[k].u8NumMessages && g_ewsList.tmdwEntries[k].messages)
					{
						is_tmdw_found = al_true;
						
						unsigned int size, index, offset;
						for(size = 0, index = 0; index < g_ewsList.tmdwEntries[k].u8NumMessages; ++index)
						{
							if(g_ewsList.tmdwEntries[k].messages[index])
								size += g_ewsList.tmdwEntries[k].messages[index]->nbytes;
						}

						if(size)
						{
							ewsDetail->message = (al_uint8 *) zero_malloc(size + 1);
							for(offset = 0, index = 0; index < g_ewsList.tmdwEntries[k].u8NumMessages; ++index)
							{
								if(g_ewsList.tmdwEntries[k].messages[index])
								{
									memcpy(ewsDetail->message + offset, g_ewsList.tmdwEntries[k].messages[index]->str_ptr, g_ewsList.tmdwEntries[k].messages[index]->nbytes);
									offset += g_ewsList.tmdwEntries[k].messages[index]->nbytes;
								}
							}
						}
						break;
					}
				}

				if(is_tcdw_found == al_false || is_tmdw_found == al_false)
				{
					/* TCDW or TMDW is missing; end the display of EWS */
					PSI_MONITOR_DEBUG_MSG("end the display of EWS for location_code %x\n", g_ewsList.trdwEntries[i].locations[j].location_code);
					SAFE_FREE(ewsDetail->message);
					return AL_FAILURE;
				}

				return AL_SUCCESS;
			}
			
		}
	}

	return AL_FAILURE;
}


#endif

#ifdef CONFIG_CI_SUPPORT
static U16BIT app_dvb_ci_get_raw_pmt_size(MID_SiutilPmtInfo_t *p)
{
    U32BIT i;
    U16BIT size;
    MID_SiutilPmtStreamInfoDescr_t *es;
    size = 12;
    size += p->info_len;
    for(i=0;i<p->comp_count;i++)
    {
        es = p->p_comp+i;
        size += 5;
        size += es->descLen;
    }
    size += 4;  /* crc */
    return size;
}

static void app_dvb_ci_fill_raw_pmt(U8BIT *pmt, U16BIT pmt_size, MID_SiutilPmtInfo_t *p)
{
    U32BIT i;
    U8BIT *ptr;
    MID_SiutilPmtStreamInfoDescr_t *es;
    memset(pmt,0,pmt_size);
    pmt[0] = 0x02;
    pmt[1] = (0xb0 | (((pmt_size-3)>>8)&0xf));
    pmt[2] = (pmt_size-3)&0xff;
    pmt[3] = (p->program_number >> 8);
    pmt[4] = (p->program_number & 0xff);
    pmt[5] = (0xc0 |
            ((p->version_number<<1)&0x3e) |
            (p->current_next_indicator&0x1));
    pmt[6] = 0x00;  /* section_number */
    pmt[7] = 0x00;  /* last_section_number */
    pmt[8] = 0xe0 | ((p->pcr_pid>>8)&0x1f);
    pmt[9] = (p->pcr_pid&0xff);
    pmt[10] = (0xf0 | ((p->info_len>>8)&0xf));
    pmt[11] = (p->info_len&0xff);
    ptr = pmt + 12;
    memcpy(ptr,p->p_info,p->info_len);
    ptr+=p->info_len;

    for(i=0;i<p->comp_count;i++)
    {
        es = p->p_comp+i;
        ptr[0] = es->stream_type; /* stream type */
        ptr[1] = (0xe0 | ((es->elementary_pid >> 8) & 0x1f));
        ptr[2] = (es->elementary_pid&0xff);
        ptr[3] = (0xf0 | ((es->descLen >> 8) & 0xf));
        ptr[4] = (es->descLen&0xff);
        ptr += 5;
        memcpy(ptr,es->p_desc,es->descLen);
        ptr += es->descLen;
    }
}

static void app_dvb_ci_bypass_pmt(MID_SiutilPmtInfo_t *p)
{
    U8BIT *pmt;
    U16BIT pmt_sz;
    pmt_sz = app_dvb_ci_get_raw_pmt_size(p);
    pmt = zero_malloc(pmt_sz);
    if(pmt)
    {
        app_dvb_ci_fill_raw_pmt(pmt,pmt_sz,p);
        MID_DTVCI_PassPMT(pmt);
        SAFE_FREE(pmt);
    }

}
#endif

static al_void _AI_PSI_Monitor_PmtCallback(al_int32 i32OrigNetId, al_int32 i32TsId, UINT16 i16PmtPid, al_void *pData)
{
	static al_uint8 s_u8OldVer = 0; /**< used to check pmt changed */
	static al_uint16 s_u16MonServiceId = 0xffff; /**< used to check pmt changed */
	MID_SiutilPmtInfo_t *pPmt = (MID_SiutilPmtInfo_t *) pData;
	al_uint32 u32DBUpdateFlag = 0;
	AL_RecHandle_t hCurrProgHdl = AL_DB_INVALIDHDL;
	al_uint16			usServiceId = 0xffff;
	al_uint16				usOrigNetId = 0xffff;
	al_uint16			usTsId = 0xffff;
	AL_DB_EDBType_t eDBType = AL_DBTYPE_MAX;
	UINT16			usPMTPid = 0;

	if (pPmt == al_null)
	{
		return;
	}
#ifdef	CONFIG_CIPLUS_SUPPORT
	if (APP_DVB_CI_GetIsPlaybackPMT())
	{
		return;
	}
#endif
	PSI_MONITOR_DEBUG_MSG("[%s:%d] \n",__FUNCTION__,__LINE__);

	if ((MID_SUCCESS != MID_PlaybackGetCurProgHandle(al_null, &hCurrProgHdl))
		|| (hCurrProgHdl == AL_DB_INVALIDHDL))
	{
		PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
		return;
	}

	if (AL_SUCCESS != AL_DB_GetRecordType(hCurrProgHdl, &eDBType, al_null))
	{
		PSI_MONITOR_ERROR_MSG("Get current active db type error.\n");
		return;
	}

#ifdef CONFIG_CI_SUPPORT
    app_dvb_ci_bypass_pmt(pPmt);
#endif

	AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usServiceId", (al_void *)&usServiceId);
	AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usOrigNetId", (al_void *)&usOrigNetId);
	AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usTsId_pat", (al_void *)&usTsId);
	AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usPMTPid", (al_void *)&usPMTPid);
	/* 1.Check pmt change */
	if ((s_u16MonServiceId != usServiceId)
    	||(s_u8OldVer != pPmt->version_number))
	{
		s_u8OldVer = pPmt->version_number;
		_AI_PSI_Monitor_CurrProgAudioStackReset();
	}

	/* 2. check service info match with current */
	if (((usOrigNetId != 0) && (usOrigNetId != i32OrigNetId)) || ((usTsId != 0) && (usTsId != i32TsId)) || (usServiceId != pPmt->program_number))
	{
		PSI_MONITOR_ERROR_MSG("pmt is not matched, usOrigNetId: %d, %d; usTsId: %d, %d; usServiceId: %d, %d; usPMTPid: %d, %d*************\n",
			usOrigNetId, i32OrigNetId, usTsId, i32TsId, usServiceId, pPmt->program_number, usPMTPid, i16PmtPid);
		 return;
	}

	if(usPMTPid == 0 && i16PmtPid != 0 )
	{
		//This means some thing happen to let usPMTPid=0, and get curr stream PMT pid, so update the value
		usPMTPid=i16PmtPid;
		AL_DB_UpdateDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usPMTPid", (al_void *)&usPMTPid);
	}
	/* 3. reset pid info */
	_AI_PSI_Monitor_PmtCallbkBeforeParseInit(eDBType, hCurrProgHdl);

	/* 4. PMT component's info check! */
#ifdef CONFIG_DTMB_SYSTEM
	_AI_PSI_Monitor_CurrProgAudioStackReset();
#endif
	_AI_PSI_Monitor_InPmtCheckComp((al_void *)pPmt, eDBType, hCurrProgHdl, &u32DBUpdateFlag);

	/* 5. PCR pid check */
	_AI_PSI_Monitor_InPmtCheckPCR((al_void *)pPmt, eDBType, hCurrProgHdl, &u32DBUpdateFlag);

	/* 6. check service scrambled? */
	_AI_PSI_Monitor_InPmtCheckScramble((al_void *)pPmt, eDBType, hCurrProgHdl, &u32DBUpdateFlag);

#ifdef CONFIG_ISDB_SYSTEM
	/*  check service locked? */
	_AI_PSI_Monitor_InPmtCheckLocked((al_void *)pPmt, eDBType, hCurrProgHdl);
#endif

	/* 7. service move detection */
	if (g_ePsiUpdateOptions & AL_PSIMONITOR_CURTP_SRV_MOVE)
    {
        al_uint16 u16NewOrgNetId;
		al_uint16 u16NewTsId;
		al_uint16 u16NewServId;

        if (dvbpsi_ServiceMoveDr(pPmt->info_len,pPmt->p_info,&u16NewOrgNetId,&u16NewTsId, &u16NewServId))
        {
        	g_stNewServiceLocation.usOldServiceId = usServiceId;
		g_stNewServiceLocation.usOrgNetId = u16NewOrgNetId;
		g_stNewServiceLocation.usTsId = u16NewTsId;
		g_stNewServiceLocation.usServiceId = u16NewServId;

		/* the service will be moved to a new location */
		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SERVICE_MOVE, 0);
        }
        else
        {
		memset(&g_stNewServiceLocation, 0, sizeof(AL_PsiMon_NewSrvPosition_t));
        }
    }

	/* 8. playback status update & presentation */
	_AI_PSI_Monitor_InPmtUpdatePlayback((al_void *)pPmt, eDBType, hCurrProgHdl, &u32DBUpdateFlag);

	s_u16MonServiceId = usServiceId;
}

static al_void _AI_PSI_Monitor_OtherPmtCallBK(al_void *pData)
{
	if (g_ePsiUpdateOptions & AL_PSIMONITOR_CURTP_SRVADDCHECKPMT)
	{
		_AI_PSI_Monitor_OtherPmtStack(pData);
	}
#ifdef CONFIG_SUPPORT_EWS
	AI_EWS_Monitor_OtherPmtCallBK(pData);
#endif
#ifdef SUPPORT_ASTRA_LCN_MONITOR
	AI_AstraLcn_Monitor_PmtOtherClbk(pData);
#endif
}

static al_void _AI_PSI_Monitor_OtherPmtRcvAllPmtCallBK(al_void *pData)
{
#ifdef SUPPORT_ASTRA_LCN_MONITOR
	AI_AstraLcn_Monitor_RcvAllPmtCK(pData);
#endif
}

/**
* @brief psi monitor replace service process.
*
* Dispose replace service, include not running/ scramble.
*
* @ param ReplaceState[input] replace service type.
*
* @return AL_SUCCESS set table type is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PSI_Monitor_ReplaceProcess(AL_PsiMon_State_Type_t ReplaceType)
{
	AL_RecHandle_t hCurProg = AL_DB_INVALIDHDL;
	AL_RecHandle_t hReplaceProg = AL_DB_INVALIDHDL;
	AL_RecHandle_t hReplacedProg = AL_DB_INVALIDHDL;

	if (((MID_SUCCESS != MID_PlaybackGetCurProgHandle(al_null, &hCurProg))
		|| (hCurProg == AL_DB_INVALIDHDL))
		&& (ReplaceType != AL_PSIMONITOR_STATE_SIMULCAST_REPLACEMENT_EXIST)
		&& (ReplaceType != AL_PSIMONITOR_STATE_SIMULCAST_REPLACED))
	{
		PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
		return AL_FAILURE;
	}

	switch (ReplaceType)
	{
		case AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACEMENT_EXIST:
			if (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_NOT_RUNNING_FLAG, al_null) == al_true)
			{
				if ((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACEMENT_EXIST, &hReplaceProg) == al_true)
					&& (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED, al_null) == al_false)
					&& (hReplaceProg != AL_DB_INVALIDHDL))
				{
					PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SERVICE_REPLACE, hReplaceProg);
					AI_PSI_Monitor_SetState(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED, &hCurProg);
				}
			}
			break;

		case AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED:
			if((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED, &hReplacedProg) == al_true)
				&& (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACEMENT_EXIST, &hReplaceProg) == al_true)
				&& (hReplaceProg != AL_DB_INVALIDHDL)
				&& (hReplacedProg != AL_DB_INVALIDHDL)
				&& (hCurProg == hReplaceProg))
			{
				PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SERVICE_REPLACE, hReplacedProg);
				AI_PSI_Monitor_ClearState(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED);
				AI_PSI_Monitor_ClearState(AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACEMENT_EXIST);
			}
			break;

		case AL_PSIMONITOR_STATE_SCRAMBLED_REPLACEMENT_EXIST:
			if ((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACEMENT_EXIST, &hReplaceProg) == al_true)
				&& (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED, al_null) == al_false)
				&& (hReplaceProg != AL_DB_INVALIDHDL))
			{
				PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SERVICE_REPLACE, hReplaceProg);
				AI_PSI_Monitor_SetState(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED, &hCurProg);
			}
			break;

		case AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED:
			if((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED, &hReplacedProg) == al_true)
				&& (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACEMENT_EXIST, &hReplaceProg) == al_true)
				&& (hReplaceProg != AL_DB_INVALIDHDL)
				&& (hReplacedProg != AL_DB_INVALIDHDL)
				&& (hCurProg == hReplaceProg))
			{
				PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SERVICE_REPLACE, hReplacedProg);
				AI_PSI_Monitor_ClearState(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED);
				AI_PSI_Monitor_ClearState(AL_PSIMONITOR_STATE_SCRAMBLED_REPLACEMENT_EXIST);
			}
			break;

		case AL_PSIMONITOR_STATE_SIMULCAST_REPLACEMENT_EXIST:
			if ((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SIMULCAST_REPLACEMENT_EXIST, &hReplaceProg) == al_true)
				&& (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SIMULCAST_REPLACED, al_null) == al_false)
				&& (hReplaceProg != AL_DB_INVALIDHDL))
			{
				AI_PSI_Monitor_SetState(AL_PSIMONITOR_STATE_SIMULCAST_REPLACED, al_null);
			}
			break;

		case AL_PSIMONITOR_STATE_SIMULCAST_REPLACED:
			if((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SIMULCAST_REPLACED, &hReplacedProg) == al_true)
				&& (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_SIMULCAST_REPLACEMENT_EXIST, &hReplaceProg) == al_true)
				&& (hReplaceProg != AL_DB_INVALIDHDL))
			{
				AI_PSI_Monitor_ClearState(AL_PSIMONITOR_STATE_SIMULCAST_REPLACED);
				AI_PSI_Monitor_ClearState(AL_PSIMONITOR_STATE_SIMULCAST_REPLACEMENT_EXIST);
			}
			break;

#ifdef EPG_REPLACE
		case AL_PSIMONITOR_STATE_EPG_REPLACEMENT_EXIST:
			if ((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_EPG_REPLACEMENT_EXIST, &hReplaceProg) == al_true)
				&& (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_EPG_REPLACED, al_null) == al_false)
				&& (hReplaceProg != AL_DB_INVALIDHDL))
			{
				AI_PSI_Monitor_SetState(AL_PSIMONITOR_STATE_EPG_REPLACED, &hCurProg);
				PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SERVICE_REPLACE, hReplaceProg);
			}
			break;

		case AL_PSIMONITOR_STATE_EPG_REPLACED:
			if((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_EPG_REPLACED, &hReplacedProg) == al_true)
				&& (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_EPG_REPLACEMENT_EXIST, &hReplaceProg) == al_true)
				&& (hReplaceProg != AL_DB_INVALIDHDL))
			{
				PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_SERVICE_REPLACE, hReplacedProg);
				AI_PSI_Monitor_ClearState(AL_PSIMONITOR_STATE_EPG_REPLACED);
				AI_PSI_Monitor_ClearState(AL_PSIMONITOR_STATE_EPG_REPLACEMENT_EXIST);
			}
			break;
#endif
		default:
			break;
	}

	return AL_SUCCESS;
}


/**
* @brief psi monitor FTa data update dispose.
*
* Parse FTA_content_management_descriptor and notify uplayer dtg cmg data update in NIT/EIT/SDT.
*
* @param u8Data[input] FTA_content_management_descriptor last one byte data.
*
* @ param u8Tbl[input] tabla type include NIT_1ST_LOOP/NIT_2ST_LOOP/SDT/EIT.
*
* @return AL_SUCCESS FTA_content_management_descriptor parse success is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PSI_Monitor_FTADataParse(al_uint8 u8Data, al_uint8 u8Tbl)
{
	do
	{
		if(u8Tbl & DTGCMG_TBL_EIT)
		{
			if((g_u8FTADataData&0x0f) != (u8Data&0x0f))
			{
				g_u8FTADataData = DTGCMG_TBL_EIT | (g_u8FTADataData&0xf0) | (u8Data&0x0f);
				break;
			}else
			{
				g_u8FTADataData |= DTGCMG_TBL_EIT;
			}
		}

		if(u8Tbl & DTGCMG_TBL_SDT)
		{
			/* EIT does not control or does not get EIT */
			if((g_u8FTADataData & DTGCMG_TBL_EIT) == 0)
			{
				if((g_u8FTADataData&0x0f) != (u8Data&0x0f))
				{
					g_u8FTADataData = DTGCMG_TBL_SDT | (g_u8FTADataData&0xf0) | (u8Data&0x0f);
					/* EIT does not control */
					if(g_u8FTADataTblParsed & DTGCMG_TBL_EIT)
					{
						break;
					}
				}
				else
				{
					g_u8FTADataData |= DTGCMG_TBL_SDT;
				}
			}
		}

		if(u8Tbl & DTGCMG_TBL_NIT_2ND_LOOP)
		{
			/* EIT&SDT does not control or does not get EIT&SDT */
			if(((g_u8FTADataData & DTGCMG_TBL_EIT) == 0)
				&& ((g_u8FTADataData & DTGCMG_TBL_SDT) == 0))
			{
				if((g_u8FTADataData&0x0f) != (u8Data&0x0f))
				{
					g_u8FTADataData = DTGCMG_TBL_NIT_2ND_LOOP | (g_u8FTADataData&0xf0) | (u8Data&0x0f);
					/* EIT&SDT does not control */
					if((g_u8FTADataTblParsed & DTGCMG_TBL_EIT)
						&& (g_u8FTADataTblParsed & DTGCMG_TBL_SDT))
					{
						break;
					}
				}
				else
				{
					g_u8FTADataData = DTGCMG_TBL_NIT_2ND_LOOP;
				}
			}
		}

		if(u8Tbl & DTGCMG_TBL_NIT_1ST_LOOP)
		{
			/* EIT&SDT&NIT2nd does not control or does not get EIT&SDT&NIT2nd */
			if(((g_u8FTADataData & DTGCMG_TBL_EIT) == 0)
				&& ((g_u8FTADataData & DTGCMG_TBL_SDT) == 0)
				&& ((g_u8FTADataData & DTGCMG_TBL_NIT_2ND_LOOP) == 0))
			{
				if((g_u8FTADataData&0x0f) != (u8Data&0x0f))
				{
					g_u8FTADataData = DTGCMG_TBL_NIT_1ST_LOOP | (g_u8FTADataData&0xf0) | (u8Data&0x0f);
					/* EIT&SDT&NIT2nd does not control */
					if((g_u8FTADataTblParsed & DTGCMG_TBL_EIT)
						&& (g_u8FTADataTblParsed & DTGCMG_TBL_SDT)
						&& (g_u8FTADataTblParsed & DTGCMG_TBL_NIT_2ND_LOOP))
					{
						break;
					}
				}
				else
				{
					g_u8FTADataData = DTGCMG_TBL_NIT_1ST_LOOP;
				}
			}
		}

		/* Just do */
		if(u8Tbl == DTGCMG_TBL_NONE)
		{
			if((g_u8FTADataTblParsed & DTGCMG_TBL_EIT)
				&& ((g_u8FTADataData & DTGCMG_TBL_EIT)==0) && (g_u8FTADataData & DTGCMG_TBL_SDT))
			{
				break;
			}
			else if((g_u8FTADataTblParsed & DTGCMG_TBL_EIT) && (g_u8FTADataTblParsed & DTGCMG_TBL_SDT)
				&& ((g_u8FTADataData & DTGCMG_TBL_EIT)==0) && ((g_u8FTADataData & DTGCMG_TBL_SDT)==0) && (g_u8FTADataData & DTGCMG_TBL_NIT_2ND_LOOP))
			{
				break;
			}
			else if((g_u8FTADataTblParsed & DTGCMG_TBL_EIT) && (g_u8FTADataTblParsed & DTGCMG_TBL_SDT) && (g_u8FTADataTblParsed & DTGCMG_TBL_NIT_2ND_LOOP)
				&& ((g_u8FTADataData & DTGCMG_TBL_EIT)==0) && ((g_u8FTADataData & DTGCMG_TBL_SDT)==0) && ((g_u8FTADataData & DTGCMG_TBL_NIT_2ND_LOOP)==0) && (g_u8FTADataData & DTGCMG_TBL_NIT_1ST_LOOP))
			{
				break;
			}
		}
		return AL_SUCCESS;
	}while(0);

	if(g_u8FTADataDataStored != g_u8FTADataData)
	{
		g_u8FTADataDataStored = g_u8FTADataData;

		PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_FTADATA_UPDATE, 0);
	}

	return AL_SUCCESS;
}

/**
* @brief psi monitor set FTA data table type.
*
* The tabla type include NIT_1ST_LOOP/NIT_2ST_LOOP/SDT/EIT.
*
* @ param u8Tbl[input] tabla type include NIT_1ST_LOOP/NIT_2ST_LOOP/SDT/EIT.
*
* @return AL_SUCCESS set table type is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PSI_Monitor_SetFTADataTbl(al_uint8 u8Tbl)
{
	g_u8FTADataTblParsed |= u8Tbl;

	return AL_SUCCESS;
}

/**
* @brief psi monitor add service list(sdt service list/nit service list/pat service list) to database.
*
* Add current TP sdt service list/nit service list/pat service list to database.
*
* @param pu32AddTotalNum[output] add services total number.
*
* @return AL_SUCCESS add  current tp service is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PSI_Monitor_AddSrv(al_uint32 *pu32AddTotalNum)
{
	AL_PSIMon_SimpleSrv_t *pnit = al_null;
	AL_PSIMon_SimpleSrv_t *psdt = al_null;
	AL_PSIMon_SimpleSrv_t *ppat = al_null;
	AL_PSIMon_SimplePmt_t *ppmt = al_null;
	al_uint32 u32TotalAddNum = 0;
	AL_RecHandle_t hCurrTpHdl = AL_DB_INVALIDHDL;
	AL_ServiceDetail_t stAddServInfo;
	AL_RecHandle_t hProgHdl = AL_DB_INVALIDHDL;
	AL_RecHandle_t hCurrProgHdl = AL_DB_INVALIDHDL;
	AL_RecHandle_t hAddProgHdl = AL_DB_INVALIDHDL;
	al_bool bFoundFlag = al_false;
	AL_DB_EDBType_t eDBType = AL_DBTYPE_MAX;
	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
	al_uint8 u8LocalRegionId = 0x3f;
	al_bool bMatchONID = al_false;
#ifdef CONFIG_CIPLUS_SUPPORT
    if (APP_CIPLUS_IsProfileSource())
    {
        return AL_FAILURE;
    }
#endif
	if(g_pstCurrSdtSrvList == al_null)
	{
		PSI_MONITOR_DEBUG_MSG("Current service list is null.\n");
		return AL_FAILURE;
	}

	al_bool bChnlock = al_false;
	AL_FW_GetContextCb(&pfPSIMonGetContext);
	if (pfPSIMonGetContext != al_null)
	{
		pfPSIMonGetContext(FW_CONTEXT_TYPE_GET_CHANNEL_LOCK , FW_CONTEXT_OP_TYPE_READ,
		(al_void *)&bChnlock, 0);
	}
	if(bChnlock)
	{
		PSI_MONITOR_ERROR_MSG("\nNot update channel list.\n");
		return AL_FAILURE;
	}

	memset(&stAddServInfo, 0, sizeof(AL_ServiceDetail_t));

	if ((MID_SUCCESS != MID_PlaybackGetCurProgHandle(al_null, &hCurrProgHdl))
		|| (hCurrProgHdl == AL_DB_INVALIDHDL))
	{
		PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
		return AL_FAILURE;
	}

	if (AL_SUCCESS != AL_DB_GetRecordType(hCurrProgHdl, &eDBType, al_null))
	{
		PSI_MONITOR_ERROR_MSG("Get current active db type error.\n");
		return AL_FAILURE;
	}

	hCurrTpHdl = hCurrProgHdl;
	if (AL_SUCCESS != AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBMULTIPLEX, &hCurrTpHdl))
	{
		PSI_MONITOR_ERROR_MSG("Get current TP handle failed!!!\n");
		return AL_FAILURE;
	}

#ifdef CONFIG_DVB_SYSTEM_DVBT2_SUPPORT
	UINT8 u8Tp_dvb_type = 0, u8PlpId = 0;
	if(eDBType == AL_DBTYPE_DVB_T)
	{
		STDBMultiplexInfo_t stTDBMultipInfo;
		memset(&stTDBMultipInfo, 0, sizeof(STDBMultiplexInfo_t));
		if (AL_SUCCESS != AL_DB_QueryDetail(hCurrTpHdl, (al_void *)&stTDBMultipInfo))
		{
			PSI_MONITOR_ERROR_MSG("Get current TP info failed!!!\n");
			return AL_FAILURE;
		}
		u8Tp_dvb_type = stTDBMultipInfo.ucTp_dvb_type;

		AL_ServiceDetail_t stCurrServInfo;
		memset(&stCurrServInfo, 0, sizeof(AL_ServiceDetail_t));

		if (AL_SUCCESS != AL_DB_QueryDetail(hCurrProgHdl, (al_void *)&stCurrServInfo))
		{
			PSI_MONITOR_ERROR_MSG("Get current service info failed!!!\n");
			return AL_FAILURE;
		}
		u8PlpId = stCurrServInfo.stDVBTServ.usPlpId;
	}
#endif

	PSIMON_MUTEX_LOCK(g_PsiMonMutex);

	psdt = g_pstCurrSdtSrvList;
	pnit = g_pstCurrNitSrvList;
	ppat = g_pstCurrPatSrvList;

	AL_FW_GetContextCb(&pfPSIMonGetContext);
	if (pfPSIMonGetContext != al_null)
	{
		/* get user setting region id */
		pfPSIMonGetContext(FW_CONTEXT_TYPE_COUNTRY_ID , FW_CONTEXT_OP_TYPE_READ,
			(al_void *)&u8LocalRegionId, 0);
	}

	if (psdt != al_null)
	{
		while (psdt)
		{
			bFoundFlag = al_false;
#if 0
			AL_RecHandle_t hTpHdl = AL_DB_INVALIDHDL;
			AL_Serv_SearchKey_t stSearchKey;
			memset(&stSearchKey, 0, sizeof(stSearchKey));
			stSearchKey.eDBType = eDBType;
			stSearchKey.eRecType = AL_RECTYPE_DVBSERVICE;
			stSearchKey.eSearchField = AL_SRV_SEARCHFIELD_ORIGNETID
									| AL_SRV_SEARCHFIELD_TSID
									| AL_SRV_SEARCHFIELD_SRVID;
		    /*zhongbaoxing added for mantis 0167629 to consider the attrib @20120204 */
		    /*This means including the deleted programs while searching the same service*/
		    stSearchKey.eIncludeAttrib |= AL_SRV_DATTRIB_DEL;
			stSearchKey.u16OrigNetId = psdt->usOrgNetId;
			stSearchKey.u16TsId = psdt->usTsId;
			stSearchKey.u16ServId = psdt->usServiceId;

			if (AL_SUCCESS == AL_DB_GetMatchedRecord((AL_DB_RecordMatchFunc)AL_Serv_MatchRecBySearchKey,
				(al_void *)&stSearchKey, eDBType, AL_RECTYPE_DVBSERVICE, AL_DB_REQ_GETFIRST, &hProgHdl))
			{
				hTpHdl = hProgHdl;
				if (AL_SUCCESS == AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBSERVICE, &hTpHdl)
					&& hTpHdl == hCurrTpHdl)
				{
					bFoundFlag = al_true;
				}
			}
#else
			al_uint16 u16OrigNetId = 0;
			al_uint16 u16TsId = 0;
			al_uint16 u16ServiceId = 0;

			hProgHdl = AL_DB_INVALIDHDL;
			while (AL_SUCCESS == AL_DB_GetChildRecord(hCurrTpHdl, &hProgHdl)
	    		&& (hProgHdl != AL_DB_INVALIDHDL))
			{
				AL_DB_QueryDetailFieldByName(hProgHdl, (al_uint8 *)"usOrigNetId", (al_void *)&u16OrigNetId);
				AL_DB_QueryDetailFieldByName(hProgHdl, (al_uint8 *)"usTsId", (al_void *)&u16TsId);
				AL_DB_QueryDetailFieldByName(hProgHdl, (al_uint8 *)"usServiceId", (al_void *)&u16ServiceId);

				if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_DTG
					#ifdef CONFIG_DVB_SYSTEM
					|| (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG && u8LocalRegionId == AREA_NORWAY)
					#endif
					)
				{
					if ((u16OrigNetId == psdt->usOrgNetId)
						&& (u16ServiceId == psdt->usServiceId))
					{
						bFoundFlag = al_true;
						break;
					}
				}
				else
				{
					if ((u16OrigNetId == psdt->usOrgNetId)
						&& (u16TsId == psdt->usTsId)
						&& (u16ServiceId == psdt->usServiceId))
					{
						bFoundFlag = al_true;
						break;
					}
				}
			}
#endif
            //zhongbaoxing added according to NorDig 2.2.1 Section 13.2.2 @20120806 +++
            if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG)
            {
                if(psdt->usOrgNetId>= 0xFF00)
                {
                    psdt = psdt->pstNext;
                    continue;
                }
            }
            //zhongbaoxing added according to NorDig 2.2.1 Section 13.2.2 @20120806 ---
			if (bFoundFlag)
			{
				psdt = psdt->pstNext;
				continue;
			}

			pnit = g_pstCurrNitSrvList;

			while (pnit)
			{
				if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_DTG
					#ifdef CONFIG_DVB_SYSTEM
					|| (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG && u8LocalRegionId == AREA_NORWAY)
					#endif
					)
				{
					if (psdt->usServiceId == pnit->usServiceId
						&& psdt->usOrgNetId == pnit->usOrgNetId)
					{
						/* get the LCN number */
						psdt->usProgNum = pnit->usProgNum;
						psdt->stProgAttrib = pnit->stProgAttrib;
						break;
					}
				}
				else
				{
					if (psdt->usServiceId == pnit->usServiceId
						&& psdt->usTsId == pnit->usTsId
						&& psdt->usOrgNetId == pnit->usOrgNetId)
					{
						/* get the LCN number */
						psdt->usProgNum = pnit->usProgNum;
						psdt->stProgAttrib = pnit->stProgAttrib;
						break;
					}
				}
				pnit=pnit->pstNext;
			}
			//zhongbaoxing added according to NorDig 2.2.1 Section 13.2.2 @20120806 +++
			if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG)
			{
				if(pnit)
				{
					if(pnit->usNetWorkId >= 0xFF01)
					{
						psdt = psdt->pstNext;
						continue;
					}
				}
			}
			//zhongbaoxing added according to NorDig 2.2.1 Section 13.2.2 @20120806 ---
			if (g_ePsiUpdateOptions & AL_PSIMONITOR_CURTP_SRVADD2)
			{
				/* double check service with PAT's service list */
				ppat = g_pstCurrPatSrvList;

				while (ppat)
				{
#if 0
					if (psdt->usServiceId == ppat->usServiceId
						&& psdt->usTsId == ppat->usTsId)
#else
					if (psdt->usServiceId == ppat->usServiceId)
#endif
					{
						psdt->usPat_TsId = ppat->usTsId;
						/* get pmt pid */
						psdt->usPMTPid = ppat->usPMTPid;
						break;
					}

					ppat = ppat->pstNext;
				}

				if (ppat == NULL)
				{
					/* the service doesn't present in PAT, it should not add to database */
					psdt = psdt->pstNext;
					continue;
				}
			}

			if (g_ePsiUpdateOptions & AL_PSIMONITOR_CURTP_SRVADDCHECKPMT)
			{
				ppmt = g_pstCurrPmtSrvList;
				while (ppmt)
				{
					if (psdt->usServiceId == ppmt->usProgNum)
					{
						if (ppmt->bHasAudio || ppmt->bHasVideo)
						{
							psdt->stProgAttrib.svrtmp = FALSE;
						}
						else
						{
							psdt->stProgAttrib.svrtmp = TRUE;
						}
						break;
					}

					ppmt = ppmt->pstNext;
				}

				if (ppmt == NULL)
				{
					/* the service doesn't present in PMT, it should not add to database */
					psdt = psdt->pstNext;
					continue;
				}
			}

			if (g_pfPsiMonCheckNotVisible != al_null)
			{
				al_uint8 bTempSrv = FALSE;
				al_uint8 bNotVisible = FALSE;
				al_uint8 bNotNeedSave = FALSE;
				bTempSrv = psdt->stProgAttrib.svrtmp;
				g_pfPsiMonCheckNotVisible(psdt->u8SDTSrvType, bTempSrv, &bNotVisible, &bNotNeedSave);

				if (bNotNeedSave)
				{
					psdt = psdt->pstNext;
					continue;
				}
				else if (bNotVisible)
				{
					psdt->stProgAttrib.notvisible = al_true;
				}
			}

			pfPSIMonGetContext(FW_CONTEXT_TYPE_ONID_MATCH , FW_CONTEXT_OP_TYPE_READ,
				(al_void *)&bMatchONID, psdt->usOrgNetId);

			/* add service to database */
			PSI_MONITOR_DEBUG_MSG("Current TP has services: id=%x, try to add to database ... \n",psdt->usServiceId);

			if (eDBType == AL_DBTYPE_DVB_C)
			{
				memset(&stAddServInfo, 0, sizeof(AL_ServiceDetail_t));
				memcpy(stAddServInfo.stDVBCServ.szProgName,psdt->pucname, DB_DVB_MAX_CHNAME_LEN - 1);
				stAddServInfo.stDVBCServ.usOrigNetId = psdt->usOrgNetId;
				stAddServInfo.stDVBCServ.usServiceId = psdt->usServiceId;
				stAddServInfo.stDVBCServ.usTsId = psdt->usTsId;
				stAddServInfo.stDVBCServ.usTsId_pat = psdt->usPat_TsId;
				stAddServInfo.stDVBCServ.usProgNo = psdt->usProgNum;
				stAddServInfo.stDVBCServ.usOrgLcn = psdt->usProgNum&DB_DVB_LCN_MASK;
				stAddServInfo.stDVBCServ.eTvRadioType = psdt->ucServiceType;
				stAddServInfo.stDVBCServ.stProgAttrib.notvisible= psdt->stProgAttrib.notvisible;
				stAddServInfo.stDVBCServ.stProgAttrib.ONIDMatched = bMatchONID;
				stAddServInfo.stDVBCServ.usPMTPid = psdt->usPMTPid;
				if (!bMatchONID
					#ifdef CONFIG_DVB_SYSTEM
					&& (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG && u8LocalRegionId == AREA_NORWAY)
					#endif
					)
				{
					stAddServInfo.stDVBCServ.usProgNo = 0;
				}
			}
			else if (eDBType == AL_DBTYPE_DVB_T)
			{
				memset(&stAddServInfo, 0, sizeof(AL_ServiceDetail_t));
				memcpy(stAddServInfo.stDVBTServ.szProgName,psdt->pucname, DB_DVB_MAX_CHNAME_LEN - 1);
				stAddServInfo.stDVBTServ.usOrigNetId = psdt->usOrgNetId;
				stAddServInfo.stDVBTServ.usServiceId = psdt->usServiceId;
				stAddServInfo.stDVBTServ.usTsId = psdt->usTsId;
				stAddServInfo.stDVBTServ.usTsId_pat = psdt->usPat_TsId;
				stAddServInfo.stDVBTServ.usProgNo = psdt->usProgNum;
				stAddServInfo.stDVBTServ.usOrgLcn = psdt->usProgNum&DB_DVB_LCN_MASK;
				stAddServInfo.stDVBTServ.eTvRadioType = psdt->ucServiceType;
				stAddServInfo.stDVBTServ.stProgAttrib.notvisible = psdt->stProgAttrib.notvisible;
				stAddServInfo.stDVBTServ.stProgAttrib.ONIDMatched = bMatchONID;
				stAddServInfo.stDVBTServ.usPMTPid = psdt->usPMTPid;
				if (!bMatchONID
					#ifdef CONFIG_DVB_SYSTEM
					&& (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG && u8LocalRegionId == AREA_NORWAY)
					#endif
					)
				{
					stAddServInfo.stDVBTServ.usProgNo = 0;
				}
				#ifdef CONFIG_DVB_SYSTEM_DVBT2_SUPPORT
				if(u8Tp_dvb_type == EDVB_DELIVER_TYPE_T2)
				{
					stAddServInfo.stDVBTServ.usPlpId = u8PlpId;
				}
				#endif
			}
			else if (eDBType == AL_DBTYPE_DVB_S)
			{
				memset(&stAddServInfo, 0, sizeof(AL_ServiceDetail_t));
				memcpy(stAddServInfo.stDVBSServ.szProgName,psdt->pucname, DB_DVB_MAX_CHNAME_LEN - 1);
				stAddServInfo.stDVBSServ.usOrigNetId = psdt->usOrgNetId;
				stAddServInfo.stDVBSServ.usServiceId = psdt->usServiceId;
				stAddServInfo.stDVBSServ.usTsId = psdt->usTsId;
				stAddServInfo.stDVBSServ.usTsId_pat = psdt->usPat_TsId;
				stAddServInfo.stDVBSServ.usProgNo = psdt->usProgNum;
				stAddServInfo.stDVBSServ.usOrgLcn = psdt->usProgNum&DB_DVB_LCN_MASK;
				stAddServInfo.stDVBSServ.eTvRadioType = psdt->ucServiceType;
				stAddServInfo.stDVBSServ.stProgAttrib.notvisible = psdt->stProgAttrib.notvisible;
				stAddServInfo.stDVBSServ.stProgAttrib.ONIDMatched = bMatchONID;
				stAddServInfo.stDVBSServ.usPMTPid = psdt->usPMTPid;
				if (!bMatchONID
					#ifdef CONFIG_DVB_SYSTEM
					&& (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG && u8LocalRegionId == AREA_NORWAY)
					#endif
					)
				{
					stAddServInfo.stDVBSServ.usProgNo = 0;
				}
			}
			#ifdef CONFIG_ISDB_SYSTEM
			else if (eDBType == AL_DBTYPE_DVB_SBTVD)
			{
				memset(&stAddServInfo, 0, sizeof(AL_ServiceDetail_t));
				memcpy(stAddServInfo.stSBTVDServ.szProgName,psdt->pucname, DB_DVB_MAX_CHNAME_LEN - 1);
				stAddServInfo.stSBTVDServ.usOrigNetId = psdt->usOrgNetId;
				stAddServInfo.stSBTVDServ.usServiceId = psdt->usServiceId;
				stAddServInfo.stSBTVDServ.usTsId = psdt->usTsId;
				stAddServInfo.stSBTVDServ.usProgNo = psdt->usProgNum;
				stAddServInfo.stSBTVDServ.eTvRadioType = psdt->ucServiceType;
				stAddServInfo.stSBTVDServ.stProgAttrib.notvisible = psdt->stProgAttrib.notvisible;
				stAddServInfo.stSBTVDServ.usPMTPid = psdt->usPMTPid;
			}
            #endif
			hAddProgHdl = hProgHdl;

			if (AL_SUCCESS != AL_DB_AddRecord(eDBType,
				psdt->ucServiceType, (al_void *)&stAddServInfo, hCurrTpHdl, &hAddProgHdl))
			{
				PSI_MONITOR_ERROR_MSG("Add service to database failed!! \n");
			}

			u32TotalAddNum++;
			psdt = psdt->pstNext;
		}
	}

	PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
	*pu32AddTotalNum = u32TotalAddNum;
	PSI_MONITOR_ERROR_MSG("need to pu32AddTotalNum: %d\n",*pu32AddTotalNum);
	return AL_SUCCESS;
}

/**
* @brief psi monitor remove service from database.
*
* Remove current TP service from database.
*
* @param pu32RemovTotalNum[output] remove services total number.
*
* @return AL_SUCCESS remove service is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PSI_Monitor_RemoveSrv(al_uint32 *pu32RemovTotalNum)
{
	AL_PSIMon_SimpleSrv_t *pList[AL_PSIMONITOR_CURRTP_SRVLIST_MAX] = {al_null};
	AL_RecHandle_t hCurrProgHdl = AL_DB_INVALIDHDL;
	AL_RecHandle_t hProgHdl = AL_DB_INVALIDHDL;
	AL_RecHandle_t hCurrTpHdl = AL_DB_INVALIDHDL;
	al_uint32 u32TotalRemovNum = 0;
	AL_DB_EDBType_t eDBType = AL_DBTYPE_MAX;
	al_uint8 u8Count = 0;
	AL_RecHandle_t hServHdl = AL_DB_INVALIDHDL;
	DBServAttrib_t stAttribute;
	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
	al_uint8 u8LocalRegionId = 0x3f;

	al_bool bChnlock = al_false;
	AL_FW_GetContextCb(&pfPSIMonGetContext);
#ifdef CONFIG_CIPLUS_SUPPORT
    if (APP_CIPLUS_IsProfileSource())
    {
        return AL_FAILURE;
    }
#endif
	if (pfPSIMonGetContext != al_null)
	{
		pfPSIMonGetContext(FW_CONTEXT_TYPE_GET_CHANNEL_LOCK , FW_CONTEXT_OP_TYPE_READ,
		(al_void *)&bChnlock, 0);
	}
	if(bChnlock)
	{
		PSI_MONITOR_ERROR_MSG("\nNot update channel list.\n");
		return AL_FAILURE;
	}

	if ((MID_SUCCESS != MID_PlaybackGetCurProgHandle(al_null, &hCurrProgHdl))
			|| (hCurrProgHdl == AL_DB_INVALIDHDL))
	{
		PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
		return AL_FAILURE;
	}

	if (AL_SUCCESS != AL_DB_GetRecordType(hCurrProgHdl, &eDBType, al_null))
	{
		PSI_MONITOR_ERROR_MSG("Get current active db type error.\n");
		return AL_FAILURE;
	}

	hCurrTpHdl = hCurrProgHdl;

	if (AL_SUCCESS != AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBMULTIPLEX, &hCurrTpHdl))
	{
		PSI_MONITOR_ERROR_MSG("Get current TP handle failed!!!\n");
		return AL_FAILURE;
	}

#ifdef CONFIG_DVB_SYSTEM_DVBT2_SUPPORT
	UINT8 u8Tp_dvb_type = 0;
	if(eDBType == AL_DBTYPE_DVB_T)
	{
		STDBMultiplexInfo_t stTDBMultipInfo;
		memset(&stTDBMultipInfo, 0, sizeof(STDBMultiplexInfo_t));
		if (AL_SUCCESS != AL_DB_QueryDetail(hCurrTpHdl, (al_void *)&stTDBMultipInfo))
		{
			PSI_MONITOR_ERROR_MSG("Get current TP info failed!!!\n");
			return AL_FAILURE;
		}
		u8Tp_dvb_type = stTDBMultipInfo.ucTp_dvb_type;
	}
#endif

	PSIMON_MUTEX_LOCK(g_PsiMonMutex);

	if (g_pstCurrSdtSrvList == NULL || g_pstCurrPatSrvList == NULL)
	{
		PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
		return AL_FAILURE;
	}

	/* Set all services unstable in current TP */
#ifdef CONFIG_DVB_SYSTEM_DVBT2_SUPPORT
	if(u8Tp_dvb_type == EDVB_DELIVER_TYPE_T2)
	{
		al_uint8 u8PlpId = 0;
		al_uint8 usPlpId = 0;

		AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usPlpId", (al_void *)&usPlpId);

		while (AL_SUCCESS == AL_DB_GetChildRecord(hCurrTpHdl, &hServHdl))
		{
			memset(&stAttribute, 0, sizeof(stAttribute));
			AL_DB_QueryDetailFieldByName(hServHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stAttribute);
			AL_DB_QueryDetailFieldByName(hServHdl, (al_uint8 *)"usPlpId", (al_void *)&u8PlpId);

			if((stAttribute.delete != al_true)
				&& usPlpId == u8PlpId)//zhongbaoxing added for mantis 171520 @20120310
			{
			#ifdef CONFIG_CIPLUS_SUPPORT
				if( stAttribute.isProfileServ )
					continue;
			#endif
				stAttribute.unStable = al_true;
			}
			AL_DB_UpdateDetailFieldByName(hServHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stAttribute);
		}
	}
	else
#endif
	{
		while (AL_SUCCESS == AL_DB_GetChildRecord(hCurrTpHdl, &hServHdl))
		{
			memset(&stAttribute, 0, sizeof(stAttribute));
			AL_DB_QueryDetailFieldByName(hServHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stAttribute);
			if(stAttribute.delete != al_true)//zhongbaoxing added for mantis 171520 @20120310
			{
			#ifdef CONFIG_CIPLUS_SUPPORT
				if( stAttribute.isProfileServ )
					continue;
			#endif
				stAttribute.unStable = al_true;
			}
			AL_DB_UpdateDetailFieldByName(hServHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stAttribute);
		}
	}

	pList[0] = g_pstCurrSdtSrvList;
	//pList[1] = g_pstCurrNitSrvList;
	pList[1] = g_pstCurrPatSrvList;

	AL_FW_GetContextCb(&pfPSIMonGetContext);
	if (pfPSIMonGetContext != al_null)
	{
		/* get user setting region id */
		pfPSIMonGetContext(FW_CONTEXT_TYPE_COUNTRY_ID , FW_CONTEXT_OP_TYPE_READ,
			(al_void *)&u8LocalRegionId, 0);
	}

	for (u8Count = 0; u8Count < 2 /*AL_PSIMONITOR_CURRTP_SRVLIST_MAX*/; u8Count++)
	{
		while (pList[u8Count])
		{
#if 0
			AL_RecHandle_t hTpHdl = AL_DB_INVALIDHDL;
			AL_Serv_SearchKey_t stSearchKey;
			memset(&stSearchKey, 0, sizeof(stSearchKey));

			stSearchKey.eDBType = eDBType;
			stSearchKey.eRecType = AL_RECTYPE_DVBSERVICE;
			stSearchKey.eSearchField = AL_SRV_SEARCHFIELD_ORIGNETID
									| AL_SRV_SEARCHFIELD_TSID
									| AL_SRV_SEARCHFIELD_SRVID;
			stSearchKey.u16OrigNetId = pList[u8Count]->usOrgNetId;
			stSearchKey.u16TsId = pList[u8Count]->usTsId;
			stSearchKey.u16ServId = pList[u8Count]->usServiceId;
			if (AL_SUCCESS == AL_DB_GetMatchedRecord((AL_DB_RecordMatchFunc)AL_Serv_MatchRecBySearchKey,
				(al_void *)&stSearchKey, eDBType, AL_RECTYPE_DVBSERVICE, AL_DB_REQ_GETFIRST, &hProgHdl))
			{
				hTpHdl = hProgHdl;
				if (AL_SUCCESS == AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBSERVICE, &hTpHdl)
					&& hTpHdl == hCurrTpHdl)
				{
					memset(&stAttribute, 0, sizeof(stAttribute));
					AL_DB_QueryDetailFieldByName(hProgHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stAttribute);
					stAttribute.unStable = al_false;
					AL_DB_UpdateDetailFieldByName(hProgHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stAttribute);
				}
			}
#else
			al_uint16 u16OrigNetId = 0;
			al_uint16 u16TsId = 0;
			al_uint16 u16ServiceId = 0;

			hProgHdl = AL_DB_INVALIDHDL;
			while (AL_SUCCESS == AL_DB_GetChildRecord(hCurrTpHdl, &hProgHdl)
	    		&& (hProgHdl != AL_DB_INVALIDHDL))
			{
				AL_DB_QueryDetailFieldByName(hProgHdl, (al_uint8 *)"usOrigNetId", (al_void *)&u16OrigNetId);
				AL_DB_QueryDetailFieldByName(hProgHdl, (al_uint8 *)"usTsId", (al_void *)&u16TsId);
				AL_DB_QueryDetailFieldByName(hProgHdl, (al_uint8 *)"usServiceId", (al_void *)&u16ServiceId);

				if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_DTG
					#ifdef CONFIG_DVB_SYSTEM
					|| (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG && u8LocalRegionId == AREA_NORWAY)
					#endif
					)
				{
					if ((u16OrigNetId == pList[u8Count]->usOrgNetId)
						&& (u16ServiceId == pList[u8Count]->usServiceId))
					{
						memset(&stAttribute, 0, sizeof(stAttribute));
						AL_DB_QueryDetailFieldByName(hProgHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stAttribute);
						stAttribute.unStable = al_false;
						AL_DB_UpdateDetailFieldByName(hProgHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stAttribute);
						#ifdef SUPPORT_ASTRA_LCN
						// ASTRA Channel List required database store duplicate services(those services have same locator)
						if (eDBType == AL_DBTYPE_DVB_S)
						{
						}
						else
						#endif
						{
						#ifdef CONFIG_CIPLUS_SUPPORT
							if( !pList[u8Count]->stProgAttrib.isProfileServ && !stAttribute.isProfileServ )
						#endif
							break;
						}
					}
				}
				else
				{
					if ((u16OrigNetId == pList[u8Count]->usOrgNetId)
						&& (u16TsId == pList[u8Count]->usTsId)
						&& (u16ServiceId == pList[u8Count]->usServiceId))
					{
						memset(&stAttribute, 0, sizeof(stAttribute));
						AL_DB_QueryDetailFieldByName(hProgHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stAttribute);
						
						if (g_ePsiUpdateOptions & AL_PSIMONITOR_CURTP_SRVADDCHECKPMT)
						{
							AL_PSIMon_SimplePmt_t *ppmt = al_null;
							ppmt = g_pstCurrPmtSrvList;
							while (ppmt)
							{
								if (pList[u8Count]->usServiceId == ppmt->usProgNum)
								{
									stAttribute.unStable = al_false;
									AL_DB_UpdateDetailFieldByName(hProgHdl, (al_uint8 *)"stProgAttrib", (al_void *)&stAttribute);
									break;
								}

								ppmt = ppmt->pstNext;
							}
						}

						#ifdef SUPPORT_ASTRA_LCN
						// ASTRA Channel List required database store duplicate services(those services have same locator)
						if (eDBType == AL_DBTYPE_DVB_S)
						{
						}
						else
						#endif
						{
						#ifdef CONFIG_CIPLUS_SUPPORT
							if( !pList[u8Count]->stProgAttrib.isProfileServ && !stAttribute.isProfileServ )
						#endif
							break;
						}

					}
				}
			}
#endif
			pList[u8Count] = pList[u8Count]->pstNext;
		}
	}

	PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);

	AL_Serv_AttribFilter_t stFilter;
	memset(&stFilter, 0, sizeof(AL_Serv_AttribFilter_t));

	stFilter.eDPositive = AL_SRV_DATTRIB_UNSTABLE;
	stFilter.eDBType = eDBType;
	stFilter.eRecType = AL_RECTYPE_DVBSERVICE;

	AL_DB_SearchRecords((AL_DB_RecordMatchFunc)AL_Serv_MatchRecByAttribute,
		(al_void *)&stFilter,eDBType, AL_RECTYPE_DVBSERVICE, 0, 0, &u32TotalRemovNum, NULL, NULL);

	*pu32RemovTotalNum = u32TotalRemovNum;

	PSI_MONITOR_ERROR_MSG("need to pu32RemovTotalNum: %d\n",*pu32RemovTotalNum);

	return AL_SUCCESS;
}

/**
* @brief Add and remove and update service timer clear.
*
* Clear add and remove and update service timer state.
*
* @param u32ClearFlag[input] need be clear time.
*
* @return AL_SUCCESS timer check is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PSI_Monitor_TimerEventClear(al_uint32 u32ClearFlag)
{
	if (u32ClearFlag&(1<<AI_PSIMONITOR_TIMER_SERVICE_ADD))
	{
		g_ePsiTimerEventArrange &= (~(1<<AI_PSIMONITOR_TIMER_SERVICE_ADD));
		g_u32PsiTimer[AI_PSIMONITOR_TIMER_SERVICE_ADD] = 0;
		g_iPsiTimerAddDiff = 0;
	}

	if (u32ClearFlag&(1<<AI_PSIMONITOR_TIMER_SERVICE_REMOVE))
	{
		g_ePsiTimerEventArrange &= (~(1<<AI_PSIMONITOR_TIMER_SERVICE_REMOVE));
		g_u32PsiTimer[AI_PSIMONITOR_TIMER_SERVICE_REMOVE] = 0;
		g_iPsiTimerRemoveDiff = 0;
	}

	if (u32ClearFlag&(1<<AI_PSIMONITOR_TIMER_SERVICE_UPDATE))
	{
		g_ePsiTimerEventArrange &= (~(1<<AI_PSIMONITOR_TIMER_SERVICE_UPDATE));
		g_u32PsiTimer[AI_PSIMONITOR_TIMER_SERVICE_UPDATE] = 0;
		g_iPsiTimerUpdateDiff = 0;
	}
#ifdef CONFIG_SUPPORT_INDONESIA_EWS
	if (u32ClearFlag&(1<<AI_PSIMONITOR_TIMER_INDONESIA_EWS_STOP))
	{
		g_ePsiTimerEventArrange &= (~(1<<AI_PSIMONITOR_TIMER_INDONESIA_EWS_STOP));
		g_u32PsiTimer[AI_PSIMONITOR_TIMER_INDONESIA_EWS_STOP] = 0;
		g_iPsiTimerEWSUpdateDiff = 0;
	}
#endif
	return AL_SUCCESS;
}


/**
* @brief Add service and remove service timer check.
*
* Add service and remove service need a timer to check, not instant dispose.
*
* @param u32MSec[input] timer valure in ms.
*
* @return AL_SUCCESS timer check is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PSI_Monitor_TimerEventCheck(al_uint32 u32MSec)
{
	AI_PsiMon_Timer_Type_t eType;
	al_int iPsiTimerDiff;
	al_uint8 u8TempCotryCode[3] = {0};
	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;

	if (g_ePsiTimerEventArrange & (1<<AI_PSIMONITOR_TIMER_SERVICE_ADD))
	{
		eType = AI_PSIMONITOR_TIMER_SERVICE_ADD;

		if (g_u32PsiTimer[eType])
		{
			if (u32MSec > g_u32PsiTimer[eType])
			{
				g_iPsiTimerAddDiff = u32MSec-g_u32PsiTimer[eType];
			}
			else
			{
				g_u32PsiTimer[eType] = u32MSec;
				g_iPsiTimerAddDiff = 0;
			}
			//PSI_MONITOR_DEBUG_MSG("[%s:%d]g_iPsiTimerAddDiff : %d\n",__FUNCTION__,__LINE__,g_iPsiTimerAddDiff);
			AL_FW_GetContextCb(&pfPSIMonGetContext);
			if (pfPSIMonGetContext != al_null)
			{
				pfPSIMonGetContext(FW_CONTEXT_TYPE_COUNTRY_CODE , FW_CONTEXT_OP_TYPE_READ,
					(al_void *)u8TempCotryCode, 0);
			}
			if ((toupper('N') == toupper(u8TempCotryCode[0]))
				&& (toupper('O') == toupper(u8TempCotryCode[1]))
				&& (toupper('R') == toupper(u8TempCotryCode[2])))
			{
				iPsiTimerDiff = PSIMON_SERVICE_ADD_DURATION_NORWAY;
			}
			else
			{
				iPsiTimerDiff = PSIMON_SERVICE_ADD_DURATION;
			}
			if (g_iPsiTimerAddDiff > iPsiTimerDiff)
			{
				g_iPsiTimerAddDiff = 0;
				_AI_PSI_Monitor_TimerEventChange(eType,al_false);
				PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_ADD_SRV, 0);
			}
		}
		else
		{
			g_u32PsiTimer[eType] = u32MSec;
			g_iPsiTimerAddDiff = 0;
		}
	}

	if (g_ePsiTimerEventArrange & (1<<AI_PSIMONITOR_TIMER_SERVICE_REMOVE))
	{
		eType = AI_PSIMONITOR_TIMER_SERVICE_REMOVE;

		if (g_u32PsiTimer[eType])
		{
			if (u32MSec > g_u32PsiTimer[eType])
			{
				g_iPsiTimerRemoveDiff = u32MSec-g_u32PsiTimer[eType];
			}
			else
			{
				g_u32PsiTimer[eType] = u32MSec;
				g_iPsiTimerRemoveDiff = 0;
			}
			//PSI_MONITOR_DEBUG_MSG("[%s:%d]g_iPsiTimerRemoveDiff : %d\n",__FUNCTION__,__LINE__,g_iPsiTimerRemoveDiff);
			AL_FW_GetContextCb(&pfPSIMonGetContext);
			if (pfPSIMonGetContext != al_null)
			{
				pfPSIMonGetContext(FW_CONTEXT_TYPE_COUNTRY_CODE , FW_CONTEXT_OP_TYPE_READ,
					(al_void *)u8TempCotryCode, 0);
			}
			if ((toupper('N') == toupper(u8TempCotryCode[0]))
				&& (toupper('O') == toupper(u8TempCotryCode[1]))
				&& (toupper('R') == toupper(u8TempCotryCode[2])))
			{
				iPsiTimerDiff = PSIMON_SERVICE_RMV_DURATION_NORWAY;
			}
			else
			{
				iPsiTimerDiff = PSIMON_SERVICE_RMV_DURATION;
			}
			if (g_iPsiTimerRemoveDiff > iPsiTimerDiff)
			{
				g_iPsiTimerRemoveDiff = 0;
				_AI_PSI_Monitor_TimerEventChange(eType,al_false);
				PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_REMOVE_SRV, 0);
			}
		}
		else
		{
			g_u32PsiTimer[eType] = u32MSec;
			g_iPsiTimerRemoveDiff = 0;
		}
	}

	if (g_ePsiTimerEventArrange & (1<<AI_PSIMONITOR_TIMER_SERVICE_UPDATE))
	{
		eType = AI_PSIMONITOR_TIMER_SERVICE_UPDATE;

		if (g_u32PsiTimer[eType])
		{
			if (u32MSec > g_u32PsiTimer[eType])
			{
				g_iPsiTimerUpdateDiff = u32MSec-g_u32PsiTimer[eType];
			}
			else
			{
				g_u32PsiTimer[eType] = u32MSec;
				g_iPsiTimerUpdateDiff = 0;
			}
			//PSI_MONITOR_DEBUG_MSG("[%s:%d]g_iPsiTimerUpdateDiff : %d\n",__FUNCTION__,__LINE__,g_iPsiTimerUpdateDiff);

			al_uint16	usTsId_pat = 0xffff;
			al_uint16	usOrigNetId = 0xffff;
			AL_RecHandle_t hCurrProgHdl = AL_DB_INVALIDHDL;

			if ((MID_SUCCESS != MID_PlaybackGetCurProgHandle(al_null, &hCurrProgHdl))
				|| (hCurrProgHdl == AL_DB_INVALIDHDL))
			{
				_AI_PSI_Monitor_TimerEventChange(eType,al_false);
				return AL_FAILURE;
			}

			if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usTsId_pat", (al_void *)&usTsId_pat))
			{
				_AI_PSI_Monitor_TimerEventChange(eType,al_false);
				return AL_FAILURE;
			}
			if (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usOrigNetId", (al_void *)&usOrigNetId))
			{
				_AI_PSI_Monitor_TimerEventChange(eType,al_false);
				return AL_FAILURE;
			}

			iPsiTimerDiff = PSIMON_SERVICE_UPDATE_DURATION;
			if (g_iPsiTimerUpdateDiff > iPsiTimerDiff)
			{
				g_iPsiTimerUpdateDiff = 0;
				_AI_PSI_Monitor_TimerEventChange(eType,al_false);
				if ((g_u16TSID != usTsId_pat) || (usOrigNetId != INVALID_ORGNETID && g_uOrigNetId == INVALID_ORGNETID) 
					|| (usOrigNetId == INVALID_ORGNETID && g_uOrigNetId != INVALID_ORGNETID))
				{
					UINT32 Param;
					Param = (g_u16TSID << 16) | 0;
					PSI_MONITOR_DEBUG_MSG("[%s:%d] g_u16TSID : %d, usTsId_pat: %d, usOrigNetId: %d ++++++++++++\n",
						__FUNCTION__,__LINE__,g_u16TSID,usTsId_pat,usOrigNetId);
					PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_TS_CHANGED, Param);
				}
				g_u16TSID = INVALID_TSID;
				g_uOrigNetId = INVALID_ORGNETID;
			}
		}
		else
		{
			g_u32PsiTimer[eType] = u32MSec;
			g_iPsiTimerUpdateDiff = 0;
		}
	}
#ifdef CONFIG_SUPPORT_INDONESIA_EWS
	if (g_ePsiTimerEventArrange & (1<<AI_PSIMONITOR_TIMER_INDONESIA_EWS_STOP))
	{
		eType = AI_PSIMONITOR_TIMER_INDONESIA_EWS_STOP;

		if (g_u32PsiTimer[eType])
		{
			if (u32MSec > g_u32PsiTimer[eType])
			{
				g_iPsiTimerEWSUpdateDiff = u32MSec-g_u32PsiTimer[eType];
			}
			else
			{
				g_u32PsiTimer[eType] = u32MSec;
				g_iPsiTimerEWSUpdateDiff = 0;
			}
			//PSI_MONITOR_DEBUG_MSG("[%s:%d]g_iPsiTimerEWSUpdateDiff : %d\n",__FUNCTION__,__LINE__,g_iPsiTimerEWSUpdateDiff);

			if (g_iPsiTimerEWSUpdateDiff > PSIMON_INDONESIA_EWS_STOP)
			{
				g_iPsiTimerEWSUpdateDiff = 0;
				_AI_PSI_Monitor_TimerEventChange(eType,al_false);

				if(g_bIsEwsActive)
				{
					_AI_PSI_Monitor_FreeEwsList(&g_ewsList);
					g_bIsEwsActive = 0;
					PSIMON_SEND_MSG(g_pfPsiMonCallbks, AI_PSIMONITOR_INDONESIA_EWS_STOP, 0);
				}
			}
		}
		else
		{
			g_u32PsiTimer[eType] = u32MSec;
			g_iPsiTimerEWSUpdateDiff = 0;
		}
	}
#endif

	return AL_SUCCESS;
}

/**
* @brief Set psi monitor sipsi state.
*
* This function used to record psi monitor sipsi info state,( NOT_RUNNING_REPLACEMENT_EXIST,
* NOT_RUNNING_FLAG, SCRAMBLED_REPLACEMENT_EXIST, NOT_RUNNING_REPLACED, SCRAMBLED_REPLACED).
*
* @param u32State[input] sipsi state.
*
* @param pParam[input] sipsi state's parameter, program handle for replacement.
*
* @return AL_SUCCESS set sipsi state is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PSI_Monitor_SetState(al_uint32 u32State, AL_RecHandle_t *pParam)
{
	switch(u32State)
	{
		case AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACEMENT_EXIST:
			if (pParam != al_null)
			{
				g_hReplacement[AI_PSIMONITOR_REPLACEMENT_TYPE_NOT_RUNNING] = *pParam;
			}
			g_u32SipsiInfoState |= u32State;
			break;

		case AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED:
			if (pParam != al_null)
			{
				g_hReplaced[AI_PSIMONITOR_REPLACEMENT_TYPE_NOT_RUNNING] = *pParam;
			}
			g_u32SipsiInfoState |= u32State;
			break;

		case AL_PSIMONITOR_STATE_SCRAMBLED_REPLACEMENT_EXIST:
			if (pParam != al_null)
			{
				g_hReplacement[AI_PSIMONITOR_REPLACEMENT_TYPE_SCRAMBLE] = *pParam;
			}
			g_u32SipsiInfoState |= u32State;
			break;

		case AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED:
			if (pParam != al_null)
			{
				g_hReplaced[AI_PSIMONITOR_REPLACEMENT_TYPE_SCRAMBLE] = *pParam;
			}
			g_u32SipsiInfoState |= u32State;
			break;

		case AL_PSIMONITOR_STATE_SIMULCAST_REPLACEMENT_EXIST:
			if (pParam != al_null)
			{
				g_hReplacement[AI_PSIMONITOR_REPLACEMENT_TYPE_SIMLCASE] = *pParam;
			}
			g_u32SipsiInfoState |= u32State;
			break;

		case AL_PSIMONITOR_STATE_SIMULCAST_REPLACED:
			if (pParam != al_null)
			{
				g_hReplaced[AI_PSIMONITOR_REPLACEMENT_TYPE_SIMLCASE] = *pParam;
			}
			g_u32SipsiInfoState |= u32State;
			break;

#ifdef EPG_REPLACE
		case AL_PSIMONITOR_STATE_EPG_REPLACEMENT_EXIST:
			if (pParam != al_null)
			{
				g_hReplacement[AI_PSIMONITOR_REPLACEMENT_TYPE_EPG] = *pParam;
			}
			g_u32SipsiInfoState |= u32State;
			break;

		case AL_PSIMONITOR_STATE_EPG_REPLACED:
			if (pParam != al_null)
			{
				g_hReplaced[AI_PSIMONITOR_REPLACEMENT_TYPE_EPG] = *pParam;
			}
			g_u32SipsiInfoState |= u32State;
			break;
#endif
		default:
			g_u32SipsiInfoState |= u32State;
			break;
	}

	return AL_SUCCESS;
}

/**
* @brief Clear psi monitor sipsi state.
*
* This function used to clear psi monitor sipsi info state,( NOT_RUNNING_REPLACEMENT_EXIST,
* NOT_RUNNING_FLAG, SCRAMBLED_REPLACEMENT_EXIST, NOT_RUNNING_REPLACED, SCRAMBLED_REPLACED).
*
* @param u32State[input] sipsi state.
*
* @return AL_SUCCESS clear sipsi state is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PSI_Monitor_ClearState(al_uint32 u32State)
{
	g_u32SipsiInfoState &= ~u32State;

	return AL_SUCCESS;
}

/**
* @brief Check psi monitor sipsi state.
*
* This function used to check psi monitor sipsi info state,( NOT_RUNNING_REPLACEMENT_EXIST,
* NOT_RUNNING_FLAG, SCRAMBLED_REPLACEMENT_EXIST, NOT_RUNNING_REPLACED, SCRAMBLED_REPLACED).
*
* @param u32State[input] sipsi state.
*
* @param pParam[output] sipsi state's parameter, program handle for replacement.
*
* @return al_ture if state exist, al_false if state not exist.
*/
al_bool AI_PSI_Monitor_CheckState(al_uint32 u32State, AL_RecHandle_t *pParam)
{
	if((g_u32SipsiInfoState&u32State) == u32State)
	{
		switch (u32State)
		{
			case AI_PSIMONITOR_STATE_NOT_RUNNING_REPLACEMENT_EXIST:
				if (pParam != al_null)
				{
					*pParam = g_hReplacement[AI_PSIMONITOR_REPLACEMENT_TYPE_NOT_RUNNING];
				}
				break;

			case AI_PSIMONITOR_STATE_NOT_RUNNING_REPLACED:
				if (pParam != al_null)
				{
					*pParam = g_hReplaced[AI_PSIMONITOR_REPLACEMENT_TYPE_NOT_RUNNING];
				}
				break;

			case AI_PSIMONITOR_STATE_SCRAMBLED_REPLACEMENT_EXIST:
				if (pParam != al_null)
				{
					*pParam = g_hReplacement[AI_PSIMONITOR_REPLACEMENT_TYPE_SCRAMBLE];
				}
				break;

			case AI_PSIMONITOR_STATE_SCRAMBLED_REPLACED:
				if (pParam != al_null)
				{
					*pParam = g_hReplaced[AI_PSIMONITOR_REPLACEMENT_TYPE_SCRAMBLE];
				}
				break;

			case AI_PSIMONITOR_STATE_SIMULCAST_REPLACEMENT_EXIST:
				if (pParam != al_null)
				{
					*pParam = g_hReplacement[AI_PSIMONITOR_REPLACEMENT_TYPE_SIMLCASE];
				}
				break;

			case AI_PSIMONITOR_STATE_SIMULCAST_REPLACED:
				if (pParam != al_null)
				{
					*pParam = g_hReplaced[AI_PSIMONITOR_REPLACEMENT_TYPE_SIMLCASE];
				}
				break;

			default:
				break;
		}

		return al_true;
	}
	return al_false;
}

#ifdef EPG_REPLACE
AL_Return_t AI_PSI_Monitor_EPG_ReplaceCheck(al_void)
{
	AL_RecHandle_t hCurrProgHdl = AL_DB_INVALIDHDL;
	AL_DB_EDBType_t eDBType = AL_DBTYPE_MAX;
	al_uint16 usTsId = 0xffff;
	al_uint16 usOrigNetId = 0xffff;
	al_uint16 usServiceId = 0xffff;
	al_uint16 totalnum = 0;
	al_uint32 CurTimeInSec = 0;
	AL_Time_t event_start_time;
	AL_RecHandle_t hReplaceProg = AL_DB_INVALIDHDL;
	FW_mode_t eFwMode = FW_NORMAL_VIEW_MODE;

	memset(&event_start_time, 0, sizeof(AL_Time_t));
	AL_FW_GetFWModule(&eFwMode);

	if (g_ePsiFollowSpec == AL_PSIMON_SPECIAL_SPEC_NORDIG)
	{
		if (eFwMode == FW_EPG_MODE)
		{
			if ((AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_EPG_REPLACEMENT_EXIST, &hReplaceProg) == al_true)
				&& (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_EPG_REPLACED, al_null) == al_false)
				&& (hReplaceProg != AL_DB_INVALIDHDL))
			{
				if ((MID_SUCCESS != MID_PlaybackGetCurProgHandle(al_null, &hCurrProgHdl))
					|| (hCurrProgHdl == AL_DB_INVALIDHDL))
				{
					PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
					return AL_FAILURE;
				}

				if (AL_SUCCESS != AL_DB_GetRecordType(hCurrProgHdl, &eDBType, al_null))
				{
					PSI_MONITOR_ERROR_MSG("Get current active db type error.\n");
					return AL_FAILURE;
				}

				if ((AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usTsId", (al_void *)&usTsId))
					|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usOrigNetId", (al_void *)&usOrigNetId))
					|| (AL_SUCCESS != AL_DB_QueryDetailFieldByName(hCurrProgHdl, (al_uint8 *)"usServiceId", (al_void *)&usServiceId)))
				{
					PSI_MONITOR_ERROR_MSG("Get service info failed!!!\n");
					return AL_FAILURE;
				}

				AL_Time_GetCurTimeInSecs(&CurTimeInSec);
				AL_Time_Secs2Date(&CurTimeInSec, &event_start_time);

				AL_Event_GetAllSchduleEventsBetweenTime(eDBType, usOrigNetId, usTsId, usServiceId,
					&event_start_time, al_null, 0, 1, al_null, al_null, &totalnum);

				if (totalnum == 0)
				{
					AI_PSI_Monitor_ReplaceProcess(AL_PSIMONITOR_STATE_EPG_REPLACEMENT_EXIST);
				}
			}
		}
		else
		{
			if (AL_PSI_Monitor_CheckState(AL_PSIMONITOR_STATE_EPG_REPLACED, al_null) == al_true)
			{
				AI_PSI_Monitor_ReplaceProcess(AL_PSIMONITOR_STATE_EPG_REPLACED);
			}
		}
	}

	return AL_SUCCESS;
}
#endif

/**
* @brief psi monitor init function.
*
* @param pfPsiMonCallbks[input] psi monitor notify framwork callback function.
*
* @return AL_SUCCESS if initialization is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PSI_Monitor_Init(AI_pfPsiMonCallback pfPsiMonCallbks)
{
	Mid_PsiMonCallbks_t stPsiMonCallbks;

	if (g_bPsiMonInited == al_true)
	{
		PSI_MONITOR_ERROR_MSG("psi monitor has inited.\n");
		return AL_SUCCESS;
	}

	if(g_PsiMonMutex == al_null)
	{
		if (GL_SUCCESS != GL_MutexCreate("PsiMonMutex", &g_PsiMonMutex))
		{
			PSI_MONITOR_ERROR_MSG("psi monitor create mutex failed.\n");
			return AL_FAILURE;
		}
	}

	MidPmtOtherCallBack pPmtOtherMonCallbks = NULL;
	MidPmtOtherCallBack pPmtOtherMonNofifyCallbks = NULL;
	MidPmtOtherCallBack pPmtOtherMonEwsCallbks = NULL;
#ifdef CONFIG_SUPPORT_INDONESIA_EWS
	pPmtOtherMonEwsCallbks = _AI_PSI_Monitor_IndonesiaEWS_PmtCallback;
#endif
	pPmtOtherMonCallbks = _AI_PSI_Monitor_OtherPmtCallBK;
	pPmtOtherMonNofifyCallbks = _AI_PSI_Monitor_OtherPmtRcvAllPmtCallBK;
	if (MID_SUCCESS != MID_PmtOtherInit(pPmtOtherMonCallbks, pPmtOtherMonNofifyCallbks, pPmtOtherMonEwsCallbks))
	{
		PSI_MONITOR_ERROR_MSG("other pmt monitor mid init failed.\n");
	}
	memset(&stPsiMonCallbks, 0, sizeof(Mid_PsiMonCallbks_t));
	stPsiMonCallbks.pfMonPMTCallbk = _AI_PSI_Monitor_PmtCallback;
	stPsiMonCallbks.pfMonTDTCallbk = _AI_PSI_Monitor_TdtCallback;
	stPsiMonCallbks.pfMonTOTCallbk = _AI_PSI_Monitor_TotCallback;
	stPsiMonCallbks.pfMonPATCallbk = _AI_PSI_Monitor_PatCallback;
	stPsiMonCallbks.pfMonSDTCallbk = _AI_PSI_Monitor_SdtCallback;
	stPsiMonCallbks.pfMonNITCallbk = _AI_PSI_Monitor_NitCallback;
	stPsiMonCallbks.pfMonCATCallbk = _AI_PSI_Monitor_CatCallback;
	stPsiMonCallbks.pfMonSDTOtherCallbk = _AI_PSI_Monitor_SdtOtherCallback;
#ifdef CONFIG_SUPPORT_INDONESIA_EWS
	stPsiMonCallbks.pfMonTxDWCallbk = _AI_PSI_Monitor_TxDWCallback;
#endif
#ifdef CONFIG_SUPPORT_KDG_CERTIFICATION
	stPsiMonCallbks.pfMonBATCallbk = _AI_PSI_Monitor_BatCallback;
#endif

	if (MID_SUCCESS != MID_PsiMonInit(&stPsiMonCallbks))
	{
		PSI_MONITOR_ERROR_MSG("psi monitor mid init failed.\n");
		return AL_FAILURE;
	}

#ifdef CONFIG_SUPPORT_HBBTV
	HBBTV_SIQuery_Init();
	HBBTV_AppManagerInit();
	DsmccRbOpenFunc();
#endif
	g_pfPsiMonCallbks = pfPsiMonCallbks;
	g_bPsiMonInited = al_true;

	AI_TpListInit(&g_hTPList);
	return AL_SUCCESS;
}

/**
* @brief psi monitor init function.
*
* @param al_void.
*
* @return AL_SUCCESS if uninitialization is successful, AL_FAILURE otherwise.
*/
AL_Return_t AI_PSI_Monitor_Uninit(al_void)
{
	if (g_bPsiMonInited != al_true)
	{
		PSI_MONITOR_ERROR_MSG("psi monitor has not inited.\n");
		return AL_UNINITIALIZED;
	}

	if (g_PsiMonMutex != al_null)
	{
		if (GL_SUCCESS != GL_MutexDelete(g_PsiMonMutex))
		{
			PSI_MONITOR_ERROR_MSG("psi monitor delete mutex failed.\n");
		}
	}

	g_PsiMonMutex = al_null;
	g_bPsiMonInited = al_false;
	g_pfPsiMonCallbks = al_null;
	MID_PsiMonUninit();
	MID_PmtOtherUninit();
	AI_TpListFree(g_hTPList);
	return AL_SUCCESS;
}

/**
* @brief psi monitor start function.
*
* Active psi monitor task, start to monitor psi table and si table change
*
* @param hCurrProg playback play program handle.
*
* @param ClearReplaceData the flag of clearing replace data.
*
* @return AL_SUCCESS start  is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_PSI_Monitor_Start(AL_RecHandle_t hCurrProg, al_bool ClearReplaceData)
{
	if (g_bPsiMonInited != al_true)
	{
		PSI_MONITOR_ERROR_MSG("psi monitor has not inited.\n");
		return AL_UNINITIALIZED;
	}

	if (g_bPsiMonStarted == al_true)
	{
		PSI_MONITOR_ERROR_MSG("psi monitor has started.\n");
		return AL_FAILURE;
	}
	g_bPsiMonStarted = al_true;
	PSI_MONITOR_DEBUG_MSG("[%s:%d] ClearReplaceData: %d\n",__FUNCTION__,__LINE__,ClearReplaceData);
	_AI_PSI_Monitor_CurrProgAudioStackReset();
	_AI_PSI_Monitor_FTADataReset();
	_AI_PSI_Monitor_ResetState(ClearReplaceData);
	AI_PSI_Monitor_TimerEventClear((1<<AI_PSIMONITOR_TIMER_SERVICE_ADD)|(1<<AI_PSIMONITOR_TIMER_SERVICE_REMOVE)|(1<<AI_PSIMONITOR_TIMER_SERVICE_UPDATE));
	MID_PsiMonNotifyProgChanged(hCurrProg);
	if (MID_SUCCESS != MID_PsiMonStart())
	{
		PSI_MONITOR_ERROR_MSG("psi monitor start failture.\n");
		return AL_FAILURE;
	}

	extern AL_DBPrivateSpec_t AL_CS_DtvGetSpecialSpec(void);
	static AL_DBTuneType_t eTuneType = AL_DB_MANUAL_SEARCH;
	AL_DBPrivateSpec_t ePriSpec = AL_CS_DtvGetSpecialSpec();

	if (AL_SUCCESS != AL_DB_RegisterDupliRecStrategy(NULL, &eTuneType, &ePriSpec))
	{
		return AL_FAILURE;
	}

	return AL_SUCCESS;
}

/**
* @brief psi monitor stop function.
*
* Stop psi monitor task, stop to monitor psi table and si table
*
* @param bExit[input] used to mark hang up psi monitor task or exit psi monitor.
*
* @return AL_SUCCESS stop is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_PSI_Monitor_Stop(al_bool bExit, al_bool ClearReplaceData)
{
	if (g_bPsiMonInited != al_true)
	{
		PSI_MONITOR_ERROR_MSG("psi monitor has not inited.\n");
		return AL_UNINITIALIZED;
	}

	if (g_bPsiMonStarted == al_false)
	{
		PSI_MONITOR_ERROR_MSG("psi monitor has not started.\n");
		return AL_FAILURE;
	}
	g_bPsiMonStarted = al_false;
	PSI_MONITOR_DEBUG_MSG("[%s:%d] ClearReplaceData: %d\n",__FUNCTION__,__LINE__,ClearReplaceData);
	if (MID_SUCCESS != MID_PsiMonStop(bExit))
	{
		PSI_MONITOR_ERROR_MSG("psi monitor stop failture.\n");
	}
	MID_PmtOtherStop(bExit);

#ifdef SUPPORT_ASTRA_LCN_MONITOR
	AI_AstraLcn_Monitor_Stop(bExit);
#endif
	_AI_PSI_Monitor_CurrProgAudioStackReset();
	_AI_PSI_Monitor_CurTpServicesReset();
	_AI_PSI_Monitor_OtherPmtReset();
	_AI_PSI_Monitor_FTADataReset();
	_AI_PSI_Monitor_ResetState(ClearReplaceData);
#ifdef CONFIG_SUPPORT_INDONESIA_EWS
	g_ewsList.u32TrdwCrc32 = 0;
	g_ewsList.u32TcdwCrc32 = 0;
	g_ewsList.u32TmdwCrc32 = 0;
#endif
	AI_PSI_Monitor_TimerEventClear((1<<AI_PSIMONITOR_TIMER_SERVICE_ADD)|(1<<AI_PSIMONITOR_TIMER_SERVICE_REMOVE)|(1<<AI_PSIMONITOR_TIMER_SERVICE_UPDATE));

	return AL_SUCCESS;
}

/**
* @brief get psi monitor running state function.
*
* Get dvb monitor current state.
*
* @param pbPsiMonState[output] psi monitor running state value.
*
* @return AL_SUCCESS get state is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_PSI_Monitor_GetState(al_bool *pbPsiMonState)
{
	if (pbPsiMonState == al_null)
	{
		PSI_MONITOR_ERROR_MSG("psi monitor get state error.\n");
		return AL_INVALID_PARAM;
	}

	*pbPsiMonState = MID_PsiMonIsRunning();

	return AL_SUCCESS;
}

/**
* @brief set psi monitor special spec
*
* Because different contry have different spec, example UK(DBook), this api to set special spec.
*
* @param eSpecConf[input] spec config
*
* @param eDynamicUpdate[input] psi monitor support dynamic update type
*
* @param pfPsiMonCheckSrvType[input] usded to check service type(TV/RADIO/DATA)
*
* @return AL_SUCCESS setup spec config is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_PSI_Monitor_SetupConf(AL_PSIMon_SpecialSpec_t eSpecConf,
	AL_PsiMon_DynamicUpdate_Type_t eDynamicUpdate, AL_pfPsiMonCheckSrvType pfPsiMonCheckSrvType, AL_pfPsiMonCheckNotVisible pfPsiMonCheckNotVisible)
{
	g_ePsiFollowSpec = eSpecConf;

	if (pfPsiMonCheckSrvType != al_null)
	{
		g_pfPsiMonCheckSrvType = pfPsiMonCheckSrvType;
	}

	if (pfPsiMonCheckNotVisible != al_null)
	{
		g_pfPsiMonCheckNotVisible = pfPsiMonCheckNotVisible;
	}
    AL_DBPrivateSpec_t ePriSpec = AL_DB_DVB_PRISPEC_EBOOK;
    AL_DBTuneType_t eTuneType = AL_DB_AUTO_SEARCH;

	if (g_ePsiUpdateOptions & AL_PSIMONITOR_USER_TOTOFFSET)
	{
		eDynamicUpdate = eDynamicUpdate | AL_PSIMONITOR_USER_TOTOFFSET;
	}

	frmwrk_pfOpConext_t pfPSIMonGetContext = al_null;
	al_uint8 u8LocalRegionId = 0x3f;
#ifdef CONFIG_DVB_SYSTEM_DVBC_SUPPORT
	al_DVBC_Operator_en op = AL_DVBC_OPERATOR_AUTO;
#endif

	AL_FW_GetContextCb(&pfPSIMonGetContext);

	if (pfPSIMonGetContext != al_null)
	{
		/* get user setting region id */
		pfPSIMonGetContext(FW_CONTEXT_TYPE_COUNTRY_ID , FW_CONTEXT_OP_TYPE_READ,
			(al_void *)&u8LocalRegionId, 0);
	#ifdef CONFIG_DVB_SYSTEM_DVBC_SUPPORT
		pfPSIMonGetContext(FW_CONTEXT_TYPE_OPERATOR , FW_CONTEXT_OP_TYPE_READ,
			(al_void *)&op, 0);
	#endif
	}

	switch(g_ePsiFollowSpec)
	{
		case AL_PSIMON_SPECIAL_SPEC_DTG:
			g_ePsiUpdateOptions = AL_PSIMONITOR_CURTP_SRVADD \
										|AL_PSIMONITOR_CURTP_SRV_REMOVE \
										|AL_PSIMONITOR_REPLACED_TO_ORIGNAL\
										|AL_PSIMONITOR_CURTP_SRV_ATR;
			ePriSpec = AL_DB_DVB_PRISPEC_DBOOK;
			break;
		case AL_PSIMON_SPECIAL_SPEC_DEMO_DEFAULT:
		case AL_PSIMON_SPECIAL_SPEC_ZBOOK:
			g_ePsiUpdateOptions = AL_PSIMONITOR_CURTP_SRVADD2 \
										| AL_PSIMONITOR_CURTP_SRVADDCHECKPMT\
										|AL_PSIMONITOR_CURTP_SRV_REMOVE \
										|AL_PSIMONITOR_CURTP_SRV_ATR;
			ePriSpec = AL_DB_DVB_PRISPEC_ZBOOK;
		#ifdef CONFIG_DVB_SYSTEM
		#ifdef CONFIG_DVB_SYSTEM_DVBC_SUPPORT
			if(u8LocalRegionId == AREA_GERMANY)
			{
			#ifdef CONFIG_SUPPORT_KDG_CERTIFICATION
				if (op == AL_DVBC_OPERATOR_KDG)
					g_ePsiUpdateOptions |= AL_PSIMONITOR_KDG_LCN_DYNAMIC_UPDATE;  /* KDG uses its private LCD in BAT */
				else
			#endif
				g_ePsiUpdateOptions |= AL_PSIMONITOR_LCN_DYNAMIC_UPDATE;
			}
		#endif
		#endif
			break;
		case AL_PSIMON_SPECIAL_SPEC_NORDIG:
			{
				g_ePsiUpdateOptions = AL_PSIMONITOR_CURTP_SRVADD2 \
											|AL_PSIMONITOR_CURTP_SRV_MOVE \
											|AL_PSIMONITOR_CURTP_SRV_REMOVE \
											|AL_PSIMONITOR_LCN_DYNAMIC_UPDATE \
											|AL_PSIMONITOR_OTHTP_SR_UPDATE \
											|AL_PSIMONITOR_CURTP_SRV_ATR;
			#ifdef CONFIG_DTMB_SYSTEM
				g_ePsiUpdateOptions |= AL_PSIMONITOR_CURTP_SRVADDCHECKPMT;
			#endif
			
			#ifdef CONFIG_DVB_SYSTEM
				if(u8LocalRegionId == AREA_GERMANY) /* Germany UnityMedia shall not use SDT-other */
				{
					g_ePsiUpdateOptions &= (~AL_PSIMONITOR_OTHTP_SR_UPDATE);
				#if defined(SUPPORT_NETWORK_UPDATE_RESCAN) && defined(CONFIG_SUPPORT_UNITY_MEDIA_CERTIFICATION)
					g_ePsiUpdateOptions |= AL_PSIMONITOR_CURNWK_TP_RESCAN;
				#endif
				}
			#ifdef CONFIG_SUPPORT_ANTENNA_READY_HD_CERTIFICATION
				if(u8LocalRegionId == AREA_FINLAND)
				{
				#ifdef SUPPORT_NETWORK_UPDATE_RESCAN
					g_ePsiUpdateOptions |= AL_PSIMONITOR_CURNWK_TP_RESCAN;
				#else
					g_ePsiUpdateOptions |= AL_PSIMONITOR_OTHTP_SR_ADD;
				#endif
				}
			#endif
			#if defined(SUPPORT_NETWORK_UPDATE_RESCAN) && defined(CONFIG_SUPPORT_BOXER_CERTIFICATION)
				if( u8LocalRegionId==AREA_DENMARK || u8LocalRegionId==AREA_SWEDEN )
				{
					g_ePsiUpdateOptions |= AL_PSIMONITOR_CURNWK_TP_RESCAN;
				}
			#endif

				if(u8LocalRegionId == AREA_THAILAND)
				{
					g_ePsiUpdateOptions |= AL_PSIMONITOR_FREQ_UPDATE;
				}

				if(u8LocalRegionId == AREA_NORWAY)
				{
					g_ePsiUpdateOptions |= AL_PSIMONITOR_OTHTP_FOND;
				}
			#endif
			}
			ePriSpec = AL_DB_DVB_PRISPEC_NORDIG;
			break;
		case AL_PSIMON_SPECIAL_SPEC_EBOOK:
			g_ePsiUpdateOptions = AL_PSIMONITOR_CURTP_SRVADD2 \
										|AL_PSIMONITOR_CURTP_SRVADDCHECKPMT\
										|AL_PSIMONITOR_CURTP_SRV_REMOVE \
										|AL_PSIMONITOR_CURTP_SRV_ATR;
		#ifdef CONFIG_DVB_SYSTEM
			if(u8LocalRegionId == AREA_HUNGARY)
			{
				g_ePsiUpdateOptions |= AL_PSIMONITOR_LCN_DYNAMIC_UPDATE;
			}
		#endif
			ePriSpec = AL_DB_DVB_PRISPEC_EBOOK;
			break;
		default:
			g_ePsiUpdateOptions = AL_PSIMONITOR_CURTP_SRVADD2 \
										|AL_PSIMONITOR_CURTP_SRVADDCHECKPMT\
										|AL_PSIMONITOR_CURTP_SRV_REMOVE \
										|AL_PSIMONITOR_CURTP_SRV_ATR;
			break;
	}
#ifdef CONFIG_DVB_SYSTEM
	if(u8LocalRegionId == AREA_VIETNAM || u8LocalRegionId == AREA_MALAYSIA)
	{
		g_ePsiUpdateOptions |= AL_PSIMONITOR_LCN_DYNAMIC_UPDATE;
	}
#endif
	if (AL_SUCCESS != AL_DB_RegisterDupliRecStrategy(NULL, &eTuneType, &ePriSpec))
	{
		return AL_FAILURE;
	}

	g_ePsiUpdateOptions = g_ePsiUpdateOptions | eDynamicUpdate;

	return AL_SUCCESS;
}
void AL_PSI_Monitor_NotAddService(void)
{
	g_ePsiUpdateOptions &= ~(AL_PSIMONITOR_CURTP_SRVADD2 | AL_PSIMONITOR_CURTP_SRVADD);

}

/**
* @brief Get other tp service list from nit service list.
*
* Nit include other tp information, this function used to get other tp service list.
*
* @param psrv[output] other tp service list.
*
* @param pName service name
*
* @param pu16SrvNum[output] service total count.
*
* @return AL_SUCCESS get other tp services is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_PSI_Monitor_GetOtherTpServList(AL_PSIMon_SimpleSrv_t *pSrv, al_uint8 *pName, al_uint16 *pu16SrvNum)
{
	PSIMON_MUTEX_LOCK(g_PsiMonMutex);
#ifdef CONFIG_CIPLUS_SUPPORT
    if (APP_CIPLUS_IsProfileSource())
    {
        return AL_FAILURE;
    }
#endif

	if (g_u16NumberOfOtherTpSrv > PSIMON_MAX_OTHERTP_SRV)
	{
		PSI_MONITOR_ERROR_MSG("There are too many new service!!!! \n");
		*pu16SrvNum = 0;
		PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
		return AL_FAILURE;
	}

	if (pSrv == NULL)
	{
		*pu16SrvNum = g_u16NumberOfOtherTpSrv;
		PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
		return AL_SUCCESS;
	}

	al_int iCount;
	AL_PSIMon_SimpleSrv_t *ptr = g_pstOtherNitSrvList;

	for(iCount = 0; iCount < g_u16NumberOfOtherTpSrv; iCount++)
	{
		if(ptr == NULL)
		{
			break;
		}

		pSrv[iCount].usOrgNetId = ptr->usOrgNetId;
		pSrv[iCount].usServiceId = ptr->usServiceId;
		pSrv[iCount].usTsId = ptr->usTsId;
		pSrv[iCount].uiFreq = ptr->uiFreq;
		pSrv[iCount].usProgNum = ptr->usProgNum;
		pSrv[iCount].ucServiceType = ptr->ucServiceType;
		pSrv[iCount].u8SDTSrvType = ptr->u8SDTSrvType;
		if(ptr->pucname)
			memcpy(&pName[iCount*DB_DVB_MAX_CHNAME_LEN],ptr->pucname,strlen((char *)ptr->pucname));
		pSrv[iCount].pucname = &pName[iCount*DB_DVB_MAX_CHNAME_LEN];
		ptr = ptr->pstNext;
	}

	*pu16SrvNum = g_u16NumberOfOtherTpSrv;
	PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);
	return AL_SUCCESS;
}

#ifdef SUPPORT_NETWORK_UPDATE_RESCAN
AL_Return_t AI_PSI_Monitor_UpdateCurrTpTSIDList(al_void)
{
	AL_DB_EDBType_t eDBType = AL_DBTYPE_MAX;
	AL_RecHandle_t hCurrProgHdl = AL_DB_INVALIDHDL;
	AL_RecHandle_t hCurrTPHdl = AL_DB_INVALIDHDL;

	if( MID_SUCCESS!=MID_PlaybackGetCurProgHandle(al_null, &hCurrProgHdl) || hCurrProgHdl==AL_DB_INVALIDHDL )
	{
		PSI_MONITOR_ERROR_MSG("Get current program handle error.\n");
		return AL_FAILURE;
	}

	if( AL_SUCCESS != AL_DB_GetRecordType(hCurrProgHdl, &eDBType, al_null) )
	{
		PSI_MONITOR_ERROR_MSG("Get current active db type error.\n");
		return AL_FAILURE;
	}

	hCurrTPHdl = hCurrProgHdl;
	if( AL_SUCCESS != AL_DB_GetRecord(AL_DB_REQ_GETPARENT, eDBType, AL_RECTYPE_DVBMULTIPLEX, &hCurrTPHdl) )
	{
		PSI_MONITOR_ERROR_MSG("Get tp handle failed !!!\n");
		return AL_FAILURE;
	}

	if( AL_SUCCESS != AL_DB_UpdateDetailFieldByName( hCurrTPHdl, (UINT8*)"ucNitVersion", &g_u8CurrNitVersion) )
	{
		PSI_MONITOR_ERROR_MSG("Warning! update hCurrTPHdl's ucNitVersion failed!\n");
		return AL_FAILURE;
	}
	if( AL_SUCCESS != AL_DB_UpdateDetailFieldByName( hCurrTPHdl, (UINT8*)"ucTSIDNum", &g_u8CurrNitTSIDNum) )
	{
		PSI_MONITOR_ERROR_MSG("Warning! update hCurrTPHdl's ucTSIDNum failed!\n");
		return AL_FAILURE;
	}
	if( AL_SUCCESS != AL_DB_UpdateDetailFieldByName( hCurrTPHdl, (UINT8*)"usTSIDList", &g_u16CurrNitTSIDList) )
	{
		PSI_MONITOR_ERROR_MSG("Warning! update hCurrTPHdl's usTSIDList failed!\n");
		return AL_FAILURE;
	}

	return AL_SUCCESS;
}

AL_Return_t AI_PSI_Monitor_GetVariedTpListFreq(al_uint32 *pu32TpListFreq)
{
	memcpy( pu32TpListFreq, g_u32TpListFreq, TDB_MAX_TSNUM_WITHIN_NETWORK*sizeof(al_uint32));

	return AL_SUCCESS;
}
#endif

/**
* @brief Get current program audio component data.
*
* psi monitor received audio stream not do parse, store to cash buffer, provide to app get.
*
* @param pAudio[output] audio component data.
*
* @param pu16AudioNum[output] audio total count.
*
* @param pu16MinAudioPid[output] min audio pid.
*
* @param pu8VideoPidCount[output] video pid count.
*
* @return AL_SUCCESS get current program audio is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_PSI_Monitor_GetCurrProgAudio(AL_PsiMon_AudioComp_t *pAudio,al_uint16 *pu16AudioNum,
	al_uint16 *pu16MinAudioPid, al_uint8 *pu8VideoPidCount)
{
	al_uint16 u16Count = 0;
	AL_PsiMon_AudioComp_t *pList = al_null;

	if (pAudio == al_null && pu16AudioNum == al_null && pu16MinAudioPid == al_null && pu8VideoPidCount == al_null)
	{
		return AL_INVALID_PARAM;
	}

	PSIMON_MUTEX_LOCK(g_PsiMonMutex);

	if (pAudio != al_null || pu16AudioNum != al_null)
	{
		pList = g_pstCurrAudioCompList;

		while(pList)
		{
			if (pAudio != al_null)
			{
				pAudio[u16Count].u8StreamType = pList->u8StreamType;
				pAudio[u16Count].u16ElementaryPid = pList->u16ElementaryPid;
				pAudio[u16Count].u16DescLen = pList->u16DescLen;
				pAudio[u16Count].pu8Desc = pList->pu8Desc;
			}
#if 0
			/* add for debug used */
			al_uint16 i = 0;
			if (pAudio[u16Count].u16DescLen > 0)
			{
				printf("descriptor data: \n");
				for (i = 0; i< pAudio[u16Count].u16DescLen; i++)
				{
					printf("0x%x", (pAudio[u16Count].pu8Desc)[i]);
				}
				printf("\n");
			}
			/* end */
#endif
			u16Count++;
			pList = pList->pstNext;
		}

		if (pu16AudioNum != al_null)
		{
			*pu16AudioNum = u16Count;
		}
	}

	if (pu16MinAudioPid != al_null)
	{
		*pu16MinAudioPid = g_u16MinAudioPid;
	}

	if (pu8VideoPidCount != al_null)
	{
		*pu8VideoPidCount = g_u8VideoPidCount;
	}

	PSIMON_MUTEX_UNLOCK(g_PsiMonMutex);

	return AL_SUCCESS;
}

/**
* @brief Get new srv position.
*
* For dispose service move descriptor, it is include new service information.
*
* @param pSrvPosition[output] new service information, service id/ts id/org net id.
*
* @return AL_SUCCESS get new service position is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_PSI_Monitor_GetNewSrvPosition(AL_PsiMon_NewSrvPosition_t *pSrvPosition)
{
	if (pSrvPosition == al_null)
	{
		return AL_INVALID_PARAM;
	}

	*pSrvPosition = g_stNewServiceLocation;

	return AL_SUCCESS;
}

/**
* @brief psi monitor get FTA data.
*
* @ param pu8Data[output] the FTA data.
*
* @return AL_SUCCESS get dtg cmg data is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_PSI_Monitor_GetFTAData(al_uint8 *pu8Data)
{
	if (pu8Data == al_null)
	{
		return AL_INVALID_PARAM;
	}

	*pu8Data = g_u8FTADataData;

	return AL_SUCCESS;
}

/**
* @brief psi monitor get HotelMode->ChannelScanLock status to limit PAT SDT Monitor.
*
* @param ChannelScanLock status .
*
* @return void.
*/

void AL_PSI_Monitor_SetChannelScanLock(al_uint32 u32Lock)
{
    if(u32Lock)
        g_bChanlScanLock = al_true;
    else
        g_bChanlScanLock = al_false;
}

/**
* @brief psi monitor get CA data.
*
* @ param pu16Data[output] the CA data.
*
* @return AL_SUCCESS get CA data is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_PSI_Monitor_GetCAData(al_uint16 *pu16Data)
{
	if (pu16Data == al_null)
	{
		return AL_INVALID_PARAM;
	}

	*pu16Data = g_CA_SYS_ID;

	return AL_SUCCESS;
}

/**
* @brief Check psi monitor sipsi state.
*
* This function used to check psi monitor sipsi info state,( NOT_RUNNING_REPLACEMENT_EXIST,
* NOT_RUNNING_FLAG, SCRAMBLED_REPLACEMENT_EXIST, NOT_RUNNING_REPLACED, SCRAMBLED_REPLACED).
*
* @param u32State[input] sipsi state.
*
* @param pParam[output] sipsi state's parameter, program handle for replacement.
*
* @return al_ture if state exist, al_false if state not exist.
*/
al_bool AL_PSI_Monitor_CheckState(al_uint32 u32State, AL_RecHandle_t *pParam)
{
	if((g_u32SipsiInfoState&u32State) == u32State)
	{
		switch (u32State)
		{
			case AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACEMENT_EXIST:
				if (pParam != al_null)
				{
					*pParam = g_hReplacement[AI_PSIMONITOR_REPLACEMENT_TYPE_NOT_RUNNING];
				}
				break;

			case AL_PSIMONITOR_STATE_NOT_RUNNING_REPLACED:
				if (pParam != al_null)
				{
					*pParam = g_hReplaced[AI_PSIMONITOR_REPLACEMENT_TYPE_NOT_RUNNING];
				}
				break;

			case AL_PSIMONITOR_STATE_SCRAMBLED_REPLACEMENT_EXIST:
				if (pParam != al_null)
				{
					*pParam = g_hReplacement[AI_PSIMONITOR_REPLACEMENT_TYPE_SCRAMBLE];
				}
				break;

			case AL_PSIMONITOR_STATE_SCRAMBLED_REPLACED:
				if (pParam != al_null)
				{
					*pParam = g_hReplaced[AI_PSIMONITOR_REPLACEMENT_TYPE_SCRAMBLE];
				}
				break;

			case AL_PSIMONITOR_STATE_SIMULCAST_REPLACEMENT_EXIST:
				if (pParam != al_null)
				{
					*pParam = g_hReplacement[AI_PSIMONITOR_REPLACEMENT_TYPE_SIMLCASE];
				}
				break;

			case AL_PSIMONITOR_STATE_SIMULCAST_REPLACED:
				if (pParam != al_null)
				{
					*pParam = g_hReplaced[AI_PSIMONITOR_REPLACEMENT_TYPE_SIMLCASE];
				}
				break;

#ifdef EPG_REPLACE
			case AL_PSIMONITOR_STATE_EPG_REPLACEMENT_EXIST:
				if (pParam != al_null)
				{
					*pParam = g_hReplacement[AI_PSIMONITOR_REPLACEMENT_TYPE_EPG];
				}
				break;

			case AL_PSIMONITOR_STATE_EPG_REPLACED:
				if (pParam != al_null)
				{
					*pParam = g_hReplaced[AI_PSIMONITOR_REPLACEMENT_TYPE_EPG];
				}
				break;
#endif
			default:
				break;
		}

		return al_true;
	}
	return al_false;
}


#ifdef __cplusplus
}
#endif
