搜索
 找回密码
 立即注册

简单一步 , 微信登陆

DTV模式下自动搜台分析

作者:sean | 时间:2016-9-28 11:09:16 | 阅读:7803| 只看该作者
本帖最后由 sean 于 2016-9-28 11:11 编辑

由于自己也是第一次分析,如果有错误请指出,谢谢
ChannelTuning Activity中的
        mTvChannelManager.switchMSrvDtvRouteCmd(currentRouteIndex);
        mTvChannelManager.startDtvAutoScan();
        TvChannelManager中的getInstance():
                 public static TvChannelManager getInstance() {
        /* Double-checked locking */
        if (mInstance == null) {
            synchronized (TvChannelManager.class) {
                if (mInstance == null) {
                    int tvsystem = TvCommonManager.getInstance().getCurrentTvSystem();
                    Log.d(TAG, "tvsystem is " + tvsystem);
                    switch (tvsystem) {
                        case TvCommonManager.TV_SYSTEM_DVBT:
                        case TvCommonManager.TV_SYSTEM_DVBC:
                        case TvCommonManager.TV_SYSTEM_DVBS:
                        case TvCommonManager.TV_SYSTEM_DVBT2:
                        case TvCommonManager.TV_SYSTEM_DVBS2:
                        case TvCommonManager.TV_SYSTEM_DTMB: {
                            mInstance = TvDvbChannelManager.getInstance();
                            break;
                        }
                        case TvCommonManager.TV_SYSTEM_ATSC: {
                            mInstance = TvAtscChannelManager.getInstance();
                            break;
                        }
                        case TvCommonManager.TV_SYSTEM_ISDB: {
                            mInstance = TvIsdbChannelManager.getInstance();
                            break;
                        }
                        default: {
                            Log.e(TAG, "Tv system is not specified!! getInstance FAIL!!");
                            break;
                        }
                    }
                }
            }
        }
        return mInstance;
    }
        TvDvbChannelManager中的getInstance();
         public static TvDvbChannelManager getInstance() {
        /* Only dvb system can get this instance */
        if ((TvCommonManager.getInstance().getCurrentTvSystem() == TvCommonManager.TV_SYSTEM_ATSC)
            || (TvCommonManager.getInstance().getCurrentTvSystem() == TvCommonManager.TV_SYSTEM_ISDB)) {
            throw new IllegalAccessError("Only dvb system can get dvb channelmanager instance");
        }
        /* Double-checked locking */
        if (mInstance == null) {
            synchronized (TvDvbChannelManager.class) {
                if (mInstance == null) {
                    try {
                        mInstance = new TvDvbChannelManager();
                    } catch (TvCommonException e) {
                        e.printStackTrace();
                        return null;
                    }
                }
            }
        }
        return (TvDvbChannelManager)mInstance;
    }
        得到了TvDvbChannelManager对象的实例mInstance,调用 startDtvAutoScan()方法,该方法在TvDvbChannelManager没有定义
        找到TvDvbChannelManager的父类TvChangeManager,在TVChangeManager中找到了startDtvAutoScan()方法,查看他的具体实现
        public boolean startDtvAutoScan() {
        try {
            return mService.startDtvAutoScan();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return false;
    }
        查看mService的赋值操作
        mDvbcScanParam = new DvbcScanParam();
        mService = ITvService.Stub.asInterface(b).getTvChannel();
        mServices是ITvChannel.aidl类型  找到他的实现类TvChannelService
        具体实现如下:
        @Override
    public boolean startDtvAutoScan() throws RemoteException {
       makeSourceDtv();//让当前的source切为DTV
        try {
            if (DtvManager.getDvbcScanManager() != null) {
                DtvManager.getDvbcScanManager().startAutoScan();
                mTuningStatus = TvChannelManager.TUNING_STATUS_DTV_AUTO_TUNING;
            }
        } catch (TvCommonException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
        DtvManager中
        public static DvbcScanManager getDvbcScanManager() {
        DtvScanImplProxy implcld = new DtvScanImplProxy();
        return (DvbcScanManager) implcld.getScanImplInstance();//返回的实例是DvbcScanManger类型
    }
        查看DvbcScanManager类中的startAutoScan()方法。 DvbcScanManager是个接口 找到他的实现类ScanManagerImpl
        在查看ScanManagerImpl.java中的具体实现,发现是个本地方法
         public native final void startAutoScan() throws TvCommonException;
         
        找到对应的jni文件ScanManagerImpl.cpp文件
        void com_mstar_android_tvapi_impl_ScanManagerImpl_startAutoScan
        (JNIEnv *env, jobject thiz) {
                ALOGI("startAutoScan");
                sp<ScanManagerImpl> ms = getScanManagerImpl(env, thiz);
                if (ms == NULL) {
                        jniThrowException(env, "com/mstar/android/tvapi/common/exception/TvIpcException", "can not connect to server");
                        return;
                }
                ms->startAutoScan();//调用supernova层中的ScanManagerImpl的startAutoScan()方法。
        }
        里面的getScanManagerImpl(env, thiz)方法实现
        static sp<ScanManagerImpl> getScanManagerImpl(JNIEnv *env, jobject thiz) {
                //return scanManagerImpl;
                Mutex::Autolock l(sLock);
                ScanManagerImpl *c**t p = (ScanManagerImpl *)env->GetLongField(thiz, fields.context);
                return sp<ScanManagerImpl>(p); //这里的ScanManagerImpl是supernova中的
        }
        
        在supernova层 ScanManagerImpl.cpp文件中调用
        void ScanManagerImpl::startAutoScan()
        {
                ALOGV("ScanManagerImpl startAutoScan\n");
                mScanManagerImpl->startAutoScan();
        }
        查看mScanManagerImpl的定义可知  
        sp<IScanManagerImpl> mScanManagerImpl; //IScanManagerImpl类型
        查看IScanManagerImpl中的
        case DTVSCANMANAGER_START_AUTO_SCAN:
    {
        printf("Receive DTVSCANMANAGER_START_AUTO_SCAN\n");
        CHECK_INTERFACE(IScanManagerImpl, data, reply);
        startAutoScan();
        return NO_ERROR;
    } break;
        
        具体实现看 ScanMnagerImplService中的
        void ScanManagerImplService::Client::startAutoScan()
        {
        #if(RELEASE_BINDER_TEST == 1)
                TEST_STARTAUTOSCAN() ;
        #endif
                TVOS_API_ESTIMATE_START()
                TVOS_API_ESTIMATE_START(LOCK)
                Mutex::Autolock lock(m_FuncLock);
                TVOS_API_ESTIMATE_END(LOCK)
                printf("ScanManagerImplService::Client::startAutoScan\n");
        
                MAPI_INPUT_SOURCE_TYPE enCurrentInputType;
                enCurrentInputType = MSrv_Control::GetInstance()->GetCurrentInputSource();
        
                if (enCurrentInputType != MAPI_INPUT_SOURCE_DTV)
                {
                        printf("startAutoScan FAILED, incorrect input source:%d\n", enCurrentInputType);
                        TVOS_API_ESTIMATE_END()
                        return;
                }
        
                bool ret = MSrv_Control::GetMSrvDtv()->StartAutoScan();//开始自动扫描
                if (!ret)
                        printf("MSrv_DTV_Player::StartAutoScan in ScanManagerImplService::Client::startAutoScan FAILED\n");
        #if (ATSC_SYSTEM_ENABLE == 1)
                MSrv_Control::GetMSrvAtvDatabase()->CommondCmd(RESET_ATV_DATA_MANAGER , 0 , 0 , NULL);
        #endif
                TVOS_API_ESTIMATE_END()
        }                              
        看下Msrv_Control中得方法
        MSrv_DTV_Player * MSrv_Control_TV::GetMSrvDtv(MAPI_SCALER_WIN eWin)
        {
                MSRV_CONTROL_TV_INFO("%s line %d\n", __PRETTY_FUNCTION__, __LINE__);
                EN_MSRV_PLAYER_LIST currentDtvPlayer = (EN_MSRV_PLAYER_LIST)(E_MSRV_DTV_PLAYER_0 + MSrv_PlayerControl::GetInstance()->GetCurrentDtvRoute(eWin));
                MSrv_DTV_Player *p = dynamic_cast<MSrv_DTV_Player *>(MSrv_PlayerControl::GetInstance()->GetMSrvPlayer(currentDtvPlayer));
                ASSERT(p);
                return p;
        }
        查看MSrv_DTV_Player方法:
        BOOL MSrv_DTV_Player::StartAutoScan()
        {
                MW_DTV_PLAYER_FUNCTION("BOOL MSrv_DTV_Player::StartAutoScan() \n");
        
                return AutoScan();
        }
        查看AutoScan()方法:
        BOOL MSrv_DTV_Player::AutoScan()
        {
                MW_DTV_PLAYER_FUNCTION("BOOL MSrv_DTV_Player::AutoScan() \n");
        
                if(!m_bInit)
                {
                        MW_DTV_PLAYER_ERROR("Error --- DTV Player not Initial !! \n");
                        ASSERT(0);
                        return FALSE;
                }
        #if (OAD_ENABLE == 1)
                if(_IsOadDownloading())
                {
                        //printf("OAD is downlaoding, cannot do AutoScan!!!\n");
                        return FALSE;
                }
        #endif
        
        #if (AUTO_TEST == 1)
                printf("[AT][SN][DTV_AutoScan Function][%u]\n", mapi_time_utility::GetTime0());//会执行这里 日志输出
        #endif
        
                m_bIsScanning = TRUE;//For ATSC UI Function
        
                return SetCMD(MSRV_DTV_BASE_CMD_AUTO_SCAN, 0);//继续调用SetCmd方法
        }
        查看SetCMD方法
        SetCMD方法中有  m_pcDtvEv->Send(cDtvPlayerInfo, bPushFront);发送一个消息
        在Msrv_DTV_Player.cpp文件中有个DtvPlayerMain方法接收消息  while循环不断的switch判断消息
        case MSRV_DTV_BASE_CMD_AUTO_SCAN:
                                                        MW_DTV_PLAYER_INFO("======> MSRV_DTV_BASE_CMD_AUTO_SCAN start \n");
        #if (HBBTV_ENABLE == 1)
                                                        if(MW_HBBTV::GetCheckedInstance())
                                                        {
                                                                MW_HBBTV::GetCheckedInstance()->StopHBBTVService();
                                                                ReleaseVideoBroadcastResource();
                                                        }
        #endif
        #if (AUTO_TEST == 1)
                                                        printf("[AT][SN][DTV_AutoScanCmd START][%u]\n", mapi_time_utility::GetTime0());
        #endif
        
                                                _DoAutoScan();//开始扫描
                                                        MW_DTV_PLAYER_INFO("======> MSRV_DTV_BASE_CMD_AUTO_SCAN end \n");
                                                        break;
        查看MSrv_DTV_Player中的_DoAutoScan()方法
        BOOL MSrv_DTV_Player::_DoAutoScan(void)
        {
                return DoAutoScan();
        }
        DoAutoScan方法定义为虚函数 virtual BOOL DoAutoScan(void) = 0; 虚函数  他自己并没有具体的实现
        找到他的子类,他的子类有很多,不同的信号制式情况下DTV的自动扫描的实现都是不同的,找到对应制式下的
        class MSrv_DTV_Player_DVB : public MSrv_DTV_Player,但是MSrv_DTV_Player_DVB中仍然没有具体的实现
        继续找到MSrv_DTV_Player_DVB的一个子类 MSrv_DTV_Player_DTMB(还有其他的子类,这里不同的子类中已经有DoAutoScan的具体实现了)
        
        查看MSrv_DTV_Player_DTMB中的DoAutoScan()方法
        BOOL MSrv_DTV_Player_DTMB:oAutoScan()
        {
                MSRV_DTMB_PLAYER_FUNCTION("MSrv_DTV_Player_DTMB:oAutoScan()\n");
        
                CHECK_DTMB_PLAYER_INITIAL_DONE();
        
                if(!m_pcScan)
                {
                        DoScanInit();//初始化扫描配置  建立几个事件传输接口
                }
                BOOL bRst = FALSE;
        
                bRst = DisableChannel();
        
                m_pcAVMonitor->ResetAVInfo();
        
                CHECK_RESULT(bRst);
        
                m_u16CurUserONID = 0;
                m_u16CurUserTSID = 0;
                m_u16CurUserSID = 0;
                m_u16CurUserServiceNumber = 0; //for MHEG5
                m_u16CurRealONID = 0;
                m_u16CurRealTSID = 0;
                m_u16CurRealSID = 0;
                m_u16CurRealServiceNumber = 0;
        
                MW_DTV_Scan_DTMB* pcScanDTMB = dynamic_cast<MW_DTV_Scan_DTMB*>(m_pcScan);
                if(NULL == pcScanDTMB)
                {
                        ASSERT(0);
                        return FALSE;
                }
        bRst = pcScanDTMB->StartAutoScan();//扫描

                CHECK_RESULT(bRst);
                HandleScanEvent();//处理扫描事件(接收消息,暂停,停止,继续等事件,)
                return TRUE;
        }
        上面中的StartAutoScan()方法是在MW_DTV_Scan_Dtmb中执行的
        BOOL MW_DTV_Scan_DTMB::StartAutoScan()
        {
                MW_DTV_SCAN_DTMB_FUNCTION("MW_DTV_Scan_DTMB::StartAutoScan()\n");
        
                CHECK_DTV_SCAN_INITIAL_DONE();
                CHECK_DTMB_SCAN_SET_DATA_DONE();
        
                MW_DTMB_ScanInfo cScanInfo;
                U32 u32res;
        
                cScanInfo.m_enScanCmd = MW_DTMB_ScanInfo::CMD_SCAN;
                cScanInfo.m_enScanType = MW_DTMB_ScanInfo::SCAN_TYPE_AUTO;
        
                cScanInfo.m_u8RFCh = 0;
                cScanInfo.m_u32Frequency = 0;
        
        u32res = m_pcScanEv->Send(cScanInfo);//发送搜索命令和搜索类型给MW_DTV_Scan_DVBT 开始进入搜索;

                if(u32res == 0)
                {
                        return TRUE;
                }
        
                return FALSE;
        }

        HandleScanEvent();接收处理搜索的事件,包括暂停,继续,停止,完成等事件。
        BOOL MSrv_DTV_Player_DVB::HandleScanEvent()
        {
                MSRV_DVB_PLAYER_FUNCTION("MSrv_DTV_Player_DVB::HandleScanEvent()\n");
        
                int retcode;
                MS_DTV_PlayerInfo cDTVInfo;
                m_bIsScanning=TRUE;
                BOOL bExitScan = FALSE;
                while(!bExitScan)
                {
                        retcode = PTH_RET_CHK(m_pcDtvEv->Wait(&cDTVInfo, 30));
                        if(retcode == 0)
                        {
                                if(cDTVInfo.u32Event <= MSRV_DTV_BASE_CMD_MAX)
                                {
                                        switch(cDTVInfo.u32Event)
                                        {
                                                case MSRV_DTV_BASE_CMD_PAUSE_SCAN:  //For auto scan
                                                        m_pcScan->ause();
                                                        break;
                                                case MSRV_DTV_BASE_CMD_RESUME_SCAN: //For auto scan
                                                        m_pcScan->Resume();
                                                        break;
                                                case MSRV_DTV_BASE_CMD_MANUAL_CHANGE_RF: //For manual scan
                                                        DoChangScanRF((U8)cDTVInfo.u32Param1);
                                                        break;
                                                case MSRV_DTV_BASE_CMD_MANUAL_CHANGE_FREQ: //For manual scan
                                                        DoChangScanFreq(cDTVInfo.u32Param1);
                                                        break;
                                                case MSRV_DTV_BASE_CMD_MANUAL_CONTINUE_SCAN:
                                                case MSRV_DTV_BASE_CMD_CONTINUE_SCAN: //For manual scan and auto scan
        #if (CI_PLUS_ENABLE == 1)
                                                        if (TRUE == IsCiOccupiedTuner(TRUE))
                                                        {
                                                                MSRV_DVB_PLAYER_INFO("Block Manual Scan \n");
                                                        }
                                                        else
        #endif
                                                        {
                                                                m_pcScan->Continue();
                                                        }
                                                        break;
                                                case MSRV_DTV_BASE_CMD_STOP_SCAN: //For manual scan and auto scan
                                                        m_pcScan->Stop();
                                                        m_u16CurRealServiceNumber = 0;
                                                        m_u8CurRealServiceType = 0;
                                                        bExitScan = TRUE;
                                                        break;
                                                case MSRV_DTV_BASE_CMD_FINISH_SCAN:
                                                        m_u16CurRealServiceNumber = 0;
                                                        m_u8CurRealServiceType = 0;
                                                        bExitScan = TRUE;
                                                        break;
                                                default:
                                                        MSRV_DVB_PLAYER_ERROR("please send MSRV_DTV_BASE_CMD_STOP_SCAN command! %d\n", cDTVInfo.u32Event);
                                                        //ASSERT(0);//remove assert, discard old message
                                                        break;
        
                                        }
                                }
                                else
                                {
                                        DoExtendCmd(cDTVInfo.u32Event, cDTVInfo.u32Param1, cDTVInfo.u32Param2, cDTVInfo.u32Param3);
                                }
                        }
                }
        
                m_bIsScanning=FALSE;
                return TRUE;
        }
        m_pcScan->Init();//调用MW_DTV_Scan_DTMB_Customer 父类的MW_DTV_Scan_DTMB父类MW_DTV_Scan中的Init 由MW_DTV_Scan::Init 再回调 MW_DTV_Scan_DTMB:oInit// bRet = DoInit();
        //NOTE:MW_DTV_Scan::Init 时创建了ScanThreadFunc 搜索线程。此线程会回调MW_DTV_Scan_DTMB 中的ScanThreadBody
        Supernova/projects/msrv/dvb/dtmb/middleware/src/MW_DTV_Scan_DTMB.cpp
        void MW_DTV_Scan_DTMB::ScanThreadBody()
        {
                MW_DTV_SCAN_DTMB_FUNCTION("MW_DTV_Scan_DTMB::ScanThreadBody \n");
        
                MW_DTMB_ScanInfo cScanInfo;
                BOOL bScanExit = FALSE;
        
                while(!bScanExit)
                {
                        MW_DTV_SCAN_DTMB_DBG("MW_DTV_Scan_DTMB::ScanMain -- wait command \n");
                        m_pcScanEv->Wait(&cScanInfo);//此处不断的获取ScanInfo 对搜索的命令进行解析
                        MW_DTV_SCAN_DTMB_DBG("MW_DTV_Scan_DTMB::ScanMain -- Get CMD %d \n", (U32)cScanInfo.m_enScanCmd);
                        if((cScanInfo.m_enScanCmd == MW_DTMB_ScanInfo::CMD_SCAN) &&
                        (cScanInfo.m_enScanType != MW_DTMB_ScanInfo::SCAN_TYPE_OADSCAN))//DTMB 的搜台进入此条件
                        {
                                m_enScanState = STATE_SCAN_INIT;
                                m_bSentStop = FALSE;
                                m_bSentContinue = FALSE;
                                CopyScanRequirementInfo(&cScanInfo);
                                if(!ScanMain())//正式进入搜索主体
                                {
                                        bScanExit = TRUE;
                                }
                                m_enScanState = STATE_SCAN_IDLE;
                                MW_DTV_SCAN_DTMB_AUTOTEST("DTV_Scan_End\n");
                                SendDTMBScanRetInfo(MW_DTV_ScanRetInfo::STATUS_SCAN_END);
                        }
        #if (OAD_ENABLE == 1)
                        else if((cScanInfo.m_enScanCmd == MW_DTMB_ScanInfo::CMD_SCAN) && (cScanInfo.m_enScanType == MW_DTMB_ScanInfo::SCAN_TYPE_OADSCAN))
                        {
                                m_enScanState = STATE_SCAN_INIT;
                                m_bSentStop = FALSE;
                                m_bSentContinue = FALSE;
                                CopyScanRequirementInfo(&cScanInfo);
                                if(!OadScanMain())
                                {
                                        bScanExit = TRUE;
                                }
                                m_enScanState = STATE_SCAN_IDLE;
                                MW_DTV_SCAN_DTMB_AUTOTEST("DTV_Scan_End\n");
                                if(m_bExitToDL == FALSE)
                                {
                                        SendDTMBScanRetInfo(MW_DTV_ScanRetInfo::STATUS_SCAN_END);
                                }
                                else
                                {
                                        SendDTMBScanRetInfo(MW_DTV_ScanRetInfo::STATUS_EXIT_TO_DL);
                                }
        
                        }
        #endif
                        else if(cScanInfo.m_enScanCmd == MW_DTMB_ScanInfo::CMD_FINALIZE)
                        {
                                bScanExit = TRUE;
                        }
                }
        }
        具体ScanMain实现
        supernova/projects/msrv/common/middleware/src/MW_DTV_Scan.cpp
        BOOL MW_DTV_Scan::ScanMain(void)
        {
                MW_DTV_SCAN_FUNCTION("MW_DTV_Scan:oStartScan \n");
        
                BOOL bFinish = FALSE;
                BOOL bRst = FALSE;
        
                while(!bFinish)
                {
                        if((m_enScanState != STATE_SCAN_INIT) && (m_enScanState != STATE_SCAN_END))
                        {
                                m_enScanState = DoHandleEvt();
                        }
                        switch(m_enScanState)
                        {
                                case STATE_SCAN_INIT:
                                {
                                        m_enScanState = ScanState_Init();
                                        break;
                                }
                                case STATE_SCAN_NEXT_CHANNEL:
                                        m_enScanState = ScanState_ScanNextChannel();
                                        break;
                                case STATE_SCAN_TUNE_TO_RF_CHANNEL:
                                        m_enScanState = ScanState_TuneToRFChannel();
                                        break;
                                case STATE_SCAN_GET_PROGRAMS:
                                        m_enScanState = ScanState_GetPrograms();
                                        break;
                                case STATE_SCAN_SAVE_PROGRAMS:
                                        m_enScanState = ScanState_SavePrograms();//主要是对上一步搜索到的节目进行存储
                                        break;
                                case STATE_SCAN_PAUSE:
                                        m_enScanState = ScanState_Pause();
                                        break;
                                case STATE_SCAN_END:
                                {
                                        m_enScanState = ScanState_End();
                                        bRst = DoCMDBReArrange();
                                        if(!bRst)
                                        {
                                                ASSERT(0);
                                                return FALSE;
                                        }
                                        bRst = DoSetFirstProg();
                                        if(!bRst)
                                        {
                                                ASSERT(0);
                                                return FALSE;
                                        }
                                        bFinish = TRUE;
        #if (AUTO_TEST == 1)
                                        if (m_enScanType == MW_DTV_ScanInfo::SCAN_TYPE_AUTO)
                                        {
                                                printf("[AT][SN][DTV_AutoScanCmd END][%u]\n", mapi_time_utility::GetTime0());
                                        }
        #endif
                                        break;
                                }
                                case STATE_SCAN_DVBS_REINIT:    //  DVBS only
                                        m_enScanState = ScanState_End();
                                        bRst = DoCMDBReArrange();
                                        if(!bRst)
                                        {
                                                ASSERT(0);
                                                return FALSE;
                                        }
                                        m_enScanState = ScanState_Init();
                                        break;
                                default:
                                        bFinish = TRUE;
                                        break;
                        }
                }
                return TRUE;
        }



收藏
收藏0
分享
分享
点赞
点赞25
反对
反对0
该会员没有填写今日想 ...
回复

使用道具 举报

大神点评6

沙发#
creass 发表于:2016-9-28 11:10:32
好专业的帖子啊
hahaahhahaha!!123
回复 支持 反对

使用道具 举报

板凳#
steven 发表于:2016-9-28 11:21:08
全是字,懒得看啊...
回复 支持 反对

使用道具 举报

地板#
sean 发表于:2016-9-28 11:37:30
steven 发表于 2016-9-28 11:21
全是字,懒得看啊...

额 代码贴的有点多了 下次贴少点
该会员没有填写今日想 ...
回复 支持 反对

使用道具 举报

5#
sean 发表于:2016-9-28 11:38:36
creass 发表于 2016-9-28 11:10
好专业的帖子啊

有错误的话还请指出,谢谢
该会员没有填写今日想 ...
回复 支持 反对

使用道具 举报

6#
xuludestiny 发表于:2016-12-26 11:49:17
字太多,确实不想看了!
感谢分析!
把水灌满
回复 支持 反对

使用道具 举报

7#
xuludestiny 发表于:2016-12-26 11:49:40
感谢分享
把水灌满
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册
手机版