[FCC] Fix to perform normal decoding for usb tuner on FCC mode.
[vuplus_dvbapp] / lib / dvb / pmt.cpp
index e5e6331..fbd9b8f 100644 (file)
 #include <dvbsi++/teletext_descriptor.h>
 #include <dvbsi++/video_stream_descriptor.h>
 #include <dvbsi++/registration_descriptor.h>
+#include <dvbsi++/ac3_descriptor.h>
+
+#include <dvbsi++/simple_application_location_descriptor.h>
+#include <dvbsi++/simple_application_boundary_descriptor.h>
+#include <dvbsi++/transport_protocol_descriptor.h>
+#include <dvbsi++/application_name_descriptor.h>
+
 
 eDVBServicePMTHandler::eDVBServicePMTHandler()
        :m_ca_servicePtr(0), m_dvb_scan(0), m_decode_demux_num(0xFF), m_no_pat_entry_delay(eTimer::create())
 {
        m_use_decode_demux = 0;
        m_pmt_pid = -1;
+       m_dsmcc_pid = -1;
+       m_service_type = livetv;
+       m_descramble = true;
+       m_ca_disabled = false;
+       m_pmt_ready = false;
        eDVBResourceManager::getInstance(m_resourceManager);
        CONNECT(m_PMT.tableReady, eDVBServicePMTHandler::PMTready);
        CONNECT(m_PAT.tableReady, eDVBServicePMTHandler::PATready);
        CONNECT(m_no_pat_entry_delay->timeout, eDVBServicePMTHandler::sendEventNoPatEntry);
+
+       CONNECT(m_AIT.tableReady, eDVBServicePMTHandler::AITready);
+       CONNECT(m_OC.tableReady, eDVBServicePMTHandler::OCready);
 }
 
 eDVBServicePMTHandler::~eDVBServicePMTHandler()
@@ -92,36 +107,54 @@ void eDVBServicePMTHandler::channelEvent(iDVBChannel *channel, int event)
        case iDVBChannel::evtSOF:
                serviceEvent(eventSOF);
                break;
+       case iDVBChannel::evtFailed+3:
+               serviceEvent(eventNoDiskSpace);
+               break;
        default:
                break;
        }
 }
 
+void eDVBServicePMTHandler::registerCAService()
+{
+       int demuxes[2] = {0,0};
+       uint8_t demuxid;
+       m_demux->getCADemuxID(demuxid);
+       demuxes[0]=demuxid;
+       if (m_decode_demux_num != 0xFF)
+               demuxes[1]=m_decode_demux_num;
+       else
+               demuxes[1]=demuxes[0];
+       eDVBCAService::register_service(m_reference, demuxes, m_ca_servicePtr);
+}
+
 void eDVBServicePMTHandler::PMTready(int error)
 {
        if (error)
                serviceEvent(eventNoPMT);
        else
        {
+               m_pmt_ready = true;
                m_have_cached_program = false;
                serviceEvent(eventNewProgramInfo);
-               if (!m_pvr_channel) // don't send campmt to camd.socket for playbacked services
+
+               mDemuxId = m_decode_demux_num;
+               if (!m_pvr_channel)
                {
                        eEPGCache::getInstance()->PMTready(this);
+               }
+
+               if (m_descramble)
+               {
                        if(!m_ca_servicePtr)
                        {
-                               int demuxes[2] = {0,0};
-                               uint8_t tmp;
-                               m_demux->getCADemuxID(tmp);
-                               demuxes[0]=tmp;
-                               if (m_decode_demux_num != 0xFF)
-                                       demuxes[1]=m_decode_demux_num;
-                               else
-                                       demuxes[1]=demuxes[0];
-                               eDVBCAService::register_service(m_reference, demuxes, m_ca_servicePtr);
+                               registerCAService();
+                       }
+                       if (!m_ca_disabled)
+                       {
                                eDVBCIInterfaces::getInstance()->recheckPMTHandlers();
+                               eDVBCIInterfaces::getInstance()->gotPMT(this);
                        }
-                       eDVBCIInterfaces::getInstance()->gotPMT(this);
                }
                if (m_ca_servicePtr)
                {
@@ -131,6 +164,9 @@ void eDVBServicePMTHandler::PMTready(int error)
                        else
                                eDebug("eDVBServicePMTHandler cannot call buildCAPMT");
                }
+
+               if (m_service_type == pvrDescramble)
+                       serviceEvent(eventStartPvrDescramble);
        }
 }
 
@@ -187,6 +223,233 @@ void eDVBServicePMTHandler::PATready(int)
                serviceEvent(eventNoPAT);
 }
 
+static void eraseHbbTVApplications(HbbTVApplicationInfoList  *applications)
+{
+       if(applications->size() == 0)
+               return;
+       for(HbbTVApplicationInfoListConstIterator info = applications->begin() ; info != applications->end() ; ++info)
+               delete(*info);
+       applications->clear();
+}
+
+void saveData(int orgid, unsigned char* data, int sectionLength)
+{
+       int fd = 0, rc = 0;
+       char fileName[255] = {0};
+       sprintf(fileName, "/tmp/ait.%d", orgid);
+
+       if (data[6] > 0) {
+               eDebug("section_number %d > 0", data[6]);
+               data[6] = 0;
+       }
+       if (data[7] > data[6]) {
+               eDebug("last_section_number %d > section_number %d", data[7], data[6]);
+               data[7] = data[6];
+       }
+
+       if((fd = open(fileName, O_RDWR|O_CREAT|O_TRUNC)) < 0)
+       {
+               eDebug("Fail to save a AIT Data.");
+               return;
+       }
+       rc = write(fd, data, sectionLength);
+       eDebug("Save Data Len : [%d]", rc);
+       close(fd);
+}
+
+#include <dvbsi++/application_profile.h>
+#include <dvbsi++/application_descriptor.h>
+#include <dvbsi++/simple_application_boundary_descriptor.h>
+#define PACK_VERSION(major,minor,micro) (((major) << 16) + ((minor) << 8) + (micro))
+#define UNPACK_VERSION(version,major,minor,micro) { \
+       major = (version)&0xff; \
+       minor = (version>>8)&0xff; \
+       micro = (version>>16)&0xff; \
+}
+void eDVBServicePMTHandler::AITready(int error)
+{
+       eDebug("AITready");
+       ePtr<eTable<ApplicationInformationSection> > ptr;
+       if (!m_AIT.getCurrent(ptr))
+       {
+               short profilecode = 0;
+               int orgid = 0, appid = 0, profileVersion = 0;
+               m_ApplicationName = m_HBBTVUrl = "";
+
+               eraseHbbTVApplications(&m_HbbTVApplications);
+
+               int sectionLength = 0;
+               for (std::vector<ApplicationInformationSection*>::const_iterator it = ptr->getSections().begin(); it != ptr->getSections().end(); ++it)
+               {
+                       std::list<ApplicationInformation *>::const_iterator i = (*it)->getApplicationInformation()->begin();
+                       memcpy(m_AITData, ptr->getBufferData(), 4096);
+                       sectionLength = (*it)->getSectionLength() + 3;
+                       eDebug("Section Length : %d, Total Section Length : %d", (*it)->getSectionLength(), sectionLength);
+                       for (; i != (*it)->getApplicationInformation()->end(); ++i)
+                       {
+                               std::string hbbtvUrl = "", applicaionName = "";
+                               std::string boundaryExtension = "";
+                               
+                               int controlCode = (*i)->getApplicationControlCode();
+                               const ApplicationIdentifier * applicationIdentifier = (*i)->getApplicationIdentifier();
+                               profilecode = 0;
+                               orgid = applicationIdentifier->getOrganisationId();
+                               appid = applicationIdentifier->getApplicationId();
+                               eDebug("found applicaions ids >> pid : %x, orgid : %d, appid : %d", m_ait_pid, orgid, appid);
+                               if (controlCode == 1)
+                                       saveData(orgid, m_AITData, sectionLength);
+                               if (controlCode == 1 || controlCode == 2) /* 1:AUTOSTART, 2:ETC */
+                               {
+                                       for (DescriptorConstIterator desc = (*i)->getDescriptors()->begin();
+                                               desc != (*i)->getDescriptors()->end(); ++desc)
+                                       {
+                                               switch ((*desc)->getTag())
+                                               {
+                                               case APPLICATION_DESCRIPTOR:
+                                               {
+                                                       ApplicationDescriptor* applicationDescriptor = (ApplicationDescriptor*)(*desc);
+                                                       const ApplicationProfileList* applicationProfiles = applicationDescriptor->getApplicationProfiles();
+                                                       ApplicationProfileConstIterator interactionit = applicationProfiles->begin();
+                                                       for(; interactionit != applicationProfiles->end(); ++interactionit)
+                                                       {
+                                                               profilecode = (*interactionit)->getApplicationProfile();
+                                                               profileVersion = PACK_VERSION(
+                                                                       (*interactionit)->getVersionMajor(),
+                                                                       (*interactionit)->getVersionMinor(),
+                                                                       (*interactionit)->getVersionMicro()
+                                                               );
+                                                       }
+                                                       break;
+                                               }
+                                               case APPLICATION_NAME_DESCRIPTOR:
+                                               {
+                                                       ApplicationNameDescriptor *nameDescriptor  = (ApplicationNameDescriptor*)(*desc);
+                                                       ApplicationNameConstIterator interactionit = nameDescriptor->getApplicationNames()->begin();
+                                                       for(; interactionit != nameDescriptor->getApplicationNames()->end(); ++interactionit)
+                                                       {
+                                                               applicaionName = (*interactionit)->getApplicationName();
+                                                               if(controlCode == 1) m_ApplicationName = applicaionName;
+                                                               break;
+                                                       }
+                                                       break;
+                                               }
+                                               case TRANSPORT_PROTOCOL_DESCRIPTOR:
+                                               {
+                                                       TransportProtocolDescriptor *transport = (TransportProtocolDescriptor*)(*desc);
+                                                       switch (transport->getProtocolId())
+                                                       {
+                                                       case 1: /* object carousel */
+                                                               if (m_dsmcc_pid >= 0)
+                                                               {
+                                                                       m_OC.begin(eApp, eDVBDSMCCDLDataSpec(m_dsmcc_pid), m_demux);
+                                                               }
+                                                               break;
+                                                       case 2: /* ip */
+                                                               break;
+                                                       case 3: /* interaction */
+                                                               {
+                                                                       InterActionTransportConstIterator interactionit = transport->getInteractionTransports()->begin();
+                                                                       for(; interactionit != transport->getInteractionTransports()->end(); ++interactionit)
+                                                                       {
+                                                                               hbbtvUrl = (*interactionit)->getUrlBase()->getUrl();
+                                                                               break;
+                                                                       }
+                                                                       break;
+                                                               }
+                                                       }
+                                                       break;
+                                               }
+                                               case GRAPHICS_CONSTRAINTS_DESCRIPTOR:
+                                                       break;
+                                               case SIMPLE_APPLICATION_LOCATION_DESCRIPTOR:
+                                               {
+                                                       SimpleApplicationLocationDescriptor *applicationlocation = (SimpleApplicationLocationDescriptor*)(*desc);
+                                                       hbbtvUrl += applicationlocation->getInitialPath();
+                                                       break;
+                                               }
+                                               case APPLICATION_USAGE_DESCRIPTOR:
+                                                       break;
+                                               case SIMPLE_APPLICATION_BOUNDARY_DESCRIPTOR:
+                                                       break;
+                                               }
+                                       }
+                               }
+                               if(!hbbtvUrl.empty())
+                               {
+                                       const char* uu = hbbtvUrl.c_str();
+                                       if(!strncmp(uu, "http://", 7) || !strncmp(uu, "dvb://", 6) || !strncmp(uu, "https://", 8))
+                                       {
+                                               if(controlCode == 1) m_HBBTVUrl = hbbtvUrl;
+                                               switch(profileVersion)
+                                               {
+                                               case 65793:
+                                               case 66049:
+                                                       m_HbbTVApplications.push_back(new HbbTVApplicationInfo(controlCode, orgid, appid, hbbtvUrl, applicaionName, profilecode));
+                                                       break;
+                                               case 1280:
+                                               case 65538:
+                                               default:
+                                                       m_HbbTVApplications.push_back(new HbbTVApplicationInfo((-1)*controlCode, orgid, appid, hbbtvUrl, applicaionName, profilecode));
+                                                       break;
+                                               }
+                                       }
+                                       else if (!boundaryExtension.empty()) {
+                                               if(boundaryExtension.at(boundaryExtension.length()-1) != '/') {
+                                                       boundaryExtension += "/";
+                                               }
+                                               boundaryExtension += hbbtvUrl;
+                                               if(controlCode == 1) m_HBBTVUrl = boundaryExtension;
+                                               switch(profileVersion)
+                                               {
+                                               case 65793:
+                                               case 66049:
+                                                       m_HbbTVApplications.push_back(new HbbTVApplicationInfo(controlCode, orgid, appid, boundaryExtension, applicaionName, profilecode));
+                                                       break;
+                                               case 1280:
+                                               case 65538:
+                                               default:
+                                                       m_HbbTVApplications.push_back(new HbbTVApplicationInfo((-1)*controlCode, orgid, appid, boundaryExtension, applicaionName, profilecode));
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               if (m_HbbTVApplications.size())
+               {
+                       for(HbbTVApplicationInfoListConstIterator infoiter = m_HbbTVApplications.begin() ; infoiter != m_HbbTVApplications.end() ; ++infoiter)
+                       {
+                               char fileName[255] = {0};
+                               sprintf(fileName, "/tmp/ait.%d", (*infoiter)->m_OrgId);
+                               if (access(fileName, 0) < 0)
+                                       saveData((*infoiter)->m_OrgId, m_AITData, sectionLength);
+                               eDebug("Found : control[%d], name[%s], url[%s]", 
+                                       (*infoiter)->m_ControlCode, (*infoiter)->m_ApplicationName.c_str(), (*infoiter)->m_HbbTVUrl.c_str());
+                       }
+                       serviceEvent(eventHBBTVInfo);
+               }
+               else eDebug("No found anything.");
+       }
+       /* for now, do not keep listening for table updates */
+       m_AIT.stop();
+}
+
+void eDVBServicePMTHandler::OCready(int error)
+{
+       eDebug("OCready");
+       ePtr<eTable<OCSection> > ptr;
+       if (!m_OC.getCurrent(ptr))
+       {
+               for (std::vector<OCSection*>::const_iterator it = ptr->getSections().begin(); it != ptr->getSections().end(); ++it)
+               {
+                       unsigned char* sectionData = (unsigned char*)(*it)->getData();
+               }
+       }
+       /* for now, do not keep listening for table updates */
+       m_OC.stop();
+}
+
 PyObject *eDVBServicePMTHandler::getCaIds(bool pair)
 {
        ePyObject ret;
@@ -225,11 +488,35 @@ PyObject *eDVBServicePMTHandler::getCaIds(bool pair)
        return ret ? (PyObject*)ret : (PyObject*)PyList_New(0);
 }
 
+PyObject *eDVBServicePMTHandler::getHbbTVApplications(void)
+{
+       ePyObject ret= PyList_New(0);;
+       if(m_HbbTVApplications.size())
+       {
+               for(HbbTVApplicationInfoListConstIterator infoiter = m_HbbTVApplications.begin() ; infoiter != m_HbbTVApplications.end() ; ++infoiter)
+               {
+                       ePyObject tuple = PyTuple_New(6);
+                       PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong((*infoiter)->m_ControlCode));
+                       PyTuple_SET_ITEM(tuple, 1, PyString_FromString((*infoiter)->m_ApplicationName.c_str()));
+                       PyTuple_SET_ITEM(tuple, 2, PyString_FromString((*infoiter)->m_HbbTVUrl.c_str()));
+                       PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong((*infoiter)->m_OrgId));
+                       PyTuple_SET_ITEM(tuple, 4, PyInt_FromLong((*infoiter)->m_AppId));
+                       PyTuple_SET_ITEM(tuple, 5, PyInt_FromLong((*infoiter)->m_ProfileCode));
+                       PyList_Append(ret, tuple);
+                       Py_DECREF(tuple);
+               }
+       }
+       return (PyObject*)ret;
+}
+
 int eDVBServicePMTHandler::getProgramInfo(program &program)
 {
        ePtr<eTable<ProgramMapSection> > ptr;
        int cached_apid_ac3 = -1;
+       int cached_apid_ddp = -1;
        int cached_apid_mpeg = -1;
+       int cached_apid_aache = -1;
+       int cached_apid_aac = -1;
        int cached_vpid = -1;
        int cached_tpid = -1;
        int ret = -1;
@@ -239,6 +526,9 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
        program.pcrPid = -1;
        program.pmtPid = -1;
        program.textPid = -1;
+       program.aitPid = -1;
+       program.isCached = false;
+       program.pmtVersion = -1;
 
        int first_ac3 = -1;
        program.defaultAudioStream = 0;
@@ -247,8 +537,11 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
        if ( m_service && !m_service->cacheEmpty() )
        {
                cached_vpid = m_service->getCacheEntry(eDVBService::cVPID);
-               cached_apid_mpeg = m_service->getCacheEntry(eDVBService::cAPID);
+               cached_apid_mpeg = m_service->getCacheEntry(eDVBService::cMPEGAPID);
                cached_apid_ac3 = m_service->getCacheEntry(eDVBService::cAC3PID);
+               cached_apid_ddp = m_service->getCacheEntry(eDVBService::cDDPPID);
+               cached_apid_aache = m_service->getCacheEntry(eDVBService::cAACHEAPID);
+               cached_apid_aac = m_service->getCacheEntry(eDVBService::cAACAPID);
                cached_tpid = m_service->getCacheEntry(eDVBService::cTPID);
        }
 
@@ -264,6 +557,7 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
                        eDVBTableSpec table_spec;
                        ptr->getSpec(table_spec);
                        program.pmtPid = table_spec.pid < 0x1fff ? table_spec.pid : -1;
+                       program.pmtVersion = table_spec.version;
                        std::vector<ProgramMapSection*>::const_iterator i;
                        for (i = ptr->getSections().begin(); i != ptr->getSections().end(); ++i)
                        {
@@ -309,6 +603,13 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
                                                video.type = videoStream::vtMPEG4_H264;
                                                isvideo = 1;
                                                //break; fall through !!!
+                                       case 0x24: // H265 HEVC
+                                               if (!isvideo)
+                                               {
+                                                       video.type = videoStream::vtH265_HEVC;
+                                                       isvideo = 1;
+                                               }
+                                               //break; fall through !!!
                                        case 0x10: // MPEG 4 Part 2
                                                if (!isvideo)
                                                {
@@ -471,9 +772,28 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
                                                                        audio.type = audioStream::atAACHE; // MPEG4-AAC
                                                                        break;
                                                                case AC3_DESCRIPTOR:
-                                                                       isaudio = 1;
+                                                               {    
+                                                                       Ac3Descriptor *ac = (Ac3Descriptor*)(*desc);
+
+                                                                       isaudio = 1; 
                                                                        audio.type = audioStream::atAC3;
+
+                                                                       if(ac->getAc3TypeFlag())
+                                                                       {    
+
+                                                                               uint8_t ac3type = ac->getAc3Type();
+                                                                               if( ( ac3type & 0x80 ) && ( (ac3type<<5) == 0xA0 || (ac3type<<5) == 0xC0) ) // From EN-300 468 v1.7.1 Table D.1
+                                                                                       audio.type = audioStream::atDDP;
+                                                                       }    
+
+                                                                       break;
+                                                               }     
+                                                               case ENHANCED_AC3_DESCRIPTOR:
+                                                                       isaudio = 1; 
+                                                                       audio.type = audioStream::atDDP;
                                                                        break;
+     
+
                                                                case REGISTRATION_DESCRIPTOR: /* some services don't have a separate AC3 descriptor */
                                                                {
                                                                        RegistrationDescriptor *d = (RegistrationDescriptor*)(*desc);
@@ -562,6 +882,38 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
                                                }
                                                prev_audio = 0;
                                        }
+                                       case 0x05: /* ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private sections */
+                                       {
+                                               for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
+                                                       desc != (*es)->getDescriptors()->end(); ++desc)
+                                               {
+                                                       m_ait_pid = -1;
+                                                       switch ((*desc)->getTag())
+                                                       {
+                                                       case APPLICATION_SIGNALLING_DESCRIPTOR:
+                                                               m_ait_pid = program.aitPid = (*es)->getPid();
+                                                               m_AIT.begin(eApp, eDVBAITSpec(program.aitPid), m_demux);
+                                                               break;
+                                                       }
+                                               }
+                                               break;
+                                       }
+                                       case 0x0b: /* ISO/IEC 13818-6 DSM-CC U-N Messages */
+                                       {
+                                               for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
+                                                       desc != (*es)->getDescriptors()->end(); ++desc)
+                                               {
+                                                       switch ((*desc)->getTag())
+                                                       {
+                                                       case CAROUSEL_IDENTIFIER_DESCRIPTOR:
+                                                               m_dsmcc_pid = (*es)->getPid();
+                                                               break;
+                                                       case STREAM_IDENTIFIER_DESCRIPTOR:
+                                                               break;
+                                                       }
+                                               }
+                                               break;
+                                       }
                                        default:
                                                break;
                                        }
@@ -592,11 +944,11 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
                                                audio.pid = (*es)->getPid();
 
                                                        /* if we find the cached pids, this will be our default stream */
-                                               if (audio.pid == cached_apid_ac3 || audio.pid == cached_apid_mpeg)
+                                               if (audio.pid == cached_apid_ac3 || audio.pid == cached_apid_ddp || audio.pid == cached_apid_mpeg || audio.pid == cached_apid_aache || audio.pid == cached_apid_aac)
                                                        program.defaultAudioStream = program.audioStreams.size();
 
                                                        /* also, we need to know the first non-mpeg (i.e. "ac3"/dts/...) stream */
-                                               if ((audio.type != audioStream::atMPEG) && ((first_ac3 == -1) || (audio.pid == cached_apid_ac3)))
+                                               if ((audio.type != audioStream::atMPEG) && ((first_ac3 == -1) || (audio.pid == cached_apid_ac3) || (audio.pid == cached_apid_ddp)))
                                                        first_ac3 = program.audioStreams.size();
 
                                                program.audioStreams.push_back(audio);
@@ -629,6 +981,9 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
                int cached_pcrpid = m_service->getCacheEntry(eDVBService::cPCRPID),
                        vpidtype = m_service->getCacheEntry(eDVBService::cVTYPE),
                        cnt=0;
+
+               program.isCached = true;
+
                if ( vpidtype == -1 )
                        vpidtype = videoStream::vtMPEG2;
                if ( cached_vpid != -1 )
@@ -648,6 +1003,33 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
                        program.audioStreams.push_back(s);
                        ++cnt;
                }
+               if ( cached_apid_ddp != -1 )
+               {
+                       audioStream s;
+                       s.type = audioStream::atDDP;
+                       s.pid = cached_apid_ddp;
+                       s.rdsPid = -1;
+                       program.audioStreams.push_back(s);
+                       ++cnt;
+               }
+               if ( cached_apid_aache != -1 )
+               {
+                       audioStream s;
+                       s.type = audioStream::atAACHE;
+                       s.pid = cached_apid_aache;
+                       s.rdsPid = -1;
+                       program.audioStreams.push_back(s);
+                       ++cnt;
+               }
+               if ( cached_apid_aac != -1 )
+               {
+                       audioStream s;
+                       s.type = audioStream::atAAC;
+                       s.pid = cached_apid_aac;
+                       s.rdsPid = -1;
+                       program.audioStreams.push_back(s);
+                       ++cnt;
+               }
                if ( cached_apid_mpeg != -1 )
                {
                        audioStream s;
@@ -756,18 +1138,20 @@ void eDVBServicePMTHandler::SDTScanEvent(int event)
        }
 }
 
-int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref, int use_decode_demux, eCueSheet *cue, bool simulate, eDVBService *service)
+int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref, int use_decode_demux, eCueSheet *cue, bool simulate, eDVBService *service, serviceType type, bool descramble)
 {
        ePtr<iTsSource> s;
-       return tuneExt(ref, use_decode_demux, s, NULL, cue, simulate, service);
+       return tuneExt(ref, use_decode_demux, s, NULL, cue, simulate, service, type, descramble);
 }
 
-int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_demux, ePtr<iTsSource> &source, const char *streaminfo_file, eCueSheet *cue, bool simulate, eDVBService *service)
+int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_demux, ePtr<iTsSource> &source, const char *streaminfo_file, eCueSheet *cue, bool simulate, eDVBService *service, serviceType type, bool descramble)
 {
        RESULT res=0;
        m_reference = ref;
        m_use_decode_demux = use_decode_demux;
        m_no_pat_entry_delay->stop();
+       m_service_type = type;
+       m_descramble = descramble;
 
                /* use given service as backup. This is used for timeshift where we want to clone the live stream using the cache, but in fact have a PVR channel */
        m_service = service;
@@ -781,11 +1165,14 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem
                if (!simulate)
                        eDebug("allocate Channel: res %d", res);
 
+               if (!res)
+                       serviceEvent(eventChannelAllocated);
+
                ePtr<iDVBChannelList> db;
                if (!m_resourceManager->getChannelList(db))
                        db->getService((eServiceReferenceDVB&)m_reference, m_service);
 
-               if (!res && !simulate)
+               if (!res && !simulate && m_descramble && !m_ca_disabled)
                        eDVBCIInterfaces::getInstance()->addPMTHandler(this);
        } else if (!simulate) // no simulation of playback services
        {
@@ -811,9 +1198,17 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem
                }
                eDebug("alloc PVR");
                        /* allocate PVR */
-               res = m_resourceManager->allocatePVRChannel(m_pvr_channel);
+               eDVBChannelID chid;
+               if (m_service_type == streamclient) ref.getChannelID(chid);
+               res = m_resourceManager->allocatePVRChannel(chid, m_pvr_channel);
                if (res)
+               {
                        eDebug("allocatePVRChannel failed!\n");
+               }
+               else if (descramble)
+               {
+                       eDVBCIInterfaces::getInstance()->addPMTHandler(this);
+               }
                m_channel = m_pvr_channel;
        }
 
@@ -851,7 +1246,7 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem
                        m_pvr_channel->setCueSheet(cue);
 
                        if (m_pvr_channel->getDemux(m_pvr_demux_tmp, (!m_use_decode_demux) ? 0 : iDVBChannel::capDecode))
-                               eDebug("Allocating %s-decoding a demux for PVR channel failed.", m_use_decode_demux ? "" : "non-");
+                               eDebug("[eDVBServicePMTHandler] Allocating %s-decoding a demux for PVR channel failed.", m_use_decode_demux ? "" : "non-");
                        else if (source)
                                m_pvr_channel->playSource(source, streaminfo_file);
                        else
@@ -891,6 +1286,9 @@ void eDVBServicePMTHandler::free()
                m_pvr_channel->setCueSheet(0);
        }
 
+       m_OC.stop();
+       m_AIT.stop();
+
        m_PMT.stop();
        m_PAT.stop();
        m_service = 0;
@@ -899,6 +1297,32 @@ void eDVBServicePMTHandler::free()
        m_demux = 0;
 }
 
+void eDVBServicePMTHandler::addCaHandler()
+{
+       m_ca_disabled = false;
+       if (m_channel)
+       {
+               eDVBCIInterfaces::getInstance()->addPMTHandler(this);
+               if (m_pmt_ready)
+               {
+                       eDVBCIInterfaces::getInstance()->recheckPMTHandlers();
+                       eDVBCIInterfaces::getInstance()->gotPMT(this);
+               }
+       }
+}
+
+void eDVBServicePMTHandler::removeCaHandler()
+{
+       m_ca_disabled = true;
+       if (m_channel)
+               eDVBCIInterfaces::getInstance()->removePMTHandler(this);
+}
+
+bool eDVBServicePMTHandler::isCiConnected()
+{
+       eDVBCIInterfaces::getInstance()->isCiConnected(this);
+}
+
 CAServiceMap eDVBCAService::exist;
 ChannelMap eDVBCAService::exist_channels;
 ePtr<eConnection> eDVBCAService::m_chanAddedConn;