more changes for service groups (replacement for zapping alternatives
[enigma2.git] / lib / service / servicedvb.cpp
index 616c7007e5ceeb9a6707d4520e152917c0ddedf5..0a7a6715499501d1cfff01d3f8fa68624f5bb70c 100644 (file)
@@ -3,6 +3,7 @@
 #include <string>
 #include <lib/service/servicedvb.h>
 #include <lib/service/service.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/gui/esubtitle.h>
 
 #include <sys/vfs.h>
+#include <sys/stat.h>
 
 #include <byteswap.h>
 #include <netinet/in.h>
 
-#define INTERNAL_TELETEXT
-
 #ifndef BYTE_ORDER
 #error no byte order defined!
 #endif
@@ -39,6 +39,7 @@ class eStaticServiceDVBInformation: public iStaticServiceInformation
 public:
        RESULT getName(const eServiceReference &ref, std::string &name);
        int getLength(const eServiceReference &ref);
+       int isPlayable(const eServiceReference &ref, const eServiceReference &ignore);
 };
 
 DEFINE_REF(eStaticServiceDVBInformation);
@@ -90,13 +91,20 @@ 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("isPlayble... 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;
+}
 
 DEFINE_REF(eStaticServiceDVBBouquetInformation);
 
@@ -133,11 +141,64 @@ RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref
                return -1;
 }
 
+int eStaticServiceDVBBouquetInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore)
+{
+       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 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)
+               {
+                       ((const eServiceReferenceDVB&)*it).getChannelID(chid);
+                       int tmp=res->canAllocateChannel(chid, chid_ignore);
+                       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 +209,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);
 };
@@ -210,6 +271,8 @@ std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReferen
                return m_parser.m_description;
        case iServiceInformation::sServiceref:
                return m_parser.m_ref.toString();
+       case iServiceInformation::sTags:
+               return m_parser.m_tags;
        default:
                return "";
        }
@@ -312,6 +375,9 @@ eServiceFactoryDVB::eServiceFactoryDVB()
        eServiceCenter::getPrivInstance(sc);
        if (sc)
                sc->addServiceFactory(eServiceFactoryDVB::id, this);
+
+       m_StaticServiceDVBInfo = new eStaticServiceDVBInformation;
+       m_StaticServiceDVBBouquetInfo = new eStaticServiceDVBBouquetInformation;
 }
 
 eServiceFactoryDVB::~eServiceFactoryDVB()
@@ -377,7 +443,7 @@ RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sort
        
        if (!m_query)
                return -1;
-       
+
        while (!m_query->getNextResult(ref))
                list.push_back(ref);
 
@@ -392,6 +458,7 @@ RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sort
 //   useable format options are
 //   R = Service Reference (as swig object .. this is very slow)
 //   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)
 //   when exactly one return value per service is selected in the format string,
 //   then each value is directly a list entry
@@ -400,7 +467,7 @@ RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sort
 //   unknown format string chars are returned as python None values !
 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
 {
-       PyObject *ret=0;
+       ePyObject ret;
        std::list<eServiceReference> tmplist;
        int retcount=1;
 
@@ -422,14 +489,17 @@ PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
                for (int cnt=0; cnt < services; ++cnt)
                {
                        eServiceReference &ref=*it++;
-                       PyObject *tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
+                       ePyObject tuple = retcount > 1 ? PyTuple_New(retcount) : ePyObject();
                        for (int i=0; i < retcount; ++i)
                        {
-                               PyObject *tmp=0;
+                               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());
                                        break;
                                case 'S':  // service reference string
                                        tmp = PyString_FromString(ref.toString().c_str());
@@ -469,7 +539,7 @@ PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
                                PyList_SET_ITEM(ret, cnt, tuple);
                }
        }
-       return ret ? ret : PyList_New(0);
+       return ret ? (PyObject*)ret : (PyObject*)PyList_New(0);
 }
 
 RESULT eDVBServiceList::getNext(eServiceReference &ref)
@@ -480,14 +550,9 @@ RESULT eDVBServiceList::getNext(eServiceReference &ref)
        return m_query->getNextResult((eServiceReferenceDVB&)ref);
 }
 
-int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
-{
-       return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
-}
-
 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;
@@ -506,11 +571,11 @@ RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
        return -1;
 }
 
-RESULT eDVBServiceList::addService(eServiceReference &ref)
+RESULT eDVBServiceList::addService(eServiceReference &ref, eServiceReference before)
 {
        if (!m_bouquet)
                return -1;
-       return m_bouquet->addService(ref);
+       return m_bouquet->addService(ref, before);
 }
 
 RESULT eDVBServiceList::removeService(eServiceReference &ref)
@@ -581,12 +646,12 @@ 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 = new eStaticServiceDVBInformation;
+                       ptr = m_StaticServiceDVBInfo;
                else // a dvb bouquet
-                       ptr = new eStaticServiceDVBBouquetInformation;
+                       ptr = m_StaticServiceDVBBouquetInfo;
        }
        else if (!ref.path.empty()) /* do we have a PVR service? */
                ptr = new eStaticServiceDVBPVRInformation(ref);
@@ -594,7 +659,7 @@ RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServic
        {
                ePtr<eDVBService> service;
                if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
-                       ptr = new eStaticServiceDVBInformation;
+                       ptr = m_StaticServiceDVBInfo;
                else
                        /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
                        ptr = service;
@@ -794,13 +859,41 @@ RESULT eDVBServicePlay::start()
 
 RESULT eDVBServicePlay::stop()
 {
+               /* add bookmark for last play position */
+       if (m_is_pvr)
+       {
+               pts_t play_position;
+               if (!getPlayPosition(play_position))
+               {
+                               /* remove last position */
+                       for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end();)
+                       {
+                               if (i->what == 3) /* current play position */
+                               {
+                                       m_cue_entries.erase(i);
+                                       i = m_cue_entries.begin();
+                                       continue;
+                               } else
+                                       ++i;
+                       }
+                       
+                       m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
+                       m_cuesheet_changed = 1;
+               }
+       }
+
        stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
 
        m_service_handler_timeshift.free();
        m_service_handler.free();
        
        if (m_is_pvr && m_cuesheet_changed)
-               saveCuesheet();
+       {
+               struct stat s;
+                               /* save cuesheet only when main file is accessible. */
+               if (!::stat(m_reference.path.c_str(), &s))
+                       saveCuesheet();
+       }
        
        return 0;
 }
@@ -1083,6 +1176,12 @@ RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
        return 0;
 }
 
+RESULT eDVBServicePlay::radioText(ePtr<iRadioText> &ptr)
+{
+       ptr = this;
+       return 0;
+}
+
 RESULT eDVBServicePlay::getName(std::string &name)
 {
        if (m_is_pvr)
@@ -1115,7 +1214,9 @@ int eDVBServicePlay::getInfo(int w)
        if (w == sCAIDs)
                return resIsPyObject;
 
-       if (m_service_handler.getProgramInfo(program))
+       eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+       
+       if (h.getProgramInfo(program))
                return -1;
        
        switch (w)
@@ -1162,7 +1263,7 @@ int eDVBServicePlay::getInfo(int w)
        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[m_current_audio_stream].pid;
+       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;
@@ -1171,6 +1272,7 @@ int eDVBServicePlay::getInfo(int w)
        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;
        default:
                return -1;
        }
@@ -1183,6 +1285,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;
        }
@@ -1204,7 +1308,8 @@ PyObject *eDVBServicePlay::getInfoObject(int w)
 int eDVBServicePlay::getNumberOfTracks()
 {
        eDVBServicePMTHandler::program program;
-       if (m_service_handler.getProgramInfo(program))
+       eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+       if (h.getProgramInfo(program))
                return 0;
        return program.audioStreams.size();
 }
@@ -1222,8 +1327,9 @@ RESULT eDVBServicePlay::selectTrack(unsigned int i)
 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
 {
        eDVBServicePMTHandler::program program;
+       eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
 
-       if (m_service_handler.getProgramInfo(program))
+       if (h.getProgramInfo(program))
                return -1;
        
        if (i >= program.audioStreams.size())
@@ -1260,8 +1366,9 @@ RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int
 int eDVBServicePlay::selectAudioStream(int i)
 {
        eDVBServicePMTHandler::program program;
+       eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
 
-       if (m_service_handler.getProgramInfo(program))
+       if (h.getProgramInfo(program))
                return -1;
        
        if ((unsigned int)i >= program.audioStreams.size())
@@ -1273,20 +1380,24 @@ int eDVBServicePlay::selectAudioStream(int i)
        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);
+
        if (m_dvb_service && !m_is_pvr)
        {
                if (program.audioStreams[i].type == eDVBAudio::aMPEG)
                {
                        m_dvb_service->setCacheEntry(eDVBService::cAPID, program.audioStreams[i].pid);
                        m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
-               }       else
+               }
+               else
                {
                        m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
                        m_dvb_service->setCacheEntry(eDVBService::cAC3PID, program.audioStreams[i].pid);
                }
        }
 
-       m_current_audio_stream = i;
+       h.resetCachedProgram();
 
        return 0;
 }
@@ -1307,6 +1418,22 @@ RESULT eDVBServicePlay::selectChannel(int i)
        return 0;
 }
 
+std::string eDVBServicePlay::getRadioText(int x)
+{
+       if (m_radiotext_parser)
+               switch(x)
+               {
+                       case 0:
+                               return convertLatin1UTF8(m_radiotext_parser->getCurrentText());
+               }
+       return "";
+}
+
+void eDVBServicePlay::radioTextUpdated()
+{
+       m_event((iPlayableService*)this, evUpdatedRadioText);
+}
+
 int eDVBServiceBase::getFrontendInfo(int w)
 {
        eUsePtr<iDVBChannel> channel;
@@ -1320,7 +1447,7 @@ int eDVBServiceBase::getFrontendInfo(int w)
 
 PyObject *eDVBServiceBase::getFrontendData(bool original)
 {
-       PyObject *ret=0;
+       ePyObject ret;
 
        eUsePtr<iDVBChannel> channel;
        if(!m_service_handler.getChannel(channel))
@@ -1338,8 +1465,8 @@ PyObject *eDVBServiceBase::getFrontendData(bool original)
                                        eDVBFrontendParametersSatellite osat;
                                        if (!feparm->getDVBS(osat))
                                        {
-                                               void PutToDict(PyObject *, const char*, long);
-                                               void PutToDict(PyObject *, const char*, const char*);
+                                               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)
@@ -1463,11 +1590,11 @@ RESULT eDVBServicePlay::activateTimeshift()
 
 PyObject *eDVBServicePlay::getCutList()
 {
-       PyObject *list = PyList_New(0);
+       ePyObject list = PyList_New(0);
        
        for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
        {
-               PyObject *tuple = PyTuple_New(2);
+               ePyObject tuple = PyTuple_New(2);
                PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
                PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
                PyList_Append(list, tuple);
@@ -1477,7 +1604,7 @@ PyObject *eDVBServicePlay::getCutList()
        return list;
 }
 
-void eDVBServicePlay::setCutList(PyObject *list)
+void eDVBServicePlay::setCutList(ePyObject list)
 {
        if (!PyList_Check(list))
                return;
@@ -1488,7 +1615,7 @@ void eDVBServicePlay::setCutList(PyObject *list)
        
        for (i=0; i<size; ++i)
        {
-               PyObject *tuple = PyList_GetItem(list, i);
+               ePyObject tuple = PyList_GET_ITEM(list, i);
                if (!PyTuple_Check(tuple))
                {
                        eDebug("non-tuple in cutlist");
@@ -1499,7 +1626,7 @@ void eDVBServicePlay::setCutList(PyObject *list)
                        eDebug("cutlist entries need to be a 2-tuple");
                        continue;
                }
-               PyObject *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));
@@ -1528,7 +1655,9 @@ void eDVBServicePlay::updateTimeshiftPids()
                return;
        
        eDVBServicePMTHandler::program program;
-       if (m_service_handler.getProgramInfo(program))
+       eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+
+       if (h.getProgramInfo(program))
                return;
        else
        {
@@ -1579,14 +1708,18 @@ void eDVBServicePlay::switchToLive()
        m_decoder = 0;
        m_decode_demux = 0;
        m_teletext_parser = 0;
+       m_radiotext_parser = 0;
+       m_subtitle_parser = 0;
+       m_new_dvb_subtitle_page_connection = 0;
        m_new_subtitle_page_connection = 0;
-       
+       m_radiotext_updated_connection = 0;
+
                /* free the timeshift service handler, we need the resources */
        m_service_handler_timeshift.free();
        m_timeshift_active = 0;
-       
+
        m_event((iPlayableService*)this, evSeekableStatusChanged);
-       
+
        updateDecoder();
 }
 
@@ -1594,19 +1727,23 @@ void eDVBServicePlay::switchToTimeshift()
 {
        if (m_timeshift_active)
                return;
-       
+
        m_decode_demux = 0;
        m_decoder = 0;
        m_teletext_parser = 0;
+       m_radiotext_parser = 0;
+       m_subtitle_parser = 0;
        m_new_subtitle_page_connection = 0;
-       
+       m_new_dvb_subtitle_page_connection = 0;
+       m_radiotext_updated_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 */
@@ -1622,7 +1759,7 @@ void eDVBServicePlay::updateDecoder()
        std::string default_ac3;
 
        if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
-               defaultac3 = default_ac3 == "enable";
+               defaultac3 = default_ac3 == "True";
 
        eDVBServicePMTHandler::program program;
        if (h.getProgramInfo(program))
@@ -1634,7 +1771,7 @@ void eDVBServicePlay::updateDecoder()
                {
                        eDebugNoNewLine(" (");
                        for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
-                               i(program.videoStreams.begin()); 
+                               i(program.videoStreams.begin());
                                i != program.videoStreams.end(); ++i)
                        {
                                if (vpid == -1)
@@ -1653,7 +1790,7 @@ void eDVBServicePlay::updateDecoder()
                {
                        eDebugNoNewLine(" (");
                        for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
-                               i(program.audioStreams.begin()); 
+                               i(program.audioStreams.begin());
                                i != program.audioStreams.end(); ++i)
                        {
                                if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
@@ -1683,10 +1820,10 @@ void eDVBServicePlay::updateDecoder()
                        m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
                if (m_cue)
                        m_cue->setDecodingDemux(m_decode_demux, m_decoder);
-#ifdef INTERNAL_TELETEXT
                m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
                m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
-#endif
+               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)
@@ -1726,17 +1863,27 @@ void eDVBServicePlay::updateDecoder()
                m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
 
                m_decoder->setVideoPID(vpid, vpidtype);
-               m_current_audio_stream = 0;
                m_decoder->setAudioPID(apid, apidtype);
                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);
 
                m_decoder->setTextPID(tpid);
 
-               if (m_teletext_parser)
-                       m_teletext_parser->start(tpid);
+               m_teletext_parser->start(program.textPid);
 
                if (!m_is_primary)
                        m_decoder->setTrickmode(1);
@@ -1806,7 +1953,7 @@ void eDVBServicePlay::loadCuesheet()
 #endif
                        what = ntohl(what);
                        
-                       if (what > 2)
+                       if (what > 3)
                                break;
                        
                        m_cue_entries.insert(cueEntry(where, what));
@@ -1862,7 +2009,7 @@ void eDVBServicePlay::cutlistToCuesheet()
        if (!m_cutlist_enabled)
        {
                m_cue->commitSpans();
-               eDebug("cutlists where disabled");
+               eDebug("cutlists were disabled");
                return;
        }
 
@@ -1883,7 +2030,7 @@ void eDVBServicePlay::cutlistToCuesheet()
                                continue;
                        } else if (i->what == 1) /* out */
                                out = i++->where;
-                       else /* mark */
+                       else /* mark (2) or last play position (3) */
                        {
                                i++;
                                continue;
@@ -1901,34 +2048,151 @@ void eDVBServicePlay::cutlistToCuesheet()
        m_cue->commitSpans();
 }
 
-RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *entry)
+RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, ePyObject tuple)
 {
        if (m_subtitle_widget)
                disableSubtitles(parent);
-       
-       if (!m_teletext_parser)
-               return -1;
-       
+
+       ePyObject entry;
+       int tuplesize = PyTuple_Size(tuple);
+       int type = 0;
+
+       if (!PyTuple_Check(tuple))
+               goto error_out;
+
+       if (tuplesize < 1)
+               goto error_out;
+
+       entry = PyTuple_GET_ITEM(tuple, 0);
+
        if (!PyInt_Check(entry))
-               return -1;
-       
-       m_subtitle_widget = new eSubtitleWidget(parent);
-       m_subtitle_widget->resize(parent->size()); /* full size */
-       
-       int page = PyInt_AsLong(entry);
-       
-       m_teletext_parser->setPage(page);
+               goto error_out;
+
+       type = PyInt_AsLong(entry);
+
+       if (type == 1)  // teletext subtitles
+       {
+               int page, magazine, pid;
+               if (tuplesize < 4)
+                       goto error_out;
+
+               if (!m_teletext_parser)
+               {
+                       eDebug("enable teletext subtitles.. no parser !!!");
+                       return -1;
+               }
+
+               entry = PyTuple_GET_ITEM(tuple, 1);
+               if (!PyInt_Check(entry))
+                       goto error_out;
+               pid = PyInt_AsLong(entry);
 
+               entry = PyTuple_GET_ITEM(tuple, 2);
+               if (!PyInt_Check(entry))
+                       goto error_out;
+               page = PyInt_AsLong(entry);
+
+               entry = PyTuple_GET_ITEM(tuple, 3);
+               if (!PyInt_Check(entry))
+                       goto error_out;
+               magazine = PyInt_AsLong(entry);
+
+               m_subtitle_widget = new eSubtitleWidget(parent);
+               m_subtitle_widget->resize(parent->size()); /* full size */
+               m_teletext_parser->setPageAndMagazine(page, magazine);
+               if (m_dvb_service)
+                       m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE,((pid&0xFFFF)<<16)|((page&0xFF)<<8)|(magazine&0xFF));
+       }
+       else if (type == 0)
+       {
+               int pid = 0, composition_page_id = 0, ancillary_page_id = 0;
+               if (!m_subtitle_parser)
+               {
+                       eDebug("enable dvb subtitles.. no parser !!!");
+                       return -1;
+               }
+               if (tuplesize < 4)
+                       goto error_out;
+
+               entry = PyTuple_GET_ITEM(tuple, 1);
+               if (!PyInt_Check(entry))
+                       goto error_out;
+               pid = PyInt_AsLong(entry);
+
+               entry = PyTuple_GET_ITEM(tuple, 2);
+               if (!PyInt_Check(entry))
+                       goto error_out;
+               composition_page_id = PyInt_AsLong(entry);
+
+               entry = PyTuple_GET_ITEM(tuple, 3);
+               if (!PyInt_Check(entry))
+                       goto error_out;
+               ancillary_page_id = PyInt_AsLong(entry);
+
+               m_subtitle_widget = new eSubtitleWidget(parent);
+               m_subtitle_widget->resize(parent->size()); /* full size */
+               m_subtitle_parser->start(pid, composition_page_id, ancillary_page_id);
+               if (m_dvb_service)
+                       m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, ((pid&0xFFFF)<<16)|((composition_page_id&0xFF)<<8)|(ancillary_page_id&0xFF));
+       }
+       else
+               goto error_out;
        return 0;
+error_out:
+       eDebug("enableSubtitles needs a tuple as 2nd argument!\n"
+               "for teletext subtitles (0, pid, teletext_page, teletext_magazine)\n"
+               "for dvb subtitles (1, pid, composition_page_id, ancillary_page_id)");
+       return -1;
 }
 
 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
 {
        delete m_subtitle_widget;
        m_subtitle_widget = 0;
+       if (m_subtitle_parser)
+       {
+               m_subtitle_parser->stop();
+               m_dvb_subtitle_pages.clear();
+       }
+       if (m_teletext_parser)
+       {
+               m_teletext_parser->setPageAndMagazine(-1, -1);
+               m_subtitle_pages.clear();
+       }
+       if (m_dvb_service)
+               m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, -1);
        return 0;
 }
 
+PyObject *eDVBServicePlay::getCachedSubtitle()
+{
+       if (m_dvb_service)
+       {
+               int tmp = m_dvb_service->getCacheEntry(eDVBService::cSUBTITLE);
+               if (tmp != -1)
+               {
+                       unsigned int data = (unsigned int)tmp;
+                       int pid = (data&0xFFFF0000)>>16;
+                       ePyObject tuple = PyTuple_New(4);
+                       eDVBServicePMTHandler::program program;
+                       eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+                       if (!h.getProgramInfo(program))
+                       {
+                               if (program.textPid==pid) // teletext
+                                       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, 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;
+}
+
 PyObject *eDVBServicePlay::getSubtitleList()
 {
        if (!m_teletext_parser)
@@ -1937,18 +2201,78 @@ PyObject *eDVBServicePlay::getSubtitleList()
                return Py_None;
        }
        
-       PyObject *l = PyList_New(0);
-       
-       for (std::set<int>::iterator i(m_teletext_parser->m_found_subtitle_pages.begin()); i != m_teletext_parser->m_found_subtitle_pages.end(); ++i)
+       ePyObject l = PyList_New(0);
+       std::set<int> added_ttx_pages;
+
+       std::set<eDVBServicePMTHandler::subtitleStream> &subs =
+               m_teletext_parser->m_found_subtitle_pages;
+
+       eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+       eDVBServicePMTHandler::program program;
+       if (h.getProgramInfo(program))
+               eDebug("getting program info failed.");
+       else
        {
-               PyObject *tuple = PyTuple_New(2);
-               char desc[20];
-               sprintf(desc, "Page %x", *i);
-               PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
-               PyTuple_SetItem(tuple, 1, PyInt_FromLong(*i));
-               PyList_Append(l, tuple);
+               for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
+                       it != program.subtitleStreams.end(); ++it)
+               {
+                       switch(it->subtitling_type)
+                       {
+                               case 0x01: // ebu teletext subtitles
+                               {
+                                       int page_number = it->teletext_page_number & 0xFF;
+                                       int magazine_number = it->teletext_magazine_number & 7;
+                                       int hash = magazine_number << 8 | page_number;
+                                       if (added_ttx_pages.find(hash) == added_ttx_pages.end())
+                                       {
+                                               ePyObject tuple = PyTuple_New(5);
+                                               PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
+                                               PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
+                                               PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
+                                               PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
+                                               PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
+                                               PyList_Append(l, tuple);
+                                               Py_DECREF(tuple);
+                                               added_ttx_pages.insert(hash);
+                                       }
+                                       break;
+                               }
+                               case 0x10 ... 0x13:
+                               case 0x20 ... 0x23: // dvb subtitles
+                               {
+                                       ePyObject tuple = PyTuple_New(5);
+                                       PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0));
+                                       PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
+                                       PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->composition_page_id));
+                                       PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->ancillary_page_id));
+                                       PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
+                                       PyList_Insert(l, 0, tuple);
+                                       Py_DECREF(tuple);
+                                       break;
+                               }
+                       }
+               }
        }
-       
+
+       for (std::set<eDVBServicePMTHandler::subtitleStream>::iterator it(subs.begin());
+               it != subs.end(); ++it)
+       {
+               int page_number = it->teletext_page_number & 0xFF;
+               int magazine_number = it->teletext_magazine_number & 7;
+               int hash = magazine_number << 8 | page_number;
+               if (added_ttx_pages.find(hash) == added_ttx_pages.end())
+               {
+                       ePyObject tuple = PyTuple_New(5);
+                       PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
+                       PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
+                       PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
+                       PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
+                       PyTuple_SET_ITEM(tuple, 4, PyString_FromString("und"));  // undetermined
+                       PyList_Append(l, tuple);
+                       Py_DECREF(tuple);
+               }
+       }
+
        return l;
 }
 
@@ -1957,26 +2281,43 @@ void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
        if (m_subtitle_widget)
        {
                m_subtitle_pages.push_back(page);
-               
                checkSubtitleTiming();
        }
 }
 
 void eDVBServicePlay::checkSubtitleTiming()
 {
+//     eDebug("checkSubtitleTiming");
+       if (!m_subtitle_widget)
+               return;
        while (1)
        {
-               if (m_subtitle_pages.empty())
+               enum { TELETEXT, DVB } type;
+               eDVBTeletextSubtitlePage page;
+               eDVBSubtitlePage dvb_page;
+               pts_t show_time;
+               if (!m_subtitle_pages.empty())
+               {
+                       page = m_subtitle_pages.front();
+                       type = TELETEXT;
+                       show_time = page.m_pts;
+               }
+               else if (!m_dvb_subtitle_pages.empty())
+               {
+                       dvb_page = m_dvb_subtitle_pages.front();
+                       type = DVB;
+                       show_time = dvb_page.m_show_time;
+               }
+               else
                        return;
        
-               eDVBTeletextSubtitlePage p = m_subtitle_pages.front();
-       
                pts_t pos = 0;
        
                if (m_decoder)
                        m_decoder->getPTS(0, pos);
-       
-               int diff = p.m_pts - pos;
+
+//             eDebug("%lld %lld", pos, show_time);
+               int diff =  show_time - pos;
                if (diff < 0)
                {
                        eDebug("[late (%d ms)]", -diff / 90);
@@ -1990,16 +2331,36 @@ void eDVBServicePlay::checkSubtitleTiming()
        
                if (!diff)
                {
-                       m_subtitle_widget->setPage(p);
-                       m_subtitle_pages.pop_front();
+                       if (type == TELETEXT)
+                       {
+                               eDebug("display teletext subtitle page");
+                               m_subtitle_widget->setPage(page);
+                               m_subtitle_pages.pop_front();
+                       }
+                       else
+                       {
+                               eDebug("display dvb subtitle Page");
+                               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);
                        break;
                }
        }
 }
 
+void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
+{
+       if (m_subtitle_widget)
+       {
+               m_dvb_subtitle_pages.push_back(p);
+               checkSubtitleTiming();
+       }
+}
+
 int eDVBServicePlay::getAC3Delay()
 {
        if (m_dvb_service)