introduce option that allows limiting recording filename character set to legacy...
[vuplus_dvbapp] / lib / service / servicedvb.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/base/object.h>
3 #include <string>
4 #include <lib/service/servicedvb.h>
5 #include <lib/service/service.h>
6 #include <lib/base/estring.h>
7 #include <lib/base/init_num.h>
8 #include <lib/base/init.h>
9 #include <lib/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/decoder.h>
12
13 #include <lib/components/file_eraser.h>
14 #include <lib/service/servicedvbrecord.h>
15 #include <lib/service/event.h>
16 #include <lib/dvb/metaparser.h>
17 #include <lib/dvb/tstools.h>
18 #include <lib/python/python.h>
19 #include <lib/base/nconfig.h> // access to python config
20
21                 /* for subtitles */
22 #include <lib/gui/esubtitle.h>
23
24 #include <sys/vfs.h>
25 #include <sys/stat.h>
26
27 #include <byteswap.h>
28 #include <netinet/in.h>
29
30 #ifndef BYTE_ORDER
31 #error no byte order defined!
32 #endif
33
34 class eStaticServiceDVBInformation: public iStaticServiceInformation
35 {
36         DECLARE_REF(eStaticServiceDVBInformation);
37 public:
38         RESULT getName(const eServiceReference &ref, std::string &name);
39         int getLength(const eServiceReference &ref);
40         int isPlayable(const eServiceReference &ref, const eServiceReference &ignore);
41         PyObject *getInfoObject(const eServiceReference &ref, int);
42 };
43
44 DEFINE_REF(eStaticServiceDVBInformation);
45
46 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
47 {
48         eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
49         if ( !ref.name.empty() )
50         {
51                 if (service.getParentTransportStreamID().get()) // linkage subservice
52                 {
53                         ePtr<iServiceHandler> service_center;
54                         if (!eServiceCenter::getInstance(service_center))
55                         {
56                                 eServiceReferenceDVB parent = service;
57                                 parent.setTransportStreamID( service.getParentTransportStreamID() );
58                                 parent.setServiceID( service.getParentServiceID() );
59                                 parent.setParentTransportStreamID(eTransportStreamID(0));
60                                 parent.setParentServiceID(eServiceID(0));
61                                 parent.name="";
62                                 ePtr<iStaticServiceInformation> service_info;
63                                 if (!service_center->info(parent, service_info))
64                                 {
65                                         if (!service_info->getName(parent, name))
66                                                 name=buildShortName(name) + " - ";
67                                 }
68                         }
69                 }
70                 else
71                         name="";
72                 name += ref.name;
73                 return 0;
74         }
75         else
76                 return -1;
77 }
78
79 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
80 {
81         return -1;
82 }
83
84 int eStaticServiceDVBInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore)
85 {
86         ePtr<eDVBResourceManager> res_mgr;
87         if ( eDVBResourceManager::getInstance( res_mgr ) )
88                 eDebug("isPlayable... no res manager!!");
89         else
90         {
91                 eDVBChannelID chid, chid_ignore;
92                 ((const eServiceReferenceDVB&)ref).getChannelID(chid);
93                 ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
94                 return res_mgr->canAllocateChannel(chid, chid_ignore);
95         }
96         return false;
97 }
98
99 extern void PutToDict(ePyObject &dict, const char*key, long value);  // defined in dvb/frontend.cpp
100 extern void PutToDict(ePyObject &dict, const char*key, ePyObject item); // defined in dvb/frontend.cpp
101 extern void PutToDict(ePyObject &dict, const char*key, const char *value); // defined in dvb/frontend.cpp
102
103 void PutSatelliteDataToDict(ePyObject &dict, eDVBFrontendParametersSatellite &feparm)
104 {
105         PutToDict(dict, "tuner_type", "DVB-S");
106         PutToDict(dict, "frequency", feparm.frequency);
107         PutToDict(dict, "symbol_rate", feparm.symbol_rate);
108         PutToDict(dict, "orbital_position", feparm.orbital_position);
109         PutToDict(dict, "inversion", feparm.inversion);
110         PutToDict(dict, "fec_inner", feparm.fec);
111         PutToDict(dict, "modulation", feparm.modulation);
112         PutToDict(dict, "polarization", feparm.polarisation);
113         if (feparm.system == eDVBFrontendParametersSatellite::System_DVB_S2)
114         {
115                 PutToDict(dict, "rolloff", feparm.rolloff);
116                 PutToDict(dict, "pilot", feparm.pilot);
117         }
118         PutToDict(dict, "system", feparm.system);
119 }
120
121 void PutTerrestrialDataToDict(ePyObject &dict, eDVBFrontendParametersTerrestrial &feparm)
122 {
123         PutToDict(dict, "tuner_type", "DVB-T");
124         PutToDict(dict, "frequency", feparm.frequency);
125         PutToDict(dict, "bandwidth", feparm.bandwidth);
126         PutToDict(dict, "code_rate_lp", feparm.code_rate_LP);
127         PutToDict(dict, "code_rate_hp", feparm.code_rate_HP);
128         PutToDict(dict, "constellation", feparm.modulation);
129         PutToDict(dict, "transmission_mode", feparm.transmission_mode);
130         PutToDict(dict, "guard_interval", feparm.guard_interval);
131         PutToDict(dict, "hierarchy_information", feparm.hierarchy);
132         PutToDict(dict, "inversion", feparm.inversion);
133 }
134
135 void PutCableDataToDict(ePyObject &dict, eDVBFrontendParametersCable &feparm)
136 {
137         PutToDict(dict, "tuner_type", "DVB-C");
138         PutToDict(dict, "frequency", feparm.frequency);
139         PutToDict(dict, "symbol_rate", feparm.symbol_rate);
140         PutToDict(dict, "modulation", feparm.modulation);
141         PutToDict(dict, "inversion", feparm.inversion);
142         PutToDict(dict, "fec_inner", feparm.fec_inner);
143 }
144
145 PyObject *eStaticServiceDVBInformation::getInfoObject(const eServiceReference &r, int what)
146 {
147         if (r.type == eServiceReference::idDVB)
148         {
149                 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)r;
150                 switch(what)
151                 {
152                         case iServiceInformation::sTransponderData:
153                         {
154                                 ePtr<eDVBResourceManager> res;
155                                 if (!eDVBResourceManager::getInstance(res))
156                                 {
157                                         ePtr<iDVBChannelList> db;
158                                         if (!res->getChannelList(db))
159                                         {
160                                                 eDVBChannelID chid;
161                                                 ref.getChannelID(chid);
162                                                 ePtr<iDVBFrontendParameters> feparm;
163                                                 if (!db->getChannelFrontendData(chid, feparm))
164                                                 {
165                                                         int system;
166                                                         if (!feparm->getSystem(system))
167                                                         {
168                                                                 ePyObject dict = PyDict_New();
169                                                                 switch(system)
170                                                                 {
171                                                                         case iDVBFrontend::feSatellite:
172                                                                         {
173                                                                                 eDVBFrontendParametersSatellite s;
174                                                                                 feparm->getDVBS(s);
175                                                                                 PutSatelliteDataToDict(dict, s);
176                                                                                 break;
177                                                                         }
178                                                                         case iDVBFrontend::feTerrestrial:
179                                                                         {
180                                                                                 eDVBFrontendParametersTerrestrial t;
181                                                                                 feparm->getDVBT(t);
182                                                                                 PutTerrestrialDataToDict(dict, t);
183                                                                                 break;
184                                                                         }
185                                                                         case iDVBFrontend::feCable:
186                                                                         {
187                                                                                 eDVBFrontendParametersCable c;
188                                                                                 feparm->getDVBC(c);
189                                                                                 PutCableDataToDict(dict, c);
190                                                                                 break;
191                                                                         }
192                                                                         default:
193                                                                                 eDebug("unknown frontend type %d", system);
194                                                                                 Py_DECREF(dict);
195                                                                                 break;
196                                                                 }
197                                                                 return dict;
198                                                         }
199                                                 }
200                                         }
201                                 }
202                         }
203                 }
204         }
205         Py_RETURN_NONE;
206 }
207
208 DEFINE_REF(eStaticServiceDVBBouquetInformation);
209
210 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
211 {
212         ePtr<iDVBChannelList> db;
213         ePtr<eDVBResourceManager> res;
214
215         int err;
216         if ((err = eDVBResourceManager::getInstance(res)) != 0)
217         {
218                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
219                 return err;
220         }
221         if ((err = res->getChannelList(db)) != 0)
222         {
223                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
224                 return err;
225         }
226
227         eBouquet *bouquet=0;
228         if ((err = db->getBouquet(ref, bouquet)) != 0)
229         {
230                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
231                 return -1;
232         }
233
234         if ( bouquet && bouquet->m_bouquet_name.length() )
235         {
236                 name = bouquet->m_bouquet_name;
237                 return 0;
238         }
239         else
240                 return -1;
241 }
242
243 int eStaticServiceDVBBouquetInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore, bool simulate)
244 {
245         if (ref.flags & eServiceReference::isGroup)
246         {
247                 ePtr<iDVBChannelList> db;
248                 ePtr<eDVBResourceManager> res;
249
250                 if (eDVBResourceManager::getInstance(res))
251                 {
252                         eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. no resource manager!");
253                         return 0;
254                 }
255
256                 if (res->getChannelList(db))
257                 {
258                         eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. no channel list!");
259                         return 0;
260                 }
261
262                 eBouquet *bouquet=0;
263                 if (db->getBouquet(ref, bouquet))
264                 {
265                         eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. getBouquet failed!");
266                         return 0;
267                 }
268
269                 int prio_order = eDVBFrontend::getTypePriorityOrder();
270                 int cur=0;
271                 eDVBChannelID chid, chid_ignore;
272                 ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
273                 for (std::list<eServiceReference>::iterator it(bouquet->m_services.begin()); it != bouquet->m_services.end(); ++it)
274                 {
275                         static unsigned char prio_map[6][3] = {
276                                 { 3, 2, 1 }, // -S -C -T
277                                 { 3, 1, 2 }, // -S -T -C
278                                 { 2, 3, 1 }, // -C -S -T
279                                 { 1, 3, 2 }, // -C -T -S
280                                 { 1, 2, 3 }, // -T -C -S
281                                 { 2, 1, 3 }  // -T -S -C
282                         };
283                         ((const eServiceReferenceDVB&)*it).getChannelID(chid);
284                         int tmp=res->canAllocateChannel(chid, chid_ignore, simulate);
285                         switch(tmp)
286                         {
287                                 case 0:
288                                         break;
289                                 case 30000: // cached DVB-T channel
290                                 case 1: // DVB-T frontend
291                                         tmp = prio_map[prio_order][2];
292                                         break;
293                                 case 40000: // cached DVB-C channel
294                                 case 2:
295                                         tmp = prio_map[prio_order][1];
296                                         break;
297                                 default: // DVB-S
298                                         tmp = prio_map[prio_order][0];
299                                         break;
300                         }
301                         if (tmp > cur)
302                         {
303                                 m_playable_service = *it;
304                                 cur = tmp;
305                         }
306                 }
307                 if (cur)
308                         return cur;
309         }
310         m_playable_service = eServiceReference();
311         return 0;
312 }
313
314 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
315 {
316         return -1;
317 }
318
319 #include <lib/dvb/epgcache.h>
320
321 RESULT eStaticServiceDVBBouquetInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &ptr, time_t start_time)
322 {
323         return eEPGCache::getInstance()->lookupEventTime(ref, start_time, ptr);
324 }
325
326 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
327 {
328         DECLARE_REF(eStaticServiceDVBPVRInformation);
329         eServiceReference m_ref;
330         eDVBMetaParser m_parser;
331 public:
332         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
333         RESULT getName(const eServiceReference &ref, std::string &name);
334         int getLength(const eServiceReference &ref);
335         RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
336         int isPlayable(const eServiceReference &ref, const eServiceReference &ignore) { return 1; }
337         int getInfo(const eServiceReference &ref, int w);
338         std::string getInfoString(const eServiceReference &ref,int w);
339 };
340
341 DEFINE_REF(eStaticServiceDVBPVRInformation);
342
343 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
344 {
345         m_ref = ref;
346         m_parser.parseFile(ref.path);
347 }
348
349 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
350 {
351         ASSERT(ref == m_ref);
352         if (m_parser.m_name.size())
353                 name = m_parser.m_name;
354         else
355         {
356                 name = ref.path;
357                 size_t n = name.rfind('/');
358                 if (n != std::string::npos)
359                         name = name.substr(n + 1);
360         }
361         return 0;
362 }
363
364 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
365 {
366         ASSERT(ref == m_ref);
367         
368         eDVBTSTools tstools;
369         
370         struct stat s;
371         stat(ref.path.c_str(), &s);
372
373         if (tstools.openFile(ref.path.c_str(), 1))
374                 return 0;
375
376                         /* check if cached data is still valid */
377         if (m_parser.m_data_ok && (s.st_size == m_parser.m_filesize) && (m_parser.m_length))
378                 return m_parser.m_length / 90000;
379
380                         /* open again, this time with stream info */
381         if (tstools.openFile(ref.path.c_str()))
382                 return 0;
383
384                         /* otherwise, re-calc length and update meta file */
385         pts_t len;
386         if (tstools.calcLen(len))
387                 return 0;
388
389         m_parser.m_length = len;
390         m_parser.m_filesize = s.st_size;
391         m_parser.updateMeta(ref.path);
392         return m_parser.m_length / 90000;
393 }
394
395 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
396 {
397         switch (w)
398         {
399         case iServiceInformation::sDescription:
400                 return iServiceInformation::resIsString;
401         case iServiceInformation::sServiceref:
402                 return iServiceInformation::resIsString;
403         case iServiceInformation::sTimeCreate:
404                 if (m_parser.m_time_create)
405                         return m_parser.m_time_create;
406                 else
407                         return iServiceInformation::resNA;
408         default:
409                 return iServiceInformation::resNA;
410         }
411 }
412
413 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
414 {
415         switch (w)
416         {
417         case iServiceInformation::sDescription:
418                 return m_parser.m_description;
419         case iServiceInformation::sServiceref:
420                 return m_parser.m_ref.toString();
421         case iServiceInformation::sTags:
422                 return m_parser.m_tags;
423         default:
424                 return "";
425         }
426 }
427
428 RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
429 {
430         if (!ref.path.empty())
431         {
432                 ePtr<eServiceEvent> event = new eServiceEvent;
433                 std::string filename = ref.path;
434                 filename.erase(filename.length()-2, 2);
435                 filename+="eit";
436                 if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
437                 {
438                         evt = event;
439                         return 0;
440                 }
441         }
442         evt = 0;
443         return -1;
444 }
445
446 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
447 {
448         DECLARE_REF(eDVBPVRServiceOfflineOperations);
449         eServiceReferenceDVB m_ref;
450 public:
451         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
452         
453         RESULT deleteFromDisk(int simulate);
454         RESULT getListOfFilenames(std::list<std::string> &);
455 };
456
457 DEFINE_REF(eDVBPVRServiceOfflineOperations);
458
459 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
460 {
461 }
462
463 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
464 {
465         if (simulate)
466                 return 0;
467         else
468         {
469                 std::list<std::string> res;
470                 if (getListOfFilenames(res))
471                         return -1;
472                 
473                 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
474                 if (!eraser)
475                         eDebug("FATAL !! can't get background file eraser");
476                 
477                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
478                 {
479                         eDebug("Removing %s...", i->c_str());
480                         if (eraser)
481                                 eraser->erase(i->c_str());
482                         else
483                                 ::unlink(i->c_str());
484                 }
485                 
486                 return 0;
487         }
488 }
489
490 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
491 {
492         res.clear();
493         res.push_back(m_ref.path);
494
495 // handling for old splitted recordings (enigma 1)
496         char buf[255];
497         int slice=1;
498         while(true)
499         {
500                 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
501                 struct stat s;
502                 if (stat(buf, &s) < 0)
503                         break;
504                 res.push_back(buf);
505         }       
506
507         res.push_back(m_ref.path + ".meta");
508         res.push_back(m_ref.path + ".ap");
509         res.push_back(m_ref.path + ".sc");
510         res.push_back(m_ref.path + ".cuts");
511         std::string tmp = m_ref.path;
512         tmp.erase(m_ref.path.length()-3);
513         res.push_back(tmp + ".eit");
514         return 0;
515 }
516
517 DEFINE_REF(eServiceFactoryDVB)
518
519 eServiceFactoryDVB::eServiceFactoryDVB()
520 {
521         ePtr<eServiceCenter> sc;
522         
523         eServiceCenter::getPrivInstance(sc);
524         if (sc)
525         {
526                 std::list<std::string> extensions;
527                 extensions.push_back("ts");
528                 extensions.push_back("trp");
529                 sc->addServiceFactory(eServiceFactoryDVB::id, this, extensions);
530         }
531
532         m_StaticServiceDVBInfo = new eStaticServiceDVBInformation;
533         m_StaticServiceDVBBouquetInfo = new eStaticServiceDVBBouquetInformation;
534 }
535
536 eServiceFactoryDVB::~eServiceFactoryDVB()
537 {
538         ePtr<eServiceCenter> sc;
539         
540         eServiceCenter::getPrivInstance(sc);
541         if (sc)
542                 sc->removeServiceFactory(eServiceFactoryDVB::id);
543 }
544
545 DEFINE_REF(eDVBServiceList);
546
547 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
548 {
549 }
550
551 eDVBServiceList::~eDVBServiceList()
552 {
553 }
554
555 RESULT eDVBServiceList::startQuery()
556 {
557         ePtr<iDVBChannelList> db;
558         ePtr<eDVBResourceManager> res;
559         
560         int err;
561         if ((err = eDVBResourceManager::getInstance(res)) != 0)
562         {
563                 eDebug("no resource manager");
564                 return err;
565         }
566         if ((err = res->getChannelList(db)) != 0)
567         {
568                 eDebug("no channel list");
569                 return err;
570         }
571         
572         ePtr<eDVBChannelQuery> q;
573         
574         if (!m_parent.path.empty())
575         {
576                 eDVBChannelQuery::compile(q, m_parent.path);
577                 if (!q)
578                 {
579                         eDebug("compile query failed");
580                         return err;
581                 }
582         }
583         
584         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
585         {
586                 eDebug("startQuery failed");
587                 return err;
588         }
589
590         return 0;
591 }
592
593 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
594 {
595         eServiceReferenceDVB ref;
596         
597         if (!m_query)
598                 return -1;
599
600         while (!m_query->getNextResult(ref))
601                 list.push_back(ref);
602
603         if (sorted)
604                 list.sort(iListableServiceCompare(this));
605
606         return 0;
607 }
608
609 //   The first argument of this function is a format string to specify the order and
610 //   the content of the returned list
611 //   useable format options are
612 //   R = Service Reference (as swig object .. this is very slow)
613 //   S = Service Reference (as python string object .. same as ref.toString())
614 //   C = Service Reference (as python string object .. same as ref.toCompareString())
615 //   N = Service Name (as python string object)
616 //   n = Short Service Name (short name brakets used) (as python string object)
617 //   when exactly one return value per service is selected in the format string,
618 //   then each value is directly a list entry
619 //   when more than one value is returned per service, then the list is a list of
620 //   python tuples
621 //   unknown format string chars are returned as python None values !
622 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
623 {
624         ePyObject ret;
625         std::list<eServiceReference> tmplist;
626         int retcount=1;
627
628         if (!format || !(retcount=strlen(format)))
629                 format = "R"; // just return service reference swig object ...
630
631         if (!getContent(tmplist, sorted))
632         {
633                 int services=tmplist.size();
634                 ePtr<iStaticServiceInformation> sptr;
635                 eServiceCenterPtr service_center;
636
637                 if (strchr(format, 'N') || strchr(format, 'n'))
638                         eServiceCenter::getPrivInstance(service_center);
639
640                 ret = PyList_New(services);
641                 std::list<eServiceReference>::iterator it(tmplist.begin());
642
643                 for (int cnt=0; cnt < services; ++cnt)
644                 {
645                         eServiceReference &ref=*it++;
646                         ePyObject tuple = retcount > 1 ? PyTuple_New(retcount) : ePyObject();
647                         for (int i=0; i < retcount; ++i)
648                         {
649                                 ePyObject tmp;
650                                 switch(format[i])
651                                 {
652                                 case 'R':  // service reference (swig)object
653                                         tmp = NEW_eServiceReference(ref);
654                                         break;
655                                 case 'C':  // service reference compare string
656                                         tmp = PyString_FromString(ref.toCompareString().c_str());
657                                         break;
658                                 case 'S':  // service reference string
659                                         tmp = PyString_FromString(ref.toString().c_str());
660                                         break;
661                                 case 'N':  // service name
662                                         if (service_center)
663                                         {
664                                                 service_center->info(ref, sptr);
665                                                 if (sptr)
666                                                 {
667                                                         std::string name;
668                                                         sptr->getName(ref, name);
669
670                                                         // filter short name brakets
671                                                         size_t pos;
672                                                         while((pos = name.find("\xc2\x86")) != std::string::npos)
673                                                                 name.erase(pos,2);
674                                                         while((pos = name.find("\xc2\x87")) != std::string::npos)
675                                                                 name.erase(pos,2);
676
677                                                         if (name.length())
678                                                                 tmp = PyString_FromString(name.c_str());
679                                                 }
680                                         }
681                                         if (!tmp)
682                                                 tmp = PyString_FromString("<n/a>");
683                                         break;
684                                 case 'n':  // short service name
685                                         if (service_center)
686                                         {
687                                                 service_center->info(ref, sptr);
688                                                 if (sptr)
689                                                 {
690                                                         std::string name;
691                                                         sptr->getName(ref, name);
692                                                         name = buildShortName(name);
693                                                         if (name.length())
694                                                                 tmp = PyString_FromString(name.c_str());
695                                                 }
696                                         }
697                                         if (!tmp)
698                                                 tmp = PyString_FromString("<n/a>");
699                                         break;
700                                 default:
701                                         if (tuple)
702                                         {
703                                                 tmp = Py_None;
704                                                 Py_INCREF(Py_None);
705                                         }
706                                         break;
707                                 }
708                                 if (tmp)
709                                 {
710                                         if (tuple)
711                                                 PyTuple_SET_ITEM(tuple, i, tmp);
712                                         else
713                                                 PyList_SET_ITEM(ret, cnt, tmp);
714                                 }
715                         }
716                         if (tuple)
717                                 PyList_SET_ITEM(ret, cnt, tuple);
718                 }
719         }
720         return ret ? (PyObject*)ret : (PyObject*)PyList_New(0);
721 }
722
723 RESULT eDVBServiceList::getNext(eServiceReference &ref)
724 {
725         if (!m_query)
726                 return -1;
727         
728         return m_query->getNextResult((eServiceReferenceDVB&)ref);
729 }
730
731 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
732 {
733         if (m_parent.flags & eServiceReference::canDescent) // bouquet
734         {
735                 ePtr<iDVBChannelList> db;
736                 ePtr<eDVBResourceManager> resm;
737
738                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
739                         return -1;
740
741                 if (db->getBouquet(m_parent, m_bouquet) != 0)
742                         return -1;
743
744                 res = this;
745                 
746                 return 0;
747         }
748         res = 0;
749         return -1;
750 }
751
752 RESULT eDVBServiceList::addService(eServiceReference &ref, eServiceReference before)
753 {
754         if (!m_bouquet)
755                 return -1;
756         return m_bouquet->addService(ref, before);
757 }
758
759 RESULT eDVBServiceList::removeService(eServiceReference &ref)
760 {
761         if (!m_bouquet)
762                 return -1;
763         return m_bouquet->removeService(ref);
764 }
765
766 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
767 {
768         if (!m_bouquet)
769                 return -1;
770         return m_bouquet->moveService(ref, pos);
771 }
772
773 RESULT eDVBServiceList::flushChanges()
774 {
775         if (!m_bouquet)
776                 return -1;
777         return m_bouquet->flushChanges();
778 }
779
780 RESULT eDVBServiceList::setListName(const std::string &name)
781 {
782         if (!m_bouquet)
783                 return -1;
784         return m_bouquet->setListName(name);
785 }
786
787 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
788 {
789         ePtr<eDVBService> service;
790         int r = lookupService(service, ref);
791         if (r)
792                 service = 0;
793                 // check resources...
794         ptr = new eDVBServicePlay(ref, service);
795         return 0;
796 }
797
798 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
799 {
800         if (ref.path.empty())
801         {
802                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
803                 return 0;
804         } else
805         {
806                 ptr = 0;
807                 return -1;
808         }
809 }
810
811 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
812 {
813         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
814         if (list->startQuery())
815         {
816                 ptr = 0;
817                 return -1;
818         }
819         
820         ptr = list;
821         return 0;
822 }
823
824 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
825 {
826         /* is a listable service? */
827         if (ref.flags & eServiceReference::canDescent) // bouquet
828         {
829                 if ( !ref.name.empty() )  // satellites or providers list
830                         ptr = m_StaticServiceDVBInfo;
831                 else // a dvb bouquet
832                         ptr = m_StaticServiceDVBBouquetInfo;
833         }
834         else if (!ref.path.empty()) /* do we have a PVR service? */
835                 ptr = new eStaticServiceDVBPVRInformation(ref);
836         else // normal dvb service
837         {
838                 ePtr<eDVBService> service;
839                 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
840                         ptr = m_StaticServiceDVBInfo;
841                 else
842                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
843                         ptr = service;
844         }
845         return 0;
846 }
847
848 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
849 {
850         if (ref.path.empty())
851         {
852                 ptr = 0;
853                 return -1;
854         } else
855         {
856                 ptr = new eDVBPVRServiceOfflineOperations(ref);
857                 return 0;
858         }
859 }
860
861 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
862 {
863                         // TODO: handle the listing itself
864         // if (ref.... == -1) .. return "... bouquets ...";
865         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
866                         // TODO: cache
867         ePtr<iDVBChannelList> db;
868         ePtr<eDVBResourceManager> res;
869         
870         int err;
871         if ((err = eDVBResourceManager::getInstance(res)) != 0)
872         {
873                 eDebug("no resource manager");
874                 return err;
875         }
876         if ((err = res->getChannelList(db)) != 0)
877         {
878                 eDebug("no channel list");
879                 return err;
880         }
881         
882                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
883         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
884         {
885                 eDebug("getService failed!");
886                 return err;
887         }
888
889         return 0;
890 }
891
892 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
893         m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
894 {
895         m_is_primary = 1;
896         m_is_pvr = !m_reference.path.empty();
897         
898         m_timeshift_enabled = m_timeshift_active = 0;
899         m_skipmode = 0;
900         
901         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
902         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
903         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
904
905         m_cuesheet_changed = 0;
906         m_cutlist_enabled = 1;
907         
908         m_subtitle_widget = 0;
909         
910         m_tune_state = -1;
911
912         m_subtitle_sync_timer = eTimer::create(eApp);
913
914         CONNECT(m_subtitle_sync_timer->timeout, eDVBServicePlay::checkSubtitleTiming);
915 }
916
917 eDVBServicePlay::~eDVBServicePlay()
918 {
919         delete m_subtitle_widget;
920 }
921
922 void eDVBServicePlay::gotNewEvent()
923 {
924 #if 0
925                 // debug only
926         ePtr<eServiceEvent> m_event_now, m_event_next;
927         getEvent(m_event_now, 0);
928         getEvent(m_event_next, 1);
929
930         if (m_event_now)
931                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
932         if (m_event_next)
933                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
934 #endif
935         m_event((iPlayableService*)this, evUpdatedEventInfo);
936 }
937
938 void eDVBServicePlay::serviceEvent(int event)
939 {
940         m_tune_state = event;
941
942         switch (event)
943         {
944         case eDVBServicePMTHandler::eventTuned:
945         {
946                 ePtr<iDVBDemux> m_demux;
947                 if (!m_service_handler.getDataDemux(m_demux))
948                 {
949                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
950                         int sid = ref.getParentServiceID().get();
951                         if (!sid)
952                                 sid = ref.getServiceID().get();
953                         if ( ref.getParentTransportStreamID().get() &&
954                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
955                                 m_event_handler.startOther(m_demux, sid);
956                         else
957                                 m_event_handler.start(m_demux, sid);
958                 }
959                 m_event((iPlayableService*)this, evTunedIn);
960                 break;
961         }
962         case eDVBServicePMTHandler::eventNoResources:
963         case eDVBServicePMTHandler::eventNoPAT:
964         case eDVBServicePMTHandler::eventNoPATEntry:
965         case eDVBServicePMTHandler::eventNoPMT:
966         case eDVBServicePMTHandler::eventTuneFailed:
967         case eDVBServicePMTHandler::eventMisconfiguration:
968         {
969                 eDebug("DVB service failed to tune - error %d", event);
970                 m_event((iPlayableService*)this, evTuneFailed);
971                 break;
972         }
973         case eDVBServicePMTHandler::eventNewProgramInfo:
974         {
975                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
976                 if (m_timeshift_enabled)
977                         updateTimeshiftPids();
978                 if (!m_timeshift_active)
979                         updateDecoder();
980                 if (m_first_program_info && m_is_pvr)
981                 {
982                         m_first_program_info = 0;
983                         seekTo(0);
984                 }
985                 m_event((iPlayableService*)this, evUpdatedInfo);
986                 break;
987         }
988         case eDVBServicePMTHandler::eventEOF:
989                 m_event((iPlayableService*)this, evEOF);
990                 break;
991         case eDVBServicePMTHandler::eventSOF:
992                 m_event((iPlayableService*)this, evSOF);
993                 break;
994         }
995 }
996
997 void eDVBServicePlay::serviceEventTimeshift(int event)
998 {
999         switch (event)
1000         {
1001         case eDVBServicePMTHandler::eventNewProgramInfo:
1002                 if (m_timeshift_active)
1003                         updateDecoder();
1004                 break;
1005         case eDVBServicePMTHandler::eventSOF:
1006                 m_event((iPlayableService*)this, evSOF);
1007                 break;
1008         case eDVBServicePMTHandler::eventEOF:
1009                 if ((!m_is_paused) && (m_skipmode >= 0))
1010                 {
1011                         eDebug("timeshift EOF, so let's go live");
1012                         switchToLive();
1013                 }
1014                 break;
1015         }
1016 }
1017
1018 RESULT eDVBServicePlay::start()
1019 {
1020         int r;
1021                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
1022                    two (one for decoding, one for data source), as we must be prepared
1023                    to start recording from the data demux. */
1024         if (m_is_pvr)
1025                 m_cue = new eCueSheet();
1026         else
1027                 m_event(this, evStart);
1028
1029         m_first_program_info = 1;
1030         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
1031         r = m_service_handler.tune(service, m_is_pvr, m_cue);
1032
1033                 /* inject EIT if there is a stored one */
1034         if (m_is_pvr)
1035         {
1036                 std::string filename = service.path;
1037                 filename.erase(filename.length()-2, 2);
1038                 filename+="eit";
1039                 ePtr<eServiceEvent> event = new eServiceEvent;
1040                 if (!event->parseFrom(filename, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get()))
1041                 {
1042                         ePtr<eServiceEvent> empty;
1043                         m_event_handler.inject(event, 0);
1044                         m_event_handler.inject(empty, 1);
1045                 }
1046         }
1047
1048         if (m_is_pvr)
1049         {
1050                 loadCuesheet();
1051                 m_event(this, evStart);
1052         }
1053         return 0;
1054 }
1055
1056 RESULT eDVBServicePlay::stop()
1057 {
1058                 /* add bookmark for last play position */
1059         if (m_is_pvr)
1060         {
1061                 pts_t play_position, length;
1062                 if (!getPlayPosition(play_position))
1063                 {
1064                                 /* remove last position */
1065                         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end();)
1066                         {
1067                                 if (i->what == 3) /* current play position */
1068                                 {
1069                                         m_cue_entries.erase(i);
1070                                         i = m_cue_entries.begin();
1071                                         continue;
1072                                 } else
1073                                         ++i;
1074                         }
1075                         
1076                         if (getLength(length))
1077                                 length = 0;
1078                         
1079                         if (length)
1080                         {
1081                                 int perc = play_position * 100LL / length;
1082                         
1083                                         /* only store last play position when between 1% and 99% */
1084                                 if ((1 < perc) && (perc < 99))
1085                                         m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
1086                         }
1087                         m_cuesheet_changed = 1;
1088                 }
1089         }
1090
1091         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
1092
1093         m_service_handler_timeshift.free();
1094         m_service_handler.free();
1095         
1096         if (m_is_pvr && m_cuesheet_changed)
1097         {
1098                 struct stat s;
1099                                 /* save cuesheet only when main file is accessible. */
1100                 if (!::stat(m_reference.path.c_str(), &s))
1101                         saveCuesheet();
1102         }
1103         m_event((iPlayableService*)this, evStopped);
1104         return 0;
1105 }
1106
1107 RESULT eDVBServicePlay::setTarget(int target)
1108 {
1109         m_is_primary = !target;
1110         return 0;
1111 }
1112
1113 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
1114 {
1115         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
1116         return 0;
1117 }
1118
1119 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
1120 {
1121                 /* note: we check for timeshift to be enabled,
1122                    not neccessary active. if you pause when timeshift
1123                    is not active, you should activate it when unpausing */
1124         if ((!m_is_pvr) && (!m_timeshift_enabled))
1125         {
1126                 ptr = 0;
1127                 return -1;
1128         }
1129
1130         ptr = this;
1131         return 0;
1132 }
1133
1134 RESULT eDVBServicePlay::setSlowMotion(int ratio)
1135 {
1136         ASSERT(ratio); /* The API changed: instead of calling setSlowMotion(0), call play! */
1137         eDebug("eDVBServicePlay::setSlowMotion(%d)", ratio);
1138         setFastForward_internal(0);
1139         if (m_decoder)
1140                 return m_decoder->setSlowMotion(ratio);
1141         else
1142                 return -1;
1143 }
1144
1145 RESULT eDVBServicePlay::setFastForward(int ratio)
1146 {
1147         eDebug("eDVBServicePlay::setFastForward(%d)", ratio);
1148         ASSERT(ratio);
1149         return setFastForward_internal(ratio);
1150 }
1151
1152 RESULT eDVBServicePlay::setFastForward_internal(int ratio)
1153 {
1154         int skipmode, ffratio;
1155         
1156         if (ratio > 8)
1157         {
1158                 skipmode = ratio;
1159                 ffratio = 1;
1160         } else if (ratio > 0)
1161         {
1162                 skipmode = 0;
1163                 ffratio = ratio;
1164         } else if (!ratio)
1165         {
1166                 skipmode = 0;
1167                 ffratio = 0;
1168         } else // if (ratio < 0)
1169         {
1170                 skipmode = ratio;
1171                 ffratio = 1;
1172         }
1173
1174         if (m_skipmode != skipmode)
1175         {
1176                 eDebug("setting cue skipmode to %d", skipmode);
1177                 if (m_cue)
1178                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
1179         }
1180         
1181         m_skipmode = skipmode;
1182         
1183         if (!m_decoder)
1184                 return -1;
1185                 
1186         if (ffratio == 0)
1187                 ; /* return m_decoder->play(); is done in caller*/
1188         else if (ffratio != 1)
1189                 return m_decoder->setFastForward(ffratio);
1190         else
1191                 return m_decoder->setTrickmode();
1192 }
1193
1194 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
1195 {
1196         if (m_is_pvr || m_timeshift_enabled)
1197         {
1198                 ptr = this;
1199                 return 0;
1200         }
1201         
1202         ptr = 0;
1203         return -1;
1204 }
1205
1206         /* TODO: when timeshift is enabled but not active, this doesn't work. */
1207 RESULT eDVBServicePlay::getLength(pts_t &len)
1208 {
1209         ePtr<iDVBPVRChannel> pvr_channel;
1210         
1211         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1212                 return -1;
1213         
1214         return pvr_channel->getLength(len);
1215 }
1216
1217 RESULT eDVBServicePlay::pause()
1218 {
1219         eDebug("eDVBServicePlay::pause");
1220         setFastForward_internal(0);
1221         if (m_decoder)
1222         {
1223                 m_is_paused = 1;
1224                 return m_decoder->pause();
1225         } else
1226                 return -1;
1227 }
1228
1229 RESULT eDVBServicePlay::unpause()
1230 {
1231         eDebug("eDVBServicePlay::unpause");
1232         setFastForward_internal(0);
1233         if (m_decoder)
1234         {
1235                 m_is_paused = 0;
1236                 return m_decoder->play();
1237         } else
1238                 return -1;
1239 }
1240
1241 RESULT eDVBServicePlay::seekTo(pts_t to)
1242 {
1243         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
1244         
1245         if (!m_decode_demux)
1246                 return -1;
1247
1248         ePtr<iDVBPVRChannel> pvr_channel;
1249         
1250         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1251                 return -1;
1252         
1253         if (!m_cue)
1254                 return -1;
1255         
1256         m_cue->seekTo(0, to);
1257         m_dvb_subtitle_pages.clear();
1258         m_subtitle_pages.clear();
1259
1260         return 0;
1261 }
1262
1263 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
1264 {
1265         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
1266         
1267         if (!m_decode_demux)
1268                 return -1;
1269
1270         ePtr<iDVBPVRChannel> pvr_channel;
1271         
1272         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1273                 return -1;
1274         
1275         int mode = 1;
1276         
1277                         /* HACK until we have skip-AP api */
1278         if ((to > 0) && (to < 100))
1279                 mode = 2;
1280         
1281         to *= direction;
1282         
1283         if (!m_cue)
1284                 return 0;
1285         
1286         m_cue->seekTo(mode, to);
1287         m_dvb_subtitle_pages.clear();
1288         m_subtitle_pages.clear();
1289         return 0;
1290 }
1291
1292 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
1293 {
1294         ePtr<iDVBPVRChannel> pvr_channel;
1295         
1296         if (!m_decode_demux)
1297                 return -1;
1298         
1299         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1300                 return -1;
1301         
1302         int r = 0;
1303
1304                 /* if there is a decoder, use audio or video PTS */
1305         if (m_decoder)
1306         {
1307                 r = m_decoder->getPTS(0, pos);
1308                 if (r)
1309                         return r;
1310         }
1311         
1312                 /* fixup */
1313         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
1314 }
1315
1316 RESULT eDVBServicePlay::setTrickmode(int trick)
1317 {
1318                 /* currently unimplemented */
1319         return -1;
1320 }
1321
1322 RESULT eDVBServicePlay::isCurrentlySeekable()
1323 {
1324         return m_is_pvr || m_timeshift_active;
1325 }
1326
1327 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
1328 {
1329         ptr = this;
1330         return 0;
1331 }
1332
1333 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
1334 {
1335         ptr = this;
1336         return 0;
1337 }
1338
1339 RESULT eDVBServicePlay::audioChannel(ePtr<iAudioChannelSelection> &ptr)
1340 {
1341         ptr = this;
1342         return 0;
1343 }
1344
1345 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1346 {
1347         ptr = this;
1348         return 0;
1349 }
1350
1351 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1352 {
1353         ptr = this;
1354         return 0;
1355 }
1356
1357 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1358 {
1359         ptr = 0;
1360         if (m_have_video_pid &&  // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
1361                 (m_timeshift_enabled || !m_is_pvr))
1362         {
1363                 if (!m_timeshift_enabled)
1364                 {
1365                         /* query config path */
1366                         std::string tspath;
1367                         if(ePythonConfigQuery::getConfigValue("config.usage.timeshift_path", tspath) == -1){
1368                                 eDebug("could not query ts path from config");
1369                                 return -4;
1370                         }
1371                         tspath.append("/");
1372                         /* we need enough diskspace */
1373                         struct statfs fs;
1374                         if (statfs(tspath.c_str(), &fs) < 0)
1375                         {
1376                                 eDebug("statfs failed!");
1377                                 return -2;
1378                         }
1379                 
1380                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1381                         {
1382                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1383                                 return -3;
1384                         }
1385                 }
1386                 ptr = this;
1387                 return 0;
1388         }
1389         return -1;
1390 }
1391
1392 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1393 {
1394         if (m_is_pvr)
1395         {
1396                 ptr = this;
1397                 return 0;
1398         }
1399         ptr = 0;
1400         return -1;
1401 }
1402
1403 RESULT eDVBServicePlay::subtitle(ePtr<iSubtitleOutput> &ptr)
1404 {
1405         ptr = this;
1406         return 0;
1407 }
1408
1409 RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
1410 {
1411         ptr = this;
1412         return 0;
1413 }
1414
1415 RESULT eDVBServicePlay::rdsDecoder(ePtr<iRdsDecoder> &ptr)
1416 {
1417         ptr = this;
1418         return 0;
1419 }
1420
1421 RESULT eDVBServicePlay::getName(std::string &name)
1422 {
1423         if (m_is_pvr)
1424         {
1425                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1426                 return i->getName(m_reference, name);
1427         }
1428         if (m_dvb_service)
1429         {
1430                 m_dvb_service->getName(m_reference, name);
1431                 if (name.empty())
1432                         name = "(...)";
1433         }
1434         else if (!m_reference.name.empty())
1435                 eStaticServiceDVBInformation().getName(m_reference, name);
1436         else
1437                 name = "DVB service";
1438         return 0;
1439 }
1440
1441 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1442 {
1443         return m_event_handler.getEvent(evt, nownext);
1444 }
1445
1446 int eDVBServicePlay::getInfo(int w)
1447 {
1448         eDVBServicePMTHandler::program program;
1449
1450         if (w == sCAIDs)
1451                 return resIsPyObject;
1452
1453         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1454
1455         int no_program_info = 0;
1456
1457         if (h.getProgramInfo(program))
1458                 no_program_info = 1;
1459
1460         switch (w)
1461         {
1462         case sVideoHeight:
1463                 if (m_decoder)
1464                         return m_decoder->getVideoHeight();
1465                 break;
1466         case sVideoWidth:
1467                 if (m_decoder)
1468                         return m_decoder->getVideoWidth();
1469                 break;
1470         case sFrameRate:
1471                 if (m_decoder)
1472                         return m_decoder->getVideoFrameRate();
1473                 break;
1474         case sProgressive:
1475                 if (m_decoder)
1476                         return m_decoder->getVideoProgressive();
1477                 break;
1478         case sAspect:
1479         {
1480                 int aspect = -1;
1481                 if (m_decoder)
1482                         aspect = m_decoder->getVideoAspect();
1483                 if (no_program_info)
1484                         break;
1485                 else if (aspect == -1 && !program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1486                 {
1487                         ePtr<eServiceEvent> evt;
1488                         if (!m_event_handler.getEvent(evt, 0))
1489                         {
1490                                 ePtr<eComponentData> data;
1491                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1492                                 {
1493                                         if ( data->getStreamContent() == 1 )
1494                                         {
1495                                                 switch(data->getComponentType())
1496                                                 {
1497                                                         // SD
1498                                                         case 1: // 4:3 SD PAL
1499                                                         case 2:
1500                                                         case 3: // 16:9 SD PAL
1501                                                         case 4: // > 16:9 PAL
1502                                                         case 5: // 4:3 SD NTSC
1503                                                         case 6: 
1504                                                         case 7: // 16:9 SD NTSC
1505                                                         case 8: // > 16:9 NTSC
1506
1507                                                         // HD
1508                                                         case 9: // 4:3 HD PAL
1509                                                         case 0xA:
1510                                                         case 0xB: // 16:9 HD PAL
1511                                                         case 0xC: // > 16:9 HD PAL
1512                                                         case 0xD: // 4:3 HD NTSC
1513                                                         case 0xE:
1514                                                         case 0xF: // 16:9 HD NTSC
1515                                                         case 0x10: // > 16:9 HD PAL
1516                                                                 return data->getComponentType();
1517                                                 }
1518                                         }
1519                                 }
1520                         }
1521                 }
1522                 else
1523                         return aspect;
1524                 break;
1525         }
1526         case sIsCrypted: if (no_program_info) return -1; return program.isCrypted();
1527         case sVideoPID: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1528         case sVideoType: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
1529         case sAudioPID: if (no_program_info) return -1; if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
1530         case sPCRPID: if (no_program_info) return -1; return program.pcrPid;
1531         case sPMTPID: if (no_program_info) return -1; return program.pmtPid;
1532         case sTXTPID: if (no_program_info) return -1; return program.textPid;
1533         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1534         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1535         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1536         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1537         case sProvider: if (!m_dvb_service) return -1; return -2;
1538         case sServiceref: return resIsString;
1539         case sDVBState: return m_tune_state;
1540         default:
1541                 break;
1542         }
1543         return -1;
1544 }
1545
1546 std::string eDVBServicePlay::getInfoString(int w)
1547 {
1548         switch (w)
1549         {
1550         case sProvider:
1551                 if (!m_dvb_service) return "";
1552                 return m_dvb_service->m_provider_name;
1553         case sServiceref:
1554                 return m_reference.toString();
1555         default:
1556                 break;
1557         }
1558         return iServiceInformation::getInfoString(w);
1559 }
1560
1561 PyObject *eDVBServicePlay::getInfoObject(int w)
1562 {
1563         switch (w)
1564         {
1565         case sCAIDs:
1566                 return m_service_handler.getCaIds();
1567         case sTransponderData:
1568                 return eStaticServiceDVBInformation().getInfoObject(m_reference, w);
1569         default:
1570                 break;
1571         }
1572         return iServiceInformation::getInfoObject(w);
1573 }
1574
1575 int eDVBServicePlay::getNumberOfTracks()
1576 {
1577         eDVBServicePMTHandler::program program;
1578         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1579         if (h.getProgramInfo(program))
1580                 return 0;
1581         return program.audioStreams.size();
1582 }
1583
1584 int eDVBServicePlay::getCurrentTrack()
1585 {
1586         eDVBServicePMTHandler::program program;
1587         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1588         if (h.getProgramInfo(program))
1589                 return 0;
1590
1591         int max = program.audioStreams.size();
1592         int i;
1593
1594         for (i = 0; i < max; ++i)
1595                 if (program.audioStreams[i].pid == m_current_audio_pid)
1596                         return i;
1597
1598         return 0;
1599 }
1600
1601 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1602 {
1603         int ret = selectAudioStream(i);
1604
1605         if (m_decoder->set())
1606                 return -5;
1607
1608         return ret;
1609 }
1610
1611 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1612 {
1613         eDVBServicePMTHandler::program program;
1614         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1615
1616         if (h.getProgramInfo(program))
1617                 return -1;
1618         
1619         if (i >= program.audioStreams.size())
1620                 return -2;
1621         
1622         info.m_pid = program.audioStreams[i].pid;
1623
1624         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1625                 info.m_description = "MPEG";
1626         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1627                 info.m_description = "AC3";
1628         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
1629                 info.m_description = "AAC";
1630         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAACHE)
1631                 info.m_description = "AAC-HE";
1632         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1633                 info.m_description = "DTS";
1634         else
1635                 info.m_description = "???";
1636
1637         if (program.audioStreams[i].component_tag != -1)
1638         {
1639                 ePtr<eServiceEvent> evt;
1640                 if (!m_event_handler.getEvent(evt, 0))
1641                 {
1642                         ePtr<eComponentData> data;
1643                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1644                                 info.m_language = data->getText();
1645                 }
1646         }
1647
1648         if (info.m_language.empty())
1649                 info.m_language = program.audioStreams[i].language_code;
1650         
1651         return 0;
1652 }
1653
1654 int eDVBServicePlay::selectAudioStream(int i)
1655 {
1656         eDVBServicePMTHandler::program program;
1657         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1658
1659         if (h.getProgramInfo(program))
1660                 return -1;
1661
1662         if ((i != -1) && ((unsigned int)i >= program.audioStreams.size()))
1663                 return -2;
1664
1665         if (!m_decoder)
1666                 return -3;
1667
1668         int stream = i;
1669         if (stream == -1)
1670                 stream = program.defaultAudioStream;
1671
1672         int apid = -1, apidtype = -1;
1673
1674         if (((unsigned int)stream) < program.audioStreams.size())
1675         {
1676                 apid = program.audioStreams[stream].pid;
1677                 apidtype = program.audioStreams[stream].type;
1678         }
1679
1680         m_current_audio_pid = apid;
1681
1682         if (m_decoder->setAudioPID(apid, apidtype))
1683         {
1684                 eDebug("set audio pid failed");
1685                 return -4;
1686         }
1687
1688                 /* 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 */
1689         if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1690                 if (!m_rds_decoder)
1691                 {
1692                         ePtr<iDVBDemux> data_demux;
1693                         if (!h.getDataDemux(data_demux))
1694                         {
1695                                 m_rds_decoder = new eDVBRdsDecoder(data_demux);
1696                                 m_rds_decoder->connectEvent(slot(*this, &eDVBServicePlay::rdsDecoderEvent), m_rds_decoder_event_connection);
1697                         }
1698                 }
1699
1700                 /* if we decided that we need one, update the pid */
1701         if (m_rds_decoder)
1702                 m_rds_decoder->start(apid);
1703
1704                         /* store new pid as default only when:
1705                                 a.) we have an entry in the service db for the current service,
1706                                 b.) we are not playing back something,
1707                                 c.) we are not selecting the default entry. (we wouldn't change 
1708                                     anything in the best case, or destroy the default setting in
1709                                     case the real default is not yet available.)
1710                         */
1711         if (m_dvb_service && !m_is_pvr && ((i != -1)
1712                 || ((m_dvb_service->getCacheEntry(eDVBService::cAPID) == -1) && (m_dvb_service->getCacheEntry(eDVBService::cAC3PID)==-1))))
1713         {
1714                 if (apidtype == eDVBAudio::aMPEG)
1715                 {
1716                         m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1717                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1718                 }
1719                 else if (apidtype == eDVBAudio::aAC3)
1720                 {
1721                         m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1722                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1723                 }
1724                 else
1725                 {
1726                         m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1727                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1728                 }
1729         }
1730
1731         h.resetCachedProgram();
1732
1733         return 0;
1734 }
1735
1736 int eDVBServicePlay::getCurrentChannel()
1737 {
1738         return m_decoder ? m_decoder->getAudioChannel() : STEREO;
1739 }
1740
1741 RESULT eDVBServicePlay::selectChannel(int i)
1742 {
1743         if (i < LEFT || i > RIGHT || i == STEREO)
1744                 i = -1;  // Stereo
1745         if (m_dvb_service)
1746                 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1747         if (m_decoder)
1748                 m_decoder->setAudioChannel(i);
1749         return 0;
1750 }
1751
1752 std::string eDVBServicePlay::getText(int x)
1753 {
1754         if (m_rds_decoder)
1755                 switch(x)
1756                 {
1757                         case RadioText:
1758                                 return convertLatin1UTF8(m_rds_decoder->getRadioText());
1759                         case RtpText:
1760                                 return convertLatin1UTF8(m_rds_decoder->getRtpText());
1761                 }
1762         return "";
1763 }
1764
1765 void eDVBServicePlay::rdsDecoderEvent(int what)
1766 {
1767         switch(what)
1768         {
1769                 case eDVBRdsDecoder::RadioTextChanged:
1770                         m_event((iPlayableService*)this, evUpdatedRadioText);
1771                         break;
1772                 case eDVBRdsDecoder::RtpTextChanged:
1773                         m_event((iPlayableService*)this, evUpdatedRtpText);
1774                         break;
1775                 case eDVBRdsDecoder::RassInteractivePicMaskChanged:
1776                         m_event((iPlayableService*)this, evUpdatedRassInteractivePicMask);
1777                         break;
1778                 case eDVBRdsDecoder::RecvRassSlidePic:
1779                         m_event((iPlayableService*)this, evUpdatedRassSlidePic);
1780                         break;
1781         }
1782 }
1783
1784 void eDVBServicePlay::showRassSlidePicture()
1785 {
1786         if (m_rds_decoder)
1787         {
1788                 if (m_decoder)
1789                 {
1790                         std::string rass_slide_pic = m_rds_decoder->getRassSlideshowPicture();
1791                         if (rass_slide_pic.length())
1792                                 m_decoder->showSinglePic(rass_slide_pic.c_str());
1793                         else
1794                                 eDebug("empty filename for rass slide picture received!!");
1795                 }
1796                 else
1797                         eDebug("no MPEG Decoder to show iframes avail");
1798         }
1799         else
1800                 eDebug("showRassSlidePicture called.. but not decoder");
1801 }
1802
1803 void eDVBServicePlay::showRassInteractivePic(int page, int subpage)
1804 {
1805         if (m_rds_decoder)
1806         {
1807                 if (m_decoder)
1808                 {
1809                         std::string rass_interactive_pic = m_rds_decoder->getRassPicture(page, subpage);
1810                         if (rass_interactive_pic.length())
1811                                 m_decoder->showSinglePic(rass_interactive_pic.c_str());
1812                         else
1813                                 eDebug("empty filename for rass interactive picture %d/%d received!!", page, subpage);
1814                 }
1815                 else
1816                         eDebug("no MPEG Decoder to show iframes avail");
1817         }
1818         else
1819                 eDebug("showRassInteractivePic called.. but not decoder");
1820 }
1821
1822 ePyObject eDVBServicePlay::getRassInteractiveMask()
1823 {
1824         if (m_rds_decoder)
1825                 return m_rds_decoder->getRassPictureMask();
1826         Py_RETURN_NONE;
1827 }
1828
1829 int eDVBServiceBase::getFrontendInfo(int w)
1830 {
1831         eUsePtr<iDVBChannel> channel;
1832         if(m_service_handler.getChannel(channel))
1833                 return 0;
1834         ePtr<iDVBFrontend> fe;
1835         if(channel->getFrontend(fe))
1836                 return 0;
1837         return fe->readFrontendData(w);
1838 }
1839
1840 PyObject *eDVBServiceBase::getFrontendData()
1841 {
1842         ePyObject ret = PyDict_New();
1843         if (ret)
1844         {
1845                 eUsePtr<iDVBChannel> channel;
1846                 if(!m_service_handler.getChannel(channel))
1847                 {
1848                         ePtr<iDVBFrontend> fe;
1849                         if(!channel->getFrontend(fe))
1850                                 fe->getFrontendData(ret);
1851                 }
1852         }
1853         else
1854                 Py_RETURN_NONE;
1855         return ret;
1856 }
1857
1858 PyObject *eDVBServiceBase::getFrontendStatus()
1859 {
1860         ePyObject ret = PyDict_New();
1861         if (ret)
1862         {
1863                 eUsePtr<iDVBChannel> channel;
1864                 if(!m_service_handler.getChannel(channel))
1865                 {
1866                         ePtr<iDVBFrontend> fe;
1867                         if(!channel->getFrontend(fe))
1868                                 fe->getFrontendStatus(ret);
1869                 }
1870         }
1871         else
1872                 Py_RETURN_NONE;
1873         return ret;
1874 }
1875
1876 PyObject *eDVBServiceBase::getTransponderData(bool original)
1877 {
1878         ePyObject ret = PyDict_New();
1879         if (ret)
1880         {
1881                 eUsePtr<iDVBChannel> channel;
1882                 if(!m_service_handler.getChannel(channel))
1883                 {
1884                         ePtr<iDVBFrontend> fe;
1885                         if(!channel->getFrontend(fe))
1886                                 fe->getTransponderData(ret, original);
1887                 }
1888         }
1889         else
1890                 Py_RETURN_NONE;
1891         return ret;
1892 }
1893
1894 PyObject *eDVBServiceBase::getAll(bool original)
1895 {
1896         ePyObject ret = getTransponderData(original);
1897         if (ret != Py_None)
1898         {
1899                 eUsePtr<iDVBChannel> channel;
1900                 if(!m_service_handler.getChannel(channel))
1901                 {
1902                         ePtr<iDVBFrontend> fe;
1903                         if(!channel->getFrontend(fe))
1904                         {
1905                                 fe->getFrontendData(ret);
1906                                 fe->getFrontendStatus(ret);
1907                         }
1908                 }
1909         }
1910         return ret;
1911 }
1912
1913 int eDVBServicePlay::getNumberOfSubservices()
1914 {
1915         ePtr<eServiceEvent> evt;
1916         if (!m_event_handler.getEvent(evt, 0))
1917                 return evt->getNumOfLinkageServices();
1918         return 0;
1919 }
1920
1921 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1922 {
1923         ePtr<eServiceEvent> evt;
1924         if (!m_event_handler.getEvent(evt, 0))
1925         {
1926                 if (!evt->getLinkageService(sub, m_reference, n))
1927                         return 0;
1928         }
1929         sub.type=eServiceReference::idInvalid;
1930         return -1;
1931 }
1932
1933 RESULT eDVBServicePlay::startTimeshift()
1934 {
1935         ePtr<iDVBDemux> demux;
1936         
1937         eDebug("Start timeshift!");
1938         
1939         if (m_timeshift_enabled)
1940                 return -1;
1941         
1942                 /* start recording with the data demux. */
1943         if (m_service_handler.getDataDemux(demux))
1944                 return -2;
1945
1946         demux->createTSRecorder(m_record);
1947         if (!m_record)
1948                 return -3;
1949
1950         std::string tspath;
1951         if(ePythonConfigQuery::getConfigValue("config.usage.timeshift_path", tspath) == -1){ 
1952                 eDebug("could not query ts path");
1953                 return -5;
1954         }
1955         tspath.append("/timeshift.XXXXXX");
1956         char* templ;
1957         templ = new char[tspath.length() + 1];
1958         strcpy(templ, tspath.c_str());
1959
1960         m_timeshift_fd = mkstemp(templ);
1961         m_timeshift_file = std::string(templ);
1962
1963         eDebug("recording to %s", templ);
1964
1965         delete [] templ;
1966
1967         if (m_timeshift_fd < 0)
1968         {
1969                 m_record = 0;
1970                 return -4;
1971         }
1972                 
1973         m_record->setTargetFD(m_timeshift_fd);
1974
1975         m_timeshift_enabled = 1;
1976         
1977         updateTimeshiftPids();
1978         m_record->start();
1979
1980         return 0;
1981 }
1982
1983 RESULT eDVBServicePlay::stopTimeshift()
1984 {
1985         if (!m_timeshift_enabled)
1986                 return -1;
1987         
1988         switchToLive();
1989         
1990         m_timeshift_enabled = 0;
1991         
1992         m_record->stop();
1993         m_record = 0;
1994         
1995         close(m_timeshift_fd);
1996         eDebug("remove timeshift file");
1997         eBackgroundFileEraser::getInstance()->erase(m_timeshift_file.c_str());
1998         
1999         return 0;
2000 }
2001
2002 int eDVBServicePlay::isTimeshiftActive()
2003 {
2004         return m_timeshift_enabled && m_timeshift_active;
2005 }
2006
2007 RESULT eDVBServicePlay::activateTimeshift()
2008 {
2009         if (!m_timeshift_enabled)
2010                 return -1;
2011         
2012         if (!m_timeshift_active)
2013         {
2014                 switchToTimeshift();
2015                 return 0;
2016         }
2017         
2018         return -2;
2019 }
2020
2021 PyObject *eDVBServicePlay::getCutList()
2022 {
2023         ePyObject list = PyList_New(0);
2024         
2025         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
2026         {
2027                 ePyObject tuple = PyTuple_New(2);
2028                 PyTuple_SET_ITEM(tuple, 0, PyLong_FromLongLong(i->where));
2029                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(i->what));
2030                 PyList_Append(list, tuple);
2031                 Py_DECREF(tuple);
2032         }
2033         
2034         return list;
2035 }
2036
2037 void eDVBServicePlay::setCutList(ePyObject list)
2038 {
2039         if (!PyList_Check(list))
2040                 return;
2041         int size = PyList_Size(list);
2042         int i;
2043         
2044         m_cue_entries.clear();
2045         
2046         for (i=0; i<size; ++i)
2047         {
2048                 ePyObject tuple = PyList_GET_ITEM(list, i);
2049                 if (!PyTuple_Check(tuple))
2050                 {
2051                         eDebug("non-tuple in cutlist");
2052                         continue;
2053                 }
2054                 if (PyTuple_Size(tuple) != 2)
2055                 {
2056                         eDebug("cutlist entries need to be a 2-tuple");
2057                         continue;
2058                 }
2059                 ePyObject ppts = PyTuple_GET_ITEM(tuple, 0), ptype = PyTuple_GET_ITEM(tuple, 1);
2060                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
2061                 {
2062                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
2063                         continue;
2064                 }
2065                 pts_t pts = PyLong_AsLongLong(ppts);
2066                 int type = PyInt_AsLong(ptype);
2067                 m_cue_entries.insert(cueEntry(pts, type));
2068                 eDebug("adding %08llx, %d", pts, type);
2069         }
2070         m_cuesheet_changed = 1;
2071         
2072         cutlistToCuesheet();
2073         m_event((iPlayableService*)this, evCuesheetChanged);
2074 }
2075
2076 void eDVBServicePlay::setCutListEnable(int enable)
2077 {
2078         m_cutlist_enabled = enable;
2079         cutlistToCuesheet();
2080 }
2081
2082 void eDVBServicePlay::updateTimeshiftPids()
2083 {
2084         if (!m_record)
2085                 return;
2086         
2087         eDVBServicePMTHandler::program program;
2088         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2089
2090         if (h.getProgramInfo(program))
2091                 return;
2092         else
2093         {
2094                 std::set<int> pids_to_record;
2095                 pids_to_record.insert(0); // PAT
2096                 if (program.pmtPid != -1)
2097                         pids_to_record.insert(program.pmtPid); // PMT
2098
2099                 if (program.textPid != -1)
2100                         pids_to_record.insert(program.textPid); // Videotext
2101
2102                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
2103                         i(program.videoStreams.begin()); 
2104                         i != program.videoStreams.end(); ++i)
2105                         pids_to_record.insert(i->pid);
2106
2107                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
2108                         i(program.audioStreams.begin()); 
2109                         i != program.audioStreams.end(); ++i)
2110                                 pids_to_record.insert(i->pid);
2111
2112                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::const_iterator
2113                         i(program.subtitleStreams.begin());
2114                         i != program.subtitleStreams.end(); ++i)
2115                                 pids_to_record.insert(i->pid);
2116
2117                 std::set<int> new_pids, obsolete_pids;
2118                 
2119                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
2120                                 m_pids_active.begin(), m_pids_active.end(),
2121                                 std::inserter(new_pids, new_pids.begin()));
2122                 
2123                 std::set_difference(
2124                                 m_pids_active.begin(), m_pids_active.end(),
2125                                 pids_to_record.begin(), pids_to_record.end(), 
2126                                 std::inserter(new_pids, new_pids.begin())
2127                                 );
2128
2129                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
2130                         m_record->addPID(*i);
2131
2132                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
2133                         m_record->removePID(*i);
2134         }
2135 }
2136
2137 void eDVBServicePlay::switchToLive()
2138 {
2139         if (!m_timeshift_active)
2140                 return;
2141         
2142         eDebug("SwitchToLive");
2143         
2144         m_cue = 0;
2145         m_decoder = 0;
2146         m_decode_demux = 0;
2147         m_teletext_parser = 0;
2148         m_rds_decoder = 0;
2149         m_subtitle_parser = 0;
2150         m_new_dvb_subtitle_page_connection = 0;
2151         m_new_subtitle_page_connection = 0;
2152         m_rds_decoder_event_connection = 0;
2153         m_video_event_connection = 0;
2154
2155                 /* free the timeshift service handler, we need the resources */
2156         m_service_handler_timeshift.free();
2157         m_timeshift_active = 0;
2158
2159         m_event((iPlayableService*)this, evSeekableStatusChanged);
2160
2161         updateDecoder();
2162 }
2163
2164 void eDVBServicePlay::switchToTimeshift()
2165 {
2166         if (m_timeshift_active)
2167                 return;
2168
2169         m_decode_demux = 0;
2170         m_decoder = 0;
2171         m_teletext_parser = 0;
2172         m_rds_decoder = 0;
2173         m_subtitle_parser = 0;
2174         m_new_subtitle_page_connection = 0;
2175         m_new_dvb_subtitle_page_connection = 0;
2176         m_rds_decoder_event_connection = 0;
2177         m_video_event_connection = 0;
2178
2179         m_timeshift_active = 1;
2180
2181         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
2182         r.path = m_timeshift_file;
2183
2184         m_cue = new eCueSheet();
2185         m_service_handler_timeshift.tune(r, 1, m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
2186
2187         eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
2188         pause();
2189         updateDecoder(); /* mainly to switch off PCR, and to set pause */
2190         
2191         m_event((iPlayableService*)this, evSeekableStatusChanged);
2192 }
2193
2194 void eDVBServicePlay::updateDecoder()
2195 {
2196         int vpid = -1, vpidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
2197
2198         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2199
2200         eDVBServicePMTHandler::program program;
2201         if (h.getProgramInfo(program))
2202                 eDebug("getting program info failed.");
2203         else
2204         {
2205                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
2206                 if (!program.videoStreams.empty())
2207                 {
2208                         eDebugNoNewLine(" (");
2209                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
2210                                 i(program.videoStreams.begin());
2211                                 i != program.videoStreams.end(); ++i)
2212                         {
2213                                 if (vpid == -1)
2214                                 {
2215                                         vpid = i->pid;
2216                                         vpidtype = i->type;
2217                                 }
2218                                 if (i != program.videoStreams.begin())
2219                                         eDebugNoNewLine(", ");
2220                                 eDebugNoNewLine("%04x", i->pid);
2221                         }
2222                         eDebugNoNewLine(")");
2223                 }
2224                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
2225                 if (!program.audioStreams.empty())
2226                 {
2227                         eDebugNoNewLine(" (");
2228                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
2229                                 i(program.audioStreams.begin());
2230                                 i != program.audioStreams.end(); ++i)
2231                         {
2232                                 if (i != program.audioStreams.begin())
2233                                         eDebugNoNewLine(", ");
2234                                 eDebugNoNewLine("%04x", i->pid);
2235                         }
2236                         eDebugNoNewLine(")");
2237                 }
2238                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
2239                 pcrpid = program.pcrPid;
2240                 eDebug(", and the text pid is %04x", program.textPid);
2241                 tpid = program.textPid;
2242         }
2243
2244         if (!m_decoder)
2245         {
2246                 h.getDecodeDemux(m_decode_demux);
2247                 if (m_decode_demux)
2248                 {
2249                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
2250                         if (m_decoder)
2251                                 m_decoder->connectVideoEvent(slot(*this, &eDVBServicePlay::video_event), m_video_event_connection);
2252                         m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
2253                         m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
2254                         m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
2255                         m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
2256                 } else
2257                 {
2258                         m_teletext_parser = 0;
2259                         m_subtitle_parser = 0;
2260                 }
2261
2262                 if (m_cue)
2263                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
2264         }
2265
2266         if (m_decoder)
2267         {
2268                 if (m_dvb_service)
2269                 {
2270                         achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
2271                         ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2272                         pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2273                 }
2274                 else // subservice or recording
2275                 {
2276                         eServiceReferenceDVB ref;
2277                         m_service_handler.getServiceReference(ref);
2278                         eServiceReferenceDVB parent = ref.getParentServiceReference();
2279                         if (!parent)
2280                                 parent = ref;
2281                         if (parent)
2282                         {
2283                                 ePtr<eDVBResourceManager> res_mgr;
2284                                 if (!eDVBResourceManager::getInstance(res_mgr))
2285                                 {
2286                                         ePtr<iDVBChannelList> db;
2287                                         if (!res_mgr->getChannelList(db))
2288                                         {
2289                                                 ePtr<eDVBService> origService;
2290                                                 if (!db->getService(parent, origService))
2291                                                 {
2292                                                         ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
2293                                                         pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
2294                                                 }
2295                                         }
2296                                 }
2297                         }
2298                 }
2299
2300                 std::string config_delay;
2301                 int config_delay_int = 0;
2302                 if(ePythonConfigQuery::getConfigValue("config.av.generalAC3delay", config_delay) == 0)
2303                         config_delay_int = atoi(config_delay.c_str());
2304                 m_decoder->setAC3Delay(ac3_delay == -1 ? config_delay_int : ac3_delay + config_delay_int);
2305
2306                 if(ePythonConfigQuery::getConfigValue("config.av.generalPCMdelay", config_delay) == 0)
2307                         config_delay_int = atoi(config_delay.c_str());
2308                 else
2309                         config_delay_int = 0;
2310                 m_decoder->setPCMDelay(pcm_delay == -1 ? config_delay_int : pcm_delay + config_delay_int);
2311
2312                 m_decoder->setVideoPID(vpid, vpidtype);
2313                 selectAudioStream();
2314
2315                 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
2316                         m_decoder->setSyncPCR(pcrpid);
2317                 else
2318                         m_decoder->setSyncPCR(-1);
2319
2320                 m_decoder->setTextPID(tpid);
2321
2322                 m_teletext_parser->start(program.textPid);
2323
2324                 if (vpid > 0 && vpid < 0x2000)
2325                         ;
2326                 else
2327                 {
2328                         std::string radio_pic;
2329                         if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
2330                                 m_decoder->setRadioPic(radio_pic);
2331                 }
2332
2333 /*              if (!m_is_primary)
2334                         m_decoder->setTrickmode();
2335                 else */ if (m_is_paused)
2336                         m_decoder->pause();
2337                 else
2338                         m_decoder->play();
2339
2340                 m_decoder->setAudioChannel(achannel);
2341
2342                 /* don't worry about non-existing services, nor pvr services */
2343                 if (m_dvb_service && !m_is_pvr)
2344                 {
2345                                 /* (audio pid will be set in selectAudioTrack */
2346                         m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
2347                         m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
2348                         m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
2349                         m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
2350                 }
2351         }
2352         m_have_video_pid = (vpid > 0 && vpid < 0x2000);
2353 }
2354
2355 void eDVBServicePlay::loadCuesheet()
2356 {
2357         std::string filename = m_reference.path + ".cuts";
2358         
2359         m_cue_entries.clear();
2360
2361         FILE *f = fopen(filename.c_str(), "rb");
2362
2363         if (f)
2364         {
2365                 eDebug("loading cuts..");
2366                 while (1)
2367                 {
2368                         unsigned long long where;
2369                         unsigned int what;
2370                         
2371                         if (!fread(&where, sizeof(where), 1, f))
2372                                 break;
2373                         if (!fread(&what, sizeof(what), 1, f))
2374                                 break;
2375                         
2376 #if BYTE_ORDER == LITTLE_ENDIAN
2377                         where = bswap_64(where);
2378 #endif
2379                         what = ntohl(what);
2380                         
2381                         if (what > 3)
2382                                 break;
2383                         
2384                         m_cue_entries.insert(cueEntry(where, what));
2385                 }
2386                 fclose(f);
2387                 eDebug("%d entries", m_cue_entries.size());
2388         } else
2389                 eDebug("cutfile not found!");
2390         
2391         m_cuesheet_changed = 0;
2392         cutlistToCuesheet();
2393         m_event((iPlayableService*)this, evCuesheetChanged);
2394 }
2395
2396 void eDVBServicePlay::saveCuesheet()
2397 {
2398         std::string filename = m_reference.path + ".cuts";
2399         
2400         FILE *f = fopen(filename.c_str(), "wb");
2401
2402         if (f)
2403         {
2404                 unsigned long long where;
2405                 int what;
2406
2407                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
2408                 {
2409 #if BYTE_ORDER == BIG_ENDIAN
2410                         where = i->where;
2411 #else
2412                         where = bswap_64(i->where);
2413 #endif
2414                         what = htonl(i->what);
2415                         fwrite(&where, sizeof(where), 1, f);
2416                         fwrite(&what, sizeof(what), 1, f);
2417                         
2418                 }
2419                 fclose(f);
2420         }
2421         
2422         m_cuesheet_changed = 0;
2423 }
2424
2425 void eDVBServicePlay::cutlistToCuesheet()
2426 {
2427         if (!m_cue)
2428         {
2429                 eDebug("no cue sheet");
2430                 return;
2431         }       
2432         m_cue->clear();
2433         
2434         if (!m_cutlist_enabled)
2435         {
2436                 m_cue->commitSpans();
2437                 eDebug("cutlists were disabled");
2438                 return;
2439         }
2440
2441         pts_t in = 0, out = 0, length = 0;
2442         
2443         getLength(length);
2444                 
2445         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
2446         
2447         int have_any_span = 0;
2448         
2449         while (1)
2450         {
2451                 if (i == m_cue_entries.end())
2452                 {
2453                         if (!have_any_span)
2454                                 break;
2455                         out = length;
2456                 } else {
2457                         if (i->what == 0) /* in */
2458                         {
2459                                 in = i++->where;
2460                                 continue;
2461                         } else if (i->what == 1) /* out */
2462                                 out = i++->where;
2463                         else /* mark (2) or last play position (3) */
2464                         {
2465                                 i++;
2466                                 continue;
2467                         }
2468                 }
2469                 
2470                 if (in < 0)
2471                         in = 0;
2472                 if (out < 0)
2473                         out = 0;
2474                 if (in > length)
2475                         in = length;
2476                 if (out > length)
2477                         out = length;
2478                 
2479                 if (in < out)
2480                 {
2481                         have_any_span = 1;
2482                         m_cue->addSourceSpan(in, out);
2483                 }
2484                 
2485                 in = length;
2486                 
2487                 if (i == m_cue_entries.end())
2488                         break;
2489         }
2490         m_cue->commitSpans();
2491 }
2492
2493 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, ePyObject tuple)
2494 {
2495         if (m_subtitle_widget)
2496                 disableSubtitles(parent);
2497
2498         ePyObject entry;
2499         int tuplesize = PyTuple_Size(tuple);
2500         int type = 0;
2501
2502         if (!PyTuple_Check(tuple))
2503                 goto error_out;
2504
2505         if (tuplesize < 1)
2506                 goto error_out;
2507
2508         entry = PyTuple_GET_ITEM(tuple, 0);
2509
2510         if (!PyInt_Check(entry))
2511                 goto error_out;
2512
2513         type = PyInt_AsLong(entry);
2514
2515         if (type == 1)  // teletext subtitles
2516         {
2517                 int page, magazine, pid;
2518                 if (tuplesize < 4)
2519                         goto error_out;
2520
2521                 if (!m_teletext_parser)
2522                 {
2523                         eDebug("enable teletext subtitles.. no parser !!!");
2524                         return -1;
2525                 }
2526
2527                 entry = PyTuple_GET_ITEM(tuple, 1);
2528                 if (!PyInt_Check(entry))
2529                         goto error_out;
2530                 pid = PyInt_AsLong(entry);
2531
2532                 entry = PyTuple_GET_ITEM(tuple, 2);
2533                 if (!PyInt_Check(entry))
2534                         goto error_out;
2535                 page = PyInt_AsLong(entry);
2536
2537                 entry = PyTuple_GET_ITEM(tuple, 3);
2538                 if (!PyInt_Check(entry))
2539                         goto error_out;
2540                 magazine = PyInt_AsLong(entry);
2541
2542                 m_subtitle_widget = new eSubtitleWidget(parent);
2543                 m_subtitle_widget->resize(parent->size()); /* full size */
2544                 m_teletext_parser->setPageAndMagazine(page, magazine);
2545                 if (m_dvb_service)
2546                         m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE,((pid&0xFFFF)<<16)|((page&0xFF)<<8)|(magazine&0xFF));
2547         }
2548         else if (type == 0)
2549         {
2550                 int pid = 0, composition_page_id = 0, ancillary_page_id = 0;
2551                 if (!m_subtitle_parser)
2552                 {
2553                         eDebug("enable dvb subtitles.. no parser !!!");
2554                         return -1;
2555                 }
2556                 if (tuplesize < 4)
2557                         goto error_out;
2558
2559                 entry = PyTuple_GET_ITEM(tuple, 1);
2560                 if (!PyInt_Check(entry))
2561                         goto error_out;
2562                 pid = PyInt_AsLong(entry);
2563
2564                 entry = PyTuple_GET_ITEM(tuple, 2);
2565                 if (!PyInt_Check(entry))
2566                         goto error_out;
2567                 composition_page_id = PyInt_AsLong(entry);
2568
2569                 entry = PyTuple_GET_ITEM(tuple, 3);
2570                 if (!PyInt_Check(entry))
2571                         goto error_out;
2572                 ancillary_page_id = PyInt_AsLong(entry);
2573
2574                 m_subtitle_widget = new eSubtitleWidget(parent);
2575                 m_subtitle_widget->resize(parent->size()); /* full size */
2576                 m_subtitle_parser->start(pid, composition_page_id, ancillary_page_id);
2577                 if (m_dvb_service)
2578                         m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, ((pid&0xFFFF)<<16)|((composition_page_id&0xFF)<<8)|(ancillary_page_id&0xFF));
2579         }
2580         else
2581                 goto error_out;
2582         return 0;
2583 error_out:
2584         eDebug("enableSubtitles needs a tuple as 2nd argument!\n"
2585                 "for teletext subtitles (0, pid, teletext_page, teletext_magazine)\n"
2586                 "for dvb subtitles (1, pid, composition_page_id, ancillary_page_id)");
2587         return -1;
2588 }
2589
2590 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
2591 {
2592         delete m_subtitle_widget;
2593         m_subtitle_widget = 0;
2594         if (m_subtitle_parser)
2595         {
2596                 m_subtitle_parser->stop();
2597                 m_dvb_subtitle_pages.clear();
2598         }
2599         if (m_teletext_parser)
2600         {
2601                 m_teletext_parser->setPageAndMagazine(-1, -1);
2602                 m_subtitle_pages.clear();
2603         }
2604         if (m_dvb_service)
2605                 m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, -1);
2606         return 0;
2607 }
2608
2609 PyObject *eDVBServicePlay::getCachedSubtitle()
2610 {
2611         if (m_dvb_service)
2612         {
2613                 int tmp = m_dvb_service->getCacheEntry(eDVBService::cSUBTITLE);
2614                 if (tmp != -1)
2615                 {
2616                         unsigned int data = (unsigned int)tmp;
2617                         int pid = (data&0xFFFF0000)>>16;
2618                         ePyObject tuple = PyTuple_New(4);
2619                         eDVBServicePMTHandler::program program;
2620                         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2621                         if (!h.getProgramInfo(program))
2622                         {
2623                                 if (program.textPid==pid) // teletext
2624                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1)); // type teletext
2625                                 else
2626                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0)); // type dvb
2627                                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong((data&0xFFFF0000)>>16)); // pid
2628                                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong((data&0xFF00)>>8)); // composition_page / page
2629                                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(data&0xFF)); // ancillary_page / magazine
2630                                 return tuple;
2631                         }
2632                 }
2633         }
2634         Py_RETURN_NONE;
2635 }
2636
2637 PyObject *eDVBServicePlay::getSubtitleList()
2638 {
2639         if (!m_teletext_parser)
2640                 Py_RETURN_NONE;
2641         
2642         ePyObject l = PyList_New(0);
2643         std::set<int> added_ttx_pages;
2644
2645         std::set<eDVBServicePMTHandler::subtitleStream> &subs =
2646                 m_teletext_parser->m_found_subtitle_pages;
2647
2648         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2649         eDVBServicePMTHandler::program program;
2650         if (h.getProgramInfo(program))
2651                 eDebug("getting program info failed.");
2652         else
2653         {
2654                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
2655                         it != program.subtitleStreams.end(); ++it)
2656                 {
2657                         switch(it->subtitling_type)
2658                         {
2659                                 case 0x01: // ebu teletext subtitles
2660                                 {
2661                                         int page_number = it->teletext_page_number & 0xFF;
2662                                         int magazine_number = it->teletext_magazine_number & 7;
2663                                         int hash = magazine_number << 8 | page_number;
2664                                         if (added_ttx_pages.find(hash) == added_ttx_pages.end())
2665                                         {
2666                                                 ePyObject tuple = PyTuple_New(5);
2667                                                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
2668                                                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2669                                                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
2670                                                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
2671                                                 PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
2672                                                 PyList_Append(l, tuple);
2673                                                 Py_DECREF(tuple);
2674                                                 added_ttx_pages.insert(hash);
2675                                         }
2676                                         break;
2677                                 }
2678                                 case 0x10 ... 0x13:
2679                                 case 0x20 ... 0x23: // dvb subtitles
2680                                 {
2681                                         ePyObject tuple = PyTuple_New(5);
2682                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0));
2683                                         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2684                                         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->composition_page_id));
2685                                         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->ancillary_page_id));
2686                                         PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
2687                                         PyList_Insert(l, 0, tuple);
2688                                         Py_DECREF(tuple);
2689                                         break;
2690                                 }
2691                         }
2692                 }
2693         }
2694
2695         for (std::set<eDVBServicePMTHandler::subtitleStream>::iterator it(subs.begin());
2696                 it != subs.end(); ++it)
2697         {
2698                 int page_number = it->teletext_page_number & 0xFF;
2699                 int magazine_number = it->teletext_magazine_number & 7;
2700                 int hash = magazine_number << 8 | page_number;
2701                 if (added_ttx_pages.find(hash) == added_ttx_pages.end())
2702                 {
2703                         ePyObject tuple = PyTuple_New(5);
2704                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
2705                         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2706                         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
2707                         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
2708                         PyTuple_SET_ITEM(tuple, 4, PyString_FromString("und"));  // undetermined
2709                         PyList_Append(l, tuple);
2710                         Py_DECREF(tuple);
2711                 }
2712         }
2713
2714         return l;
2715 }
2716
2717 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2718 {
2719         if (m_subtitle_widget)
2720         {
2721                 pts_t pos = 0;
2722                 if (m_decoder)
2723                         m_decoder->getPTS(0, pos);
2724                 eDebug("got new subtitle page %lld %lld %d", pos, page.m_pts, page.m_have_pts);
2725                 m_subtitle_pages.push_back(page);
2726                 checkSubtitleTiming();
2727         }
2728 }
2729
2730 void eDVBServicePlay::checkSubtitleTiming()
2731 {
2732         eDebug("checkSubtitleTiming");
2733         if (!m_subtitle_widget)
2734                 return;
2735         while (1)
2736         {
2737                 enum { TELETEXT, DVB } type;
2738                 eDVBTeletextSubtitlePage page;
2739                 eDVBSubtitlePage dvb_page;
2740                 pts_t show_time;
2741                 if (!m_subtitle_pages.empty())
2742                 {
2743                         page = m_subtitle_pages.front();
2744                         type = TELETEXT;
2745                         show_time = page.m_pts;
2746                 }
2747                 else if (!m_dvb_subtitle_pages.empty())
2748                 {
2749                         dvb_page = m_dvb_subtitle_pages.front();
2750                         type = DVB;
2751                         show_time = dvb_page.m_show_time;
2752                 }
2753                 else
2754                         return;
2755         
2756                 pts_t pos = 0;
2757         
2758                 if (m_decoder)
2759                         m_decoder->getPTS(0, pos);
2760
2761                 eDebug("%lld %lld", pos, show_time);
2762                 int diff =  show_time - pos;
2763                 if (diff < 0)
2764                 {
2765                         eDebug("[late (%d ms)]", -diff / 90);
2766                         diff = 0;
2767                 }
2768 //              if (diff > 900000)
2769 //              {
2770 //                      eDebug("[invalid]");
2771 //                      diff = 0;
2772 //              }
2773         
2774                 if ((diff/90)<20)
2775                 {
2776                         if (type == TELETEXT)
2777                         {
2778                                 eDebug("display teletext subtitle page %lld", show_time);
2779                                 m_subtitle_widget->setPage(page);
2780                                 m_subtitle_pages.pop_front();
2781                         }
2782                         else
2783                         {
2784                                 eDebug("display dvb subtitle Page %lld", show_time);
2785                                 m_subtitle_widget->setPage(dvb_page);
2786                                 m_dvb_subtitle_pages.pop_front();
2787                         }
2788                 } else
2789                 {
2790                         eDebug("start subtitle delay %d", diff / 90);
2791                         m_subtitle_sync_timer->start(diff / 90, 1);
2792                         break;
2793                 }
2794         }
2795 }
2796
2797 void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
2798 {
2799         if (m_subtitle_widget)
2800         {
2801                 pts_t pos = 0;
2802                 if (m_decoder)
2803                         m_decoder->getPTS(0, pos);
2804                 eDebug("got new subtitle page %lld %lld", pos, p.m_show_time);
2805                 m_dvb_subtitle_pages.push_back(p);
2806                 checkSubtitleTiming();
2807         }
2808 }
2809
2810 int eDVBServicePlay::getAC3Delay()
2811 {
2812         if (m_dvb_service)
2813                 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2814         else if (m_decoder)
2815                 return m_decoder->getAC3Delay();
2816         else
2817                 return 0;
2818 }
2819
2820 int eDVBServicePlay::getPCMDelay()
2821 {
2822         if (m_dvb_service)
2823                 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2824         else if (m_decoder)
2825                 return m_decoder->getPCMDelay();
2826         else
2827                 return 0;
2828 }
2829
2830 void eDVBServicePlay::setAC3Delay(int delay)
2831 {
2832         if (m_dvb_service)
2833                 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2834         if (m_decoder)
2835                 m_decoder->setAC3Delay(delay);
2836 }
2837
2838 void eDVBServicePlay::setPCMDelay(int delay)
2839 {
2840         if (m_dvb_service)
2841                 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2842         if (m_decoder)
2843                 m_decoder->setPCMDelay(delay);
2844 }
2845
2846 void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)
2847 {
2848         switch(event.type) {
2849                 case iTSMPEGDecoder::videoEvent::eventSizeChanged:
2850                         m_event((iPlayableService*)this, evVideoSizeChanged);
2851                         break;
2852                 case iTSMPEGDecoder::videoEvent::eventFrameRateChanged:
2853                         m_event((iPlayableService*)this, evVideoFramerateChanged);
2854                         break;
2855                 case iTSMPEGDecoder::videoEvent::eventProgressiveChanged:
2856                         m_event((iPlayableService*)this, evVideoProgressiveChanged);
2857                         break;
2858                 default:
2859                         break;
2860         }
2861 }
2862
2863 RESULT eDVBServicePlay::stream(ePtr<iStreamableService> &ptr)
2864 {
2865         ptr = this;
2866         return 0;
2867 }
2868
2869 PyObject *eDVBServicePlay::getStreamingData()
2870 {
2871         eDVBServicePMTHandler::program program;
2872         if (m_service_handler.getProgramInfo(program))
2873         {
2874                 Py_RETURN_NONE;
2875         }
2876
2877         ePyObject r = program.createPythonObject();
2878         ePtr<iDVBDemux> demux;
2879         if (!m_service_handler.getDataDemux(demux))
2880         {
2881                 uint8_t demux_id;
2882                 if (!demux->getCADemuxID(demux_id))
2883                         PutToDict(r, "demux", demux_id);
2884         }
2885
2886         return r;
2887 }
2888
2889
2890 DEFINE_REF(eDVBServicePlay)
2891
2892 PyObject *eDVBService::getInfoObject(const eServiceReference &ref, int w)
2893 {
2894         switch (w)
2895         {
2896         case iServiceInformation::sTransponderData:
2897                 return eStaticServiceDVBInformation().getInfoObject(ref, w);
2898         default:
2899                 break;
2900         }
2901         return iStaticServiceInformation::getInfoObject(ref, w);
2902 }
2903
2904 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");