Patch by Moritz Venn: Allow to set an additional delay via config.
[vuplus_dvbapp] / lib / service / servicedvb.cpp
index 627ccec..012493f 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/nconfig.h> // access to python config
 #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/base/nconfig.h> // access to python config
 
                /* for subtitles */
 #include <lib/gui/esubtitle.h>
 #error no byte order defined!
 #endif
 
-#define TSPATH "/media/hdd"
-
 class eStaticServiceDVBInformation: public iStaticServiceInformation
 {
        DECLARE_REF(eStaticServiceDVBInformation);
 public:
        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);
@@ -63,16 +63,7 @@ RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::
                                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) + " - ";
                                }
                        }
                }
@@ -90,13 +81,129 @@ int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
        return -1;
 }
 
-class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
+int eStaticServiceDVBInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore)
 {
-       DECLARE_REF(eStaticServiceDVBBouquetInformation);
-public:
-       RESULT getName(const eServiceReference &ref, std::string &name);
-       int getLength(const eServiceReference &ref);
-};
+       ePtr<eDVBResourceManager> res_mgr;
+       if ( eDVBResourceManager::getInstance( res_mgr ) )
+               eDebug("isPlayable... no res manager!!");
+       else
+       {
+               eDVBChannelID chid, chid_ignore;
+               ((const eServiceReferenceDVB&)ref).getChannelID(chid);
+               ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
+               return res_mgr->canAllocateChannel(chid, chid_ignore);
+       }
+       return false;
+}
+
+extern void PutToDict(ePyObject &dict, const char*key, long value);  // defined in dvb/frontend.cpp
+extern void PutToDict(ePyObject &dict, const char*key, ePyObject item); // defined in dvb/frontend.cpp
+extern void PutToDict(ePyObject &dict, const char*key, const char *value); // defined in dvb/frontend.cpp
+
+void PutSatelliteDataToDict(ePyObject &dict, eDVBFrontendParametersSatellite &feparm)
+{
+       PutToDict(dict, "tuner_type", "DVB-S");
+       PutToDict(dict, "frequency", feparm.frequency);
+       PutToDict(dict, "symbol_rate", feparm.symbol_rate);
+       PutToDict(dict, "orbital_position", feparm.orbital_position);
+       PutToDict(dict, "inversion", feparm.inversion);
+       PutToDict(dict, "fec_inner", feparm.fec);
+       PutToDict(dict, "modulation", feparm.modulation);
+       PutToDict(dict, "polarization", feparm.polarisation);
+       if (feparm.system == eDVBFrontendParametersSatellite::System_DVB_S2)
+       {
+               PutToDict(dict, "rolloff", feparm.rolloff);
+               PutToDict(dict, "pilot", feparm.pilot);
+       }
+       PutToDict(dict, "system", feparm.system);
+}
+
+void PutTerrestrialDataToDict(ePyObject &dict, eDVBFrontendParametersTerrestrial &feparm)
+{
+       PutToDict(dict, "tuner_type", "DVB-T");
+       PutToDict(dict, "frequency", feparm.frequency);
+       PutToDict(dict, "bandwidth", feparm.bandwidth);
+       PutToDict(dict, "code_rate_lp", feparm.code_rate_LP);
+       PutToDict(dict, "code_rate_hp", feparm.code_rate_HP);
+       PutToDict(dict, "constellation", feparm.modulation);
+       PutToDict(dict, "transmission_mode", feparm.transmission_mode);
+       PutToDict(dict, "guard_interval", feparm.guard_interval);
+       PutToDict(dict, "hierarchy_information", feparm.hierarchy);
+       PutToDict(dict, "inversion", feparm.inversion);
+}
+
+void PutCableDataToDict(ePyObject &dict, eDVBFrontendParametersCable &feparm)
+{
+       PutToDict(dict, "tuner_type", "DVB-C");
+       PutToDict(dict, "frequency", feparm.frequency);
+       PutToDict(dict, "symbol_rate", feparm.symbol_rate);
+       PutToDict(dict, "modulation", feparm.modulation);
+       PutToDict(dict, "inversion", feparm.inversion);
+       PutToDict(dict, "fec_inner", feparm.fec_inner);
+}
+
+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);
 
@@ -133,11 +240,89 @@ RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref
                return -1;
 }
 
+int eStaticServiceDVBBouquetInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore, bool simulate)
+{
+       if (ref.flags & eServiceReference::isGroup)
+       {
+               ePtr<iDVBChannelList> db;
+               ePtr<eDVBResourceManager> res;
+
+               if (eDVBResourceManager::getInstance(res))
+               {
+                       eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. no resource manager!");
+                       return 0;
+               }
+
+               if (res->getChannelList(db))
+               {
+                       eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. no channel list!");
+                       return 0;
+               }
+
+               eBouquet *bouquet=0;
+               if (db->getBouquet(ref, bouquet))
+               {
+                       eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. getBouquet failed!");
+                       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)
+               {
+                       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);
+                       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;
+                               cur = tmp;
+                       }
+               }
+               if (cur)
+                       return cur;
+       }
+       m_playable_service = eServiceReference();
+       return 0;
+}
+
 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
 {
        return -1;
 }
 
+#include <lib/dvb/epgcache.h>
+
+RESULT eStaticServiceDVBBouquetInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &ptr, time_t start_time)
+{
+       return eEPGCache::getInstance()->lookupEventTime(ref, start_time, ptr);
+}
+
 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
 {
        DECLARE_REF(eStaticServiceDVBPVRInformation);
@@ -148,7 +333,7 @@ public:
        RESULT getName(const eServiceReference &ref, std::string &name);
        int getLength(const eServiceReference &ref);
        RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
-
+       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);
 };
@@ -164,7 +349,15 @@ eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceR
 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;
 }
 
@@ -174,14 +367,29 @@ int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
        
        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;
 
+                       /* otherwise, re-calc length and update meta file */
        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)
@@ -313,7 +521,12 @@ eServiceFactoryDVB::eServiceFactoryDVB()
        
        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;
@@ -399,6 +612,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)
+//   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
@@ -419,7 +633,7 @@ PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
                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);
@@ -428,14 +642,14 @@ PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
                for (int cnt=0; cnt < services; ++cnt)
                {
                        eServiceReference &ref=*it++;
-                       ePyObject tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
+                       ePyObject tuple = retcount > 1 ? PyTuple_New(retcount) : ePyObject();
                        for (int i=0; i < retcount; ++i)
                        {
                                ePyObject tmp;
                                switch(format[i])
                                {
                                case 'R':  // service reference (swig)object
-                                       tmp = New_eServiceReference(ref);
+                                       tmp = NEW_eServiceReference(ref);
                                        break;
                                case 'C':  // service reference compare string
                                        tmp = PyString_FromString(ref.toCompareString().c_str());
@@ -451,6 +665,30 @@ PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
                                                {
                                                        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());
                                                }
@@ -491,7 +729,7 @@ RESULT eDVBServiceList::getNext(eServiceReference &ref)
 
 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
 {
-       if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
+       if (m_parent.flags & eServiceReference::canDescent) // bouquet
        {
                ePtr<iDVBChannelList> db;
                ePtr<eDVBResourceManager> resm;
@@ -585,7 +823,7 @@ RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableServ
 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
 {
        /* is a listable service? */
-       if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
+       if (ref.flags & eServiceReference::canDescent) // bouquet
        {
                if ( !ref.name.empty() )  // satellites or providers list
                        ptr = m_StaticServiceDVBInfo;
@@ -668,7 +906,11 @@ eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *serv
        
        m_subtitle_widget = 0;
        
-       CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
+       m_tune_state = -1;
+
+       m_subtitle_sync_timer = eTimer::create(eApp);
+
+       CONNECT(m_subtitle_sync_timer->timeout, eDVBServicePlay::checkSubtitleTiming);
 }
 
 eDVBServicePlay::~eDVBServicePlay()
@@ -694,6 +936,8 @@ void eDVBServicePlay::gotNewEvent()
 
 void eDVBServicePlay::serviceEvent(int event)
 {
+       m_tune_state = event;
+
        switch (event)
        {
        case eDVBServicePMTHandler::eventTuned:
@@ -711,11 +955,17 @@ void eDVBServicePlay::serviceEvent(int event)
                        else
                                m_event_handler.start(m_demux, sid);
                }
+               m_event((iPlayableService*)this, evTunedIn);
                break;
        }
+       case eDVBServicePMTHandler::eventNoResources:
+       case eDVBServicePMTHandler::eventNoPAT:
+       case eDVBServicePMTHandler::eventNoPATEntry:
+       case eDVBServicePMTHandler::eventNoPMT:
        case eDVBServicePMTHandler::eventTuneFailed:
+       case eDVBServicePMTHandler::eventMisconfiguration:
        {
-               eDebug("DVB service failed to tune");
+               eDebug("DVB service failed to tune - error %d", event);
                m_event((iPlayableService*)this, evTuneFailed);
                break;
        }
@@ -755,7 +1005,8 @@ void eDVBServicePlay::serviceEventTimeshift(int event)
                m_event((iPlayableService*)this, evSOF);
                break;
        case eDVBServicePMTHandler::eventEOF:
-               switchToLive();
+               if ((!m_is_paused) && (m_skipmode >= 0))
+                       switchToLive();
                break;
        }
 }
@@ -768,6 +1019,8 @@ RESULT eDVBServicePlay::start()
                   to start recording from the data demux. */
        if (m_is_pvr)
                m_cue = new eCueSheet();
+       else
+               m_event(this, evStart);
 
        m_first_program_info = 1;
        eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
@@ -789,10 +1042,10 @@ RESULT eDVBServicePlay::start()
        }
 
        if (m_is_pvr)
+       {
                loadCuesheet();
-
-       m_event(this, evStart);
-       m_event((iPlayableService*)this, evSeekableStatusChanged);
+               m_event(this, evStart);
+       }
        return 0;
 }
 
@@ -801,7 +1054,7 @@ RESULT eDVBServicePlay::stop()
                /* 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 */
@@ -816,7 +1069,17 @@ RESULT eDVBServicePlay::stop()
                                        ++i;
                        }
                        
-                       m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
+                       if (getLength(length))
+                               length = 0;
+                       
+                       if (length)
+                       {
+                               int perc = play_position * 100LL / length;
+                       
+                                       /* only store last play position when between 1% and 99% */
+                               if ((1 < perc) && (perc < 99))
+                                       m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
+                       }
                        m_cuesheet_changed = 1;
                }
        }
@@ -833,7 +1096,7 @@ RESULT eDVBServicePlay::stop()
                if (!::stat(m_reference.path.c_str(), &s))
                        saveCuesheet();
        }
-       
+       m_event((iPlayableService*)this, evStopped);
        return 0;
 }
 
@@ -908,7 +1171,7 @@ RESULT eDVBServicePlay::setFastForward(int ratio)
 
        return m_decoder->setFastForward(ffratio);
 }
-    
+
 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
 {
        if (m_is_pvr || m_timeshift_enabled)
@@ -968,6 +1231,9 @@ RESULT eDVBServicePlay::seekTo(pts_t to)
                return -1;
        
        m_cue->seekTo(0, to);
+       m_dvb_subtitle_pages.clear();
+       m_subtitle_pages.clear();
+
        return 0;
 }
 
@@ -995,6 +1261,8 @@ RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
                return 0;
        
        m_cue->seekTo(mode, to);
+       m_dvb_subtitle_pages.clear();
+       m_subtitle_pages.clear();
        return 0;
 }
 
@@ -1072,9 +1340,16 @@ RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
        {
                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;
-                       if (statfs(TSPATH "/.", &fs) < 0)
+                       if (statfs(tspath.c_str(), &fs) < 0)
                        {
                                eDebug("statfs failed!");
                                return -2;
@@ -1115,7 +1390,7 @@ RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
        return 0;
 }
 
-RESULT eDVBServicePlay::radioText(ePtr<iRadioText> &ptr)
+RESULT eDVBServicePlay::rdsDecoder(ePtr<iRdsDecoder> &ptr)
 {
        ptr = this;
        return 0;
@@ -1154,14 +1429,38 @@ int eDVBServicePlay::getInfo(int w)
                return resIsPyObject;
 
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
-       
+
+       int no_program_info = 0;
+
        if (h.getProgramInfo(program))
-               return -1;
-       
+               no_program_info = 1;
+
        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:
-               if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
+       {
+               int aspect = -1;
+               if (m_decoder)
+                       aspect = m_decoder->getVideoAspect();
+               if (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))
@@ -1198,22 +1497,28 @@ int eDVBServicePlay::getInfo(int w)
                                }
                        }
                }
-               return -1;
-       case sIsCrypted: return program.isCrypted();
-       case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
-       case sVideoType: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
-       case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
-       case sPCRPID: return program.pcrPid;
-       case sPMTPID: return program.pmtPid;
-       case sTXTPID: return program.textPid;
+               else
+                       return aspect;
+               break;
+       }
+       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;
        case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
        case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
        case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
        case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
        case sProvider: if (!m_dvb_service) return -1; return -2;
+       case sServiceref: return resIsString;
+       case sDVBState: return m_tune_state;
        default:
-               return -1;
+               break;
        }
+       return -1;
 }
 
 std::string eDVBServicePlay::getInfoString(int w)
@@ -1223,6 +1528,8 @@ std::string eDVBServicePlay::getInfoString(int w)
        case sProvider:
                if (!m_dvb_service) return "";
                return m_dvb_service->m_provider_name;
+       case sServiceref:
+               return m_reference.toString();
        default:
                break;
        }
@@ -1235,6 +1542,8 @@ PyObject *eDVBServicePlay::getInfoObject(int w)
        {
        case sCAIDs:
                return m_service_handler.getCaIds();
+       case sTransponderData:
+               return eStaticServiceDVBInformation().getInfoObject(m_reference, w);
        default:
                break;
        }
@@ -1250,6 +1559,23 @@ int eDVBServicePlay::getNumberOfTracks()
        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);
@@ -1271,12 +1597,16 @@ RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int
        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";
+       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
@@ -1306,30 +1636,68 @@ int eDVBServicePlay::selectAudioStream(int i)
 
        if (h.getProgramInfo(program))
                return -1;
-       
-       if ((unsigned int)i >= program.audioStreams.size())
+
+       if ((i != -1) && ((unsigned int)i >= program.audioStreams.size()))
                return -2;
-       
+
        if (!m_decoder)
                return -3;
-       
-       if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
-               return -4;
 
-       if (m_radiotext_parser)
-               m_radiotext_parser->start(program.audioStreams[i].pid);
+       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;
+       }
+
+       m_current_audio_pid = apid;
 
-       if (m_dvb_service && !m_is_pvr)
+       if (m_decoder->setAudioPID(apid, apidtype))
        {
-               if (program.audioStreams[i].type == eDVBAudio::aMPEG)
+               eDebug("set audio pid failed");
+               return -4;
+       }
+
+               /* 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 (!m_rds_decoder)
                {
-                       m_dvb_service->setCacheEntry(eDVBService::cAPID, program.audioStreams[i].pid);
+                       ePtr<iDVBDemux> data_demux;
+                       if (!h.getDataDemux(data_demux))
+                       {
+                               m_rds_decoder = new eDVBRdsDecoder(data_demux);
+                               m_rds_decoder->connectEvent(slot(*this, &eDVBServicePlay::rdsDecoderEvent), m_rds_decoder_event_connection);
+                       }
+               }
+
+               /* if we decided that we need one, update the pid */
+       if (m_rds_decoder)
+               m_rds_decoder->start(apid);
+
+                       /* 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 && !m_is_pvr && ((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);
                }
                else
                {
                        m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
-                       m_dvb_service->setCacheEntry(eDVBService::cAC3PID, program.audioStreams[i].pid);
+                       m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
                }
        }
 
@@ -1354,20 +1722,81 @@ RESULT eDVBServicePlay::selectChannel(int i)
        return 0;
 }
 
-std::string eDVBServicePlay::getRadioText(int x)
+std::string eDVBServicePlay::getText(int x)
 {
-       if (m_radiotext_parser)
+       if (m_rds_decoder)
                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 "";
 }
 
-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)
 {
-       m_event((iPlayableService*)this, evUpdatedRadioText);
+       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()
+{
+       if (m_rds_decoder)
+               return m_rds_decoder->getRassPictureMask();
+       Py_RETURN_NONE;
 }
 
 int eDVBServiceBase::getFrontendInfo(int w)
@@ -1381,48 +1810,75 @@ int eDVBServiceBase::getFrontendInfo(int 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)
        {
-               ret = Py_None;
-               Py_INCREF(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)
+       {
+               eUsePtr<iDVBChannel> channel;
+               if(!m_service_handler.getChannel(channel))
+               {
+                       ePtr<iDVBFrontend> fe;
+                       if(!channel->getFrontend(fe))
+                       {
+                               fe->getFrontendData(ret);
+                               fe->getFrontendStatus(ret);
+                       }
+               }
        }
        return ret;
 }
@@ -1464,12 +1920,23 @@ RESULT eDVBServicePlay::startTimeshift()
        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_file = templ;
-       
+       m_timeshift_file = std::string(templ);
+
        eDebug("recording to %s", templ);
-       
+
+       delete [] templ;
+
        if (m_timeshift_fd < 0)
        {
                m_record = 0;
@@ -1500,7 +1967,7 @@ RESULT eDVBServicePlay::stopTimeshift()
        
        close(m_timeshift_fd);
        eDebug("remove timeshift file");
-       remove(m_timeshift_file.c_str());
+       eBackgroundFileEraser::getInstance()->erase(m_timeshift_file.c_str());
        
        return 0;
 }
@@ -1531,8 +1998,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);
-               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);
        }
@@ -1551,7 +2018,7 @@ void eDVBServicePlay::setCutList(ePyObject list)
        
        for (i=0; i<size; ++i)
        {
-               ePyObject tuple = PyList_GetItem(list, i);
+               ePyObject tuple = PyList_GET_ITEM(list, i);
                if (!PyTuple_Check(tuple))
                {
                        eDebug("non-tuple in cutlist");
@@ -1562,7 +2029,7 @@ void eDVBServicePlay::setCutList(ePyObject list)
                        eDebug("cutlist entries need to be a 2-tuple");
                        continue;
                }
-               ePyObject ppts = PyTuple_GetItem(tuple, 0), ptype = PyTuple_GetItem(tuple, 1);
+               ePyObject ppts = PyTuple_GET_ITEM(tuple, 0), ptype = PyTuple_GET_ITEM(tuple, 1);
                if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
                {
                        eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
@@ -1615,6 +2082,11 @@ void eDVBServicePlay::updateTimeshiftPids()
                        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(), 
@@ -1644,11 +2116,12 @@ void eDVBServicePlay::switchToLive()
        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_radiotext_updated_connection = 0;
+       m_rds_decoder_event_connection = 0;
+       m_video_event_connection = 0;
 
                /* free the timeshift service handler, we need the resources */
        m_service_handler_timeshift.free();
@@ -1667,36 +2140,34 @@ void eDVBServicePlay::switchToTimeshift()
        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_radiotext_updated_connection = 0;
+       m_rds_decoder_event_connection = 0;
+       m_video_event_connection = 0;
 
        m_timeshift_active = 1;
 
-       m_event((iPlayableService*)this, evSeekableStatusChanged);
-
        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 */
+
+       eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
+       pause();
+       updateDecoder(); /* mainly to switch off PCR, and to set pause */
+       
+       m_event((iPlayableService*)this, evSeekableStatusChanged);
 }
 
 void eDVBServicePlay::updateDecoder()
 {
-       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;
 
        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.");
@@ -1729,14 +2200,6 @@ void eDVBServicePlay::updateDecoder()
                                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);
@@ -1753,13 +2216,22 @@ void eDVBServicePlay::updateDecoder()
        {
                h.getDecodeDemux(m_decode_demux);
                if (m_decode_demux)
+               {
                        m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
+                       if (m_decoder)
+                               m_decoder->connectVideoEvent(slot(*this, &eDVBServicePlay::video_event), m_video_event_connection);
+                       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);
+               } else
+               {
+                       m_teletext_parser = 0;
+                       m_subtitle_parser = 0;
+               }
+
                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);
        }
 
        if (m_decoder)
@@ -1795,25 +2267,24 @@ void eDVBServicePlay::updateDecoder()
                                }
                        }
                }
-               m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
-               m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
+
+               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(ac3_delay == -1 ? config_delay_int : ac3_delay + config_delay_int);
+
+               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(pcm_delay == -1 ? config_delay_int : pcm_delay + config_delay_int);
 
                m_decoder->setVideoPID(vpid, vpidtype);
-               m_decoder->setAudioPID(apid, apidtype);
+               selectAudioStream();
+
                if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
-               {
                        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);
 
@@ -1824,7 +2295,10 @@ void eDVBServicePlay::updateDecoder()
                if (!m_is_primary)
                        m_decoder->setTrickmode(1);
 
-               m_decoder->start();
+               if (m_is_paused)
+                       m_decoder->preroll();
+               else
+                       m_decoder->start();
 
                if (vpid > 0 && vpid < 0x2000)
                        ;
@@ -1837,29 +2311,16 @@ void eDVBServicePlay::updateDecoder()
 
                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 */
                if (m_dvb_service && !m_is_pvr)
                {
-                       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_have_video_pid = (vpid > 0 && vpid < 0x2000);
 }
 
@@ -1973,7 +2434,16 @@ 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)
                        m_cue->addSourceSpan(in, out);
                
                in = length;
@@ -2125,17 +2595,13 @@ PyObject *eDVBServicePlay::getCachedSubtitle()
                        }
                }
        }
-       Py_INCREF(Py_None);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 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;
@@ -2216,6 +2682,10 @@ void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
 {
        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();
        }
@@ -2223,7 +2693,7 @@ void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
 
 void eDVBServicePlay::checkSubtitleTiming()
 {
-//     eDebug("checkSubtitleTiming");
+       eDebug("checkSubtitleTiming");
        if (!m_subtitle_widget)
                return;
        while (1)
@@ -2252,37 +2722,37 @@ void eDVBServicePlay::checkSubtitleTiming()
                if (m_decoder)
                        m_decoder->getPTS(0, pos);
 
-//             eDebug("%lld %lld", pos, show_time);
+               eDebug("%lld %lld", pos, show_time);
                int diff =  show_time - pos;
                if (diff < 0)
                {
                        eDebug("[late (%d ms)]", -diff / 90);
                        diff = 0;
                }
-               if (diff > 900000)
-               {
-                       eDebug("[invalid]");
-                       diff = 0;
-               }
+//             if (diff > 900000)
+//             {
+//                     eDebug("[invalid]");
+//                     diff = 0;
+//             }
        
-               if (!diff)
+               if ((diff/90)<20)
                {
                        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
                        {
-                               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
                {
-//                     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;
                }
        }
@@ -2292,6 +2762,10 @@ void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
 {
        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();
        }
@@ -2333,6 +2807,62 @@ void eDVBServicePlay::setPCMDelay(int delay)
                m_decoder->setPCMDelay(delay);
 }
 
+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)
 
+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");