make channel selection service description color configurable
[enigma2.git] / lib / service / servicedvb.cpp
index 47956dfac14a7e0d085d1aad765fce590bf57d6c..558bf0c22cd0273428aa24577915a72b6182df3c 100644 (file)
@@ -6,7 +6,6 @@
 #include <lib/base/estring.h>
 #include <lib/base/init_num.h>
 #include <lib/base/init.h>
 #include <lib/base/estring.h>
 #include <lib/base/init_num.h>
 #include <lib/base/init.h>
-#include <lib/base/nconfig.h> // access to python config
 #include <lib/dvb/dvb.h>
 #include <lib/dvb/db.h>
 #include <lib/dvb/decoder.h>
 #include <lib/dvb/dvb.h>
 #include <lib/dvb/db.h>
 #include <lib/dvb/decoder.h>
@@ -17,6 +16,7 @@
 #include <lib/dvb/metaparser.h>
 #include <lib/dvb/tstools.h>
 #include <lib/python/python.h>
 #include <lib/dvb/metaparser.h>
 #include <lib/dvb/tstools.h>
 #include <lib/python/python.h>
+#include <lib/base/nconfig.h> // access to python config
 
                /* for subtitles */
 #include <lib/gui/esubtitle.h>
 
                /* for subtitles */
 #include <lib/gui/esubtitle.h>
@@ -31,8 +31,6 @@
 #error no byte order defined!
 #endif
 
 #error no byte order defined!
 #endif
 
-#define TSPATH "/media/hdd"
-
 class eStaticServiceDVBInformation: public iStaticServiceInformation
 {
        DECLARE_REF(eStaticServiceDVBInformation);
 class eStaticServiceDVBInformation: public iStaticServiceInformation
 {
        DECLARE_REF(eStaticServiceDVBInformation);
@@ -40,6 +38,7 @@ public:
        RESULT getName(const eServiceReference &ref, std::string &name);
        int getLength(const eServiceReference &ref);
        int isPlayable(const eServiceReference &ref, const eServiceReference &ignore);
        RESULT getName(const eServiceReference &ref, std::string &name);
        int getLength(const eServiceReference &ref);
        int isPlayable(const eServiceReference &ref, const eServiceReference &ignore);
+       PyObject *getInfoObject(const eServiceReference &ref, int);
 };
 
 DEFINE_REF(eStaticServiceDVBInformation);
 };
 
 DEFINE_REF(eStaticServiceDVBInformation);
@@ -64,16 +63,7 @@ RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::
                                if (!service_center->info(parent, service_info))
                                {
                                        if (!service_info->getName(parent, name))
                                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+=" - ";
-                                       }
+                                               name=buildShortName(name) + " - ";
                                }
                        }
                }
                                }
                        }
                }
@@ -95,7 +85,7 @@ int eStaticServiceDVBInformation::isPlayable(const eServiceReference &ref, const
 {
        ePtr<eDVBResourceManager> res_mgr;
        if ( eDVBResourceManager::getInstance( res_mgr ) )
 {
        ePtr<eDVBResourceManager> res_mgr;
        if ( eDVBResourceManager::getInstance( res_mgr ) )
-               eDebug("isPlayble... no res manager!!");
+               eDebug("isPlayable... no res manager!!");
        else
        {
                eDVBChannelID chid, chid_ignore;
        else
        {
                eDVBChannelID chid, chid_ignore;
@@ -106,6 +96,74 @@ int eStaticServiceDVBInformation::isPlayable(const eServiceReference &ref, const
        return false;
 }
 
        return false;
 }
 
+extern void PutToDict(ePyObject &dict, const char*key, long value);  // defined in dvb/frontend.cpp
+extern void PutSatelliteDataToDict(ePyObject &dict, eDVBFrontendParametersSatellite &feparm); // defined in dvb/frontend.cpp
+extern void PutTerrestrialDataToDict(ePyObject &dict, eDVBFrontendParametersTerrestrial &feparm); // defined in dvb/frontend.cpp
+extern void PutCableDataToDict(ePyObject &dict, eDVBFrontendParametersCable &feparm); // defined in dvb/frontend.cpp
+
+PyObject *eStaticServiceDVBInformation::getInfoObject(const eServiceReference &r, int what)
+{
+       if (r.type == eServiceReference::idDVB)
+       {
+               const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)r;
+               switch(what)
+               {
+                       case iServiceInformation::sTransponderData:
+                       {
+                               ePtr<eDVBResourceManager> res;
+                               if (!eDVBResourceManager::getInstance(res))
+                               {
+                                       ePtr<iDVBChannelList> db;
+                                       if (!res->getChannelList(db))
+                                       {
+                                               eDVBChannelID chid;
+                                               ref.getChannelID(chid);
+                                               ePtr<iDVBFrontendParameters> feparm;
+                                               if (!db->getChannelFrontendData(chid, feparm))
+                                               {
+                                                       int system;
+                                                       if (!feparm->getSystem(system))
+                                                       {
+                                                               ePyObject dict = PyDict_New();
+                                                               switch(system)
+                                                               {
+                                                                       case iDVBFrontend::feSatellite:
+                                                                       {
+                                                                               eDVBFrontendParametersSatellite s;
+                                                                               feparm->getDVBS(s);
+                                                                               PutSatelliteDataToDict(dict, s);
+                                                                               break;
+                                                                       }
+                                                                       case iDVBFrontend::feTerrestrial:
+                                                                       {
+                                                                               eDVBFrontendParametersTerrestrial t;
+                                                                               feparm->getDVBT(t);
+                                                                               PutTerrestrialDataToDict(dict, t);
+                                                                               break;
+                                                                       }
+                                                                       case iDVBFrontend::feCable:
+                                                                       {
+                                                                               eDVBFrontendParametersCable c;
+                                                                               feparm->getDVBC(c);
+                                                                               PutCableDataToDict(dict, c);
+                                                                               break;
+                                                                       }
+                                                                       default:
+                                                                               eDebug("unknown frontend type %d", system);
+                                                                               Py_DECREF(dict);
+                                                                               break;
+                                                               }
+                                                               return dict;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       Py_RETURN_NONE;
+}
+
 DEFINE_REF(eStaticServiceDVBBouquetInformation);
 
 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
 DEFINE_REF(eStaticServiceDVBBouquetInformation);
 
 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
@@ -141,7 +199,7 @@ RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref
                return -1;
 }
 
                return -1;
 }
 
-int eStaticServiceDVBBouquetInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore)
+int eStaticServiceDVBBouquetInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore, bool simulate)
 {
        if (ref.flags & eServiceReference::isGroup)
        {
 {
        if (ref.flags & eServiceReference::isGroup)
        {
@@ -167,13 +225,38 @@ int eStaticServiceDVBBouquetInformation::isPlayable(const eServiceReference &ref
                        return 0;
                }
 
                        return 0;
                }
 
+               int prio_order = eDVBFrontend::getTypePriorityOrder();
                int cur=0;
                eDVBChannelID chid, chid_ignore;
                ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
                for (std::list<eServiceReference>::iterator it(bouquet->m_services.begin()); it != bouquet->m_services.end(); ++it)
                {
                int cur=0;
                eDVBChannelID chid, chid_ignore;
                ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
                for (std::list<eServiceReference>::iterator it(bouquet->m_services.begin()); it != bouquet->m_services.end(); ++it)
                {
+                       static unsigned char prio_map[6][3] = {
+                               { 3, 2, 1 }, // -S -C -T
+                               { 3, 1, 2 }, // -S -T -C
+                               { 2, 3, 1 }, // -C -S -T
+                               { 1, 3, 2 }, // -C -T -S
+                               { 1, 2, 3 }, // -T -C -S
+                               { 2, 1, 3 }  // -T -S -C
+                       };
                        ((const eServiceReferenceDVB&)*it).getChannelID(chid);
                        ((const eServiceReferenceDVB&)*it).getChannelID(chid);
-                       int tmp=res->canAllocateChannel(chid, chid_ignore);
+                       int tmp=res->canAllocateChannel(chid, chid_ignore, simulate);
+                       switch(tmp)
+                       {
+                               case 0:
+                                       break;
+                               case 30000: // cached DVB-T channel
+                               case 1: // DVB-T frontend
+                                       tmp = prio_map[prio_order][2];
+                                       break;
+                               case 40000: // cached DVB-C channel
+                               case 2:
+                                       tmp = prio_map[prio_order][1];
+                                       break;
+                               default: // DVB-S
+                                       tmp = prio_map[prio_order][0];
+                                       break;
+                       }
                        if (tmp > cur)
                        {
                                m_playable_service = *it;
                        if (tmp > cur)
                        {
                                m_playable_service = *it;
@@ -212,6 +295,7 @@ public:
        int isPlayable(const eServiceReference &ref, const eServiceReference &ignore) { return 1; }
        int getInfo(const eServiceReference &ref, int w);
        std::string getInfoString(const eServiceReference &ref,int w);
        int isPlayable(const eServiceReference &ref, const eServiceReference &ignore) { return 1; }
        int getInfo(const eServiceReference &ref, int w);
        std::string getInfoString(const eServiceReference &ref,int w);
+       PyObject *getInfoObject(const eServiceReference &r, int what);
 };
 
 DEFINE_REF(eStaticServiceDVBPVRInformation);
 };
 
 DEFINE_REF(eStaticServiceDVBPVRInformation);
@@ -225,7 +309,15 @@ eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceR
 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
 {
        ASSERT(ref == m_ref);
 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
 {
        ASSERT(ref == m_ref);
-       name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
+       if (m_parser.m_name.size())
+               name = m_parser.m_name;
+       else
+       {
+               name = ref.path;
+               size_t n = name.rfind('/');
+               if (n != std::string::npos)
+                       name = name.substr(n + 1);
+       }
        return 0;
 }
 
        return 0;
 }
 
@@ -235,14 +327,29 @@ int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
        
        eDVBTSTools tstools;
        
        
        eDVBTSTools tstools;
        
+       struct stat s;
+       stat(ref.path.c_str(), &s);
+
+       if (tstools.openFile(ref.path.c_str(), 1))
+               return 0;
+
+                       /* check if cached data is still valid */
+       if (m_parser.m_data_ok && (s.st_size == m_parser.m_filesize) && (m_parser.m_length))
+               return m_parser.m_length / 90000;
+
+                       /* open again, this time with stream info */
        if (tstools.openFile(ref.path.c_str()))
                return 0;
 
        if (tstools.openFile(ref.path.c_str()))
                return 0;
 
+                       /* otherwise, re-calc length and update meta file */
        pts_t len;
        if (tstools.calcLen(len))
                return 0;
 
        pts_t len;
        if (tstools.calcLen(len))
                return 0;
 
-       return len / 90000;
+       m_parser.m_length = len;
+       m_parser.m_filesize = s.st_size;
+       m_parser.updateMeta(ref.path);
+       return m_parser.m_length / 90000;
 }
 
 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
 }
 
 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
@@ -253,6 +360,8 @@ int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w
                return iServiceInformation::resIsString;
        case iServiceInformation::sServiceref:
                return iServiceInformation::resIsString;
                return iServiceInformation::resIsString;
        case iServiceInformation::sServiceref:
                return iServiceInformation::resIsString;
+       case iServiceInformation::sFileSize:
+               return m_parser.m_filesize;
        case iServiceInformation::sTimeCreate:
                if (m_parser.m_time_create)
                        return m_parser.m_time_create;
        case iServiceInformation::sTimeCreate:
                if (m_parser.m_time_create)
                        return m_parser.m_time_create;
@@ -278,6 +387,17 @@ std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReferen
        }
 }
 
        }
 }
 
+PyObject *eStaticServiceDVBPVRInformation::getInfoObject(const eServiceReference &r, int what)
+{
+       switch (what)
+       {
+       case iServiceInformation::sFileSize:
+               return PyLong_FromLongLong(m_parser.m_filesize);
+       default:
+               Py_RETURN_NONE;
+       }
+}
+
 RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
 {
        if (!ref.path.empty())
 RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
 {
        if (!ref.path.empty())
@@ -305,6 +425,7 @@ public:
        
        RESULT deleteFromDisk(int simulate);
        RESULT getListOfFilenames(std::list<std::string> &);
        
        RESULT deleteFromDisk(int simulate);
        RESULT getListOfFilenames(std::list<std::string> &);
+       RESULT reindex();
 };
 
 DEFINE_REF(eDVBPVRServiceOfflineOperations);
 };
 
 DEFINE_REF(eDVBPVRServiceOfflineOperations);
@@ -359,6 +480,7 @@ RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string
 
        res.push_back(m_ref.path + ".meta");
        res.push_back(m_ref.path + ".ap");
 
        res.push_back(m_ref.path + ".meta");
        res.push_back(m_ref.path + ".ap");
+       res.push_back(m_ref.path + ".sc");
        res.push_back(m_ref.path + ".cuts");
        std::string tmp = m_ref.path;
        tmp.erase(m_ref.path.length()-3);
        res.push_back(m_ref.path + ".cuts");
        std::string tmp = m_ref.path;
        tmp.erase(m_ref.path.length()-3);
@@ -366,6 +488,42 @@ RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string
        return 0;
 }
 
        return 0;
 }
 
+RESULT eDVBPVRServiceOfflineOperations::reindex()
+{
+       const char *filename = m_ref.path.c_str();
+       eDebug("reindexing %s...", filename);
+
+       eMPEGStreamInformation info;
+       eMPEGStreamParserTS parser(info);
+       
+       info.startSave(filename);
+       
+       eRawFile f;
+       
+       int err = f.open(m_ref.path.c_str(), 0);
+       if (err < 0)
+               return -1;
+       
+       off_t length = f.length();
+       unsigned char buffer[188*256*4];
+       while (1)
+       {
+               off_t offset = f.lseek(0, SEEK_CUR);
+               eDebug("at %08llx / %08llx (%d %%)", offset, length, (int)(offset * 100 / length));
+               int r = f.read(buffer, sizeof(buffer));
+               if (!r)
+                       break;
+               if (r < 0)
+                       return r;
+               parser.parseData(offset, buffer, r);
+       }
+       
+       info.stopSave();
+       f.close();
+       
+       return 0;
+}
+
 DEFINE_REF(eServiceFactoryDVB)
 
 eServiceFactoryDVB::eServiceFactoryDVB()
 DEFINE_REF(eServiceFactoryDVB)
 
 eServiceFactoryDVB::eServiceFactoryDVB()
@@ -374,7 +532,12 @@ eServiceFactoryDVB::eServiceFactoryDVB()
        
        eServiceCenter::getPrivInstance(sc);
        if (sc)
        
        eServiceCenter::getPrivInstance(sc);
        if (sc)
-               sc->addServiceFactory(eServiceFactoryDVB::id, this);
+       {
+               std::list<std::string> extensions;
+               extensions.push_back("ts");
+               extensions.push_back("trp");
+               sc->addServiceFactory(eServiceFactoryDVB::id, this, extensions);
+       }
 
        m_StaticServiceDVBInfo = new eStaticServiceDVBInformation;
        m_StaticServiceDVBBouquetInfo = new eStaticServiceDVBBouquetInformation;
 
        m_StaticServiceDVBInfo = new eStaticServiceDVBInformation;
        m_StaticServiceDVBBouquetInfo = new eStaticServiceDVBBouquetInformation;
@@ -460,6 +623,7 @@ RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sort
 //   S = Service Reference (as python string object .. same as ref.toString())
 //   C = Service Reference (as python string object .. same as ref.toCompareString())
 //   N = Service Name (as python string object)
 //   S = Service Reference (as python string object .. same as ref.toString())
 //   C = Service Reference (as python string object .. same as ref.toCompareString())
 //   N = Service Name (as python string object)
+//   n = Short Service Name (short name brakets used) (as python string object)
 //   when exactly one return value per service is selected in the format string,
 //   then each value is directly a list entry
 //   when more than one value is returned per service, then the list is a list of
 //   when exactly one return value per service is selected in the format string,
 //   then each value is directly a list entry
 //   when more than one value is returned per service, then the list is a list of
@@ -480,7 +644,7 @@ PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
                ePtr<iStaticServiceInformation> sptr;
                eServiceCenterPtr service_center;
 
                ePtr<iStaticServiceInformation> sptr;
                eServiceCenterPtr service_center;
 
-               if (strchr(format, 'N'))
+               if (strchr(format, 'N') || strchr(format, 'n'))
                        eServiceCenter::getPrivInstance(service_center);
 
                ret = PyList_New(services);
                        eServiceCenter::getPrivInstance(service_center);
 
                ret = PyList_New(services);
@@ -512,6 +676,30 @@ PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
                                                {
                                                        std::string name;
                                                        sptr->getName(ref, name);
                                                {
                                                        std::string name;
                                                        sptr->getName(ref, name);
+
+                                                       // filter short name brakets
+                                                       size_t pos;
+                                                       while((pos = name.find("\xc2\x86")) != std::string::npos)
+                                                               name.erase(pos,2);
+                                                       while((pos = name.find("\xc2\x87")) != std::string::npos)
+                                                               name.erase(pos,2);
+
+                                                       if (name.length())
+                                                               tmp = PyString_FromString(name.c_str());
+                                               }
+                                       }
+                                       if (!tmp)
+                                               tmp = PyString_FromString("<n/a>");
+                                       break;
+                               case 'n':  // short service name
+                                       if (service_center)
+                                       {
+                                               service_center->info(ref, sptr);
+                                               if (sptr)
+                                               {
+                                                       std::string name;
+                                                       sptr->getName(ref, name);
+                                                       name = buildShortName(name);
                                                        if (name.length())
                                                                tmp = PyString_FromString(name.c_str());
                                                }
                                                        if (name.length())
                                                                tmp = PyString_FromString(name.c_str());
                                                }
@@ -682,30 +870,41 @@ RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<
 
 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
 {
 
 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
 {
-                       // TODO: handle the listing itself
-       // if (ref.... == -1) .. return "... bouquets ...";
-       // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
-                       // TODO: cache
-       ePtr<iDVBChannelList> db;
-       ePtr<eDVBResourceManager> res;
-       
-       int err;
-       if ((err = eDVBResourceManager::getInstance(res)) != 0)
+       if (!ref.path.empty()) // playback
        {
        {
-               eDebug("no resource manager");
-               return err;
+               eDVBMetaParser parser;
+               int ret=parser.parseFile(ref.path);
+               service = new eDVBService;
+               if (!ret)
+                       eDVBDB::getInstance()->parseServiceData(service, parser.m_service_data);
        }
        }
-       if ((err = res->getChannelList(db)) != 0)
+       else
        {
        {
-               eDebug("no channel list");
-               return err;
-       }
+                       // TODO: handle the listing itself
+               // if (ref.... == -1) .. return "... bouquets ...";
+               // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
+                       // TODO: cache
+               ePtr<iDVBChannelList> db;
+               ePtr<eDVBResourceManager> res;
+       
+               int err;
+               if ((err = eDVBResourceManager::getInstance(res)) != 0)
+               {
+                       eDebug("no resource manager");
+                       return err;
+               }
+               if ((err = res->getChannelList(db)) != 0)
+               {
+                       eDebug("no channel list");
+                       return err;
+               }
        
                /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
        
                /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
-       if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
-       {
-               eDebug("getService failed!");
-               return err;
+               if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
+               {
+                       eDebug("getService failed!");
+                       return err;
+               }
        }
 
        return 0;
        }
 
        return 0;
@@ -717,8 +916,8 @@ eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *serv
        m_is_primary = 1;
        m_is_pvr = !m_reference.path.empty();
        
        m_is_primary = 1;
        m_is_pvr = !m_reference.path.empty();
        
-       m_timeshift_enabled = m_timeshift_active = 0;
-       m_skipmode = 0;
+       m_timeshift_enabled = m_timeshift_active = 0, m_timeshift_changed = 0;
+       m_skipmode = m_fastforward = m_slowmotion = 0;
        
        CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
        CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
        
        CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
        CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
@@ -730,12 +929,37 @@ eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *serv
        m_subtitle_widget = 0;
        
        m_tune_state = -1;
        m_subtitle_widget = 0;
        
        m_tune_state = -1;
-       
-       CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
+
+       m_subtitle_sync_timer = eTimer::create(eApp);
+
+       CONNECT(m_subtitle_sync_timer->timeout, eDVBServicePlay::checkSubtitleTiming);
 }
 
 eDVBServicePlay::~eDVBServicePlay()
 {
 }
 
 eDVBServicePlay::~eDVBServicePlay()
 {
+       if (m_is_pvr)
+       {
+               eDVBMetaParser meta;
+               int ret=meta.parseFile(m_reference.path);
+               if (!ret)
+               {
+                       char tmp[255];
+                       meta.m_service_data="";
+                       sprintf(tmp, "f:%x", m_dvb_service->m_flags);
+                       meta.m_service_data += tmp;
+                       // cached pids
+                       for (int x=0; x < eDVBService::cacheMax; ++x)
+                       {
+                               int entry = m_dvb_service->getCacheEntry((eDVBService::cacheID)x);
+                               if (entry != -1)
+                               {
+                                       sprintf(tmp, ",c:%02d%04x", x, entry);
+                                       meta.m_service_data += tmp;
+                               }
+                       }
+                       meta.updateMeta(m_reference.path);
+               }
+       }
        delete m_subtitle_widget;
 }
 
        delete m_subtitle_widget;
 }
 
@@ -757,7 +981,6 @@ void eDVBServicePlay::gotNewEvent()
 
 void eDVBServicePlay::serviceEvent(int event)
 {
 
 void eDVBServicePlay::serviceEvent(int event)
 {
-       eDebug("service %p: error %d", this, event);
        m_tune_state = event;
 
        switch (event)
        m_tune_state = event;
 
        switch (event)
@@ -777,12 +1000,15 @@ void eDVBServicePlay::serviceEvent(int event)
                        else
                                m_event_handler.start(m_demux, sid);
                }
                        else
                                m_event_handler.start(m_demux, sid);
                }
+               m_event((iPlayableService*)this, evTunedIn);
                break;
        }
                break;
        }
+       case eDVBServicePMTHandler::eventNoResources:
        case eDVBServicePMTHandler::eventNoPAT:
        case eDVBServicePMTHandler::eventNoPATEntry:
        case eDVBServicePMTHandler::eventNoPMT:
        case eDVBServicePMTHandler::eventTuneFailed:
        case eDVBServicePMTHandler::eventNoPAT:
        case eDVBServicePMTHandler::eventNoPATEntry:
        case eDVBServicePMTHandler::eventNoPMT:
        case eDVBServicePMTHandler::eventTuneFailed:
+       case eDVBServicePMTHandler::eventMisconfiguration:
        {
                eDebug("DVB service failed to tune - error %d", event);
                m_event((iPlayableService*)this, evTuneFailed);
        {
                eDebug("DVB service failed to tune - error %d", event);
                m_event((iPlayableService*)this, evTuneFailed);
@@ -803,6 +1029,9 @@ void eDVBServicePlay::serviceEvent(int event)
                m_event((iPlayableService*)this, evUpdatedInfo);
                break;
        }
                m_event((iPlayableService*)this, evUpdatedInfo);
                break;
        }
+       case eDVBServicePMTHandler::eventPreStart:
+               loadCuesheet();
+               break;
        case eDVBServicePMTHandler::eventEOF:
                m_event((iPlayableService*)this, evEOF);
                break;
        case eDVBServicePMTHandler::eventEOF:
                m_event((iPlayableService*)this, evEOF);
                break;
@@ -824,27 +1053,41 @@ void eDVBServicePlay::serviceEventTimeshift(int event)
                m_event((iPlayableService*)this, evSOF);
                break;
        case eDVBServicePMTHandler::eventEOF:
                m_event((iPlayableService*)this, evSOF);
                break;
        case eDVBServicePMTHandler::eventEOF:
-               switchToLive();
+               if ((!m_is_paused) && (m_skipmode >= 0))
+               {
+                       eDebug("timeshift EOF, so let's go live");
+                       switchToLive();
+               }
                break;
        }
 }
 
 RESULT eDVBServicePlay::start()
 {
                break;
        }
 }
 
 RESULT eDVBServicePlay::start()
 {
-       int r;
+       eServiceReferenceDVB service = (eServiceReferenceDVB&)m_reference;
+
                /* 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. */
        if (m_is_pvr)
                /* 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. */
        if (m_is_pvr)
+       {
+               eDVBMetaParser meta;
+               if (!meta.parseFile(m_reference.path))
+               {
+                       service = meta.m_ref;
+                       service.path = m_reference.path;
+               }
                m_cue = new eCueSheet();
                m_cue = new eCueSheet();
+       }
+       else
+               m_event(this, evStart);
 
        m_first_program_info = 1;
 
        m_first_program_info = 1;
-       eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
-       r = m_service_handler.tune(service, m_is_pvr, m_cue);
+       m_service_handler.tune(service, m_is_pvr, m_cue, false, m_dvb_service);
 
 
-               /* inject EIT if there is a stored one */
        if (m_is_pvr)
        {
        if (m_is_pvr)
        {
+               /* inject EIT if there is a stored one */
                std::string filename = service.path;
                filename.erase(filename.length()-2, 2);
                filename+="eit";
                std::string filename = service.path;
                filename.erase(filename.length()-2, 2);
                filename+="eit";
@@ -855,13 +1098,8 @@ RESULT eDVBServicePlay::start()
                        m_event_handler.inject(event, 0);
                        m_event_handler.inject(empty, 1);
                }
                        m_event_handler.inject(event, 0);
                        m_event_handler.inject(empty, 1);
                }
+               m_event(this, evStart);
        }
        }
-
-       if (m_is_pvr)
-               loadCuesheet();
-
-       m_event(this, evStart);
-       m_event((iPlayableService*)this, evSeekableStatusChanged);
        return 0;
 }
 
        return 0;
 }
 
@@ -870,7 +1108,7 @@ RESULT eDVBServicePlay::stop()
                /* add bookmark for last play position */
        if (m_is_pvr)
        {
                /* add bookmark for last play position */
        if (m_is_pvr)
        {
-               pts_t play_position;
+               pts_t play_position, length;
                if (!getPlayPosition(play_position))
                {
                                /* remove last position */
                if (!getPlayPosition(play_position))
                {
                                /* remove last position */
@@ -885,7 +1123,13 @@ RESULT eDVBServicePlay::stop()
                                        ++i;
                        }
                        
                                        ++i;
                        }
                        
-                       m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
+                       if (getLength(length))
+                               length = 0;
+                       
+                       if (length)
+                       {
+                               m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
+                       }
                        m_cuesheet_changed = 1;
                }
        }
                        m_cuesheet_changed = 1;
                }
        }
@@ -902,7 +1146,7 @@ RESULT eDVBServicePlay::stop()
                if (!::stat(m_reference.path.c_str(), &s))
                        saveCuesheet();
        }
                if (!::stat(m_reference.path.c_str(), &s))
                        saveCuesheet();
        }
-       
+       m_event((iPlayableService*)this, evStopped);
        return 0;
 }
 
        return 0;
 }
 
@@ -935,16 +1179,30 @@ RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
 
 RESULT eDVBServicePlay::setSlowMotion(int ratio)
 {
 
 RESULT eDVBServicePlay::setSlowMotion(int ratio)
 {
+       ASSERT(ratio); /* The API changed: instead of calling setSlowMotion(0), call play! */
+       eDebug("eDVBServicePlay::setSlowMotion(%d)", ratio);
+       setFastForward_internal(0);
        if (m_decoder)
        if (m_decoder)
+       {
+               m_slowmotion = ratio;
                return m_decoder->setSlowMotion(ratio);
                return m_decoder->setSlowMotion(ratio);
+       }
        else
                return -1;
 }
 
 RESULT eDVBServicePlay::setFastForward(int ratio)
 {
        else
                return -1;
 }
 
 RESULT eDVBServicePlay::setFastForward(int ratio)
 {
-       int skipmode, ffratio;
-       
+       eDebug("eDVBServicePlay::setFastForward(%d)", ratio);
+       ASSERT(ratio);
+       return setFastForward_internal(ratio);
+}
+
+RESULT eDVBServicePlay::setFastForward_internal(int ratio, bool final_seek)
+{
+       int skipmode, ffratio, ret = 0;
+       pts_t pos=0;
+
        if (ratio > 8)
        {
                skipmode = ratio;
        if (ratio > 8)
        {
                skipmode = ratio;
@@ -969,15 +1227,30 @@ RESULT eDVBServicePlay::setFastForward(int ratio)
                if (m_cue)
                        m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
        }
                if (m_cue)
                        m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
        }
-       
+
        m_skipmode = skipmode;
        m_skipmode = skipmode;
-       
+
+       if (final_seek)
+               eDebug("trickplay stopped .. ret %d, pos %lld", getPlayPosition(pos), pos);
+
+       m_fastforward = ffratio;
+
        if (!m_decoder)
                return -1;
 
        if (!m_decoder)
                return -1;
 
-       return m_decoder->setFastForward(ffratio);
+       if (ffratio == 0)
+               ; /* return m_decoder->play(); is done in caller*/
+       else if (ffratio != 1)
+               ret = m_decoder->setFastForward(ffratio);
+       else
+               ret = m_decoder->setTrickmode();
+
+       if (pos)
+               eDebug("final seek after trickplay ret %d", seekTo(pos));
+
+       return ret;
 }
 }
-    
+
 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
 {
        if (m_is_pvr || m_timeshift_enabled)
 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
 {
        if (m_is_pvr || m_timeshift_enabled)
@@ -1003,20 +1276,26 @@ RESULT eDVBServicePlay::getLength(pts_t &len)
 
 RESULT eDVBServicePlay::pause()
 {
 
 RESULT eDVBServicePlay::pause()
 {
-       if (!m_is_paused && m_decoder)
+       eDebug("eDVBServicePlay::pause");
+       setFastForward_internal(0, m_slowmotion || m_fastforward > 1);
+       if (m_decoder)
        {
        {
+               m_slowmotion = 0;
                m_is_paused = 1;
                m_is_paused = 1;
-               return m_decoder->freeze(0);
+               return m_decoder->pause();
        } else
                return -1;
 }
 
 RESULT eDVBServicePlay::unpause()
 {
        } else
                return -1;
 }
 
 RESULT eDVBServicePlay::unpause()
 {
-       if (m_is_paused && m_decoder)
+       eDebug("eDVBServicePlay::unpause");
+       setFastForward_internal(0, m_slowmotion || m_fastforward > 1);
+       if (m_decoder)
        {
        {
+               m_slowmotion = 0;
                m_is_paused = 0;
                m_is_paused = 0;
-               return m_decoder->unfreeze();
+               return m_decoder->play();
        } else
                return -1;
 }
        } else
                return -1;
 }
@@ -1037,6 +1316,9 @@ RESULT eDVBServicePlay::seekTo(pts_t to)
                return -1;
        
        m_cue->seekTo(0, to);
                return -1;
        
        m_cue->seekTo(0, to);
+       m_dvb_subtitle_pages.clear();
+       m_subtitle_pages.clear();
+
        return 0;
 }
 
        return 0;
 }
 
@@ -1064,6 +1346,8 @@ RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
                return 0;
        
        m_cue->seekTo(mode, to);
                return 0;
        
        m_cue->seekTo(mode, to);
+       m_dvb_subtitle_pages.clear();
+       m_subtitle_pages.clear();
        return 0;
 }
 
        return 0;
 }
 
@@ -1093,14 +1377,20 @@ RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
 
 RESULT eDVBServicePlay::setTrickmode(int trick)
 {
 
 RESULT eDVBServicePlay::setTrickmode(int trick)
 {
-       if (m_decoder)
-               m_decoder->setTrickmode(trick);
-       return 0;
+               /* currently unimplemented */
+       return -1;
 }
 
 RESULT eDVBServicePlay::isCurrentlySeekable()
 {
 }
 
 RESULT eDVBServicePlay::isCurrentlySeekable()
 {
-       return m_is_pvr || m_timeshift_active;
+       int ret = 0;
+       if (m_decoder)
+       {
+               ret = (m_is_pvr || m_timeshift_active) ? 3 : 0; // fast forward/backward possible and seeking possible
+               if (m_decoder->getVideoProgressive() == -1)
+                       ret &= ~2;
+       }
+       return ret;
 }
 
 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
 }
 
 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
@@ -1141,9 +1431,16 @@ RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
        {
                if (!m_timeshift_enabled)
                {
        {
                if (!m_timeshift_enabled)
                {
-                               /* we need enough diskspace */
+                       /* query config path */
+                       std::string tspath;
+                       if(ePythonConfigQuery::getConfigValue("config.usage.timeshift_path", tspath) == -1){
+                               eDebug("could not query ts path from config");
+                               return -4;
+                       }
+                       tspath.append("/");
+                       /* we need enough diskspace */
                        struct statfs fs;
                        struct statfs fs;
-                       if (statfs(TSPATH "/.", &fs) < 0)
+                       if (statfs(tspath.c_str(), &fs) < 0)
                        {
                                eDebug("statfs failed!");
                                return -2;
                        {
                                eDebug("statfs failed!");
                                return -2;
@@ -1184,7 +1481,7 @@ RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
        return 0;
 }
 
        return 0;
 }
 
-RESULT eDVBServicePlay::radioText(ePtr<iRadioText> &ptr)
+RESULT eDVBServicePlay::rdsDecoder(ePtr<iRdsDecoder> &ptr)
 {
        ptr = this;
        return 0;
 {
        ptr = this;
        return 0;
@@ -1197,7 +1494,7 @@ RESULT eDVBServicePlay::getName(std::string &name)
                ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
                return i->getName(m_reference, name);
        }
                ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
                return i->getName(m_reference, name);
        }
-       if (m_dvb_service)
+       else if (m_dvb_service)
        {
                m_dvb_service->getName(m_reference, name);
                if (name.empty())
        {
                m_dvb_service->getName(m_reference, name);
                if (name.empty())
@@ -1218,25 +1515,43 @@ RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
 int eDVBServicePlay::getInfo(int w)
 {
        eDVBServicePMTHandler::program program;
 int eDVBServicePlay::getInfo(int w)
 {
        eDVBServicePMTHandler::program program;
-       
-       eDebug("get info in %p", this);
 
        if (w == sCAIDs)
                return resIsPyObject;
 
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
 
        if (w == sCAIDs)
                return resIsPyObject;
 
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
-       
+
        int no_program_info = 0;
        int no_program_info = 0;
-       
+
        if (h.getProgramInfo(program))
                no_program_info = 1;
        if (h.getProgramInfo(program))
                no_program_info = 1;
-       
-       eDebug("ok");
+
        switch (w)
        {
        switch (w)
        {
+       case sVideoHeight:
+               if (m_decoder)
+                       return m_decoder->getVideoHeight();
+               break;
+       case sVideoWidth:
+               if (m_decoder)
+                       return m_decoder->getVideoWidth();
+               break;
+       case sFrameRate:
+               if (m_decoder)
+                       return m_decoder->getVideoFrameRate();
+               break;
+       case sProgressive:
+               if (m_decoder)
+                       return m_decoder->getVideoProgressive();
+               break;
        case sAspect:
        case sAspect:
-               if (!no_program_info) return -1; 
-               if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
+       {
+               int aspect = -1;
+               if (m_decoder)
+                       aspect = m_decoder->getVideoAspect();
+               if (aspect == -1 && no_program_info)
+                       break;
+               else if (aspect == -1 && !program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
                {
                        ePtr<eServiceEvent> evt;
                        if (!m_event_handler.getEvent(evt, 0))
                {
                        ePtr<eServiceEvent> evt;
                        if (!m_event_handler.getEvent(evt, 0))
@@ -1273,14 +1588,41 @@ int eDVBServicePlay::getInfo(int w)
                                }
                        }
                }
                                }
                        }
                }
-               return -1;
-       case sIsCrypted: if (!no_program_info) return -1; return program.isCrypted();
-       case sVideoPID: if (!no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
-       case sVideoType: if (!no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
-       case sAudioPID: if (!no_program_info) return -1; if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
-       case sPCRPID: if (!no_program_info) return -1; return program.pcrPid;
-       case sPMTPID: if (!no_program_info) return -1; return program.pmtPid;
-       case sTXTPID: if (!no_program_info) return -1; return program.textPid;
+               else
+                       return aspect;
+               break;
+       }
+       case sIsCrypted: if (no_program_info) return -1; return program.isCrypted();
+       case sVideoPID:
+               if (m_dvb_service)
+               {
+                       int vpid = m_dvb_service->getCacheEntry(eDVBService::cVPID);
+                       if (vpid != -1)
+                               return vpid;
+               }
+               if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
+       case sVideoType: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
+       case sAudioPID:
+               if (m_dvb_service)
+               {
+                       int apid = m_dvb_service->getCacheEntry(eDVBService::cAPID);
+                       if (apid != -1)
+                               return apid;
+                       apid = m_dvb_service->getCacheEntry(eDVBService::cAC3PID);
+                       if (apid != -1)
+                               return apid;
+               }
+               if (no_program_info) return -1; if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
+       case sPCRPID:
+               if (m_dvb_service)
+               {
+                       int pcrpid = m_dvb_service->getCacheEntry(eDVBService::cPCRPID);
+                       if (pcrpid != -1)
+                               return pcrpid;
+               }
+               if (no_program_info) return -1; return program.pcrPid;
+       case sPMTPID: if (no_program_info) return -1; return program.pmtPid;
+       case sTXTPID: if (no_program_info) return -1; 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();
        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();
@@ -1289,8 +1631,9 @@ int eDVBServicePlay::getInfo(int w)
        case sServiceref: return resIsString;
        case sDVBState: return m_tune_state;
        default:
        case sServiceref: return resIsString;
        case sDVBState: return m_tune_state;
        default:
-               return -1;
+               break;
        }
        }
+       return -1;
 }
 
 std::string eDVBServicePlay::getInfoString(int w)
 }
 
 std::string eDVBServicePlay::getInfoString(int w)
@@ -1314,6 +1657,8 @@ PyObject *eDVBServicePlay::getInfoObject(int w)
        {
        case sCAIDs:
                return m_service_handler.getCaIds();
        {
        case sCAIDs:
                return m_service_handler.getCaIds();
+       case sTransponderData:
+               return eStaticServiceDVBInformation().getInfoObject(m_reference, w);
        default:
                break;
        }
        default:
                break;
        }
@@ -1329,11 +1674,28 @@ int eDVBServicePlay::getNumberOfTracks()
        return program.audioStreams.size();
 }
 
        return program.audioStreams.size();
 }
 
+int eDVBServicePlay::getCurrentTrack()
+{
+       eDVBServicePMTHandler::program program;
+       eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+       if (h.getProgramInfo(program))
+               return 0;
+
+       int max = program.audioStreams.size();
+       int i;
+
+       for (i = 0; i < max; ++i)
+               if (program.audioStreams[i].pid == m_current_audio_pid)
+                       return i;
+
+       return 0;
+}
+
 RESULT eDVBServicePlay::selectTrack(unsigned int i)
 {
        int ret = selectAudioStream(i);
 
 RESULT eDVBServicePlay::selectTrack(unsigned int i)
 {
        int ret = selectAudioStream(i);
 
-       if (m_decoder->start())
+       if (m_decoder->set())
                return -5;
 
        return ret;
                return -5;
 
        return ret;
@@ -1350,12 +1712,16 @@ RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int
        if (i >= program.audioStreams.size())
                return -2;
        
        if (i >= program.audioStreams.size())
                return -2;
        
+       info.m_pid = program.audioStreams[i].pid;
+
        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::atAAC)
                info.m_description = "AAC";
        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::atAAC)
                info.m_description = "AAC";
+       else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAACHE)
+               info.m_description = "AAC-HE";
        else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
                info.m_description = "DTS";
        else
        else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
                info.m_description = "DTS";
        else
@@ -1382,33 +1748,88 @@ int eDVBServicePlay::selectAudioStream(int i)
 {
        eDVBServicePMTHandler::program program;
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
 {
        eDVBServicePMTHandler::program program;
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+       pts_t position = -1;
 
        if (h.getProgramInfo(program))
                return -1;
 
        if (h.getProgramInfo(program))
                return -1;
-       
-       if ((unsigned int)i >= program.audioStreams.size())
+
+       if ((i != -1) && ((unsigned int)i >= program.audioStreams.size()))
                return -2;
                return -2;
-       
+
        if (!m_decoder)
                return -3;
        if (!m_decoder)
                return -3;
-       
-       if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
+
+       int stream = i;
+       if (stream == -1)
+               stream = program.defaultAudioStream;
+
+       int apid = -1, apidtype = -1;
+
+       if (((unsigned int)stream) < program.audioStreams.size())
+       {
+               apid = program.audioStreams[stream].pid;
+               apidtype = program.audioStreams[stream].type;
+       }
+
+       if (i != -1 && apid != m_current_audio_pid && (m_is_pvr || m_timeshift_active))
+               eDebug("getPlayPosition ret %d, pos %lld in selectAudioStream", getPlayPosition(position), position);
+
+       m_current_audio_pid = apid;
+
+       if (m_is_primary && m_decoder->setAudioPID(apid, apidtype))
+       {
+               eDebug("set audio pid failed");
                return -4;
                return -4;
+       }
+
+       if (position != -1)
+               eDebug("seekTo ret %d", seekTo(position));
 
 
-       if (m_radiotext_parser)
-               m_radiotext_parser->start(program.audioStreams[i].pid);
+       int rdsPid = apid;
 
 
-       if (m_dvb_service && !m_is_pvr)
+               /* if we are not in PVR mode, timeshift is not active and we are not in pip mode, check if we need to enable the rds reader */
+       if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
        {
        {
-               if (program.audioStreams[i].type == eDVBAudio::aMPEG)
+               int different_pid = program.videoStreams.empty() && program.audioStreams.size() == 1 && program.audioStreams[stream].rdsPid != -1;
+               if (different_pid)
+                       rdsPid = program.audioStreams[stream].rdsPid;
+               if (!m_rds_decoder || m_rds_decoder->getPid() != rdsPid)
                {
                {
-                       m_dvb_service->setCacheEntry(eDVBService::cAPID, program.audioStreams[i].pid);
+                       m_rds_decoder = 0;
+                       ePtr<iDVBDemux> data_demux;
+                       if (!h.getDataDemux(data_demux))
+                       {
+                               m_rds_decoder = new eDVBRdsDecoder(data_demux, different_pid);
+                               m_rds_decoder->connectEvent(slot(*this, &eDVBServicePlay::rdsDecoderEvent), m_rds_decoder_event_connection);
+                               m_rds_decoder->start(rdsPid);
+                       }
+               }
+       }
+
+                       /* store new pid as default only when:
+                               a.) we have an entry in the service db for the current service,
+                               b.) we are not playing back something,
+                               c.) we are not selecting the default entry. (we wouldn't change 
+                                   anything in the best case, or destroy the default setting in
+                                   case the real default is not yet available.)
+                       */
+       if (m_dvb_service && ((i != -1)
+               || ((m_dvb_service->getCacheEntry(eDVBService::cAPID) == -1) && (m_dvb_service->getCacheEntry(eDVBService::cAC3PID)==-1))))
+       {
+               if (apidtype == eDVBAudio::aMPEG)
+               {
+                       m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
                        m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
                }
                        m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
                }
+               else if (apidtype == eDVBAudio::aAC3)
+               {
+                       m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
+                       m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
+               }
                else
                {
                        m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
                else
                {
                        m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
-                       m_dvb_service->setCacheEntry(eDVBService::cAC3PID, program.audioStreams[i].pid);
+                       m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
                }
        }
 
                }
        }
 
@@ -1433,20 +1854,81 @@ RESULT eDVBServicePlay::selectChannel(int i)
        return 0;
 }
 
        return 0;
 }
 
-std::string eDVBServicePlay::getRadioText(int x)
+std::string eDVBServicePlay::getText(int x)
 {
 {
-       if (m_radiotext_parser)
+       if (m_rds_decoder)
                switch(x)
                {
                switch(x)
                {
-                       case 0:
-                               return convertLatin1UTF8(m_radiotext_parser->getCurrentText());
+                       case RadioText:
+                               return convertLatin1UTF8(m_rds_decoder->getRadioText());
+                       case RtpText:
+                               return convertLatin1UTF8(m_rds_decoder->getRtpText());
                }
        return "";
 }
 
                }
        return "";
 }
 
-void eDVBServicePlay::radioTextUpdated()
+void eDVBServicePlay::rdsDecoderEvent(int what)
+{
+       switch(what)
+       {
+               case eDVBRdsDecoder::RadioTextChanged:
+                       m_event((iPlayableService*)this, evUpdatedRadioText);
+                       break;
+               case eDVBRdsDecoder::RtpTextChanged:
+                       m_event((iPlayableService*)this, evUpdatedRtpText);
+                       break;
+               case eDVBRdsDecoder::RassInteractivePicMaskChanged:
+                       m_event((iPlayableService*)this, evUpdatedRassInteractivePicMask);
+                       break;
+               case eDVBRdsDecoder::RecvRassSlidePic:
+                       m_event((iPlayableService*)this, evUpdatedRassSlidePic);
+                       break;
+       }
+}
+
+void eDVBServicePlay::showRassSlidePicture()
+{
+       if (m_rds_decoder)
+       {
+               if (m_decoder)
+               {
+                       std::string rass_slide_pic = m_rds_decoder->getRassSlideshowPicture();
+                       if (rass_slide_pic.length())
+                               m_decoder->showSinglePic(rass_slide_pic.c_str());
+                       else
+                               eDebug("empty filename for rass slide picture received!!");
+               }
+               else
+                       eDebug("no MPEG Decoder to show iframes avail");
+       }
+       else
+               eDebug("showRassSlidePicture called.. but not decoder");
+}
+
+void eDVBServicePlay::showRassInteractivePic(int page, int subpage)
+{
+       if (m_rds_decoder)
+       {
+               if (m_decoder)
+               {
+                       std::string rass_interactive_pic = m_rds_decoder->getRassPicture(page, subpage);
+                       if (rass_interactive_pic.length())
+                               m_decoder->showSinglePic(rass_interactive_pic.c_str());
+                       else
+                               eDebug("empty filename for rass interactive picture %d/%d received!!", page, subpage);
+               }
+               else
+                       eDebug("no MPEG Decoder to show iframes avail");
+       }
+       else
+               eDebug("showRassInteractivePic called.. but not decoder");
+}
+
+ePyObject eDVBServicePlay::getRassInteractiveMask()
 {
 {
-       m_event((iPlayableService*)this, evUpdatedRadioText);
+       if (m_rds_decoder)
+               return m_rds_decoder->getRassPictureMask();
+       Py_RETURN_NONE;
 }
 
 int eDVBServiceBase::getFrontendInfo(int w)
 }
 
 int eDVBServiceBase::getFrontendInfo(int w)
@@ -1460,48 +1942,75 @@ int eDVBServiceBase::getFrontendInfo(int w)
        return fe->readFrontendData(w);
 }
 
        return fe->readFrontendData(w);
 }
 
-PyObject *eDVBServiceBase::getFrontendData(bool original)
+PyObject *eDVBServiceBase::getFrontendData()
 {
 {
-       ePyObject ret;
+       ePyObject ret = PyDict_New();
+       if (ret)
+       {
+               eUsePtr<iDVBChannel> channel;
+               if(!m_service_handler.getChannel(channel))
+               {
+                       ePtr<iDVBFrontend> fe;
+                       if(!channel->getFrontend(fe))
+                               fe->getFrontendData(ret);
+               }
+       }
+       else
+               Py_RETURN_NONE;
+       return ret;
+}
 
 
-       eUsePtr<iDVBChannel> channel;
-       if(!m_service_handler.getChannel(channel))
+PyObject *eDVBServiceBase::getFrontendStatus()
+{
+       ePyObject ret = PyDict_New();
+       if (ret)
        {
        {
-               ePtr<iDVBFrontend> fe;
-               if(!channel->getFrontend(fe))
+               eUsePtr<iDVBChannel> channel;
+               if(!m_service_handler.getChannel(channel))
                {
                {
-                       ret = fe->readTransponderData(original);
-                       if (ret)
-                       {
-                               ePtr<iDVBFrontendParameters> feparm;
-                               channel->getCurrentFrontendParameters(feparm);
-                               if (feparm)
-                               {
-                                       eDVBFrontendParametersSatellite osat;
-                                       if (!feparm->getDVBS(osat))
-                                       {
-                                               void PutToDict(ePyObject &, const char*, long);
-                                               void PutToDict(ePyObject &, const char*, const char*);
-                                               PutToDict(ret, "orbital_position", osat.orbital_position);
-                                               const char *tmp = "UNKNOWN";
-                                               switch(osat.polarisation)
-                                               {
-                                                       case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
-                                                       case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
-                                                       case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
-                                                       case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
-                                                       default:break;
-                                               }
-                                               PutToDict(ret, "polarization", tmp);
-                                       }
-                               }
-                       }
+                       ePtr<iDVBFrontend> fe;
+                       if(!channel->getFrontend(fe))
+                               fe->getFrontendStatus(ret);
                }
        }
                }
        }
-       if (!ret)
+       else
+               Py_RETURN_NONE;
+       return ret;
+}
+
+PyObject *eDVBServiceBase::getTransponderData(bool original)
+{
+       ePyObject ret = PyDict_New();
+       if (ret)
+       {
+               eUsePtr<iDVBChannel> channel;
+               if(!m_service_handler.getChannel(channel))
+               {
+                       ePtr<iDVBFrontend> fe;
+                       if(!channel->getFrontend(fe))
+                               fe->getTransponderData(ret, original);
+               }
+       }
+       else
+               Py_RETURN_NONE;
+       return ret;
+}
+
+PyObject *eDVBServiceBase::getAll(bool original)
+{
+       ePyObject ret = getTransponderData(original);
+       if (ret != Py_None)
        {
        {
-               ret = Py_None;
-               Py_INCREF(ret);
+               eUsePtr<iDVBChannel> channel;
+               if(!m_service_handler.getChannel(channel))
+               {
+                       ePtr<iDVBFrontend> fe;
+                       if(!channel->getFrontend(fe))
+                       {
+                               fe->getFrontendData(ret);
+                               fe->getFrontendStatus(ret);
+                       }
+               }
        }
        return ret;
 }
        }
        return ret;
 }
@@ -1543,12 +2052,23 @@ RESULT eDVBServicePlay::startTimeshift()
        if (!m_record)
                return -3;
 
        if (!m_record)
                return -3;
 
-       char templ[]=TSPATH "/timeshift.XXXXXX";
+       std::string tspath;
+       if(ePythonConfigQuery::getConfigValue("config.usage.timeshift_path", tspath) == -1){ 
+               eDebug("could not query ts path");
+               return -5;
+       }
+       tspath.append("/timeshift.XXXXXX");
+       char* templ;
+       templ = new char[tspath.length() + 1];
+       strcpy(templ, tspath.c_str());
+
        m_timeshift_fd = mkstemp(templ);
        m_timeshift_fd = mkstemp(templ);
-       m_timeshift_file = templ;
-       
+       m_timeshift_file = std::string(templ);
+
        eDebug("recording to %s", templ);
        eDebug("recording to %s", templ);
-       
+
+       delete [] templ;
+
        if (m_timeshift_fd < 0)
        {
                m_record = 0;
        if (m_timeshift_fd < 0)
        {
                m_record = 0;
@@ -1565,12 +2085,13 @@ RESULT eDVBServicePlay::startTimeshift()
        return 0;
 }
 
        return 0;
 }
 
-RESULT eDVBServicePlay::stopTimeshift()
+RESULT eDVBServicePlay::stopTimeshift(bool swToLive)
 {
        if (!m_timeshift_enabled)
                return -1;
        
 {
        if (!m_timeshift_enabled)
                return -1;
        
-       switchToLive();
+       if (swToLive)
+               switchToLive();
        
        m_timeshift_enabled = 0;
        
        
        m_timeshift_enabled = 0;
        
@@ -1579,7 +2100,7 @@ RESULT eDVBServicePlay::stopTimeshift()
        
        close(m_timeshift_fd);
        eDebug("remove timeshift file");
        
        close(m_timeshift_fd);
        eDebug("remove timeshift file");
-       remove(m_timeshift_file.c_str());
+       eBackgroundFileEraser::getInstance()->erase(m_timeshift_file.c_str());
        
        return 0;
 }
        
        return 0;
 }
@@ -1610,8 +2131,8 @@ PyObject *eDVBServicePlay::getCutList()
        for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
        {
                ePyObject tuple = PyTuple_New(2);
        for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
        {
                ePyObject tuple = PyTuple_New(2);
-               PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
-               PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
+               PyTuple_SET_ITEM(tuple, 0, PyLong_FromLongLong(i->where));
+               PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(i->what));
                PyList_Append(list, tuple);
                Py_DECREF(tuple);
        }
                PyList_Append(list, tuple);
                Py_DECREF(tuple);
        }
@@ -1694,6 +2215,11 @@ void eDVBServicePlay::updateTimeshiftPids()
                        i != program.audioStreams.end(); ++i)
                                pids_to_record.insert(i->pid);
 
                        i != program.audioStreams.end(); ++i)
                                pids_to_record.insert(i->pid);
 
+               for (std::vector<eDVBServicePMTHandler::subtitleStream>::const_iterator
+                       i(program.subtitleStreams.begin());
+                       i != program.subtitleStreams.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(), 
                std::set<int> new_pids, obsolete_pids;
                
                std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
@@ -1719,23 +2245,26 @@ void eDVBServicePlay::switchToLive()
        if (!m_timeshift_active)
                return;
        
        if (!m_timeshift_active)
                return;
        
+       eDebug("SwitchToLive");
+       
        m_cue = 0;
        m_decoder = 0;
        m_decode_demux = 0;
        m_teletext_parser = 0;
        m_cue = 0;
        m_decoder = 0;
        m_decode_demux = 0;
        m_teletext_parser = 0;
-       m_radiotext_parser = 0;
+       m_rds_decoder = 0;
        m_subtitle_parser = 0;
        m_new_dvb_subtitle_page_connection = 0;
        m_new_subtitle_page_connection = 0;
        m_subtitle_parser = 0;
        m_new_dvb_subtitle_page_connection = 0;
        m_new_subtitle_page_connection = 0;
-       m_radiotext_updated_connection = 0;
+       m_rds_decoder_event_connection = 0;
+       m_video_event_connection = 0;
+       m_is_paused = m_skipmode = m_fastforward = m_slowmotion = 0; /* not supported in live mode */
 
                /* free the timeshift service handler, we need the resources */
        m_service_handler_timeshift.free();
        m_timeshift_active = 0;
 
                /* free the timeshift service handler, we need the resources */
        m_service_handler_timeshift.free();
        m_timeshift_active = 0;
+       m_timeshift_changed = 1;
 
 
-       m_event((iPlayableService*)this, evSeekableStatusChanged);
-
-       updateDecoder();
+       updateDecoder(true);
 }
 
 void eDVBServicePlay::switchToTimeshift()
 }
 
 void eDVBServicePlay::switchToTimeshift()
@@ -1746,36 +2275,35 @@ void eDVBServicePlay::switchToTimeshift()
        m_decode_demux = 0;
        m_decoder = 0;
        m_teletext_parser = 0;
        m_decode_demux = 0;
        m_decoder = 0;
        m_teletext_parser = 0;
-       m_radiotext_parser = 0;
+       m_rds_decoder = 0;
        m_subtitle_parser = 0;
        m_new_subtitle_page_connection = 0;
        m_new_dvb_subtitle_page_connection = 0;
        m_subtitle_parser = 0;
        m_new_subtitle_page_connection = 0;
        m_new_dvb_subtitle_page_connection = 0;
-       m_radiotext_updated_connection = 0;
+       m_rds_decoder_event_connection = 0;
+       m_video_event_connection = 0;
 
        m_timeshift_active = 1;
 
        m_timeshift_active = 1;
-
-       m_event((iPlayableService*)this, evSeekableStatusChanged);
+       m_timeshift_changed = 1;
 
        eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
        r.path = m_timeshift_file;
 
        m_cue = new eCueSheet();
 
        eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
        r.path = m_timeshift_file;
 
        m_cue = new eCueSheet();
-       m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
-       updateDecoder(); /* mainly to switch off PCR */
+       m_cue->seekTo(0, -1000);
+       m_service_handler_timeshift.tune(r, 1, m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
+
+       eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
+       pause();
+       updateDecoder(true); /* mainly to switch off PCR, and to set pause */
 }
 
 }
 
-void eDVBServicePlay::updateDecoder()
+void eDVBServicePlay::updateDecoder(bool sendSeekableStateChanged)
 {
 {
-       int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
+       int vpid = -1, vpidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
+       bool mustPlay = false;
 
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
 
 
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
 
-       bool defaultac3=false;
-       std::string default_ac3;
-
-       if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
-               defaultac3 = default_ac3 == "True";
-
        eDVBServicePMTHandler::program program;
        if (h.getProgramInfo(program))
                eDebug("getting program info failed.");
        eDVBServicePMTHandler::program program;
        if (h.getProgramInfo(program))
                eDebug("getting program info failed.");
@@ -1808,14 +2336,6 @@ void eDVBServicePlay::updateDecoder()
                                i(program.audioStreams.begin());
                                i != program.audioStreams.end(); ++i)
                        {
                                i(program.audioStreams.begin());
                                i != program.audioStreams.end(); ++i)
                        {
-                               if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
-                               {
-                                       if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
-                                       {
-                                               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);
@@ -1831,25 +2351,54 @@ void eDVBServicePlay::updateDecoder()
        if (!m_decoder)
        {
                h.getDecodeDemux(m_decode_demux);
        if (!m_decoder)
        {
                h.getDecodeDemux(m_decode_demux);
+               if (m_timeshift_changed)
+                       m_decoder = 0;
                if (m_decode_demux)
                if (m_decode_demux)
+               {
                        m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
                        m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
+                       if (m_decoder)
+                               m_decoder->connectVideoEvent(slot(*this, &eDVBServicePlay::video_event), m_video_event_connection);
+                       if (m_is_primary)
+                       {
+                               m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
+                               m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
+                               m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
+                               m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
+                               if (m_timeshift_changed)
+                               {
+                                       ePyObject subs = getCachedSubtitle();
+                                       if (subs != Py_None)
+                                       {
+                                               int type = PyInt_AsLong(PyTuple_GET_ITEM(subs, 0)),
+                                                   pid = PyInt_AsLong(PyTuple_GET_ITEM(subs, 1)),
+                                                   comp_page = PyInt_AsLong(PyTuple_GET_ITEM(subs, 2)), // ttx page
+                                                   anc_page = PyInt_AsLong(PyTuple_GET_ITEM(subs, 3)); // ttx magazine
+                                               if (type == 0) // dvb
+                                                       m_subtitle_parser->start(pid, comp_page, anc_page);
+                                               else if (type == 1) // ttx
+                                                       m_teletext_parser->setPageAndMagazine(comp_page, anc_page);
+                                       }
+                                       Py_DECREF(subs);
+                               }
+                       }
+               }
                if (m_cue)
                        m_cue->setDecodingDemux(m_decode_demux, m_decoder);
                if (m_cue)
                        m_cue->setDecodingDemux(m_decode_demux, m_decoder);
-               m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
-               m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
-               m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
-               m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
+               mustPlay = true;
        }
 
        }
 
+       m_timeshift_changed = 0;
+
        if (m_decoder)
        {
        if (m_decoder)
        {
+               bool wasSeekable = m_decoder->getVideoProgressive() != -1;
                if (m_dvb_service)
                {
                        achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
                        ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
                        pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
                }
                if (m_dvb_service)
                {
                        achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
                        ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
                        pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
                }
-               else // subservice or recording
+               else // subservice
                {
                        eServiceReferenceDVB ref;
                        m_service_handler.getServiceReference(ref);
                {
                        eServiceReferenceDVB ref;
                        m_service_handler.getServiceReference(ref);
@@ -1874,36 +2423,23 @@ void eDVBServicePlay::updateDecoder()
                                }
                        }
                }
                                }
                        }
                }
-               m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
-               m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
+
+               setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
+               setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
 
                m_decoder->setVideoPID(vpid, vpidtype);
 
                m_decoder->setVideoPID(vpid, vpidtype);
-               m_decoder->setAudioPID(apid, apidtype);
+               selectAudioStream();
+
                if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
                if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
-               {
                        m_decoder->setSyncPCR(pcrpid);
                        m_decoder->setSyncPCR(pcrpid);
-                       if (apid != -1)
-                       {
-                               ePtr<iDVBDemux> data_demux;
-                               if (!h.getDataDemux(data_demux))
-                               {
-                                       m_radiotext_parser = new eDVBRadioTextParser(data_demux);
-                                       m_radiotext_parser->connectUpdatedRadiotext(slot(*this, &eDVBServicePlay::radioTextUpdated), m_radiotext_updated_connection);
-                                       m_radiotext_parser->start(apid);
-                               }
-                       }
-               }
                else
                        m_decoder->setSyncPCR(-1);
 
                else
                        m_decoder->setSyncPCR(-1);
 
-               m_decoder->setTextPID(tpid);
-
-               m_teletext_parser->start(program.textPid);
-
-               if (!m_is_primary)
-                       m_decoder->setTrickmode(1);
-
-               m_decoder->start();
+               if (m_is_primary)
+               {
+                       m_decoder->setTextPID(tpid);
+                       m_teletext_parser->start(program.textPid);
+               }
 
                if (vpid > 0 && vpid < 0x2000)
                        ;
 
                if (vpid > 0 && vpid < 0x2000)
                        ;
@@ -1914,32 +2450,29 @@ void eDVBServicePlay::updateDecoder()
                                m_decoder->setRadioPic(radio_pic);
                }
 
                                m_decoder->setRadioPic(radio_pic);
                }
 
+               if (mustPlay)
+                       m_decoder->play();
+               else
+                       m_decoder->set();
+
                m_decoder->setAudioChannel(achannel);
 
                m_decoder->setAudioChannel(achannel);
 
-// 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 */
                /* don't worry about non-existing services, nor pvr services */
-               if (m_dvb_service && !m_is_pvr)
+               if (m_dvb_service)
                {
                {
-                       if (apidtype == eDVBAudio::aMPEG)
-                       {
-                               m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
-                               m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
-                       }
-                       else
-                       {
-                               m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
-                               m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
-                       }
+                               /* (audio pid will be set in selectAudioTrack */
                        m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
                        m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
                        m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
                        m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
                }
                        m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
                        m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
                        m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
                        m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
                }
+               if (!sendSeekableStateChanged && (m_decoder->getVideoProgressive() != -1) != wasSeekable)
+                       sendSeekableStateChanged = true;
        }
        m_have_video_pid = (vpid > 0 && vpid < 0x2000);
        }
        m_have_video_pid = (vpid > 0 && vpid < 0x2000);
+
+       if (sendSeekableStateChanged)
+               m_event((iPlayableService*)this, evSeekableStatusChanged);
 }
 
 void eDVBServicePlay::loadCuesheet()
 }
 
 void eDVBServicePlay::loadCuesheet()
@@ -2034,11 +2567,16 @@ void eDVBServicePlay::cutlistToCuesheet()
                
        std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
        
                
        std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
        
+       int have_any_span = 0;
+       
        while (1)
        {
                if (i == m_cue_entries.end())
        while (1)
        {
                if (i == m_cue_entries.end())
+               {
+                       if (!have_any_span && !in)
+                               break;
                        out = length;
                        out = length;
-               else {
+               else {
                        if (i->what == 0) /* in */
                        {
                                in = i++->where;
                        if (i->what == 0) /* in */
                        {
                                in = i++->where;
@@ -2052,8 +2590,21 @@ void eDVBServicePlay::cutlistToCuesheet()
                        }
                }
                
                        }
                }
                
-               if (in != out)
+               if (in < 0)
+                       in = 0;
+               if (out < 0)
+                       out = 0;
+               if (in > length)
+                       in = length;
+               if (out > length)
+                       out = length;
+               
+               if (in < out)
+               {
+                       have_any_span = 1;
                        m_cue->addSourceSpan(in, out);
                        m_cue->addSourceSpan(in, out);
+                       in = out = 0;
+               }
                
                in = length;
                
                
                in = length;
                
@@ -2197,24 +2748,20 @@ PyObject *eDVBServicePlay::getCachedSubtitle()
                                        PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1)); // type teletext
                                else
                                        PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0)); // type dvb
                                        PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1)); // type teletext
                                else
                                        PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0)); // type dvb
-                               PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong((data&0xFFFF0000)>>16)); // pid
+                               PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(pid)); // pid
                                PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong((data&0xFF00)>>8)); // composition_page / page
                                PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(data&0xFF)); // ancillary_page / magazine
                                return tuple;
                        }
                }
        }
                                PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong((data&0xFF00)>>8)); // composition_page / page
                                PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(data&0xFF)); // ancillary_page / magazine
                                return tuple;
                        }
                }
        }
-       Py_INCREF(Py_None);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 PyObject *eDVBServicePlay::getSubtitleList()
 {
        if (!m_teletext_parser)
 }
 
 PyObject *eDVBServicePlay::getSubtitleList()
 {
        if (!m_teletext_parser)
-       {
-               Py_INCREF(Py_None);
-               return Py_None;
-       }
+               Py_RETURN_NONE;
        
        ePyObject l = PyList_New(0);
        std::set<int> added_ttx_pages;
        
        ePyObject l = PyList_New(0);
        std::set<int> added_ttx_pages;
@@ -2295,6 +2842,10 @@ void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
 {
        if (m_subtitle_widget)
        {
 {
        if (m_subtitle_widget)
        {
+               pts_t pos = 0;
+               if (m_decoder)
+                       m_decoder->getPTS(0, pos);
+               eDebug("got new subtitle page %lld %lld %d", pos, page.m_pts, page.m_have_pts);
                m_subtitle_pages.push_back(page);
                checkSubtitleTiming();
        }
                m_subtitle_pages.push_back(page);
                checkSubtitleTiming();
        }
@@ -2302,7 +2853,7 @@ void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
 
 void eDVBServicePlay::checkSubtitleTiming()
 {
 
 void eDVBServicePlay::checkSubtitleTiming()
 {
-//     eDebug("checkSubtitleTiming");
+       eDebug("checkSubtitleTiming");
        if (!m_subtitle_widget)
                return;
        while (1)
        if (!m_subtitle_widget)
                return;
        while (1)
@@ -2331,37 +2882,41 @@ void eDVBServicePlay::checkSubtitleTiming()
                if (m_decoder)
                        m_decoder->getPTS(0, pos);
 
                if (m_decoder)
                        m_decoder->getPTS(0, pos);
 
-//             eDebug("%lld %lld", pos, show_time);
-               int diff =  show_time - pos;
+               eDebug("%lld %lld", pos, show_time);
+               int diff = show_time - pos;
+               if (type == TELETEXT && !page.m_have_pts)
+               {
+                       eDebug("ttx subtitle page without pts... immediate show");
+                       diff = 0;
+               }
                if (diff < 0)
                {
                        eDebug("[late (%d ms)]", -diff / 90);
                        diff = 0;
                }
                if (diff < 0)
                {
                        eDebug("[late (%d ms)]", -diff / 90);
                        diff = 0;
                }
-               if (diff > 900000)
+               if (abs(diff) > 1800000)
                {
                {
-                       eDebug("[invalid]");
+                       eDebug("[invalid]... immediate show!");
                        diff = 0;
                }
                        diff = 0;
                }
-       
-               if (!diff)
+               if ((diff/90)<20)
                {
                        if (type == TELETEXT)
                        {
                {
                        if (type == TELETEXT)
                        {
-                               eDebug("display teletext subtitle page");
+                               eDebug("display teletext subtitle page %lld", show_time);
                                m_subtitle_widget->setPage(page);
                                m_subtitle_pages.pop_front();
                        }
                        else
                        {
                                m_subtitle_widget->setPage(page);
                                m_subtitle_pages.pop_front();
                        }
                        else
                        {
-                               eDebug("display dvb subtitle Page");
+                               eDebug("display dvb subtitle Page %lld", show_time);
                                m_subtitle_widget->setPage(dvb_page);
                                m_dvb_subtitle_pages.pop_front();
                        }
                } else
                {
                                m_subtitle_widget->setPage(dvb_page);
                                m_dvb_subtitle_pages.pop_front();
                        }
                } else
                {
-//                     eDebug("start subtitle delay %d", diff / 90);
-                       m_subtitle_sync_timer.start(diff / 90, 1);
+                       eDebug("start subtitle delay %d", diff / 90);
+                       m_subtitle_sync_timer->start(diff / 90, 1);
                        break;
                }
        }
                        break;
                }
        }
@@ -2371,6 +2926,10 @@ void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
 {
        if (m_subtitle_widget)
        {
 {
        if (m_subtitle_widget)
        {
+               pts_t pos = 0;
+               if (m_decoder)
+                       m_decoder->getPTS(0, pos);
+               eDebug("got new subtitle page %lld %lld", pos, p.m_show_time);
                m_dvb_subtitle_pages.push_back(p);
                checkSubtitleTiming();
        }
                m_dvb_subtitle_pages.push_back(p);
                checkSubtitleTiming();
        }
@@ -2400,18 +2959,86 @@ void eDVBServicePlay::setAC3Delay(int delay)
 {
        if (m_dvb_service)
                m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
 {
        if (m_dvb_service)
                m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
-       if (m_decoder)
-               m_decoder->setAC3Delay(delay);
+       if (m_decoder) {
+               std::string config_delay;
+               int config_delay_int = 0;
+               if(ePythonConfigQuery::getConfigValue("config.av.generalAC3delay", config_delay) == 0)
+                       config_delay_int = atoi(config_delay.c_str());
+               m_decoder->setAC3Delay(delay + config_delay_int);
+       }
 }
 
 void eDVBServicePlay::setPCMDelay(int delay)
 {
        if (m_dvb_service)
                m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
 }
 
 void eDVBServicePlay::setPCMDelay(int delay)
 {
        if (m_dvb_service)
                m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
-       if (m_decoder)
-               m_decoder->setPCMDelay(delay);
+       if (m_decoder) {
+               std::string config_delay;
+               int config_delay_int = 0;
+               if(ePythonConfigQuery::getConfigValue("config.av.generalPCMdelay", config_delay) == 0)
+                       config_delay_int = atoi(config_delay.c_str());
+               else
+                       config_delay_int = 0;
+               m_decoder->setPCMDelay(delay + config_delay_int);
+       }
+}
+
+void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)
+{
+       switch(event.type) {
+               case iTSMPEGDecoder::videoEvent::eventSizeChanged:
+                       m_event((iPlayableService*)this, evVideoSizeChanged);
+                       break;
+               case iTSMPEGDecoder::videoEvent::eventFrameRateChanged:
+                       m_event((iPlayableService*)this, evVideoFramerateChanged);
+                       break;
+               case iTSMPEGDecoder::videoEvent::eventProgressiveChanged:
+                       m_event((iPlayableService*)this, evVideoProgressiveChanged);
+                       break;
+               default:
+                       break;
+       }
+}
+
+RESULT eDVBServicePlay::stream(ePtr<iStreamableService> &ptr)
+{
+       ptr = this;
+       return 0;
+}
+
+PyObject *eDVBServicePlay::getStreamingData()
+{
+       eDVBServicePMTHandler::program program;
+       if (m_service_handler.getProgramInfo(program))
+       {
+               Py_RETURN_NONE;
+       }
+
+       ePyObject r = program.createPythonObject();
+       ePtr<iDVBDemux> demux;
+       if (!m_service_handler.getDataDemux(demux))
+       {
+               uint8_t demux_id;
+               if (!demux->getCADemuxID(demux_id))
+                       PutToDict(r, "demux", demux_id);
+       }
+
+       return r;
 }
 
 }
 
+
 DEFINE_REF(eDVBServicePlay)
 
 DEFINE_REF(eDVBServicePlay)
 
+PyObject *eDVBService::getInfoObject(const eServiceReference &ref, int w)
+{
+       switch (w)
+       {
+       case iServiceInformation::sTransponderData:
+               return eStaticServiceDVBInformation().getInfoObject(ref, w);
+       default:
+               break;
+       }
+       return iStaticServiceInformation::getInfoObject(ref, w);
+}
+
 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");
 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");