扫台2

理解不深,尽量记录扫台流程关于si的部分,免得以后又重新看。

结合上篇《扫台》,直接从ScanThread线程xWorkerThread状态机看起。

si_agent_threadfuntion

SI_AGENT_STATUS_STOPPED

xWorkerThread CH_SCAN_STATE_INIT

关注CH_SCAN_STATE_INIT这个case,跑了xStageInit()这个函数:

1
2
3
4
5
6
7
8
9
10
11
12
/*
* vendor/realtek/frameworks/native/appclass/ \
* MediaControl/Component/Channel/Scan/TableScanner.cpp
*/

void CTableScanner::xStageInit()
{
// 省略代码段
m_pFreqScanDetector->Mf_ScanInit(scanMode, param, m_bDelNosignalMux,scanModeEx);
// 省略代码段
m_scanState = CH_SCAN_STATE_BEGIN_FREQ;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 
* vendor/realtek/frameworks/native/appclass/ \
* MediaControl/Component/Channel/Scan/DtvFreqDetector.cpp
*/

void CDtvFreqDetector::Mf_ScanInit(
CH_SCAN_MODE scanMode,
UINT32 param,
bool bDelNoSignalMux,
CH_SCAN_MODE_EX modeEx
)
{
// 省略代码段
pDtvFlow->PrepareAutoScanFlow();
// 省略代码段
m_pIDtvMedia->GetSiMgr()->ScanInit(getSiScanType(scanMode), param, typeEx);
// 省略代码段
}
1
2
3
4
5
6
7
8
9
10
11
/*
* vendor/realtek/frameworks/native/appclass/ \
* DriverBasedDtvApp/DriverBasedDtvApp.cpp
*/

bool DriverBasedDtvApp::PrepareAutoScanFlow()
{
ALOGD("[%s %s %d]\n",__FILE__, __func__, __LINE__);
//Q: need to stop VDEC and ADEC if they are present?
return OpenSdec();
}

可见扫台前有个OpenSdec的动作,Sdec是System Decoder的意思(类似的还有用Vdec和Adec分别表示Video Decoder、Audio Decoder)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
* vendor/realtek/frameworks/native/appclass/ \
* DriverBasedDtvApp/DriverBasedDtvApp.cpp
*/

bool DriverBasedDtvApp::OpenSdec()
{
if(m_sdec < SDEC_CH_MAX)
return true;

int index = RHAL_SDEC_AcquireChannel("DTV_LIVE", SDEC_CH_PVR_ONLY);
if(index < 0)
{
ALOGE("[%s %d] fail to acquire SDEC\n", __func__, __LINE__);
return false;
}
m_sdec = (SDEC_CHANNEL_T)index;

ALOGD("[%s %d] m_sdec = %d\n", __func__, __LINE__, m_sdec);
m_sdecSrc = (m_sdec == SDEC_CH_A) ? HAL_AUDIO_RESOURCE_SDEC0 : HAL_AUDIO_RESOURCE_SDEC1;
if(RHAL_SDEC_InitChannel(m_sdec) != API_OK)
{
ALOGE("[%s %d] ERROR : RHAL_SDEC_InitChannel fails. m_sdec = %d", __func__, __LINE__, m_sdec);
return false;
}
if(RHAL_SDEC_SetBufferOwner(m_sdec, SDEC_KERNEL_DRIVER) != API_OK)
{
ALOGE("[%s %d] ERROR : RHAL_SDEC_Run fails. m_sdec = %d", __func__, __LINE__, m_sdec);
return false;
}
ALOGD("[%s %d] Set RHAL_SDEC_EnableTimeStampPadding. m_sdec = %d", __func__, __LINE__, m_sdec);
if(RHAL_SDEC_EnableTimeStampPadding(m_sdec, true) != API_OK)
{
ALOGE("[%s %d] ERROR : RHAL_SDEC_EnableTimeStampPadding fails. m_sdec = %d", __func__, __LINE__, m_sdec);
return false;
}
if(RHAL_SDEC_Run(m_sdec) != API_OK)
{
ALOGE("[%s %d] ERROR : RHAL_SDEC_Run fails. m_sdec = %d", __func__, __LINE__, m_sdec);
return false;
}
if(!SetSdecInputConfig())
return false;

if(m_pSiInterface == 0)
m_pSiInterface = new CSiInterface(this, m_tvsystem);

if(m_pSiInterface)
{
m_pSiInterface->InitSiEngine(m_sdec, m_siHandle);
// ConnectAudio to decide audio preiview on
ALOGD("[%s %d] Set audio preview on first, AudioPreviewOn: %d\n", __func__, __LINE__, m_status.bIsAudioPreviewOn);
m_pSiInterface->SetAudioPreviewMode(m_status.bIsAudioPreviewOn);
}
return true;
}

然后InitSiEngine,Engine是用来干嘛的?理解不足,名字就像做一些si管理统筹工作的,然后siEngineOut、m_siEngineIn做一些状态更新,发消息等的信息输入输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/*
* vendor/realtek/frameworks/native/appclass/ \
* DriverBasedDtvApp/CSiInterface.cpp
*/

bool CSiInterface::InitSiEngine(SDEC_CHANNEL_T sdec, unsigned int siHandle)
{
SI_ENGINE_OUT siEngineOut;
int ret = -1;

siEngineOut.InsertFilterList = insertFilterList;
siEngineOut.RemoveFilterList = removeFilterList;
siEngineOut.RemoveAllFilters = removeAllFilters;
siEngineOut.SetActiveComponent = setActiveComponent;
siEngineOut.PostEvent = postEvent;
siEngineOut.SetSiState = setSiState;
siEngineOut.CheckScramble = checkScramble;
siEngineOut.ResetPosition = resetPosition;
siEngineOut.FeedbackPrivateInfo = feedbackPrivateInfo;
siEngineOut.GetPIDByFilterType = getPIDByFilterType;//#ifdef ENABLE_MHEG5
m_siHandle = siHandle;
m_sdec = sdec;

memset(&m_siEngineIn, 0, sizeof(m_siEngineIn));
if (m_tvSystem== RT_TV_SYSTEM_ATSC){
#ifdef ATSC_T
ret = AttachSiAtscEngine((unsigned int)this, &siEngineOut, m_siHandle, &m_siEngineIn);
#endif
}
else if (m_tvSystem==RT_TV_SYSTEM_DVB){
#ifdef DVB_T
ret = AttachSiEngine((unsigned int)this, &siEngineOut, m_siHandle, &m_siEngineIn);
#endif
}
else {
ALOGE("%s_%d: unknown tvsystem, fail to InitSiEngine\n", __func__, __LINE__);
return false;
}
if(ret == 1)
{
m_siEngineIn.SetSdecCh(siHandle, (int)m_sdec);
m_bSiEngineAttached = true;
RemoveAllFilters();
}
else
ALOGE("%s_%d: unknown tvsystem, fail to InitSiEngine\n", __func__, __LINE__);


return m_bSiEngineAttached;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/tpInterface/PVR/siEngine.c
*/

int AttachSiEngine(
unsigned int navHandle, /* IN: handle of the nav outside */
SI_ENGINE_OUT* pSiEngineOut, /* IN: outgoing interface for SI engine */
unsigned int siHandle, /* IN: handle of the SI engine */
SI_ENGINE_IN* pSiEngineIn /* OUT: incoming interface for SI engine */
)
{
void *tp1, *tp2;
int ret = 1;

if (!pSiEngineOut || !pSiEngineIn || !siHandle)
return FALSE;

SI_Get_TP((SI*)siHandle, &tp1);

SI_TPInterface_New(&tp2, navHandle, (void*)pSiEngineOut
#ifdef SI_USE_SDEC
,siHandle,SDEC_CH_MAX
#endif
);

SI_Set_TP((SI*)siHandle, tp2);

if(tp1)
{
SI_TPInterface_Destroy(&tp1);
}

// Functions for TS engine to call upon.
pSiEngineIn->StoreSiPacket = SI_PVRInterface_StorePackets;
pSiEngineIn->StoreSiState = SI_PVRInterface_StoreSiState;
pSiEngineIn->Flush = SI_PVRInterface_Flush;
pSiEngineIn->GetBufferLength= SI_GetRingBufferLength;
#ifdef SI_USE_SDEC
pSiEngineIn->SetSdecCh = SetSdecCh;
#endif

#ifdef FEATURE_001
pSiEngineIn->GetPAT = NULL;
#endif // FEATURE_001

return ret;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/api/SI_Api.c
*/

ErrCode SI_Set_TP(
SI *pSI,
void *tp
)
{
SI_API_BEGIN();
SI_ASSERT(pSI);

pSI->tp = tp;
pSI->collector->tp = tp;
SI_Agent_New(&pSI->agent, pSI, pSI->db, pSI->collector, pSI->tp);

SI_API_RETURN(SI_ERR_OK);
}

这个SI_Agent_New还挺长,先记一点关键的,这个Agent的概念又该怎么理解呢?不懂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/agent/SI_Agent.c
*/

ErrCode SI_Agent_New(
SI_AGENT **ppAgent,
SI *pSI,
SI_DATABASE *pDatabase,
SI_COLLECTOR *pCollector,
void *pTPHandle
)
{
//省略代码段
agent->agentObjHandle = (void*)SiAgtIF_CreateSiAgentObject("UND", pSI, pDatabase, pTPHandle);
//省略代码段
agent->status = SI_AGENT_STATUS_STOPPED;
//省略代码段
SiAgtIF_RegisterCBF(agent->agentObjHandle, SI_Callback_ScanChannel, SI_AGENT_CBF_TYPE_SCAN_CHANNEL);
//省略代码段
pthread_create(&__agentThread, NULL, (void*)&si_agent_threadfuntion, NULL);
//省略代码段
}

这里要分3部分看:

  • SiAgtIF_CreateSiAgentObject

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /*
    * vendor/realtek/frameworks/native/appclass/ \
    * Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siAgentInterface.c
    */

    SIAGENT_OBJECT_P SiAgtIF_CreateSiAgentObject( char* pAgentObjectName, SI_HANDLE si, SIDB_HANDLE handleSidb, DEMUXER_HANDLE handleDemuxer )
    {
    return SiAgent_CreateSiAgentObject( pAgentObjectName, si, handleSidb, handleDemuxer );
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    /*
    * vendor/realtek/frameworks/native/appclass/ \
    * Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siAgentObject.c
    */

    SIAGENT_OBJECT_P SiAgent_CreateSiAgentObject( char* pAgentObjectName, SI_HANDLE si, SIDB_HANDLE handleSidb, DEMUXER_HANDLE handleDemuxer )
    {
    //省略代码段
    //Private Method:
    pSiAgentObj->ExecMainTaskSM = SiAgentObj_ExecMainTaskSM ;
    pSiAgentObj->ExecSubTaskSM = SiAgentObj_ExecSubTaskSM ;
    pSiAgentObj->CheckSubTaskInQueue = SiAgentObj_CheckSubTaskInQueue ;
    pSiAgentObj->GetSubTaskFromQueue = SiAgentObj_GetSubTaskFromQueue ;
    pSiAgentObj->CheckMainTaskInQueue = SiAgentObj_CheckMainTaskInQueue ;
    pSiAgentObj->GetMainTaskFromQueue = SiAgentObj_GetMainTaskFromQueue ;
    //Public Method:
    pSiAgentObj->GetSidbHandle = SiAgentObj_GetSidbHandle ;
    pSiAgentObj->GetObjectId = SiAgentObj_GetObjectId ;
    pSiAgentObj->Run = SiAgentObj_Run ;
    pSiAgentObj->CheckAllSmIdle = SiAgentObj_CheckAllSmIdle ;
    pSiAgentObj->InsertMainTaskIntoQueue = SiAgentObj_InsertMainTaskIntoQueue ;
    pSiAgentObj->StopAllTask = SiAgentObj_StopAllTask ;
    pSiAgentObj->RegisterCBF = SiAgentObj_RegisterCBF ;
    //省略代码段
    }

    这里主要是设置SiAgentObject的一些方法,比如Run、ExecMainTaskSM等,后面会用到。

  • SI_Callback_ScanChannel

    设置回调,后面会用到:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    /*
    * vendor/realtek/frameworks/native/appclass/ \
    * Si/liveTV_SiDvb/librtd/si4/api/SI_Api.c
    */

    void *SI_Callback_ScanChannel(SI *si, void *arg)
    {
    SI_DATABASE_TS_NODE *ts = (SI_DATABASE_TS_NODE*)arg;

    //省略代码段

    //kjw note: SI_STATE_AUTOSCAN has thread issue. Beware it if someone modify the code in the future!
    if( SI_HAS_STATE(si->state, SI_STATE_AUTOSCAN) ) {

    //to update scanned ch count for AP
    if( ts != NULL) {
    if(!(SI_HAS_STATE(si->state, SI_STATE_UPDATE)&&ts->strength==(MANUAL_SCAN_STRENGTH-STRENGTH_DIFF_THRESHOLD)))//keep manual scan service in high priority for update scan
    {
    ts->strength=si->strength;
    ts->snr=(unsigned short)(si->snr*100);
    }
    printf("\033[1;31m %s=>freq: %d, strength:%d ,snr:%d \033 [m\n",__FUNCTION__,ts->frequency,ts->strength,ts->snr);
    SI_Channel_UpdateChList_Append(si->chMgr, si->db, ts,true);
    #ifdef ENABLE_NEW_DVB
    if(IS_SUPPORT_TRD(si))
    {
    si_BuildTRD(si,ts);
    }
    #endif
    }
    }
    else
    { //manual scan(tuner or file playback scan)

    if( ts != NULL) {
    si_channel_updatePartialChList(si->chMgr, si->db, ts->frequency,FALSE,FALSE,FALSE,SI_TID_ALL);
    ts->snr=ts->strength=MANUAL_SCAN_STRENGTH-STRENGTH_DIFF_THRESHOLD;//best mux, manual scan is high priority


    }
    else
    { //no PAT or PMT
    }
    }
    //if(SI_IS_MONITOR_NETWORK_SDT(si))
    if(ts!=NULL)
    {

    if(SI_IS_ADD_CH_IN_NO_SDT(si))
    {
    int Tv=1,Radio=1,Data=1;
    SI_CHANNEL_EXT *_ch;
    _ch = si->chMgr->chList;
    while(_ch)
    {
    if(_ch->oriChannelNameLen == 0)
    {
    if( get_ServiceType(si,_ch->serviceType)==SI_DVB_SERVICE_DTV)
    {
    snprintf((char*)_ch->super.channelName,SI_CH_CHANNELNAME_MAXLEN-1,"TV %d",Tv);
    _ch->super.channelNameLen=strlen((char*)_ch->super.channelName);
    Tv++;
    }
    else if( get_ServiceType(si,_ch->serviceType)==SI_DVB_SERVICE_RADIO)
    {
    snprintf((char*)_ch->super.channelName,SI_CH_CHANNELNAME_MAXLEN-1,"Radio %d",Radio);
    _ch->super.channelNameLen=strlen((char*)_ch->super.channelName);
    Radio++;
    }
    else if( get_ServiceType(si,_ch->serviceType)==SI_DVB_SERVICE_DATA)
    {
    snprintf((char*)_ch->super.channelName,SI_CH_CHANNELNAME_MAXLEN-1,"Data %d",Data);
    _ch->super.channelNameLen=strlen((char*)_ch->super.channelName);
    Data++;
    }

    }
    _ch = _ch->next;
    }

    }

    //省略代码动态

    SiMessage_Store(&si->mq, SI_MESSAGE_CH_INFO_READY,
    #if 0//def FIX_DTV_LABS_HK_ISSUE_48
    pDupLcnList
    #else
    arg == NULL ? 1 : 0
    #endif
    );

    //省略代码段
    }
  • si_agent_threadfuntion

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    /*
    * vendor/realtek/frameworks/native/appclass/ \
    * Si/liveTV_SiDvb/librtd/si4/agent/SI_Agent.c
    */

    static void si_agent_threadfuntion()
    {
    SI_AGENT_LIST_NODE *agentNode;
    SI_AGENT *agent=NULL;
    //int checkSize=0,sleepCount=0, countDown = 0;
    //not more than 100ms.
    //stream may be 4MB/s.
    //checkSize=64*188;//almost=>(4*1024*1024)*3/10/10/10;
    pthread_setname_np(pthread_self(), __FUNCTION__);
    while(!__stopAgentThread)
    {
    //sleepCount=0;
    pthread_mutex_lock(&__agentListMutex);
    agentNode = __agentList;
    while(agentNode)
    {
    agent = agentNode->agent;
    agentNode = agentNode->next;
    SI_Agent_CollectSection(agent);

    // Split SI_SLEEP(30) to 3 times to avoid overflowing while huge data comes
    /*
    countDown = 3 ;
    while(countDown--)
    {
    if (agent && !__stopAgentThread && sleepCount<3 &&
    SI_PVRTP_GetRingBufferLength((unsigned int)agent->tp)<checkSize) {
    SI_SLEEP(10);
    sleepCount++;
    }
    }*/
    }

    pthread_mutex_unlock(&__agentListMutex);

    // sleep to context switch while SI_Agent_New blocked on mutex
    //if (sleepCount)
    {
    SI_SLEEP(10);
    }
    }
    pthread_exit(NULL);

    }

    主要看SI_Agent_CollectSection这个:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    /*
    * vendor/realtek/frameworks/native/appclass/ \
    * Si/liveTV_SiDvb/librtd/si4/agent/SI_Agent.c
    */

    void * SI_Agent_CollectSection(SI_AGENT *agent)
    {
    BOOL stopped;
    if (agent==NULL)
    return NULL;
    pthread_mutex_lock(&agent->mutexCollect);
    if(agent->waitingForReset == TRUE)
    {
    SI_Collector_Reset(agent->collector,TRUE,TRUE);
    agent->waitingForReset=FALSE;
    } else {
    if(agent->status == SI_AGENT_STATUS_TO_STOP)
    {
    stopped = FALSE;
    while(!stopped)
    {
    SiAgtIF_Run(agent->agentObjHandle);//close all filter
    SiAgtIF_CheckAllSmIdle(agent->agentObjHandle, &stopped);
    }
    agent->status = SI_AGENT_STATUS_STOPPED;
    }
    else if(agent->status == SI_AGENT_STATUS_RUNNING)
    {
    SiAgtIF_Run(agent->agentObjHandle);
    SI_Collector_CollectSection(agent->collector, agent->db, agent->tp);
    }
    }
    pthread_mutex_unlock(&agent->mutexCollect);
    return NULL;
    }

    刚才SI_Agent_New的时候,已经把SI_AGENT_STATUS状态设定为SI_AGENT_STATUS_STOPPED,所以现在si_agent_threadfuntion这个线程里,基本是卡住了的。

至此,CH_SCAN_STATE_INIT阶段结束了,紧跟着的CH_SCAN_STATE_BEGIN_FREQ阶段没有si相关的内容,可以跳过,接着来到CH_SCAN_STATE_SCANNING阶段。

RunStateProc FREQ_SCAN_STATE_CHECK_FRONTEND

函数xStageCheckFrontend如下:

1
2
3
4
5
6
7
8
9
10
11
12
/*
* vendor/realtek/frameworks/native/appclass/ \
* MediaControl/Component/Channel/Scan/DtvFreqDetector.cpp
*/

void CDtvFreqDetector::xStageCheckFrontend()
{
//省略代码段
m_pIDtvMedia->GetSiMgr()->ScanStart(m_curFreq, m_modulation, m_curBandwidth, symbolrate, m_curPhyChNum, tuner->getRFStrength(), tuner->getSignalSNR(), m_serviceID);

m_scanState = FREQ_SCAN_STATE_CHECK_SI;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
* vendor/realtek/frameworks/native/appclass/ \
* MediaControl/Component/Si/DvbSiMgr.cpp
*/

void CDvbSiMgr::ScanStart(UINT32 frequency, RT_MODULATION modulation, UINT32 bandwidth, UINT32 symbolrate, UINT32 phyChNum,UINT32 strength,float snr, UINT16 serviceID)
{
SI* siHandle = (SI*)m_pTvMedia->GetDtvFlow()->GetSiHandle();
SI_DVB_MODULATION siModulation;

switch(modulation)
{
case RT_MOD_QAM16:
siModulation=SI_DVB_16_QAM;
break;
case RT_MOD_QAM32:
siModulation=SI_DVB_32_QAM;
break;
case RT_MOD_QAM64:
siModulation=SI_DVB_64_QAM;
break;
case RT_MOD_QAM128:
siModulation=SI_DVB_128_QAM;
break;
default:
case RT_MOD_QAM256:
siModulation=SI_DVB_256_QAM;
break;
}

SI_SetState(siHandle, SI_STATE_SCAN);
SI_ScanChannelEx(siHandle, frequency, 0, bandwidth,siModulation,symbolrate, strength,snr,serviceID,(unsigned char)phyChNum);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/api/SI_Api.c
*/

ErrCode SI_ScanChannelEx(
SI *pSI,
unsigned int frequency,
int offset,
unsigned int bandwidth,
unsigned char modulation,
unsigned int symbolrate,
unsigned int strength,
float snr,
unsigned short serviceID,
unsigned char phyChNum
)
{
//省略代码段

//force agent to start.
SI_Start(pSI);

//省略代码段

// call si agent
SI_Agent_ScanChannel(pSI->agent, frequency);

//debug...
SI_DB_PRINT_ALL_TSNODE(pSI->db);

SI_API_RETURN(SI_ERR_OK);
}

其中,SI_Start方法会把SI_AGENT_STATUS状态更新为SI_AGENT_STATUS_RUNNING,SI_Agent_ScanChannel方法则设置FilterTaskPool:

  • SI_Start(pSI)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /*
    * vendor/realtek/frameworks/native/appclass/ \
    * Si/liveTV_SiDvb/librtd/si4/api/SI_Api.c
    */

    ErrCode SI_Start(
    SI *pSI
    )
    {
    SI_API_BEGIN();
    SI_ASSERT(pSI);

    // start si agent thread
    SI_Agent_Start(pSI->agent);

    SI_API_RETURN(SI_ERR_OK);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /*
    * vendor/realtek/frameworks/native/appclass/ \
    * Si/liveTV_SiDvb/librtd/si4/agent/SI_Agent.c
    */

    ErrCode SI_Agent_Start(SI_AGENT *pAgent)
    {
    SI_AGENT_BEGIN();
    SI_ASSERT(pAgent);

    SIAG_IF_LOCK(pAgent);

    pAgent->status = SI_AGENT_STATUS_RUNNING;

    #ifdef _SI_DEBUG_AGENT_LIFE
    {
    pthread_t self;
    self = pthread_self();
    printf("siA call st from %p addr:%p\n", (void*)self, pAgent);
    }
    #endif//_SI_DEBUG_AGENT_LIFE

    SIAG_IF_UNLOCK(pAgent);

    SI_AGENT_RETURN(SI_ERR_OK);
    }
  • SI_Agent_ScanChannel(pSI->agent, frequency)

    这里也设置了一遍SI_AGENT_STATUS_RUNNING

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    /*
    * vendor/realtek/frameworks/native/appclass/ \
    * Si/liveTV_SiDvb/librtd/si4/agent/SI_Agent.c
    */

    ErrCode SI_Agent_ScanChannel(
    SI_AGENT *pAgent,
    unsigned int frequency
    )
    {
    //省略代码段
    if(frequency == SI_API_SCANFILE_FREQUENCY)
    {
    SiAgtIF_ScanProgram((SIAGENT_OBJECT_P)pAgent->agentObjHandle, ts);
    }
    else
    {
    SiAgtIF_ScanChannel((SIAGENT_OBJECT_P)pAgent->agentObjHandle, ts);
    }

    pAgent->status = SI_AGENT_STATUS_RUNNING;
    //省略代码段
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /*
    * vendor/realtek/frameworks/native/appclass/ \
    * Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siAgentInterface.c
    */

    BOOL SiAgtIF_ScanChannel( SIAGENT_OBJECT_P pSiAgentObj, TABLE_TREE_TS_LAYER_P tsNode )
    {
    MAIN_TASK_P pMainTask ;
    pMainTask = SiAgent_SM_GenMainTask_ScanCh(tsNode);
    INSERT_MAIN_TASK_INTO_QUEUE( pSiAgentObj, pMainTask ) ;
    return TRUE ;
    }

    以上可以看到,通过SiAgent_SM_GenMainTask_ScanCh设置pMainTask,然后将其放入Queue中,SIAGENT_THREAD_SLEEP这个1毫秒不知道是干嘛的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #define SIAGENT_THREAD_SLEEP_TIME 1

    #define SIAGENT_THREAD_SLEEP(ms) {\
    struct timespec delay ;\
    delay.tv_sec = ms / 1000 ;\
    delay.tv_nsec = ((ms % 1000)*1000000) ;\
    nanosleep(&delay,NULL) ;\
    }

    #define INSERT_MAIN_TASK_INTO_QUEUE(pAgent, pMainTask) {\
    pthread_mutex_lock(&siAgentTaskMutex);\
    pAgent->InsertMainTaskIntoQueue(pAgent, pMainTask);\
    pthread_mutex_unlock(&siAgentTaskMutex);\
    SIAGENT_THREAD_SLEEP(SIAGENT_THREAD_SLEEP_TIME);\
    }

    看看是怎么设置pMainTask:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    /*
    * vendor/realtek/frameworks/native/appclass/ \
    * Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siAgentStateMachine.c
    */

    MAIN_TASK_P SiAgent_SM_GenMainTask_ScanCh( TABLE_TREE_TS_LAYER_P tsAddr )
    {
    MAIN_TASK_P pMainTask ;

    pMainTask = (MAIN_TASK_P) SM_MALLOC( sizeof(MAIN_TASK_T) ) ;
    if(pMainTask!=NULL)
    {
    memset(pMainTask,0,sizeof(MAIN_TASK_T) ) ;
    pMainTask->stateNumber = START_EXEC_TASK ;
    pMainTask->lastStateNumber = NO_PREVIOUS_STATE ;
    pMainTask->StateMachineFunction = SiAgent_SM_Main_ScanCh ;
    pMainTask->pFilterTaskPool = NULL ;
    pMainTask->argScanCh.tsAddr = tsAddr ;
    }

    return pMainTask ;
    }

    主要是要设置StateMachineFunction这个,看看它指向的SiAgent_SM_Main_ScanCh,同时请注意,此刻pFilterTaskPool是设置为空的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    /*
    * vendor/realtek/frameworks/native/appclass/ \
    * Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siAgentStateMachine.c
    */

    void SiAgent_SM_Main_ScanCh( SIAGENT_OBJECT_P pSiAgentObj, MAIN_TASK_P pMainTask)
    {
    int noWaitCount=0;
    unsigned int execCount = 1 ;
    PROGRAMS_INFO_P pProgramsInfo ;
    unsigned int i ;
    unsigned int pmtCount,neeToWaitCAT=0,count=0;

    for( ; execCount > 0 ; execCount -- )
    {
    MAIN_SM_STATE_MSG( pSiAgentObj, pMainTask, "MainTask-ScanCH");

    switch(pMainTask->stateNumber)
    {
    case SM_MAIN_SCANCH_ST_START:
    //Reset Bean Packer
    SiAgtFW_ResetBeanPacker( pSiAgentObj, TRUE);
    pMainTask->pFilterTaskPool = SiAgent_GenScanChGetPatFtp( pSiAgentObj, pMainTask->argScanCh.tsAddr );
    pMainTask->stateNumber = SM_MAIN_SCANCH_ST_WAIT_GET_PAT ;
    break ;
    case SM_MAIN_SCANCH_ST_END:

    if( pMainTask->pFilterTaskPool != NULL )
    {
    SiAgent_StopAllFilterTasks( pSiAgentObj, pMainTask->pFilterTaskPool );
    SM_FREE( pMainTask->pFilterTaskPool );
    }
    break ;
    case SM_MAIN_SCANCH_ST_WAIT_GET_PAT:
    NULL_CHECK(pMainTask->pFilterTaskPool,pMainTask->stateNumber);
    NULL_CHECK(pMainTask->pFilterTaskPool->filterTask,pMainTask->stateNumber);
    if( pMainTask->pFilterTaskPool->totalFilterTaskNumber == pMainTask->pFilterTaskPool->doneFilterTaskNumber ||
    pMainTask->pFilterTaskPool->filterTask[0].filterTaskState == FILTER_TASK_STATE_DONE)
    {

    if(( pMainTask->pFilterTaskPool->filterTask[0].typeTimeoutClosed.closedReason == FILTER_TASK_CLOSED_REASON_TIMEOUT )&&
    (!SI_IS_SCAN_CH_SKIP_PAT_INVALID(pSiAgentObj->si)))
    { //No PAT
    SM_FREE( pMainTask->pFilterTaskPool );
    pMainTask->stateNumber = SM_MAIN_SCANCH_ST_END ;

    #ifdef _DEBUG_SIAGENT_SM_
    printf("No PAT\n");
    #endif //_DEBUG_SIAGENT_SM_

    //Msg to AP : No VC in TS (No PAT) !!!!!!!!!!!!!
    if(pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_SCAN_CHANNEL] != NULL)
    {
    pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_SCAN_CHANNEL](pSiAgentObj->si, NULL);
    }
    }
    else
    {
    BOOL bOpenPMT=TRUE;
    //Got PAT
    #if 0
    if(pSiAgentObj->si->eScanBase == SI_SCAN_SDT_BASE && pMainTask->pFilterTaskPool->totalFilterTaskNumber>1)
    {
    if(pMainTask->pFilterTaskPool->filterTask[1].filterTaskState != FILTER_TASK_STATE_DONE)
    {
    break;
    }
    }
    #endif
    #ifdef _DEBUG_SIAGENT_SM_
    printf("Got PAT\n");
    #endif //_DEBUG_SIAGENT_SM_
    for (i=1; i<pMainTask->pFilterTaskPool->totalFilterTaskNumber; i++) {
    if (pMainTask->pFilterTaskPool->filterTask[i].typeTimeoutClosed.closedReason == FILTER_TASK_CLOSED_REASON_TIMEOUT) {
    if (pMainTask->pFilterTaskPool->filterTask[i].chkTableReceiveFunction == CHK_TABLE_RECEIVE_FUNC_A_NIT) {
    printf("No NIT.\n");
    } else if (pMainTask->pFilterTaskPool->filterTask[i].chkTableReceiveFunction == CHK_TABLE_RECEIVE_FUNC_A_SDT) {
    printf("No SDT.\n");
    }
    } else {
    if (pMainTask->pFilterTaskPool->filterTask[i].chkTableReceiveFunction == CHK_TABLE_RECEIVE_FUNC_A_NIT) {
    printf("Got NIT.\n");
    } else if (pMainTask->pFilterTaskPool->filterTask[i].chkTableReceiveFunction == CHK_TABLE_RECEIVE_FUNC_A_SDT) {
    printf("Got SDT.\n");
    }
    }
    }

    if(/*SI_IS_UNITYMEDIA(*/pSiAgentObj->si->bSkipPMT/*)*/&&(SI_HAS_STATE(pSiAgentObj->si->state, SI_STATE_AUTOSCAN)
    ||SI_HAS_STATE(pSiAgentObj->si->state, SI_STATE_NETWORKSCAN)))
    {
    bOpenPMT=FALSE;
    }
    SM_FREE( pMainTask->pFilterTaskPool );
    pProgramsInfo = SiAgtFW_GetProgramsInfo( pSiAgentObj, pMainTask->argScanCh.tsAddr );
    pMainTask->pFilterTaskPool = SiAgent_GenScanChGetTablesFtp( pSiAgentObj, pMainTask->argScanCh.tsAddr, pProgramsInfo , /*pSiAgentObj->si->eScanBase == SI_SCAN_SDT_BASE ? FALSE :*/ TRUE,bOpenPMT);
    SiAgtFW_FreeProgramsInfo(pSiAgentObj, &pProgramsInfo );
    pMainTask->stateNumber = SM_MAIN_SCANCH_ST_WAIT_GET_TABLES ;
    }
    }
    break ;
    case SM_MAIN_SCANCH_ST_WAIT_GET_TABLES:
    #ifndef ENABLE_NEW_DVB//why need CAT in NO CA project
    neeToWaitCAT=1;
    #endif
    count=0;
    noWaitCount=0;

    if( SI_HAS_STATE(pSiAgentObj->si->state, SI_STATE_AUTOSCAN) && (/*SI_IS_SATELLITE(pSiAgentObj->si)||*/SI_IS_CABLE(pSiAgentObj->si)) && SiAgtFW_CheckPatExist( pSiAgentObj, pMainTask->argScanCh.tsAddr ) == TRUE
    && SiAgtFW_CheckActualSdtReceive( pSiAgentObj, pMainTask->argScanCh.tsAddr ,TRUE)==TRUE
    && SiAgtFW_CheckActualNitReceive( pSiAgentObj, pMainTask->argScanCh.tsAddr,NULL) == FALSE
    && SiAgtFW_DuplicateNit(pSiAgentObj,pMainTask->argScanCh.tsAddr )==TRUE)
    {
    noWaitCount++;
    }
    NULL_CHECK(pMainTask->pFilterTaskPool,pMainTask->stateNumber);
    NULL_CHECK(pMainTask->pFilterTaskPool->filterTask,pMainTask->stateNumber);
    if ((pMainTask->pFilterTaskPool->totalFilterTaskNumber-1)==pMainTask->pFilterTaskPool->doneFilterTaskNumber) {
    for (i=0; i<pMainTask->pFilterTaskPool->totalFilterTaskNumber; i++) {
    if(i==SI_AGENT_FILTER_GET_SCAN_CH_TABLE_INDEX_CAT)continue;
    if (pMainTask->pFilterTaskPool->filterTask[i].typeTimeoutClosed.closedReason==FILTER_TASK_CLOSED_REASON_RECEIVED) {
    count++;
    }
    }
    #ifndef ENABLE_NIKE_CUNCUNTONG
    if(SI_IS_KABEL_DEUTSCHLAND(pSiAgentObj->si))
    {
    }
    else if (SI_ENABLE_BAT_6100(pSiAgentObj->si)==FALSE &&
    pMainTask->pFilterTaskPool->filterTask[SI_AGENT_FILTER_GET_SCAN_CH_TABLE_INDEX_BAT_6100].typeTimeoutClosed.closedReason==FILTER_TASK_CLOSED_REASON_TIMEOUT) {
    count++;
    }
    #endif
    #ifndef ENABLE_NEW_DVB//why need CAT in NO CA project
    if ((count+1)==pMainTask->pFilterTaskPool->totalFilterTaskNumber) {
    neeToWaitCAT=SiAgtFW_NeedToQueryCAT(pSiAgentObj, pMainTask->argScanCh.tsAddr);
    }
    #endif

    }

    if( ((pMainTask->pFilterTaskPool->doneFilterTaskNumber+noWaitCount) >= pMainTask->pFilterTaskPool->totalFilterTaskNumber ) ||
    ((pMainTask->pFilterTaskPool->totalFilterTaskNumber-1)==pMainTask->pFilterTaskPool->doneFilterTaskNumber &&
    #ifdef ENABLE_NEW_DVB//why need CAT in NO CA project
    pMainTask->pFilterTaskPool->filterTask[SI_AGENT_FILTER_GET_SCAN_CH_TABLE_INDEX_CAT].filterTaskState==FILTER_TASK_STATE_DOING
    #else
    neeToWaitCAT==0 &&
    pMainTask->pFilterTaskPool->filterTask[SI_AGENT_FILTER_GET_SCAN_CH_TABLE_INDEX_CAT].typeTimeoutClosed.closedReason!=FILTER_TASK_CLOSED_REASON_RECEIVED
    #endif
    ) )
    {
    pmtCount = 0 ;



    //if( pMainTask->pFilterTaskPool->totalFilterTaskNumber > SI_AGENT_FILTER_GET_SCAN_CH_TABLE_PREFIX )//for empty PAT
    {
    for( i =0; i < pMainTask->pFilterTaskPool->totalFilterTaskNumber ; i ++ )
    {
    if( pMainTask->pFilterTaskPool->filterTask[i].chkTableReceiveFunction == CHK_TABLE_RECEIVE_FUNC_PMT
    && pMainTask->pFilterTaskPool->filterTask[i].typeTimeoutClosed.closedReason == FILTER_TASK_CLOSED_REASON_RECEIVED )
    {
    pmtCount ++ ;
    }
    }
    }


    if( pmtCount > 0 || pSiAgentObj->si->eScanBase == SI_SCAN_SDT_BASE || pSiAgentObj->si->eScanBase == SI_SCAN_NIT_BASE)
    { //Got PMT
    printf("Got PMT[%d],fail:%d.\n",pmtCount,(pMainTask->pFilterTaskPool->totalFilterTaskNumber-SI_AGENT_FILTER_GET_SCAN_CH_TABLE_PREFIX-pmtCount));
    if( pMainTask->pFilterTaskPool->filterTask[SI_AGENT_FILTER_GET_SCAN_CH_TABLE_INDEX_NIT].typeTimeoutClosed.closedReason == FILTER_TASK_CLOSED_REASON_RECEIVED ) {
    printf("Got NIT.\n");
    #ifdef GET_SCAN_PARAM_FROM_NIT
    pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_GET_NIT](pSiAgentObj->si, NULL);
    #endif
    }
    if( pMainTask->pFilterTaskPool->filterTask[SI_AGENT_FILTER_GET_SCAN_CH_TABLE_INDEX_SDT].typeTimeoutClosed.closedReason == FILTER_TASK_CLOSED_REASON_RECEIVED ) {
    printf("Got SDT.\n");
    }
    if( pMainTask->pFilterTaskPool->filterTask[SI_AGENT_FILTER_GET_SCAN_CH_TABLE_INDEX_CAT].typeTimeoutClosed.closedReason == FILTER_TASK_CLOSED_REASON_RECEIVED ) {
    printf("Got CAT.\n");
    }
    #ifdef ENABLE_NIKE_CUNCUNTONG
    if( pMainTask->pFilterTaskPool->filterTask[SI_AGENT_FILTER_GET_SCAN_CH_TABLE_INDEX_BAT_6000].typeTimeoutClosed.closedReason == FILTER_TASK_CLOSED_REASON_RECEIVED)
    printf("Got BAT_0x6000.\n");
    #else
    if (SI_ENABLE_BAT_6100(pSiAgentObj->si)) {
    if( pMainTask->pFilterTaskPool->filterTask[SI_AGENT_FILTER_GET_SCAN_CH_TABLE_INDEX_BAT_6100].typeTimeoutClosed.closedReason == FILTER_TASK_CLOSED_REASON_RECEIVED ) {
    printf("Got BAT[0x6100].\n");
    } else {
    printf("Fail BAT[0x6100].\n");
    }
    }
    #endif




    SM_FREE( pMainTask->pFilterTaskPool );
    #if 0
    if(SI_IS_HD_PLUS/*SI_IS_SATELLITE*/(pSiAgentObj->si) && !SiAgtFW_IsSgtExist(pSiAgentObj))
    {
    pMainTask->pFilterTaskPool=SiAgent_GenScanSgtFtp(pSiAgentObj,pMainTask->argScanCh.tsAddr);
    if(pMainTask->pFilterTaskPool!=NULL)
    {
    pMainTask->stateNumber = SM_MAIN_SCANCH_ST_WAIT_SGT_TABLES;
    break;

    }
    }
    #endif
    pMainTask->stateNumber = SM_MAIN_SCANCH_ST_END ;

    //Msg to AP : Some VCs in TS !!!!!!!!!!!!!
    if(pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_SCAN_CHANNEL] != NULL)
    {
    //pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_SCAN_CHANNEL](pSiAgentObj->si, (void*)1);
    pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_SCAN_CHANNEL](pSiAgentObj->si, pMainTask->argScanCh.tsAddr);
    }
    }
    else
    { //No PMT

    #ifdef _DEBUG_SIAGENT_SM_
    printf("No PMT\n");
    #endif //_DEBUG_SIAGENT_SM_

    SM_FREE( pMainTask->pFilterTaskPool );
    pMainTask->stateNumber = SM_MAIN_SCANCH_ST_END ;

    //Msg to AP : No VC in TS (No PMT) !!!!!!!!!!!!!
    if(pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_SCAN_CHANNEL] != NULL)
    {
    pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_SCAN_CHANNEL](pSiAgentObj->si, NULL);
    }
    }
    }

    break ;
    case SM_MAIN_SCANCH_ST_WAIT_SGT_TABLES:
    NULL_CHECK(pMainTask->pFilterTaskPool,pMainTask->stateNumber);
    if (pMainTask->pFilterTaskPool->totalFilterTaskNumber==pMainTask->pFilterTaskPool->doneFilterTaskNumber)
    {
    pMainTask->stateNumber = SM_MAIN_SCANCH_ST_END ;
    if(pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_SCAN_CHANNEL] != NULL)
    {
    pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_SCAN_CHANNEL](pSiAgentObj->si, pMainTask->argScanCh.tsAddr);
    }
    }

    break;
    default:
    SM_DBG_MSG(DBG_MSG_LEVEL_ERROR, "[SiAgent-%s]:'Main Task - Scan Channel' has unknown state(%d).",pSiAgentObj->agentObjectName, pMainTask->stateNumber);
    pMainTask->stateNumber = SM_MAIN_SCANCH_ST_END ;
    execCount ++ ;
    break ;
    }
    }
    MAIN_TASK_ENDING_MSG( pSiAgentObj, pMainTask, "MainTask-ScanCH");
    }

    可以看到,当拿到PMT时,调用

    1
    pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_SCAN_CHANNEL](pSiAgentObj->si, pMainTask->argScanCh.tsAddr);

    也就是前面注册的回调函数SI_Callback_ScanChannel。

至此,ScanStart()跑完,然后RunStateProc状态机状态被更新为FREQ_SCAN_STATE_CHECK_SI。

RunStateProc FREQ_SCAN_STATE_CHECK_SI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
* vendor/realtek/frameworks/native/appclass/ \
* MediaControl/Component/Channel/Scan/DtvFreqDetector.cpp
*/

void CDtvFreqDetector::xStageCheckSi()
{
DTV_STACK::TunerMgr* tuner = DTV_STACK::TunerMgr::getInstance();

RETRY:
if (m_pIDtvMedia->GetSiMgr()->ScanIsDone(&m_bIsGetService) == false)
{
m_pIDtvMedia->GetSiMgr()->SetSignalInfo(tuner->getRFStrength(), tuner->getSignalSNR());
usleep(10000);

#ifdef ENABLE_SUPPORT_DVB_S
if(m_curLoHz != 0)
{
if(!m_bCancelScan)
goto RETRY;
}
#endif
return;
}

// Terrestrial case :
// We should check if we need to check current frequency again with different parameters
if (HasHandleCurFreqAgainInDvbT())
{
return;
}

// Fill modulation to each channel to prevent error when playing channel
m_pIDtvMedia->GetSiMgr()->SetModulation(m_curFreq, m_modulation);
m_scanState = FREQ_SCAN_STATE_END_FREQ;

#ifdef ENABLE_SUPPORT_DVB_S
if(m_curLoHz != 0)
{
UpdateChInfo();
SendEvent(RT_SCAN_EVENT_FREQ_DONE, m_curFreq);
m_scanState = FREQ_SCAN_STATE_BLIND_SCAN_TP;
}
#endif
return;
}

关注这个ScanIsDone:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/*
* vendor/realtek/frameworks/native/appclass/ \
* MediaControl/Component/Si/DvbSiMgr.cpp
*/

bool CDvbSiMgr::ScanIsDone(bool *bGetCh)
{
SI_MESSAGE message;
UINT32 data = 0;
DriverBasedDtvApp *pDvbApp = m_pTvMedia->GetDtvFlow();

if (pDvbApp->GetSiMessage(&message, &data) == false)
return false;

if (message == SI_MESSAGE_RESET_CHANNEL && data>0) {
xResetChannel(data);
return false;
}
else if(message == SI_MESSAGE_CHANNEL_UPDATE && data>0) {
xUpdateChannelMgr(data);
return false;
}
else if (message == SI_MESSAGE_CH_INFO_READY)
{
ALOGD("[%s %d] SI_MESSAGE_CH_INFO_READY\n",__func__,__LINE__);
if(bGetCh!=NULL)
{
*bGetCh = data == 0 ? true : false;
}
}
else if (message == SI_MESSAGE_SSU_SW_NOT_FOUND||message == SI_MESSAGE_SSU_SWINFO_READY)
{
if(bGetCh!=NULL)
{
*bGetCh = message == SI_MESSAGE_SSU_SWINFO_READY ? true : false;
}
}
else/* if (message != SI_MESSAGE_CH_INFO_READY)*/
return false;

return true;
}

收到这个SI_MESSAGE_CH_INFO_READY消息,就认为Check SI完成,这个消息就是回调函数SI_Callback_ScanChannel发出来的。然后接着跑RunStateProc的剩余流程。

SI_AGENT_STATUS_RUNNING

上面讲到,SiAgent_SM_Main_ScanCh的时候,如果拿到PMT,就认为扫到台,接着会跑SI_Callback_ScanChannel这个回调函数,但是SiAgent_SM_Main_ScanCh什么时候才会被调用呢?SiAgent_SM_GenMainTask_ScanCh只是设置了pMainTask->StateMachineFunction,但是还没有执行,什么时候执行?

RunStateProc FREQ_SCAN_STATE_CHECK_FRONTEND

别忘了,si_agent_threadfuntion这个线程里,SI_Agent_CollectSection函数还卡着呢,什么时候才跑进所需的流程?要看SI_AGENT_STATUS这个状态,根据前面的分析,在Check Frontend阶段,状态被更新为SI_AGENT_STATUS_RUNNING。

好戏开场了:

1
2
3
4
5
else if(agent->status == SI_AGENT_STATUS_RUNNING)
{
SiAgtIF_Run(agent->agentObjHandle);
SI_Collector_CollectSection(agent->collector, agent->db, agent->tp);
}

先讲SiAgtIF_Run:

1
2
3
4
5
6
7
8
9
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siAgentInterface.c
*/

void SiAgtIF_Run( SIAGENT_OBJECT_P pSiAgentObj )
{
pSiAgentObj->Run( pSiAgentObj );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siAgentObject.c
*/

void SiAgentObj_Run( SIAGENT_OBJECT_P pSiAgentObj )
{
int i;
pSiAgentObj->ExecMainTaskSM( pSiAgentObj );
for (i=0; i<SUB_TASK_QUEUE_NUMBER; i++) {
pSiAgentObj->ExecSubTaskSM( pSiAgentObj, i);
}
if (pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_MONITOR_TICK] != NULL) {
pSiAgentObj->siAgentCBFs[SI_AGENT_CBF_TYPE_MONITOR_TICK](pSiAgentObj->si,NULL);
}
}

这里的ExecMainTaskSM就是SiAgentObj_ExecMainTaskSM,由最开始CH_SCAN_STATE_INIT阶段初始化的,现在终于派上用场:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siAgentObject.c
*/

void SiAgentObj_ExecMainTaskSM( SIAGENT_OBJECT_P pSiAgentObj )
{
BOOL result ;
MAIN_TASK_INFO_P pExecMainTaskInfo = &(pSiAgentObj->execMainTaskInfo) ;

CHECK_MAIN_TASK_IN_QUEUE( pSiAgentObj, &result);

if( result == TRUE )
{ //New Task in Queue
if( pExecMainTaskInfo->pExecMainTask != NULL )
{ //Finish Current Task
pExecMainTaskInfo->pExecMainTask->stateNumber = STOP_EXEC_TASK ;
pExecMainTaskInfo->pExecMainTask->StateMachineFunction( pSiAgentObj, pExecMainTaskInfo->pExecMainTask ) ;
AGENTOBJ_FREE(pExecMainTaskInfo->pExecMainTask);
}
//Load New Task into State Machine
GET_MAIN_TASK_FROM_QUEUE( pSiAgentObj, &(pExecMainTaskInfo->pExecMainTask));

pExecMainTaskInfo->pExecMainTask->lastTaskIsChgCh = pExecMainTaskInfo->lastTaskIsChgCh ;
pExecMainTaskInfo->pExecMainTask->lastTsAddr = pExecMainTaskInfo->lastTsAddr ;

if( (pExecMainTaskInfo->pExecMainTask->StateMachineFunction == SiAgent_SM_Main_ChangeCh) ||
(pExecMainTaskInfo->pExecMainTask->StateMachineFunction == SiAgent_SM_Main_RecordPrg) )
{
pExecMainTaskInfo->lastTaskIsChgCh = TRUE ;
pExecMainTaskInfo->lastTsAddr = pExecMainTaskInfo->pExecMainTask->argChangeCh.tsAddr ;//argChangeCh==argRecordPrg
}
#ifdef ENABLE_SYSTEM_SOFTWARE_UPDATE
else if (pExecMainTaskInfo->pExecMainTask->StateMachineFunction == SiAgent_SM_Main_ChgChSsuDecode)
{
pExecMainTaskInfo->lastTaskIsChgCh = TRUE ;
pExecMainTaskInfo->lastTsAddr = pExecMainTaskInfo->pExecMainTask->argChgChSsuDcr.tsAddr ;//argChangeCh==argRecordPrg
}
#endif//ENABLE_SYSTEM_SOFTWARE_UPDATE
else if (pExecMainTaskInfo->pExecMainTask->StateMachineFunction!=SiAgent_SM_Main_Stop)
{
pExecMainTaskInfo->lastTaskIsChgCh = FALSE ;
}

}

if( pExecMainTaskInfo->pExecMainTask != NULL )
{
if( pExecMainTaskInfo->pExecMainTask->pFilterTaskPool != NULL )
{
//Update Filter Task State
SiAgent_UpdateFilterTaskState( pSiAgentObj, pExecMainTaskInfo->pExecMainTask->pFilterTaskPool );
}

//EXEC TASK
pExecMainTaskInfo->pExecMainTask->StateMachineFunction( pSiAgentObj, pExecMainTaskInfo->pExecMainTask ) ;

if( pExecMainTaskInfo->pExecMainTask->pFilterTaskPool != NULL )
{
//EXEC Filter Task
SiAgent_ExecuteFilterTask( pSiAgentObj, pExecMainTaskInfo->pExecMainTask->pFilterTaskPool );
}

if( pExecMainTaskInfo->pExecMainTask->stateNumber == STOP_EXEC_TASK )
{
AGENTOBJ_FREE(pExecMainTaskInfo->pExecMainTask);
}
}
}

前面流程,SI_AGENT_STATUS_RUNNING在Check Frontend阶段被设置了,这个时候,si_agent_threadfuntion线程可以进以下流程:

si_agent_threadfuntion()

SI_Agent_CollectSection(agent)

SiAgtIF_Run(agent->agentObjHandle)

SiAgentObj_Run(SIAGENT_OBJECT_P pSiAgentObj)

pSiAgentObj->ExecMainTaskSM(pSiAgentObj)

SiAgentObj_ExecMainTaskSM( SIAGENT_OBJECT_P pSiAgentObj )

前面把MainTask放入队列的时候,线程延迟1毫秒,让出CPU使用权,现在SiAgentObj_ExecMainTaskSM CHECK_MAIN_TASK_IN_QUEUE( pSiAgentObj, &result),也是同样的做法:

1
2
3
4
5
6
#define  CHECK_MAIN_TASK_IN_QUEUE(pAgent, pResult) {\
pthread_mutex_lock(&siAgentTaskMutex);\
pAgent->CheckMainTaskInQueue(pAgent, pResult);\
pthread_mutex_unlock(&siAgentTaskMutex);\
SIAGENT_THREAD_SLEEP(SIAGENT_THREAD_SLEEP_TIME);\
}

所以,这个有什么用?不知道。反正SiAgentObj_ExecMainTaskSM里面的执行时机搞不懂。😂

然后再讲SI_Collector_CollectSection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/collector/SI_Collector.c
*/

ErrCode SI_Collector_CollectSection(
SI_COLLECTOR *pCollector,
SI_DATABASE *pDatabase,
void *tp
)
{
//省略代码段

for(i=0; i<pCollector->beanQueueNum; i++)
{
//省略代码段
// get bean queue and beanQLen from tp or something
SI_TPInterface_GetBeanQueue(tp, i, &beanQueueLen, &beanQueue);
if(!beanQueueLen)
{ //beanQueueLen = 0
if(beanQueue)
{
SI_TPInterface_DropBeanQueue(tp, beanQueue);
}
continue;
}

beanQueueToParseLen = beanQueueLen + pCollector->beanCtrlInfo[i].surplusLength;

//kjw: todo
//if beanQueueToParseLen == beanQueueLen, we don't need to dup beanQueueToParse again...

beanQueueToParse = SI_COLLECTOR_MALLOC(beanQueueToParseLen);
if (beanQueueToParse==NULL)
continue;

if(pCollector->beanCtrlInfo[i].allocatedAddr)
{
memcpy(beanQueueToParse, pCollector->beanCtrlInfo[i].surplusAddr, pCollector->beanCtrlInfo[i].surplusLength);
SI_COLLECTOR_FREE(pCollector->beanCtrlInfo[i].allocatedAddr);
pCollector->beanCtrlInfo[i].allocatedAddr = NULL;
}
memcpy(beanQueueToParse+pCollector->beanCtrlInfo[i].surplusLength, beanQueue, beanQueueLen);

SI_TPInterface_DropBeanQueue(tp, beanQueue);


surplusLen = beanQueueToParseLen;
pthread_mutex_lock(&pCollector->mutexSectionFilter);//#ifdef ENABLE_MHEG5, fix not thread safe
si_collector_insert_to_database(pCollector, pDatabase, &surplusLen, beanQueueToParse);
pthread_mutex_unlock(&pCollector->mutexSectionFilter);//#ifdef ENABLE_MHEG5, fix not thread safe

//省略代码段
}

SI_COLLECTOR_RETURN(SI_ERR_OK);
}

这里应该是从SI_TPInterface_GetBeanQueue拿ts packet,加打印信息,continue关键字会一直拦截后面的语句,所以这里的作用单纯是拿ts packet?

RunStateProc FREQ_SCAN_STATE_CHECK_SI

再绕回来讲SiAgentObj_ExecMainTaskSM执行时机,其实没得讲,因为不知道。总之,Check SI的时候,SiAgentObj_ExecMainTaskSM会跑进以下3个流程:

SiAgent_UpdateFilterTaskState( pSiAgentObj, pExecMainTaskInfo->pExecMainTask->pFilterTaskPool );

pExecMainTaskInfo->pExecMainTask->StateMachineFunction( pSiAgentObj, pExecMainTaskInfo->pExecMainTask ) ;

SiAgent_ExecuteFilterTask( pSiAgentObj, pExecMainTaskInfo->pExecMainTask->pFilterTaskPool );

SiAgent_UpdateFilterTaskState这个是更新Filter状态的,比如说Receive到某个Table之后就把closedReason更新为FILTER_TASK_CLOSED_REASON_RECEIVED,并关掉对应的Filter;

StateMachineFunction这个,也就是对应扫台的SiAgent_SM_Main_ScanCh,用来设置Filter的,也通过Filter的closedReason判断是否拿到PMT,如果是FILTER_TASK_CLOSED_REASON_RECEIVED,则拿到;

SiAgent_ExecuteFilterTask是用来实际执行Filter的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siAgentFilterTaskExecutor.c
*/

void SiAgent_ExecuteFilterTask( SIAGENT_OBJECT_P pSiAgentObj, FILTER_TASK_POOL_P pFilterTaskPool )
{
unsigned short totalFilterTaskNumber ;
unsigned short i ;
time_t targetCurrentTime ;
BOOL bCreate;

FTE_DBG_MSG(DBG_MSG_LEVEL_INFO, "[SiAgent-%s]:Execute Filter Task.",pSiAgentObj->agentObjectName);

if( pFilterTaskPool->doingFilterTaskNumber < pFilterTaskPool->maxSecFilterNumber )
{
targetCurrentTime = SiAgent_GetTime(pSiAgentObj);

pFilterTaskPool->targetCurrentTime = targetCurrentTime ;

totalFilterTaskNumber = pFilterTaskPool->totalFilterTaskNumber ;

for( i = 0 ; i < totalFilterTaskNumber ; i ++ )
{
if( pFilterTaskPool->filterTask[i].filterTaskState == FILTER_TASK_STATE_TO_DO )
{
if( pFilterTaskPool->doingFilterTaskNumber < pFilterTaskPool->maxSecFilterNumber )
{
bCreate=TRUE;

switch( pFilterTaskPool->filterTask[i].filterTaskType )
{
case FILTER_TASK_TYPE_TIMEOUT_AUTO_CLOSED:
if(pFilterTaskPool->filterTask[i].typeTimeoutClosed.endingTime>0)
{
bCreate=SiAgent_FTE_EnableSecFilter( pSiAgentObj, &(pFilterTaskPool->filterTask[i]) );
if(bCreate)
{
pFilterTaskPool->filterTask[i].typeTimeoutClosed.timeout=pFilterTaskPool->filterTask[i].typeTimeoutClosed.endingTime;
pFilterTaskPool->filterTask[i].typeTimeoutClosed.endingTime += (targetCurrentTime+1) ;//fix incorrect timeout ,0.99999~1
}
}
else
{
pFilterTaskPool->filterTask[i].filterTaskState = FILTER_TASK_STATE_DOING;
pFilterTaskPool->todoFilterTaskNumber -- ;
bCreate=FALSE;
pFilterTaskPool->doneFilterTaskNumber ++ ;
pFilterTaskPool->filterTask[i].typeTimeoutClosed.closedReason = FILTER_TASK_CLOSED_REASON_TIMEOUT ;
pFilterTaskPool->filterTask[i].filterTaskState = FILTER_TASK_STATE_DONE ;
}
break ;
case FILTER_TASK_TYPE_RECEIVE_AUTO_CLOSED:
case FILTER_TASK_TYPE_OPEN_CONTINUOUSLY :
bCreate=SiAgent_FTE_EnableSecFilter( pSiAgentObj, &(pFilterTaskPool->filterTask[i]) );
break ;
default :
break ;
}
if(bCreate)
{
pFilterTaskPool->filterTask[i].filterTaskState = FILTER_TASK_STATE_DOING;
pFilterTaskPool->todoFilterTaskNumber -- ;
pFilterTaskPool->doingFilterTaskNumber ++ ;
}
}
}
}

}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siAgentFilterTaskExecutor.c
*/

BOOL SiAgent_FTE_EnableSecFilter( SIAGENT_OBJECT_P pSiAgentObj, FILTER_TASK_P pFilterTask )
{
FTE_DBG_MSG(DBG_MSG_LEVEL_INFO, "[SiAgent-%s]:Enable Virtual Section Filter.",pSiAgentObj->agentObjectName);

switch( pFilterTask->secFilterFunction )
{
case SEC_FLTR_FUNC_GET_TABLE :
return SiAgent_Enable_GetTableFilter( pSiAgentObj, pFilterTask->argGetTable.pid, pFilterTask->argGetTable.tid ) ;
break;
case SEC_FLTR_FUNC_MONITOR_PAT :
return SiAgent_Enable_MonitorPatFilter( pSiAgentObj, pFilterTask->argMonitorPat.pid, pFilterTask->argMonitorPat.tid, pFilterTask->argMonitorPat.tsid, pFilterTask->argMonitorPat.version ) ;
break;
case SEC_FLTR_FUNC_GET_PMT :
return SiAgent_Enable_GetPmtFilter( pSiAgentObj, pFilterTask->argGetPmt.pid, pFilterTask->argGetPmt.tid, pFilterTask->argGetPmt.programNumber ) ;
break;
case SEC_FLTR_FUNC_MONITOR_PMT :
return SiAgent_Enable_MonitorPmtFilter( pSiAgentObj, pFilterTask->argMonitorPmt.pid, pFilterTask->argMonitorPmt.tid, pFilterTask->argMonitorPmt.programNumber, pFilterTask->argMonitorPmt.version ) ;
break;
case SEC_FLTR_FUNC_MONITOR_TABLE :
return SiAgent_Enable_MonitorTableFilter( pSiAgentObj, pFilterTask->argMonitorTable.pid, pFilterTask->argMonitorTable.tid, pFilterTask->argMonitorTable.version ) ;
break;
case SEC_FLTR_FUNC_GET_APF_EIT :
return SiAgent_Enable_GetApfEitFilter( pSiAgentObj, pFilterTask->argGetApfEit.pid, pFilterTask->argGetApfEit.tid, pFilterTask->argGetApfEit.serviceId, pFilterTask->argGetApfEit.sectionNumber ) ;
break;
case SEC_FLTR_FUNC_MONITOR_APF_EIT:
return SiAgent_Enable_MonitorApfEitFilter( pSiAgentObj, pFilterTask->argMonitorApfEit.pid, pFilterTask->argMonitorApfEit.tid, pFilterTask->argMonitorApfEit.serviceId, pFilterTask->argMonitorApfEit.sectionNumber, pFilterTask->argMonitorApfEit.version ) ;
break;
#ifdef ENABLE_SYSTEM_SOFTWARE_UPDATE
case SEC_FLTR_FUNC_GET_DXI :
return SiAgent_Enable_GetDxiFilter(pSiAgentObj, pFilterTask->argGetDxi.pid, pFilterTask->argGetDxi.tid, pFilterTask->argGetDxi.id );
break;
case SEC_FLTR_FUNC_MONITOR_DXI :
return SiAgent_Enable_MonitorDxiFilter(pSiAgentObj, pFilterTask->argMonitorDxi.pid, pFilterTask->argMonitorDxi.tid, pFilterTask->argMonitorDxi.id, pFilterTask->argMonitorDxi.versionFlag );
break;
case SEC_FLTR_FUNC_GET_SSU_DDB :
return SiAgent_Enable_GetSsuDdbFilter(pSiAgentObj, pFilterTask->argGetSsuDdb.pid, pFilterTask->argGetSsuDdb.tid, pFilterTask->argGetSsuDdb.moduleIdMsb );
break;
#endif//ENABLE_SYSTEM_SOFTWARE_UPDATE
default :
break;
}
return FALSE;
}

这里,要拿PMT,要依次跑SEC_FLTR_FUNC_GET_TABLE、SEC_FLTR_FUNC_GET_PMT,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siAgentVirSecFilterMgr.c
*/

BOOL SiAgent_Enable_GetTableFilter( SIAGENT_OBJECT_P pSiAgentObj, unsigned short pid, unsigned char tid )
{
PID_LAYER_P pPidLayer ;
SEC_FILTER_LAYER_P pSecFilterLayer = NULL; // FIXED_CID_14323
SEC_FILTER_LAYER_T argSecFilter ;
SEC_FILTER_LAYER_P pSecFilterLinkList ;
BOOL ret=FALSE;

VSFM_LOCK(pSiAgentObj);

pPidLayer = SiAgent_VSFM_SearchPidLayer( pSiAgentObj, pid ) ;

if( pPidLayer == NULL )
{
pPidLayer = SiAgent_VSFM_CreatePidLayer( pSiAgentObj, pid ) ;
}

argSecFilter.secFilterFunction = SEC_FLTR_FUNC_GET_TABLE ;
argSecFilter.argGetTable.pid = pid ;
argSecFilter.argGetTable.tid = tid ;

if( pPidLayer != NULL )
{
pSecFilterLayer = SiAgent_VSFM_SearchSecFilterLayer( pSiAgentObj, pPidLayer, &argSecFilter ) ;
if( pSecFilterLayer == NULL )
{
pSecFilterLayer = (SEC_FILTER_LAYER_P) VSFM_MALLOC( sizeof(SEC_FILTER_LAYER_T) ) ;
if(pSecFilterLayer!=NULL)
{
memset(pSecFilterLayer,0,sizeof(SEC_FILTER_LAYER_T));
VSFM_FILTER_SET_OWNER(pSecFilterLayer->owner, SF_OWNER_AGENT);

pSecFilterLayer->referenceCount = 1 ;
pSecFilterLayer->secFilterFunction = SEC_FLTR_FUNC_GET_TABLE ;
pSecFilterLayer->argGetTable.pid = pid ;
pSecFilterLayer->argGetTable.tid = tid ;

pSecFilterLinkList = (SEC_FILTER_LAYER_P) &(pPidLayer->secFilterLinkList) ;

if( pSecFilterLinkList->fd == pSecFilterLinkList )
{
pSecFilterLinkList->fd = pSecFilterLayer ;
pSecFilterLinkList->bk = pSecFilterLayer ;
pSecFilterLayer->fd = pSecFilterLinkList ;
pSecFilterLayer->bk = pSecFilterLinkList ;
}
else
{
pSecFilterLinkList->bk->fd = pSecFilterLayer ;
pSecFilterLayer->bk = pSecFilterLinkList->bk ;
pSecFilterLayer->fd = pSecFilterLinkList ;
pSecFilterLinkList->bk = pSecFilterLayer ;
}

SIAGENT_VSFM_DBG_MSG(DBG_MSG_LEVEL_INFO, "[SiAgent-%s]:SiAgent_Enable_GetTableFilter(pid:0x%04x,tid:0x%02x) - refcnt:%d",pSiAgentObj->agentObjectName,pid,tid,pSecFilterLayer->referenceCount);
}
}
else
{
pSecFilterLayer->referenceCount ++ ;
SIAGENT_VSFM_DBG_MSG(DBG_MSG_LEVEL_INFO, "[SiAgent-%s]:SiAgent_Enable_GetTableFilter(pid:0x%04x,tid:0x%02x) - refcnt:%d",pSiAgentObj->agentObjectName,pid,tid,pSecFilterLayer->referenceCount);
}
ret=TRUE;
}


VSFM_UNLOCK(pSiAgentObj);
return ret;
}

无论哪个secFilterFunction,都会跑SiAgent_VSFM_CreatePidLayer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siAgentVirSecFilterMgr.c
*/

static PID_LAYER_P SiAgent_VSFM_CreatePidLayer( SIAGENT_OBJECT_P pSiAgentObj, unsigned short pid )
{

PID_LAYER_P pPidLinkList = (PID_LAYER_P) &(pSiAgentObj->pidLinkList) ;
PID_LAYER_P pPidLayer ;


pPidLayer = (PID_LAYER_P) VSFM_MALLOC( sizeof(PID_LAYER_T) ) ;
if(pPidLayer!=NULL)
{
if(!SiAgtFW_EnablePidFilter( pSiAgentObj, pid ))
{
VSFM_FREE(pPidLayer);
return NULL;
}

pPidLayer->pid = pid ;
pPidLayer->secFilterLinkList.fd = &(pPidLayer->secFilterLinkList) ;
pPidLayer->secFilterLinkList.bk = &(pPidLayer->secFilterLinkList) ;

if( pPidLinkList->fd == pPidLinkList )
{
pPidLinkList->fd = pPidLayer ;
pPidLinkList->bk = pPidLayer ;
pPidLayer->fd = pPidLinkList ;
pPidLayer->bk = pPidLinkList ;
}
else
{
pPidLinkList->bk->fd = pPidLayer ;
pPidLayer->bk = pPidLinkList->bk ;
pPidLayer->fd = pPidLinkList ;
pPidLinkList->bk = pPidLayer ;
}

SiAgtFW_CreateSectionBuffer( pSiAgentObj, pid );
}
return pPidLayer ;
}
1
2
3
4
5
6
7
8
9
10
11
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/agent/siagent2_dvr/siFunctionWrapper.c
*/

BOOL SiAgtFW_EnablePidFilter( SIAGENT_OBJECT_P pSiAgentObj, unsigned short pid )
{
if(pSiAgentObj->handleDemuxer)
return SI_TPInterface_SetFilter(pSiAgentObj->handleDemuxer, pid, SI_FILTER_SI, SI_CODEC_OTHERS) == SI_TP_ERR_OK ? TRUE :FALSE;
return FALSE;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/tpInterface/PVR/tp.c
*/

ErrCode SI_TPInterface_SetFilter(
void *tp,
unsigned int pid,
SI_FILTER_TYPE type,
SI_CODEC_TYPE codecType
)
{
//省略代码段
if(type==SI_FILTER_SI)
{
ret=SI_BeanGen_EnablePid( _tp->bgHandle, pid
#ifdef SI_USE_SDEC
,_tp->siHandle,_tp->sdecChannel
#endif
);

}
//省略代码段
filter.pid = pid;
filter.bActive = 1;
filter.type = type;
filter.codecType = codecType;
//省略代码段
_tp->tsFuncs.InsertFilterList(_tp->navHandle, count, &filter);
//省略代码段
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/tpInterface/PVR/siBeanGen.c
*/

ErrCode SI_BeanGen_EnablePid(BEAN_GENERATOR *pBeanGen,unsigned int pid
#ifdef SI_USE_SDEC
,unsigned int transaction_id,int ch
#endif

)
{
int i;
BEANGEN_FILTERINFO *bgfInfo;

for(i=0; i<BEANGEN_FILTERNUM; i++)
{
bgfInfo = pBeanGen->filterInfo+i;

if(bgfInfo->pid==pid)
{
SI_BEAN_LOG(SI_BEAN_LEVEL_WARNING, "SI_BeanGen_EnablePid re-enable 0x%04x\n", pid);
return SI_TP_ERR_OK;
}
}

for(i=0; i<BEANGEN_FILTERNUM; i++)
{
bgfInfo = pBeanGen->filterInfo+i;

if(bgfInfo->pid>0x1fFF)
{
#ifdef SI_USE_SDEC
bgfInfo->SecfIndex=0xff;
if(ch!=SDEC_CH_MAX)
{
SDEC_SECTION_FILTER_T filter;//={0};
memset(&filter,0,sizeof(filter));
filter.pid=pid;
filter.transaction_id=transaction_id;
#ifdef SI_USE_HW_CRC
if(PID_TDT!=pid)filter.crc_chksum=1;
#endif
if(RHAL_SDEC_RequestSection(ch, &filter, &bgfInfo->SecfIndex, 0, fnSDECDataHandlingCB)!=API_OK)
{
return SI_TP_ERR_BEAN_PID_FULL;
}
}
#endif

bgfInfo->pid = pid;
bgfInfo->tid = 0xff;
bgfInfo->remainedSecLen = 0;

SI_BEAN_LOG(SI_BEAN_LEVEL_INFO, "SI_BeanGen_EnablePid first-enable 0x%04x\n", pid);

return SI_TP_ERR_OK;
}
}

SI_BEAN_LOG(SI_BEAN_LEVEL_WARNING, "warn!! SI_BeanGen_EnablePid not enable 0x%04x\n", pid);

return SI_TP_ERR_BEAN_PID_FULL;
}

RHAL_SDEC_RequestSection参数传入了fnSDECDataHandlingCB:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
* vendor/realtek/frameworks/native/rtkhal/ \
* hal_src/hal/src/sdec/rhal_sdec.cpp
*/

DTV_STATUS_T RHAL_SDEC_RequestSection(SDEC_CHANNEL_T ch, SDEC_SECTION_FILTER_T *pSectionFilter, UINT8 *pSecfIndex, UINT32 gpbSize, pfnSDECDataHandlingCB pfnCallBack)
{
SECTION_CALL_DEBUG(RTD_LOG_MODULE_SDEC) ;
CAutoLock AutoLock(&Sdec_CritSec) ;
CAutoLock AutoLockCB(&Sdec_CritSecForCB) ;
CHECK_SDEC_MODULE_INIT(0) ;
CHECK_CH_PARAM_VALID(ch) ;

if (!pSectionFilter || !pSecfIndex || !pfnCallBack) return INVALID_PARAMS ;


DTV_STATUS_T ret ;
DEMUX_ADD_SEC_FILTER_T secFilter ;
UINT8 posVal[10]={0}, posMsk[10]={0}, negVal[10]={0}, negMsk[10]={0} ;
SINT32 secfIndex ;
UINT8 filterID, i ;
UINT8 *virAddr ;

SECTION_DEBUG(RTD_LOG_MODULE_SDEC, "pid = %d, gpbSize = %d\n", pSectionFilter->pid, gpbSize) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "transaction_id = %d\n", pSectionFilter->transaction_id) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "pid = %d\n", pSectionFilter->pid) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "table_id = %d\n", pSectionFilter->table_id) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "section_syntax_indicator = %d\n", pSectionFilter->section_syntax_indicator) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "table_id_extension = %d\n", pSectionFilter->table_id_extension) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "version_number = %d\n", pSectionFilter->version_number) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "current_next_indicator = %d\n", pSectionFilter->current_next_indicator) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "last_section_number = %d\n", pSectionFilter->last_section_number) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "protocol_version = %d\n", pSectionFilter->protocol_version) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "table_id_filter_mask = %d\n", pSectionFilter->table_id_filter_mask) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "table_id_extension_filter_mask = %d\n", pSectionFilter->table_id_extension_filter_mask) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "section_syntax_indicator_filter = %d\n", pSectionFilter->section_syntax_indicator_filter) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "version_number_filter = %d\n", pSectionFilter->version_number_filter) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "not_version_number_filter = %d\n", pSectionFilter->not_version_number_filter) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "current_next_indicator_filter = %d\n", pSectionFilter->current_next_indicator_filter) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "last_section_number_filter = %d\n", pSectionFilter->last_section_number_filter) ;
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "protocol_version_filter = %d\n", pSectionFilter->protocol_version_filter) ;

posVal[0] = pSectionFilter->table_id ;
posVal[1] = pSectionFilter->section_syntax_indicator << 7 ;
posVal[2] = 0 ;
posVal[3] = pSectionFilter->table_id_extension >> 8 ;
posVal[4] = pSectionFilter->table_id_extension & 0xFF ;
posVal[5] = pSectionFilter->version_number << 1 | pSectionFilter->current_next_indicator ;
posVal[6] = 0 ; // map to section_number
posVal[7] = pSectionFilter->last_section_number ; // map to last_section_number
posVal[8] = pSectionFilter->protocol_version ;

posMsk[0] = pSectionFilter->table_id_filter_mask;
posMsk[1] = (pSectionFilter->section_syntax_indicator_filter) ? 0x80 : 0x00 ;
posMsk[2] = 0;
posMsk[3] = pSectionFilter->table_id_extension_filter_mask >> 8 ;
posMsk[4] = pSectionFilter->table_id_extension_filter_mask & 0xFF ;
posMsk[5] = (((pSectionFilter->version_number_filter) ? 0x1F : 0x0) << 1) | ((pSectionFilter->current_next_indicator_filter) ? 0x1 : 0x0) ;
posMsk[6] = 0;
posMsk[7] = (pSectionFilter->last_section_number_filter) ? 0xFF : 0x00 ;
posMsk[8] = (pSectionFilter->protocol_version_filter) ? 0xFF: 0x00 ;

negVal[5] = pSectionFilter->version_number << 1;
negMsk[5] = (pSectionFilter->not_version_number_filter ? 0x1F : 0x0) << 1;

secFilter.ch = MAP_TO_DEMUX_CH(ch) ;
secFilter.param.PID = pSectionFilter->pid ;
secFilter.param.crc_en = pSectionFilter->crc_chksum ; // 1: crc; 2: checksum
secFilter.param.one_shoot = pSectionFilter->once_flag == 1 ? 1 : 0 ; // To get section data only once,"1" should be set.
secFilter.param.toggle_mode_en = 0 ;

// for (i = 0 ; i < 10 ; i++)
// {
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "func %s, line %d, posVal[%d] = 0x%x\n", __func__, __LINE__, i, posVal[i]) ;
// }
// for (i = 0 ; i < 10 ; i++)
// {
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "func %s, line %d, posMsk[%d] = 0x%x\n", __func__, __LINE__, i, posMsk[i]) ;
// }
//
// RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "pid %d, crc_chksum %d, once_flag %d\n", pSectionFilter->pid, pSectionFilter->crc_chksum, pSectionFilter->once_flag) ;

memcpy(&secFilter.param.PosVal, posVal, sizeof(secFilter.param.PosVal)) ;
memcpy(&secFilter.param.PosMsk, posMsk, sizeof(secFilter.param.PosMsk)) ;
memcpy(&secFilter.param.NegVal, negVal, sizeof(secFilter.param.NegVal)) ;
memcpy(&secFilter.param.NegMsk, negMsk, sizeof(secFilter.param.NegMsk)) ;

secFilter.size = gpbSize; /* decide how many size of buffer for this section */

CHECK_IOCTL_RESULT(KADP_SDEC_SetGetProperty(DEMUX_PROPERTY_ADD_SECTION_FILTER, (void *)&secFilter, &secfIndex)) ;


SDEC_CALLBACK_T *pSec = &Sdec_Info.stSection[MAP_TO_DEMUX_CH(ch)][secfIndex] ;
RINGBUFFER_HEADER *pHeader = (RINGBUFFER_HEADER *)(Sdec_Info.bufferHeaderPoll.virAddr + (secFilter.headerPhyAddr - (UINT32)Sdec_Info.bufferHeaderPoll.phyAddr));

pSec->phyAddrOffset = Sdec_Info.secBufferInfo.phyAddrOffset;
pSec->pWrPtr = &pHeader->writePtr;
pSec->pRdPtr = &pHeader->readPtr[0];
pSec->pRdTmpPtr = &pHeader->readPtr[1];
pSec->pBufferLower = (UINT8 *)pHeader->beginAddr;
pSec->pBufferUpper = pSec->pBufferLower + pHeader->size;

pSec->pfnCallBack = pfnCallBack ;
pSec->msgType.msgId = 0x67301 ; // MSG_SDEC2SIPSIP_SECTION_ACQUIRED ;
pSec->msgType.channel = ch ;
pSec->msgType.filterId = secfIndex ;
pSec->msgType.pid = pSectionFilter->pid ;
pSec->msgType.transactionId = pSectionFilter->transaction_id ;
pSec->msgType.pData = 0 ;
pSec->msgType.dataLen = 0 ;
pSec->msgType.tableType = pSectionFilter->table_id ; // ONLY for PSIP
pSec->msgType.entryId = 0 ; // ONLY for PSIP
pSec->msgType.bufLower = (UINT32)pSec->pBufferLower + pSec->phyAddrOffset;
pSec->msgType.bufUpper = pSec->msgType.bufLower + pHeader->size;
*pSecfIndex = secfIndex ;
pSec->used = 1 ;

SECTION_DEBUG(RTD_LOG_MODULE_SDEC, "phyAddrOfSet 0x%x, pWrPtr 0x%x, pRdPtr 0x%x\n", pSec->phyAddrOffset, pSec->pWrPtr, pSec->pRdPtr) ;
SECTION_DEBUG(RTD_LOG_MODULE_SDEC, "*pWrPtr 0x%x, *pRdPtr 0x%x, *pRdTmpPtr 0x%x\n", *pSec->pWrPtr, *pSec->pRdPtr, *pSec->pRdTmpPtr) ;
SECTION_DEBUG(RTD_LOG_MODULE_SDEC, "pBufferLower 0x%x, pBufferUpper 0x%x, gpbSize %d\n", pSec->pBufferLower, pSec->pBufferUpper, gpbSize) ;
SECTION_DEBUG(RTD_LOG_MODULE_SDEC, "secfIndex = %d\n", secfIndex) ;
return API_OK ;
}

到这里好像就没了?PMT信息好像还是没有拿到呢?

_SDEC_Thread

🔥汁还是太年轻了,这里有另外一个线程_SDEC_Thread要说明一下。

从TVservice启动的时候开始:

1
2
3
4
5
6
7
8
9
10
11
/*
* vendor/realtek/frameworks/native/services/ \
* tvservice/main_tvservice.cpp
*/

int main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
{
//省略代码段
BootManager::GetInstance()->Initial();
//省略代码段
}
1
2
3
4
5
6
7
8
9
/*
* vendor/realtek/frameworks/native/appclass/ \
* BootManager/BootManager.cpp
*/

bool BootManager::Initial()
{
return m_pBootManagerImpl->Initial();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
* vendor/realtek/frameworks/native/appclass/ \
* BootManager/BootManagerImpl.cpp
*/

bool BootManagerImpl::Initial()
{
//省略代码段
RegisterInitFunc();
//省略代码段
}

void BootManagerImpl::RegisterInitFunc()
{
//省略代码段
m_pInitFuncImplMgr->RegisterInitFunc(&BootManagerImpl::InitDTV, INIT_PRIORITY_3, INIT_MODULE_DTV);
//省略代码段
}

bool BootManagerImpl::InitDTV()
{
DUMP_TRACE_LOG();
#ifdef ENABLE_TUNNERCHECK
if (m_bWithTuner)
#endif
{
m_pHalModulesInit = new HalModulesInit();
}
return true;
}

1
2
3
4
5
6
7
8
9
10
11
12
/*
* vendor/realtek/frameworks/native/rtkhal/ \
* hal_src/hal/src/hal_module_manager/HalModulesInit.cpp
*/

HalModulesInit::HalModulesInit()
{
//省略代码段
if(RHAL_SDEC_InitializeModule()!=API_OK)
ALOGE("[%s %d] RHAL_SDEC_InitializeModule fails\n", __func__, __LINE__);
//省略代码段
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/*
* vendor/realtek/frameworks/native/rtkhal/ \
* hal_src/hal/src/sdec/rhal_sdec.cpp
*/

DTV_STATUS_T RHAL_SDEC_InitializeModule(void)
{
RTD_LOGGER_CALL(RTD_LOG_MODULE_SDEC) ;
return _Initiallize() ;
}

static DTV_STATUS_T _Initiallize()
{
//省略代码段
// Create SDEC thread
if (pthread_create(&_sdec_thread_id, NULL, _SDEC_Thread, NULL) != 0)
{
RTD_LOG_ERROR(RTD_LOG_MODULE_SDEC, "[%s %d] %s - SDEC thread creation failed\n", __FILE__, __LINE__, __func__) ;
return API_NOT_OK ;
}
else
_isRunSdecThread = 1 ;

Sdec_IsInit = 1 ;

return API_OK ;
}

static void *_SDEC_Thread(void*)
{
// check error for debug
#if !defined(CONTINUE_LOOP_IF_SECTION_BUFFER_INFO_IS_INVALID)
#define CONTINUE_LOOP_IF_SECTION_BUFFER_INFO_IS_INVALID(index, size, buffer_info, msg) \
if (index >= Sdec_Info.secBufferInfo.maxIndex || size > MAX_SECTION_SIZE) \
{ \
RTD_LOG_ERROR(RTD_LOG_MODULE_SDEC,"func %s, line %d, Please Debug !! index %d, size %d\n", __func__, __LINE__, (index), (size)); \
RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "Before clean section buffer : TmpRd 0x%x, Wr 0x%x, pLower 0x%x, pUpper 0x%x\n", (buffer_info).pRdTmpPtr,(buffer_info).pWrPtr, (buffer_info).pBufferLower, (buffer_info).pBufferUpper); \
RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "Before clean section buffer : Sectiondata CH: %d PID:0x%x - tid:0x%x \n", (msg).channel, (msg).pid, (msg).tableType); \
(buffer_info).pRdTmpPtr = (buffer_info).pWrPtr; \
(buffer_info).pRdPtr = (buffer_info).pWrPtr; \
RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "After clean section buffer : TmpRd 0x%x, Wr 0x%x, pLower 0x%x, pUpper 0x%x\n", (buffer_info).pRdTmpPtr,(buffer_info).pWrPtr, (buffer_info).pBufferLower, (buffer_info).pBufferUpper); \
RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "After clean section buffer : Sectiondata CH: %d PID:0x%x - tid:0x%x \n", (msg).channel, (msg).pid, (msg).tableType); \
Sdec_CritSecForCB.Unlock(); \
continue; \
}
#endif
const char* threadName = "SdecThread";
pli_setThreadName((char*)threadName) ;
SDEC_MSG_TYPE_T msgType ;
SINT32 i, j, index, size;
UINT32 r;
UINT8 *ptr, *pVirAddr;
struct pollfd fds ;
SDEC_CALLBACK_T *pCB;
fds.fd = Sdec_Info.fd ;
fds.events = POLLIN ; // the input event

memset(&msgType, 0x0, sizeof(SDEC_MSG_TYPE_T)) ;

while(1)
{
if (poll(&fds, 1, POLL_INTERVAL) > 0) // wait POLL_INTERVAL ms
{
if (fds.revents & POLLIN) // the output event
{

/* Section */
for (i = 0 ; i < DEMUX_CH_NUM ; i++)
{
for (j = 0 ; j < MAX_SECTION_NUM ; j++)
{
pCB = &Sdec_Info.stSection[i][j] ;
Sdec_CritSecForCB.Lock();
/* check if new section is coming */
if (pCB->used && pCB->pRdPtr && BS_DISTANCE_TO_READ(*pCB->pRdTmpPtr, *pCB->pWrPtr, pCB->pBufferLower, pCB->pBufferUpper) > 4)
{
ptr = (UINT8 *)(*pCB->pRdTmpPtr);
pVirAddr = ptr + pCB->phyAddrOffset;
r = *(UINT32 *)pVirAddr ;
index = r >> 16 ; /* the section data belong to number of section chunk */
size = r & 0xffff ; /* section data size, if size is 0, index indicates its location */
// RTD_LOG_ERROR(RTD_LOG_MODULE_SDEC,"func %s, line %d, ptr 0x%x, index %d, size %d\n", __func__, __LINE__, ptr, index, size) ;

CONTINUE_LOOP_IF_SECTION_BUFFER_INFO_IS_INVALID(index, size, *pCB, msgType);

if (!size) /* jump to next index */
{
ptr = Sdec_Info.secBufferInfo.phyAddr + SDEC_EACH_SEC_UNIT_SIZE*index ; /* physical address */
pVirAddr = ptr + pCB->phyAddrOffset ; /* virtual address */
size = (*(UINT32 *)pVirAddr) & 0xffff ;
index = (*(UINT32 *)pVirAddr) >> 16 ;
// RTD_LOG_ERROR(RTD_LOG_MODULE_SDEC,"func %s, line %d, ptr 0x%x, index %d, size %d\n", __func__, __LINE__, ptr, index, size) ;
}

CONTINUE_LOOP_IF_SECTION_BUFFER_INFO_IS_INVALID(index, size, *pCB, msgType);

ptr +=4 ; /* move to data address, first 4 bytes is (index, size) */
memcpy(&msgType, &pCB->msgType, sizeof(SDEC_MSG_TYPE_T)) ;
msgType.pData = ptr + Sdec_Info.secBufferInfo.phyAddrOffset;
msgType.dataLen = size ;
*pCB->pRdTmpPtr = ((ULONG)(ptr) + size + 3) & ~0x3 ; /* move to next section */
SECTION_DEBUG(RTD_LOG_MODULE_SDEC, "[%s %d] %s - section filter id_%d callback\n", __FILE__, __LINE__, __func__, msgType.filterId) ;
KADP_SDEC_DEBUG_INFO(msgType.pid,SDEC_DEBUG_LOG_CONTROL_CALLBACK, "Sectiondata1 CH: %d PID:0x%x - tid:0x%x, [0x%x](%s) DataLen:%d\n", msgType.channel, msgType.pid, msgType.tableType, 0,"------" ,msgType.dataLen);
Sdec_CritSecForCB.Unlock();

pCB->pfnCallBack(&msgType) ;

}
else if(pCB->used && msgType.pData && pCB->msgType.msgId==0x67401&&j==MAX_SECTION_NUM-1){
memcpy(&msgType, &pCB->msgType, sizeof(SDEC_MSG_TYPE_T)) ;
int ret = KADP_SDEC_GetPCRAdaptionField((DEMUX_CHANNEL_T)msgType.channel,msgType.pid,msgType.pData,&msgType.dataLen);
Sdec_CritSecForCB.Unlock();
RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "_SDEC_Thread get pcr ret=%d\n", ret);
if(ret ==0){
RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "_SDEC_Thread get pcr dataLen=%d data=%02x %02x %02x %02x \n", msgType.dataLen,msgType.pData[0],msgType.pData[1],msgType.pData[2],msgType.pData[3]);
pCB->pfnCallBack(&msgType) ;
}
}else{
Sdec_CritSecForCB.Unlock();
}
}
}

/* PES */
for (i = 0 ; i < DEMUX_CH_NUM ; i++)
{
for (j = 0 ; j < MAX_PES_NUM ; j++)
{
pCB = &Sdec_Info.stPes[i][j];
Sdec_CritSecForCB.Lock();
if (pCB->used && pCB->status == DEMUX_PESBUFFER_OP_PENDING_FOR_INIT){
if (*(pCB->pReserved2)==DEMUX_PESBUFFER_OP_INITIALIZED){
pCB->status = DEMUX_PESBUFFER_OP_INITIALIZED;

}
else{
Sdec_CritSecForCB.Unlock();
continue;
}

}
if (pCB->pRdPtr)
{
RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "Rd 0x%x, Wr 0x%x, pLower 0x%x, pUpper 0x%x\n", *pCB->pRdTmpPtr, *pCB->pWrPtr, pCB->pBufferLower, pCB->pBufferUpper) ;
}

/* check if new PES is coming */
if (pCB->used && pCB->pRdPtr && BS_DISTANCE_TO_READ(*pCB->pRdTmpPtr, *pCB->pWrPtr, pCB->pBufferLower, pCB->pBufferUpper) > 4)
{
ptr = (UINT8 *)(*pCB->pRdTmpPtr);
pVirAddr = ptr + pCB->phyAddrOffset;

memcpy(&msgType, &pCB->msgType, sizeof(SDEC_MSG_TYPE_T)) ;
/* get PES size */
UINT8 *pPesStart = ptr;
size = 0;
for(int i = 0; i < DEMUX_PESDATA_PREFIX_PESLENGTH; i++)
{
size += *(pPesStart + pCB->phyAddrOffset) << (i << 3);
if ((pPesStart + 1) >= pCB->pBufferUpper) /* move to base */
pPesStart = pCB->pBufferLower;
else
pPesStart++;
}


/* move to data address (first DEMUX_PESDATA_PREFIX_PESLENGTH bytes is size) */

ptr +=DEMUX_PESDATA_PREFIX_PESLENGTH;

if (ptr >= pCB->pBufferUpper)
{
ptr -= (pCB->pBufferUpper - pCB->pBufferLower);
}

msgType.pData = ptr + pCB->phyAddrOffset;
msgType.dataLen = size ;

ptr += size; /* move to next PES */
if (ptr >= pCB->pBufferUpper)
{
ptr -= (pCB->pBufferUpper - pCB->pBufferLower);
}
*pCB->pRdTmpPtr = (ULONG)(ptr) ; /* move to next PES */

RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "[%s %d] %s - pes filter id_%d callback, ptr 0x%x, size %d\n", __FILE__, __LINE__, __func__, msgType.filterId, msgType.pData, msgType.dataLen) ;
KADP_SDEC_DEBUG_INFO(msgType.pid,SDEC_DEBUG_LOG_CONTROL_CALLBACK, "PESdata CH: %d PID:0x%x -tid: 0x%x, [0x%x](%s) DataLen:%d\n",
msgType.channel, msgType.pid, 0, 0, "------" ,msgType.dataLen);

Sdec_CritSecForCB.Unlock();
pCB->pfnCallBack(&msgType) ;

}
else
{
Sdec_CritSecForCB.Unlock();
}
}
}

}
}
if(!_isRunSdecThread)
{
RTD_LOG_DEBUG(RTD_LOG_MODULE_SDEC, "[%s %d] %s - Exit _SDEC_Thread\n", __FILE__, __LINE__, __func__) ;
break ;
}
}
pthread_exit(NULL);
#if defined(CONTINUE_LOOP_IF_SECTION_BUFFER_INFO_IS_INVALID)
#undef CONTINUE_LOOP_IF_SECTION_BUFFER_INFO_IS_INVALID
#endif

return NULL;
}

开机之后,TVservice就有一个_SDEC_Thread在跑,其中的while(1)循环里Section部分,会check if new section is coming。_

前面分析,扫台线程ScanThread Check SI的时候,也就是si_agent_threadfuntion SI_AGENT_STATUS_RUNNING的时候,最后行为是在RHAL_SDEC_RequestSection,其中的

1
pSec->pfnCallBack           = pfnCallBack ;

声明了函数指针。

所以这个_SDEC_Thread检测到有section来临时,会跑这个回调函数咯:

1
pCB->pfnCallBack(&msgType) ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/collector/SI_Collector.c
*/

DTV_STATUS_T fnSDECDataHandlingCB(SDEC_MSG_TYPE_T *pMsg)
{
if(pMsg!=NULL)
{
SI *pSI=(SI*)pMsg->transactionId;
if(pSI!=NULL)
{
unsigned char section[4096];
if(pMsg->dataLen<=4096)
{
#ifdef SI_SDEC_SIMULATE
si_collector_copy_section(pSI->collector,pSI->db,pMsg->dataLen,pMsg->pData,pMsg->pid);
#else

RHAL_SDEC_CopySectionData(pMsg->channel,pMsg->filterId,pMsg->pid,section,pMsg->pData,pMsg->dataLen);
//RHAL_SDEC_ReturnSectionBuffer(pMsg->channel, pMsg->filterId, pMsg->pid, pMsg->pData, pMsg->dataLen);
pthread_mutex_lock(&pSI->collector->mutexSectionFilter);//#ifdef ENABLE_MHEG5, fix not thread safe
si_collector_copy_section(pSI->collector,pSI->db,pMsg->dataLen,section,pMsg->pid);
pthread_mutex_unlock(&pSI->collector->mutexSectionFilter);//#ifdef ENABLE_MHEG5, fix not thread safe
#endif
}

}
}
return API_OK;
}


static void si_collector_copy_section(
SI_COLLECTOR *pCollector,
SI_DATABASE *pDatabase,
unsigned int sectionLength,
unsigned char *sectionBuf,
int pid
)
{

{
int i;
char tid = sectionBuf[0];
unsigned short tidEx;
SI_Database_Lock(pDatabase);
SI_Database_InsertSection(pDatabase, sectionLength, sectionBuf, pid);
SI_Database_Unlock(pDatabase);
#ifdef _SI_EXPORT_SECTION_FILTER
if( err != SI_ERR_CRC_ERROR ) {
//ps. SI_Callback_Section "should" check crc when send it out
if( pCollector->sectionCB[SI_SECTIONCOLLECTOR_CBF_TYPE_CUSTOMIZED_SECTION] != NULL)
pCollector->sectionCB[SI_SECTIONCOLLECTOR_CBF_TYPE_CUSTOMIZED_SECTION](pDatabase, sectionLength, &sectionBuf, pid);
}
#endif//_SI_EXPORT_SECTION_FILTER


#ifdef ENABLE_SYSTEM_SOFTWARE_UPDATE
//kjw ssu todo: need to check crc
if( tid == SI_TID_DSM_DXI || tid == SI_TID_DSM_DDB || tid == SI_SSU_UNT)
{

if (pCollector->sectionCB[SI_SECTIONCOLLECTOR_CBF_TYPE_SSU_SECTION])
{
if(sectionLength >=30)
{ // min length of ddb,dXi is 30
//crc is checked in individual table
pCollector->sectionCB[SI_SECTIONCOLLECTOR_CBF_TYPE_SSU_SECTION](pDatabase, sectionLength, &sectionBuf, pid);
}
}

}

#endif//ENABLE_SYSTEM_SOFTWARE_UPDATE

//
/*
if (pCollector->sorted_sectionFilterCb==0) {
//sort callback pointer by desc.
qsort(pCollector->sectionFilterCb, SI_COLLECTION_CALLBACK_MAX, sizeof(SI_COLLECTOR_SECTION_FILTER_CALLBACK), compare_SI_COLLECTOR_SECTION_FILTER_CALLBACK);
pCollector->sorted_sectionFilterCb=1;
}
*/
for (i=0; i<SI_COLLECTION_CALLBACK_MAX; i++) {
SI_COLLECTOR_SECTION_FILTER_CALLBACK *pSectionFilterCb;
SI_Collector_SectionCallbackEx pCallback;
SI_Collector_SectionCallbackEx_userdata pCallback_userdata;



pSectionFilterCb=&pCollector->sectionFilterCb[i];
if (pSectionFilterCb->pCallback==NULL)
continue;
if (pid!=pSectionFilterCb->pid)
continue;
if (pSectionFilterCb->pid==pid &&
((pSectionFilterCb->tid==(unsigned short)-1) || ((pSectionFilterCb->tid&pSectionFilterCb->tidMask)==(tid&pSectionFilterCb->tidMask))) //#ifdef ENABLE_MHEG5, for OB SSF api(for receive 0x3B/0x3C/0x3D data in one section filter)
) {
if (pSectionFilterCb->tidEx!=(unsigned short)-1 &&
SI_IS_ISDB_T(pDatabase->si) &&
(tid==SI_TID_DSM_DDB ||
tid==SI_TID_DSM_DXI||
tid==SI_TID_DSM_3E ||
tid==SI_TID_DSM_3D||
tid==SI_TID_DSM_3A||
tid==SI_TID_DSM_3F )
) {
//ETSI TR 101 202 V1.2.1 Table B.1
if (sectionLength>=5) {
tidEx = (unsigned short)((unsigned short)(sectionBuf[3])<<8|sectionBuf[4]);
if (tidEx==pSectionFilterCb->tidEx) {
if (pSectionFilterCb->callback_index==SI_Collector_SectionCallbackEx_INDEX_0)
{
pCallback=pSectionFilterCb->pCallback;
pthread_mutex_unlock(&pCollector->mutexSectionFilter);
pCallback(pSectionFilterCb->user_data, sectionLength, &sectionBuf, pid,tid,tidEx,false);
pthread_mutex_lock(&pCollector->mutexSectionFilter);

}
else
{
pCallback_userdata=pSectionFilterCb->pCallback_userdata;
pthread_mutex_unlock(&pCollector->mutexSectionFilter);
pCallback_userdata(pSectionFilterCb->user_data, sectionLength, &sectionBuf, pid,tid,tidEx,false,pSectionFilterCb->user_data_len);
pthread_mutex_lock(&pCollector->mutexSectionFilter);
}
}
}
} else {
tidEx=-1;
if(pSectionFilterCb->tidEx!=(unsigned short)-1 && sectionLength>=5)
{
tidEx = (unsigned short)((unsigned short)(sectionBuf[3])<<8|sectionBuf[4]);
}
if(pSectionFilterCb->tidEx == tidEx)
{
if (pSectionFilterCb->callback_index==SI_Collector_SectionCallbackEx_INDEX_0)
{
pCallback=pSectionFilterCb->pCallback;
pthread_mutex_unlock(&pCollector->mutexSectionFilter);
pCallback(pSectionFilterCb->user_data, sectionLength, &sectionBuf, pid,tid,tidEx,false);
pthread_mutex_lock(&pCollector->mutexSectionFilter);
}
else
{
pCallback_userdata=pSectionFilterCb->pCallback_userdata;
pthread_mutex_unlock(&pCollector->mutexSectionFilter);
pCallback_userdata(pSectionFilterCb->user_data, sectionLength, &sectionBuf, pid,tid,tidEx,false,pSectionFilterCb->user_data_len);
pthread_mutex_lock(&pCollector->mutexSectionFilter);
}
}
}
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
* vendor/realtek/frameworks/native/appclass/ \
* Si/liveTV_SiDvb/librtd/si4/database/SI_DatabaseSection.c
*/


ErrCode SI_Database_InsertSection(
SI_DATABASE *pDatabase,
unsigned int sectionLength,
unsigned char *sectionRawBuffer,
unsigned int pid
)
{
//省略代码段
switch(tid)
{
case SI_TID_PAT:
if (pid==PID_PAT)
err = si_database_insert_pat(pDatabase, sectionLength, sectionRawBuffer);
break;
case SI_TID_CAT:
if (pid==PID_CAT)
err = si_database_insert_cat(pDatabase, sectionLength, sectionRawBuffer);
break;
case SI_TID_PMT:
err = si_database_insert_pmt(pDatabase, sectionLength, sectionRawBuffer,pid);
break;
//省略代码段
default:
err = SI_ERR_SECTION_NOT_CHECKED;
break;
}
//省略代码段
SI_DB_RETURN(err);
}

static ErrCode si_database_insert_pmt(
SI_DATABASE *pDatabase,
unsigned int sectionLength,
unsigned char *sectionRawBuffer,
unsigned short pid
)
{
SI_DATABASE_TS_NODE *ts=NULL;
SI_DATABASE_VC_NODE *vc=NULL;
SI_DATABASE_SECTION *pmt=NULL;
unsigned short programNumber;
//int dataLen, infoLen;
unsigned char secNo=0,secNoLast=0,ver;

SI_DB_BEGIN();
//---- check length ----
if(sectionLength < 16)
SI_DB_RETURN(SI_ERR_SECTION_TOO_SHORT);

if((((unsigned int)sectionRawBuffer[1]&0x0F)<<8) + sectionRawBuffer[2] + 3 != sectionLength)
SI_DB_RETURN(SI_ERR_INVALIDSECTIONLENGTH);

if(si_database_check_crc(sectionRawBuffer, sectionLength))
SI_DB_RETURN(SI_ERR_CRC_ERROR);

//----------------------
ts = pDatabase->currentTS;
SI_ASSERT(ts);
secNo=sectionRawBuffer[6];
secNoLast=sectionRawBuffer[7];
ver = (sectionRawBuffer[5]&0x3F)>>1;

//get programNum and it's associated vc
SI_DB_GET_TABLEEXTENSION(sectionRawBuffer, programNumber);
SI_DB_GET_VCNODE_ADDR(ts, vc, programNumber);
if(!vc)
SI_DB_RETURN(SI_ERR_CANNOTINSERT);
if(vc->pmtPID == PID_NULL_PACKET || vc->pmtPID == 0)
{
vc->pmtPID=pid;
}
if (vc->pmtPID!=pid) {
SI_DB_RETURN(SI_ERR_CANNOTINSERT);
}

if (secNo>=SI_DB_SECTION_NUM_MAX || secNoLast>=SI_DB_SECTION_NUM_MAX ||
secNo>secNoLast) {
SI_DB_RETURN(SI_ERR_INVALIDSECTIONLENGTH);
}

if ((vc->pmt.count!=(secNoLast+1)) ||
((vc->pmt.ppSec!=NULL) && (vc->pmt.ver != ver))) {
SI_Database_DestroyMultiSection(pDatabase,ts,&vc->pmt,0);

}
if(vc->pmt.ppSec==NULL)
{
SI_Database_CreateMultiSection(&vc->pmt,secNoLast+1,ver);
}
else if(vc->pmt.ppSec[secNo])
{

vc->gotPMT=SI_Database_Is_Got_Mulit_Section(&vc->pmt);
if(SI_DB_COMPARE_SECOBJ_AND_SECBUF(vc->pmt.ppSec[secNo], sectionRawBuffer, sectionLength)==0)
{
if(ait_update.pmt == pid && ait_update.update)
goto CHECK_AIT;
SI_DB_RETURN(SI_ERR_DATAALREADYEXIST);
} else {
SI_Database_DestroyMultiSection(pDatabase,ts,&vc->pmt,0);
SI_Database_CreateMultiSection(&vc->pmt,secNoLast+1,ver);
}
}
pmt=si_database_GEN_SECTION(pDatabase,ts, vc,sectionLength, sectionRawBuffer,0);
vc->pmt.ppSec[secNo] = pmt;
vc->gotPMT=SI_Database_Is_Got_Mulit_Section(&vc->pmt);
printf("vc->gotPMT=%d,pid=%d %s,%s,%d\n",vc->gotPMT,pid,__FILE__,__FUNCTION__,__LINE__);

printf("\033[1;31m[vv] %s %d freq:%d, ver:%x sid %x\033[m\n",__FUNCTION__,__LINE__,ts->frequency,ver,
programNumber);

//vc->pmt = pmt;
#if 1//def ENABLE_NEW_DVB
vc->PMTParsed=FALSE;
#endif

SI_DB_RETURN(SI_ERR_OK);
}

到si_database_GEN_SECTION这里就算是组段完成了(具体细节没有去看了)?然后vc->gotPMT被置TRUE认为拿到了PMT

整理一下_SDEC_Thread线程创建:

TVservice

Initial

RegisterInitFunc

InitDTV

HalModulesInit

RHAL_SDEC_InitializeModule

_Initiallize

_SDEC_Thread

执行:

_SDEC_Thread

fnSDECDataHandlingCB

si_collector_copy_section

SI_Database_InsertSection

si_database_insert_pat

si_database_insert_pmt

si_database_GEN_SECTION

SI_Database_Is_Got_Mulit_Section

总结

不要忘了si_agent_threadfuntion线程,重新整理下:

si_agent_threadfuntion

SI_Agent_CollectSection

SiAgtIF_Run

SiAgentObj_ExecMainTaskSM

SiAgent_UpdateFilterTaskState

SiAgent_FTE_CheckTableReceive

SiAgtFW_CheckPatReceive

SiAgtFW_CheckPmtReceive

SI_Database_GetSectionReceiveFlag

SiAgent_SM_Main_ScanCh

SiAgent_GenScanChGetPatFtp

SiAgent_GenScanChGetTablesFtp

SI_Callback_ScanChannel

SI_Channel_UpdateChList_Append

si_channel_get_update_ch_list_in_ts

si_channel_new_channel_object

si_channel_fill_ch

SI_Database_GetChannelInfo

si_database_get_logical_num_and_onid

__si_database_get_logical_num_and_onid

SiAgent_ExecuteFilterTask

SiAgent_FTE_EnableSecFilter

SiAgent_Enable_GetTableFilter

SiAgent_Enable_GetPmtFilter

SiAgent_VSFM_CreatePidLayer

SiAgtFW_EnablePidFilter

SI_TPInterface_SetFilter

SI_BeanGen_EnablePid

RHAL_SDEC_RequestSection

fnSDECDataHandlingCB

SI_Collector_CollectSection

SI_TPInterface_GetBeanQueue

在扫台线程ScanThread Check SI,也就是si_agent_threadfuntion SI Agent Running阶段,注册fnSDECDataHandlingCB回调函数,_SDEC_Thread线程在Section来临时,执行这个回调函数,做组段动作,并拿数据和置位相应的状态位,si_agent_threadfuntion 根据这些状态位再更新FilterTaskState,判断扫台成功,再回调SI_Callback_ScanChannel发消息告诉ScanThread线程Check SI成功。

有点多,有点乱,这只是个大概,还有一些Bean、TaskPool的设计和实现细节需要理解。我不理解,我都是瞎写的。😅