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