add ability to copy providers or all services from satellites to favourites (this...
[enigma2.git] / lib / service / servicedvb.cpp
index 9e77a7a7a33ecf7310c8152fe78f457e489dd8fd..827b7f362702ec89f734852ded841dd453c0ad4b 100644 (file)
@@ -8,10 +8,12 @@
 
 #include <lib/dvb/dvb.h>
 #include <lib/dvb/db.h>
+#include <lib/dvb/decoder.h>
 
 #include <lib/service/servicedvbrecord.h>
 #include <lib/dvb/metaparser.h>
 #include <lib/dvb/tstools.h>
+#include <lib/python/python.h>
 
 class eStaticServiceDVBInformation: public iStaticServiceInformation
 {
@@ -25,9 +27,40 @@ DEFINE_REF(eStaticServiceDVBInformation);
 
 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
 {
+       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
@@ -75,7 +108,7 @@ RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref
 
        if ( bouquet && bouquet->m_bouquet_name.length() )
        {
-               name = "[Bouquet] " + bouquet->m_bouquet_name;
+               name = bouquet->m_bouquet_name;
                return 0;
        }
        else
@@ -96,6 +129,9 @@ public:
        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);
@@ -129,7 +165,32 @@ int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
        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
 {
@@ -245,7 +306,32 @@ RESULT eDVBServiceList::startQuery()
        return 0;
 }
 
-RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list)
+RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
+{
+       eServiceReferenceDVB ref;
+
+       if (!m_query || !list || !PyList_Check(list))
+               return -1;
+
+       std::list<eServiceReferenceDVB> tmplist;
+
+       while (!m_query->getNextResult(ref))
+               tmplist.push_back(ref);
+
+       if (sorted)
+               tmplist.sort(iListableServiceCompare(this));
+
+       for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
+               it != tmplist.end(); ++it)
+       {
+               PyObject *refobj = New_eServiceReference(*it);
+               PyList_Append(list, refobj);
+               Py_DECREF(refobj);
+       }
+       return 0;
+}
+
+RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
 {
        eServiceReferenceDVB ref;
        
@@ -254,6 +340,10 @@ RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list)
        
        while (!m_query->getNextResult(ref))
                list.push_back(ref);
+
+       if (sorted)
+               list.sort(iListableServiceCompare(this));
+
        return 0;
 }
 
@@ -319,6 +409,13 @@ RESULT eDVBServiceList::flushChanges()
        return m_bouquet->flushChanges();
 }
 
+RESULT eDVBServiceList::setListName(const std::string &name)
+{
+       if (!m_bouquet)
+               return -1;
+       return m_bouquet->setListName(name);
+}
+
 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
 {
        ePtr<eDVBService> service;
@@ -365,24 +462,19 @@ RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServic
                        ptr = new eStaticServiceDVBInformation;
                else // a dvb bouquet
                        ptr = new eStaticServiceDVBBouquetInformation;
-               return 0;
        }
        else if (!ref.path.empty()) /* do we have a PVR service? */
-       {
                ptr = new eStaticServiceDVBPVRInformation(ref);
-               return 0;
-       }
        else // normal dvb service
        {
                ePtr<eDVBService> service;
-               int r = lookupService(service, ref);
-               if (r) // no eDVBService avail for this reference ( Linkage Services... )
+               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;
-               return 0;
        }
+       return 0;
 }
 
 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
@@ -430,11 +522,13 @@ RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServ
 }
 
 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
-       m_reference(ref), m_dvb_service(service), m_service_handler(0), m_is_paused(0)
+       m_reference(ref), m_dvb_service(service), m_is_paused(0)
 {
        m_is_pvr = !ref.path.empty();
+       m_timeshift_enabled = m_timeshift_active = 0;
        
        CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
+       CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
        CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
 }
 
@@ -465,12 +559,18 @@ void eDVBServicePlay::serviceEvent(int event)
        case eDVBServicePMTHandler::eventTuned:
        {
                ePtr<iDVBDemux> m_demux;
-               if (!m_service_handler.getDemux(m_demux))
+               if (!m_service_handler.getDataDemux(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:
@@ -481,101 +581,50 @@ void eDVBServicePlay::serviceEvent(int event)
        }
        case eDVBServicePMTHandler::eventNewProgramInfo:
        {
-               int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1;
-               eDVBServicePMTHandler::program program;
-               if (m_service_handler.getProgramInfo(program))
-                       eDebug("getting program info failed.");
-               else
-               {
-                       eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
-                       if (!program.videoStreams.empty())
-                       {
-                               eDebugNoNewLine(" (");
-                               for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
-                                       i(program.videoStreams.begin()); 
-                                       i != program.videoStreams.end(); ++i)
-                               {
-                                       if (vpid == -1)
-                                               vpid = i->pid;
-                                       if (i != program.videoStreams.begin())
-                                               eDebugNoNewLine(", ");
-                                       eDebugNoNewLine("%04x", i->pid);
-                               }
-                               eDebugNoNewLine(")");
-                       }
-                       eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
-                       if (!program.audioStreams.empty())
-                       {
-                               eDebugNoNewLine(" (");
-                               for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
-                                       i(program.audioStreams.begin()); 
-                                       i != program.audioStreams.end(); ++i)
-                               {
-                                       if (apid == -1)
-                                       {
-                                               apid = i->pid;
-                                               apidtype = i->type;
-                                       }
-                                       if (i != program.audioStreams.begin())
-                                               eDebugNoNewLine(", ");
-                                       eDebugNoNewLine("%04x", i->pid);
-                               }
-                               eDebugNoNewLine(")");
-                       }
-                       eDebug(", and the pcr pid is %04x", program.pcrPid);
-                       if (program.pcrPid != 0x1fff)
-                               pcrpid = program.pcrPid;
-               }
-               
-               if (!m_decoder)
-               {
-                       ePtr<iDVBDemux> demux;
-                       m_service_handler.getDemux(demux);
-                       if (demux)
-                               demux->getMPEGDecoder(m_decoder);
-               }
-
-               if (m_decoder)
-               {
-                       m_decoder->setVideoPID(vpid);
-                       m_current_audio_stream = 0;
-                       m_decoder->setAudioPID(apid, apidtype);
-                       if (!m_is_pvr)
-                               m_decoder->setSyncPCR(pcrpid);
-                       else
-                               m_decoder->setSyncPCR(-1);
-                       m_decoder->start();
-// how we can do this better?
-// update cache pid when the user changed the audio track or video track
-// TODO handling of difference audio types.. default audio types..
-                               
-                               /* don't worry about non-existing services, nor pvr services */
-                       if (m_dvb_service && !m_is_pvr)
-                       {
-                               m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
-                               m_dvb_service->setCachePID(eDVBService::cAPID, apid);
-                               m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
-                       }
-               }
-               
+               eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
+               if (m_timeshift_enabled)
+                       updateTimeshiftPids();
+               if (!m_timeshift_active)
+                       updateDecoder();
+               m_event((iPlayableService*)this, evUpdatedInfo);
+               break;
+       }
+       case eDVBServicePMTHandler::eventEOF:
+       {
+               m_event((iPlayableService*)this, evEnd);
                break;
        }
        }
 }
 
+void eDVBServicePlay::serviceEventTimeshift(int event)
+{
+       switch (event)
+       {
+       case eDVBServicePMTHandler::eventNewProgramInfo:
+               if (m_timeshift_active)
+                       updateDecoder();
+               break;
+       case eDVBServicePMTHandler::eventEOF:
+               switchToLive();
+               break;
+       }
+}
+
 RESULT eDVBServicePlay::start()
 {
        int r;
-       eDebug("starting DVB service");
-       r = m_service_handler.tune((eServiceReferenceDVB&)m_reference);
-       eDebug("tune result: %d", r);
+               /* in pvr mode, we only want to use one demux. in tv mode, we're using 
+                  two (one for decoding, one for data source), as we must be prepared
+                  to start recording from the data demux. */
+       r = m_service_handler.tune((eServiceReferenceDVB&)m_reference, m_is_pvr);
        m_event(this, evStart);
+       m_event((iPlayableService*)this, evSeekableStatusChanged);
        return 0;
 }
 
 RESULT eDVBServicePlay::stop()
 {
-       eDebug("stopping..");
        return 0;
 }
 
@@ -587,19 +636,38 @@ RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &ev
 
 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
 {
-       if (m_is_pvr)
+               /* note: we check for timeshift to be enabled,
+                  not neccessary active. if you pause when timeshift
+                  is not active, you should activate it when unpausing */
+       if ((!m_is_pvr) && (!m_timeshift_enabled))
        {
-               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)
+       if (m_is_pvr || m_timeshift_active)
        {
                ptr = this;
                return 0;
@@ -644,41 +712,54 @@ RESULT eDVBServicePlay::unpause()
 
 RESULT eDVBServicePlay::seekTo(pts_t to)
 {
-       return -1;
+       eDebug("eDVBServicePlay::seekTo: jump %lld", to);
+       
+       if (!m_decode_demux)
+               return -1;
+
+       ePtr<iDVBPVRChannel> pvr_channel;
+       
+       if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
+               return -1;
+       
+       return pvr_channel->seekTo(m_decode_demux, 0, to);
 }
 
 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
 {
        eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
+       
+       if (!m_decode_demux)
+               return -1;
 
        ePtr<iDVBPVRChannel> pvr_channel;
        
-       if (m_service_handler.getPVRChannel(pvr_channel))
+       if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
                return -1;
        
        to *= direction;
        
-       ePtr<iDVBDemux> demux;
-       m_service_handler.getDemux(demux);
-       if (!demux)
-               return -1;
-       
-       return pvr_channel->seekTo(demux, 1, to);
+       return pvr_channel->seekTo(m_decode_demux, 1, to);
 }
 
 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
 {
        ePtr<iDVBPVRChannel> pvr_channel;
        
-       if (m_service_handler.getPVRChannel(pvr_channel))
+       if (!m_decode_demux)
                return -1;
        
-       ePtr<iDVBDemux> demux;
-       m_service_handler.getDemux(demux);
-       if (!demux)
+       if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
                return -1;
        
-       return pvr_channel->getCurrentPosition(demux, pos);
+       return pvr_channel->getCurrentPosition(m_decode_demux, pos, 1);
+}
+
+RESULT eDVBServicePlay::setTrickmode(int trick)
+{
+       if (m_decoder)
+               m_decoder->setTrickmode(trick);
+       return 0;
 }
 
 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
@@ -699,14 +780,39 @@ RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
        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_is_pvr)
+       {
+               ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
+               return i->getName(m_reference, name);
+       }
        if (m_dvb_service)
        {
                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;
 }
@@ -725,12 +831,51 @@ int eDVBServicePlay::getInfo(int w)
        
        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 sTXTPID: return program.textPid;
        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();
@@ -789,9 +934,20 @@ RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int
                info.m_description = "DTS";
        else
                info.m_description = "???";
-       
-               /* CHECK here for component tag override. */
-       info.m_language = program.audioStreams[i].language_code;
+
+       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;
 }
@@ -803,7 +959,7 @@ int eDVBServicePlay::selectAudioStream(int i)
        if (m_service_handler.getProgramInfo(program))
                return -1;
        
-       if (i >= program.audioStreams.size())
+       if ((unsigned int)i >= program.audioStreams.size())
                return -2;
        
        if (!m_decoder)
@@ -812,6 +968,19 @@ int eDVBServicePlay::selectAudioStream(int i)
        if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
                return -4;
 
+       if (m_dvb_service && !m_is_pvr)
+       {
+               if (program.audioStreams[i].type == eDVBAudio::aMPEG)
+               {
+                       m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
+                       m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
+               }       else
+               {
+                       m_dvb_service->setCachePID(eDVBService::cAPID, -1);
+                       m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
+               }
+       }
+
        m_current_audio_stream = i;
 
        return 0;
@@ -819,6 +988,8 @@ int eDVBServicePlay::selectAudioStream(int i)
 
 int eDVBServicePlay::getFrontendInfo(int w)
 {
+       if (m_is_pvr)
+               return 0;
        eUsePtr<iDVBChannel> channel;
        if(m_service_handler.getChannel(channel))
                return 0;
@@ -828,6 +999,277 @@ int eDVBServicePlay::getFrontendInfo(int w)
        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, m_reference, n))
+                       return 0;
+       }
+       sub.type=eServiceReference::idInvalid;
+       return -1;
+}
+
+RESULT eDVBServicePlay::startTimeshift()
+{
+       ePtr<iDVBDemux> demux;
+       
+       eDebug("Start timeshift!");
+       
+       if (m_timeshift_enabled)
+               return -1;
+       
+               /* start recording with the data demux. */
+       if (m_service_handler.getDataDemux(demux))
+               return -2;
+
+       demux->createTSRecorder(m_record);
+       if (!m_record)
+               return -3;
+
+       char templ[]="/media/hdd/timeshift.XXXXXX";
+       m_timeshift_fd = mkstemp(templ);
+       m_timeshift_file = templ;
+       
+       eDebug("recording to %s", templ);
+       
+       if (m_timeshift_fd < 0)
+       {
+               m_record = 0;
+               return -4;
+       }
+               
+       m_record->setTargetFD(m_timeshift_fd);
+
+       m_timeshift_enabled = 1;
+       
+       updateTimeshiftPids();
+       m_record->start();
+
+       return 0;
+}
+
+RESULT eDVBServicePlay::stopTimeshift()
+{
+       if (!m_timeshift_enabled)
+               return -1;
+       
+       switchToLive();
+       
+       m_timeshift_enabled = 0;
+       
+       m_record->stop();
+       m_record = 0;
+       
+       close(m_timeshift_fd);
+       remove(m_timeshift_file.c_str());
+       
+       return 0;
+}
+
+int eDVBServicePlay::isTimeshiftActive()
+{
+       return m_timeshift_enabled && m_timeshift_active;
+}
+
+RESULT eDVBServicePlay::activateTimeshift()
+{
+       if (!m_timeshift_enabled)
+               return -1;
+       
+       if (!m_timeshift_active)
+       {
+               switchToTimeshift();
+               return 0;
+       }
+       
+       return -2;
+}
+
+void eDVBServicePlay::updateTimeshiftPids()
+{
+       if (!m_record)
+               return;
+       
+       eDVBServicePMTHandler::program program;
+       if (m_service_handler.getProgramInfo(program))
+               return;
+       else
+       {
+               std::set<int> pids_to_record;
+               pids_to_record.insert(0); // PAT
+               if (program.pmtPid != -1)
+                       pids_to_record.insert(program.pmtPid); // PMT
+
+               if (program.textPid != -1)
+                       pids_to_record.insert(program.textPid); // Videotext
+
+               for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
+                       i(program.videoStreams.begin()); 
+                       i != program.videoStreams.end(); ++i)
+                       pids_to_record.insert(i->pid);
+
+               for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
+                       i(program.audioStreams.begin()); 
+                       i != program.audioStreams.end(); ++i)
+                               pids_to_record.insert(i->pid);
+
+               std::set<int> new_pids, obsolete_pids;
+               
+               std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
+                               m_pids_active.begin(), m_pids_active.end(),
+                               std::inserter(new_pids, new_pids.begin()));
+               
+               std::set_difference(
+                               m_pids_active.begin(), m_pids_active.end(),
+                               pids_to_record.begin(), pids_to_record.end(), 
+                               std::inserter(new_pids, new_pids.begin())
+                               );
+
+               for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
+                       m_record->addPID(*i);
+
+               for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
+                       m_record->removePID(*i);
+       }
+}
+
+void eDVBServicePlay::switchToLive()
+{
+       if (!m_timeshift_active)
+               return;
+       
+       m_decoder = 0;
+       m_decode_demux = 0;
+               /* free the timeshift service handler, we need the resources */
+       m_service_handler_timeshift.free();
+       m_timeshift_active = 0;
+       
+       m_event((iPlayableService*)this, evSeekableStatusChanged);
+       
+       updateDecoder();
+}
+
+void eDVBServicePlay::switchToTimeshift()
+{
+       if (m_timeshift_active)
+               return;
+       
+       m_decode_demux = 0;
+       m_decoder = 0;
+       
+       m_timeshift_active = 1;
+
+       m_event((iPlayableService*)this, evSeekableStatusChanged);
+       
+       eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
+       r.path = m_timeshift_file;
+       
+       m_service_handler_timeshift.tune(r, 1); /* use the decoder demux for everything */
+}
+
+void eDVBServicePlay::updateDecoder()
+{
+       int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
+       eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+
+       eDVBServicePMTHandler::program program;
+       if (h.getProgramInfo(program))
+               eDebug("getting program info failed.");
+       else
+       {
+               eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
+               if (!program.videoStreams.empty())
+               {
+                       eDebugNoNewLine(" (");
+                       for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
+                               i(program.videoStreams.begin()); 
+                               i != program.videoStreams.end(); ++i)
+                       {
+                               if (vpid == -1)
+                                       vpid = i->pid;
+                               if (i != program.videoStreams.begin())
+                                       eDebugNoNewLine(", ");
+                               eDebugNoNewLine("%04x", i->pid);
+                       }
+                       eDebugNoNewLine(")");
+               }
+               eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
+               if (!program.audioStreams.empty())
+               {
+                       eDebugNoNewLine(" (");
+                       for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
+                               i(program.audioStreams.begin()); 
+                               i != program.audioStreams.end(); ++i)
+                       {
+                               if (apid == -1)
+                               {
+                                       apid = i->pid;
+                                       apidtype = i->type;
+                               }
+                               if (i != program.audioStreams.begin())
+                                       eDebugNoNewLine(", ");
+                               eDebugNoNewLine("%04x", i->pid);
+                       }
+                       eDebugNoNewLine(")");
+               }
+               eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
+               pcrpid = program.pcrPid;
+               eDebug(", and the text pid is %04x", program.textPid);
+               tpid = program.textPid;
+       }
+
+       if (!m_decoder)
+       {
+               h.getDecodeDemux(m_decode_demux);
+               if (m_decode_demux)
+                       m_decode_demux->getMPEGDecoder(m_decoder);
+       }
+
+       if (m_decoder)
+       {
+               m_decoder->setVideoPID(vpid);
+               m_current_audio_stream = 0;
+               m_decoder->setAudioPID(apid, apidtype);
+               if (!(m_is_pvr || m_timeshift_active))
+                       m_decoder->setSyncPCR(pcrpid);
+               else
+                       m_decoder->setSyncPCR(-1);
+               m_decoder->setTextPID(tpid);
+               m_decoder->start();
+// how we can do this better?
+// update cache pid when the user changed the audio track or video track
+// TODO handling of difference audio types.. default audio types..
+                               
+               /* don't worry about non-existing services, nor pvr services */
+               if (m_dvb_service && !m_is_pvr)
+               {
+                       if (apidtype == eDVBAudio::aMPEG)
+                       {
+                               m_dvb_service->setCachePID(eDVBService::cAPID, apid);
+                               m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
+                       }
+                       else
+                       {
+                               m_dvb_service->setCachePID(eDVBService::cAPID, -1);
+                               m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
+                       }
+                       m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
+                       m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
+                       m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
+               }
+       }
+}
+
 DEFINE_REF(eDVBServicePlay)
 
 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");