optimize
[enigma2.git] / lib / service / servicedvb.cpp
index 94833f446f75d7a3a55d768156a8e40c8a0064df..cad2ea087925f1e4866de8b81d96c889228fcda4 100644 (file)
@@ -25,9 +25,40 @@ DEFINE_REF(eStaticServiceDVBInformation);
 
 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
 {
 
 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
 {
-       if ( ref.name.length() )
+       eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
+       if ( !ref.name.empty() )
        {
        {
-               name = ref.name;
+               if (service.getParentTransportStreamID().get()) // linkage subservice
+               {
+                       ePtr<iServiceHandler> service_center;
+                       if (!eServiceCenter::getInstance(service_center))
+                       {
+                               eServiceReferenceDVB parent = service;
+                               parent.setTransportStreamID( service.getParentTransportStreamID() );
+                               parent.setServiceID( service.getParentServiceID() );
+                               parent.setParentTransportStreamID(eTransportStreamID(0));
+                               parent.setParentServiceID(eServiceID(0));
+                               parent.name="";
+                               ePtr<iStaticServiceInformation> service_info;
+                               if (!service_center->info(parent, service_info))
+                               {
+                                       if (!service_info->getName(parent, name))
+                                       {
+                                               // just show short name
+                                               unsigned int pos = name.find("\xc2\x86");
+                                               if ( pos != std::string::npos )
+                                                       name.erase(0, pos+2);
+                                               pos = name.find("\xc2\x87");
+                                               if ( pos != std::string::npos )
+                                                       name.erase(pos);
+                                               name+=" - ";
+                                       }
+                               }
+                       }
+               }
+               else
+                       name="";
+               name += ref.name;
                return 0;
        }
        else
                return 0;
        }
        else
@@ -66,7 +97,7 @@ RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref
                return err;
        }
 
                return err;
        }
 
-       const eBouquet *bouquet=0;
+       eBouquet *bouquet=0;
        if ((err = db->getBouquet(ref, bouquet)) != 0)
        {
                eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
        if ((err = db->getBouquet(ref, bouquet)) != 0)
        {
                eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
@@ -75,7 +106,7 @@ RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref
 
        if ( bouquet && bouquet->m_bouquet_name.length() )
        {
 
        if ( bouquet && bouquet->m_bouquet_name.length() )
        {
-               name = "[Bouquet] " + bouquet->m_bouquet_name;
+               name = bouquet->m_bouquet_name;
                return 0;
        }
        else
                return 0;
        }
        else
@@ -96,6 +127,9 @@ public:
        eStaticServiceDVBPVRInformation(const eServiceReference &ref);
        RESULT getName(const eServiceReference &ref, std::string &name);
        int getLength(const eServiceReference &ref);
        eStaticServiceDVBPVRInformation(const eServiceReference &ref);
        RESULT getName(const eServiceReference &ref, std::string &name);
        int getLength(const eServiceReference &ref);
+       
+       int getInfo(const eServiceReference &ref, int w);
+       std::string getInfoString(const eServiceReference &ref,int w);
 };
 
 DEFINE_REF(eStaticServiceDVBPVRInformation);
 };
 
 DEFINE_REF(eStaticServiceDVBPVRInformation);
@@ -129,7 +163,32 @@ int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
        return len / 90000;
 }
 
        return len / 90000;
 }
 
+int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
+{
+       switch (w)
+       {
+       case iServiceInformation::sDescription:
+               return iServiceInformation::resIsString;
+       case iServiceInformation::sTimeCreate:
+               if (m_parser.m_time_create)
+                       return m_parser.m_time_create;
+               else
+                       return iServiceInformation::resNA;
+       default:
+               return iServiceInformation::resNA;
+       }
+}
 
 
+std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
+{
+       switch (w)
+       {
+       case iServiceInformation::sDescription:
+               return m_parser.m_description;
+       default:
+               return "";
+       }
+}
 
 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
 {
 
 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
 {
@@ -280,10 +339,9 @@ RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
                if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
                        return -1;
 
                if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
                        return -1;
 
-                       // FIXME!
-               if (db->getBouquet(m_parent, (const eBouquet*&)m_bouquet) != 0)
+               if (db->getBouquet(m_parent, m_bouquet) != 0)
                        return -1;
                        return -1;
-               
+
                res = this;
                
                return 0;
                res = this;
                
                return 0;
@@ -294,24 +352,30 @@ RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
 
 RESULT eDVBServiceList::addService(eServiceReference &ref)
 {
 
 RESULT eDVBServiceList::addService(eServiceReference &ref)
 {
-       ASSERT(m_bouquet);
-//     return m_bouquet->addService(ref);
-       return -1;
+       if (!m_bouquet)
+               return -1;
+       return m_bouquet->addService(ref);
 }
 
 RESULT eDVBServiceList::removeService(eServiceReference &ref)
 {
 }
 
 RESULT eDVBServiceList::removeService(eServiceReference &ref)
 {
-       ASSERT(m_bouquet);
-//     return m_bouquet->removeService(ref);
-       return -1;
+       if (!m_bouquet)
+               return -1;
+       return m_bouquet->removeService(ref);
 }
 
 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
 {
 }
 
 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
 {
-       ASSERT(m_bouquet);
-       
-//     return m_bouquet->moveService(ref, pos);
-       return -1;
+       if (!m_bouquet)
+               return -1;
+       return m_bouquet->moveService(ref, pos);
+}
+
+RESULT eDVBServiceList::flushChanges()
+{
+       if (!m_bouquet)
+               return -1;
+       return m_bouquet->flushChanges();
 }
 
 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
 }
 
 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
@@ -353,28 +417,26 @@ RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableServ
 
 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
 {
 
 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
 {
-               /* do we have a PVR service? */
-       if (ref.flags & eServiceReference::flagDirectory) // bouquet
+       /* is a listable service? */
+       if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
        {
        {
-               ptr = new eStaticServiceDVBBouquetInformation;
-               return 0;
+               if ( !ref.name.empty() )  // satellites or providers list
+                       ptr = new eStaticServiceDVBInformation;
+               else // a dvb bouquet
+                       ptr = new eStaticServiceDVBBouquetInformation;
        }
        }
-       else if (!ref.path.empty())
-       {
+       else if (!ref.path.empty()) /* do we have a PVR service? */
                ptr = new eStaticServiceDVBPVRInformation(ref);
                ptr = new eStaticServiceDVBPVRInformation(ref);
-               return 0;
-       }
-       else
+       else // normal dvb service
        {
                ePtr<eDVBService> service;
        {
                ePtr<eDVBService> service;
-               int r = lookupService(service, ref);
-               if (r)
+               if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
                        ptr = new eStaticServiceDVBInformation;
                else
                        /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
                        ptr = service;
                        ptr = new eStaticServiceDVBInformation;
                else
                        /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
                        ptr = service;
-               return 0;
        }
        }
+       return 0;
 }
 
 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
 }
 
 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
@@ -425,6 +487,7 @@ eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *serv
        m_reference(ref), m_dvb_service(service), m_service_handler(0), m_is_paused(0)
 {
        m_is_pvr = !ref.path.empty();
        m_reference(ref), m_dvb_service(service), m_service_handler(0), m_is_paused(0)
 {
        m_is_pvr = !ref.path.empty();
+       m_timeshift_enabled = 0;
        
        CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
        CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
        
        CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
        CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
@@ -459,10 +522,16 @@ void eDVBServicePlay::serviceEvent(int event)
                ePtr<iDVBDemux> m_demux;
                if (!m_service_handler.getDemux(m_demux))
                {
                ePtr<iDVBDemux> m_demux;
                if (!m_service_handler.getDemux(m_demux))
                {
-//                     eventStartedEventAcquisition
-                       m_event_handler.start(m_demux, ((eServiceReferenceDVB&)m_reference).getServiceID().get());
+                       eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
+                       int sid = ref.getParentServiceID().get();
+                       if (!sid)
+                               sid = ref.getServiceID().get();
+                       if ( ref.getParentTransportStreamID().get() &&
+                               ref.getParentTransportStreamID() != ref.getTransportStreamID() )
+                               m_event_handler.startOther(m_demux, sid);
+                       else
+                               m_event_handler.start(m_demux, sid);
                }
                }
-//                     eventNoEvent
                break;
        }
        case eDVBServicePMTHandler::eventTuneFailed:
                break;
        }
        case eDVBServicePMTHandler::eventTuneFailed:
@@ -473,7 +542,7 @@ void eDVBServicePlay::serviceEvent(int event)
        }
        case eDVBServicePMTHandler::eventNewProgramInfo:
        {
        }
        case eDVBServicePMTHandler::eventNewProgramInfo:
        {
-               int vpid = -1, apid = -1, pcrpid = -1;
+               int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1;
                eDVBServicePMTHandler::program program;
                if (m_service_handler.getProgramInfo(program))
                        eDebug("getting program info failed.");
                eDVBServicePMTHandler::program program;
                if (m_service_handler.getProgramInfo(program))
                        eDebug("getting program info failed.");
@@ -504,7 +573,10 @@ void eDVBServicePlay::serviceEvent(int event)
                                        i != program.audioStreams.end(); ++i)
                                {
                                        if (apid == -1)
                                        i != program.audioStreams.end(); ++i)
                                {
                                        if (apid == -1)
+                                       {
                                                apid = i->pid;
                                                apid = i->pid;
+                                               apidtype = i->type;
+                                       }
                                        if (i != program.audioStreams.begin())
                                                eDebugNoNewLine(", ");
                                        eDebugNoNewLine("%04x", i->pid);
                                        if (i != program.audioStreams.begin())
                                                eDebugNoNewLine(", ");
                                        eDebugNoNewLine("%04x", i->pid);
@@ -527,7 +599,8 @@ void eDVBServicePlay::serviceEvent(int event)
                if (m_decoder)
                {
                        m_decoder->setVideoPID(vpid);
                if (m_decoder)
                {
                        m_decoder->setVideoPID(vpid);
-                       m_decoder->setAudioPID(apid, 0);
+                       m_current_audio_stream = 0;
+                       m_decoder->setAudioPID(apid, apidtype);
                        if (!m_is_pvr)
                                m_decoder->setSyncPCR(pcrpid);
                        else
                        if (!m_is_pvr)
                                m_decoder->setSyncPCR(pcrpid);
                        else
@@ -545,7 +618,8 @@ void eDVBServicePlay::serviceEvent(int event)
                                m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
                        }
                }
                                m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
                        }
                }
-               
+
+               m_event((iPlayableService*)this, evUpdatedInfo);
                break;
        }
        }
                break;
        }
        }
@@ -575,16 +649,32 @@ RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &ev
 
 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
 {
 
 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
 {
-       if (m_is_pvr)
+       if (!m_is_pvr)
        {
        {
-               ptr = this;
-               return 0;
+               ptr = 0;
+               return -1;
        }
 
        }
 
-       ptr = 0;
-       return -1;
+       ptr = this;
+       return 0;
 }
 
 }
 
+RESULT eDVBServicePlay::setSlowMotion(int ratio)
+{
+       if (m_decoder)
+               return m_decoder->setSlowMotion(ratio);
+       else
+               return -1;
+}
+
+RESULT eDVBServicePlay::setFastForward(int ratio)
+{
+       if (m_decoder)
+               return m_decoder->setFastForward(ratio);
+       else
+               return -1;
+}
+    
 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
 {
        if (m_is_pvr)
 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
 {
        if (m_is_pvr)
@@ -632,7 +722,19 @@ RESULT eDVBServicePlay::unpause()
 
 RESULT eDVBServicePlay::seekTo(pts_t to)
 {
 
 RESULT eDVBServicePlay::seekTo(pts_t to)
 {
-       return -1;
+       eDebug("eDVBServicePlay::seekTo: jump %lld", to);
+
+       ePtr<iDVBPVRChannel> pvr_channel;
+       
+       if (m_service_handler.getPVRChannel(pvr_channel))
+               return -1;
+       
+       ePtr<iDVBDemux> demux;
+       m_service_handler.getDemux(demux);
+       if (!demux)
+               return -1;
+       
+       return pvr_channel->seekTo(demux, 0, to);
 }
 
 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
 }
 
 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
@@ -644,7 +746,14 @@ RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
        if (m_service_handler.getPVRChannel(pvr_channel))
                return -1;
        
        if (m_service_handler.getPVRChannel(pvr_channel))
                return -1;
        
-       return pvr_channel->seekToPosition(SEEK_CUR, to);
+       to *= direction;
+       
+       ePtr<iDVBDemux> demux;
+       m_service_handler.getDemux(demux);
+       if (!demux)
+               return -1;
+       
+       return pvr_channel->seekTo(demux, 1, to);
 }
 
 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
 }
 
 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
@@ -654,7 +763,25 @@ RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
        if (m_service_handler.getPVRChannel(pvr_channel))
                return -1;
        
        if (m_service_handler.getPVRChannel(pvr_channel))
                return -1;
        
-       return pvr_channel->getCurrentPosition(pos);
+       ePtr<iDVBDemux> demux;
+       m_service_handler.getDemux(demux);
+       if (!demux)
+               return -1;
+       
+       return pvr_channel->getCurrentPosition(demux, pos, 1);
+}
+
+RESULT eDVBServicePlay::setTrickmode(int trick)
+{
+       if (m_decoder)
+               m_decoder->setTrickmode(trick);
+       return 0;
+}
+
+RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
+{
+       ptr = this;
+       return 0;
 }
 
 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
 }
 
 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
@@ -663,6 +790,29 @@ RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
        return 0;
 }
 
        return 0;
 }
 
+RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
+{
+       ptr = this;
+       return 0;
+}
+
+RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
+{
+       ptr = this;
+       return 0;
+}
+
+RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
+{
+       if (m_timeshift_enabled || !m_is_pvr)
+       {
+               ptr = this;
+               return 0;
+       }
+       ptr = 0;
+       return -1;
+}
+
 RESULT eDVBServicePlay::getName(std::string &name)
 {
        if (m_dvb_service)
 RESULT eDVBServicePlay::getName(std::string &name)
 {
        if (m_dvb_service)
@@ -670,7 +820,10 @@ RESULT eDVBServicePlay::getName(std::string &name)
                m_dvb_service->getName(m_reference, name);
                if (name.empty())
                        name = "(...)";
                m_dvb_service->getName(m_reference, name);
                if (name.empty())
                        name = "(...)";
-       } else
+       }
+       else if (!m_reference.name.empty())
+               eStaticServiceDVBInformation().getName(m_reference, name);
+       else
                name = "DVB service";
        return 0;
 }
                name = "DVB service";
        return 0;
 }
@@ -680,6 +833,228 @@ RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
        return m_event_handler.getEvent(evt, nownext);
 }
 
        return m_event_handler.getEvent(evt, nownext);
 }
 
+int eDVBServicePlay::getInfo(int w)
+{
+       eDVBServicePMTHandler::program program;
+
+       if (m_service_handler.getProgramInfo(program))
+               return -1;
+       
+       switch (w)
+       {
+       case sAspect:
+               if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
+               {
+                       ePtr<eServiceEvent> evt;
+                       if (!m_event_handler.getEvent(evt, 0))
+                       {
+                               ePtr<eComponentData> data;
+                               if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
+                               {
+                                       if ( data->getStreamContent() == 1 )
+                                       {
+                                               switch(data->getComponentType())
+                                               {
+                                                       // SD
+                                                       case 1: // 4:3 SD PAL
+                                                       case 2:
+                                                       case 3: // 16:9 SD PAL
+                                                       case 4: // > 16:9 PAL
+                                                       case 5: // 4:3 SD NTSC
+                                                       case 6: 
+                                                       case 7: // 16:9 SD NTSC
+                                                       case 8: // > 16:9 NTSC
+
+                                                       // HD
+                                                       case 9: // 4:3 HD PAL
+                                                       case 0xA:
+                                                       case 0xB: // 16:9 HD PAL
+                                                       case 0xC: // > 16:9 HD PAL
+                                                       case 0xD: // 4:3 HD NTSC
+                                                       case 0xE:
+                                                       case 0xF: // 16:9 HD NTSC
+                                                       case 0x10: // > 16:9 HD PAL
+                                                               return data->getComponentType();
+                                               }
+                                       }
+                               }
+                       }
+               }
+               return -1;
+       case sIsCrypted: return program.isCrypted;
+       case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
+       case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
+       case sPCRPID: return program.pcrPid;
+       case sPMTPID: return program.pmtPid;
+       case sTXTPID: return -1;
+       case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
+       case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
+       case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
+       case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
+       case sProvider: if (!m_dvb_service) return -1; return -2;
+       default:
+               return -1;
+       }
+}
+
+std::string eDVBServicePlay::getInfoString(int w)
+{      
+       switch (w)
+       {
+       case sProvider:
+               if (!m_dvb_service) return "";
+               return m_dvb_service->m_provider_name;
+       default:
+               return "";
+       }
+}
+
+int eDVBServicePlay::getNumberOfTracks()
+{
+       eDVBServicePMTHandler::program program;
+       if (m_service_handler.getProgramInfo(program))
+               return 0;
+       return program.audioStreams.size();
+}
+
+RESULT eDVBServicePlay::selectTrack(unsigned int i)
+{
+       int ret = selectAudioStream(i);
+
+       if (m_decoder->start())
+               return -5;
+
+       return ret;
+}
+
+RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
+{
+       eDVBServicePMTHandler::program program;
+
+       if (m_service_handler.getProgramInfo(program))
+               return -1;
+       
+       if (i >= program.audioStreams.size())
+               return -2;
+       
+       if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
+               info.m_description = "MPEG";
+       else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
+               info.m_description = "AC3";
+       else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
+               info.m_description = "DTS";
+       else
+               info.m_description = "???";
+
+       if (program.audioStreams[i].component_tag != -1)
+       {
+               ePtr<eServiceEvent> evt;
+               if (!m_event_handler.getEvent(evt, 0))
+               {
+                       ePtr<eComponentData> data;
+                       if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
+                               info.m_language = data->getText();
+               }
+       }
+
+       if (info.m_language.empty())
+               info.m_language = program.audioStreams[i].language_code;
+       
+       return 0;
+}
+
+int eDVBServicePlay::selectAudioStream(int i)
+{
+       eDVBServicePMTHandler::program program;
+
+       if (m_service_handler.getProgramInfo(program))
+               return -1;
+       
+       if ((unsigned int)i >= program.audioStreams.size())
+               return -2;
+       
+       if (!m_decoder)
+               return -3;
+       
+       if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
+               return -4;
+
+       m_current_audio_stream = i;
+
+       return 0;
+}
+
+int eDVBServicePlay::getFrontendInfo(int w)
+{
+       if (m_is_pvr)
+               return 0;
+       eUsePtr<iDVBChannel> channel;
+       if(m_service_handler.getChannel(channel))
+               return 0;
+       ePtr<iDVBFrontend> fe;
+       if(channel->getFrontend(fe))
+               return 0;
+       return fe->readFrontendData(w);
+}
+
+int eDVBServicePlay::getNumberOfSubservices()
+{
+       ePtr<eServiceEvent> evt;
+       if (!m_event_handler.getEvent(evt, 0))
+               return evt->getNumOfLinkageServices();
+       return 0;
+}
+
+RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
+{
+       ePtr<eServiceEvent> evt;
+       if (!m_event_handler.getEvent(evt, 0))
+       {
+               if (!evt->getLinkageService(sub, n))
+               {
+                       eServiceReferenceDVB &subservice = (eServiceReferenceDVB&) sub;
+                       eServiceReferenceDVB &current = (eServiceReferenceDVB&) m_reference;
+                       subservice.setDVBNamespace(current.getDVBNamespace());
+                       if ( current.getParentTransportStreamID().get() )
+                       {
+                               subservice.setParentTransportStreamID( current.getParentTransportStreamID() );
+                               subservice.setParentServiceID( current.getParentServiceID() );
+                       }
+                       else
+                       {
+                               subservice.setParentTransportStreamID( current.getTransportStreamID() );
+                               subservice.setParentServiceID( current.getServiceID() );
+                       }
+                       if ( subservice.getParentTransportStreamID() == subservice.getTransportStreamID() &&
+                               subservice.getParentServiceID() == subservice.getServiceID() )
+                       {
+                               subservice.setParentTransportStreamID( eTransportStreamID(0) );
+                               subservice.setParentServiceID( eServiceID(0) );
+                       }
+                       return 0;
+               }
+       }
+       sub.type=eServiceReference::idInvalid;
+       return -1;
+}
+
+RESULT eDVBServicePlay::startTimeshift()
+{
+       if (m_timeshift_enabled)
+               return -1;
+       eDebug("TIMESHIFT - start!");
+       return 0;
+}
+
+RESULT eDVBServicePlay::stopTimeshift()
+{
+       if (!m_timeshift_enabled)
+               return -1;
+       m_timeshift_enabled = 0;
+       eDebug("timeshift disabled");
+       return 0;
+}
+
 DEFINE_REF(eDVBServicePlay)
 
 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");
 DEFINE_REF(eDVBServicePlay)
 
 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");