dvb subtitles are working now
[vuplus_dvbapp] / lib / service / servicedvb.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/base/object.h>
3 #include <string>
4 #include <lib/service/servicedvb.h>
5 #include <lib/service/service.h>
6 #include <lib/base/init_num.h>
7 #include <lib/base/init.h>
8 #include <lib/base/nconfig.h> // access to python config
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
20                 /* for subtitles */
21 #include <lib/gui/esubtitle.h>
22
23 #include <sys/vfs.h>
24 #include <sys/stat.h>
25
26 #include <byteswap.h>
27 #include <netinet/in.h>
28
29 #define INTERNAL_TELETEXT
30
31 #ifndef BYTE_ORDER
32 #error no byte order defined!
33 #endif
34
35 #define TSPATH "/media/hdd"
36
37 class eStaticServiceDVBInformation: public iStaticServiceInformation
38 {
39         DECLARE_REF(eStaticServiceDVBInformation);
40 public:
41         RESULT getName(const eServiceReference &ref, std::string &name);
42         int getLength(const eServiceReference &ref);
43 };
44
45 DEFINE_REF(eStaticServiceDVBInformation);
46
47 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
48 {
49         eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
50         if ( !ref.name.empty() )
51         {
52                 if (service.getParentTransportStreamID().get()) // linkage subservice
53                 {
54                         ePtr<iServiceHandler> service_center;
55                         if (!eServiceCenter::getInstance(service_center))
56                         {
57                                 eServiceReferenceDVB parent = service;
58                                 parent.setTransportStreamID( service.getParentTransportStreamID() );
59                                 parent.setServiceID( service.getParentServiceID() );
60                                 parent.setParentTransportStreamID(eTransportStreamID(0));
61                                 parent.setParentServiceID(eServiceID(0));
62                                 parent.name="";
63                                 ePtr<iStaticServiceInformation> service_info;
64                                 if (!service_center->info(parent, service_info))
65                                 {
66                                         if (!service_info->getName(parent, name))
67                                         {
68                                                 // just show short name
69                                                 unsigned int pos = name.find("\xc2\x86");
70                                                 if ( pos != std::string::npos )
71                                                         name.erase(0, pos+2);
72                                                 pos = name.find("\xc2\x87");
73                                                 if ( pos != std::string::npos )
74                                                         name.erase(pos);
75                                                 name+=" - ";
76                                         }
77                                 }
78                         }
79                 }
80                 else
81                         name="";
82                 name += ref.name;
83                 return 0;
84         }
85         else
86                 return -1;
87 }
88
89 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
90 {
91         return -1;
92 }
93
94 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
95 {
96         DECLARE_REF(eStaticServiceDVBBouquetInformation);
97 public:
98         RESULT getName(const eServiceReference &ref, std::string &name);
99         int getLength(const eServiceReference &ref);
100 };
101
102 DEFINE_REF(eStaticServiceDVBBouquetInformation);
103
104 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
105 {
106         ePtr<iDVBChannelList> db;
107         ePtr<eDVBResourceManager> res;
108
109         int err;
110         if ((err = eDVBResourceManager::getInstance(res)) != 0)
111         {
112                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
113                 return err;
114         }
115         if ((err = res->getChannelList(db)) != 0)
116         {
117                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
118                 return err;
119         }
120
121         eBouquet *bouquet=0;
122         if ((err = db->getBouquet(ref, bouquet)) != 0)
123         {
124                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
125                 return -1;
126         }
127
128         if ( bouquet && bouquet->m_bouquet_name.length() )
129         {
130                 name = bouquet->m_bouquet_name;
131                 return 0;
132         }
133         else
134                 return -1;
135 }
136
137 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
138 {
139         return -1;
140 }
141
142 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
143 {
144         DECLARE_REF(eStaticServiceDVBPVRInformation);
145         eServiceReference m_ref;
146         eDVBMetaParser m_parser;
147 public:
148         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
149         RESULT getName(const eServiceReference &ref, std::string &name);
150         int getLength(const eServiceReference &ref);
151         RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
152
153         int getInfo(const eServiceReference &ref, int w);
154         std::string getInfoString(const eServiceReference &ref,int w);
155 };
156
157 DEFINE_REF(eStaticServiceDVBPVRInformation);
158
159 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
160 {
161         m_ref = ref;
162         m_parser.parseFile(ref.path);
163 }
164
165 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
166 {
167         ASSERT(ref == m_ref);
168         name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
169         return 0;
170 }
171
172 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
173 {
174         ASSERT(ref == m_ref);
175         
176         eDVBTSTools tstools;
177         
178         if (tstools.openFile(ref.path.c_str()))
179                 return 0;
180
181         pts_t len;
182         if (tstools.calcLen(len))
183                 return 0;
184
185         return len / 90000;
186 }
187
188 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
189 {
190         switch (w)
191         {
192         case iServiceInformation::sDescription:
193                 return iServiceInformation::resIsString;
194         case iServiceInformation::sServiceref:
195                 return iServiceInformation::resIsString;
196         case iServiceInformation::sTimeCreate:
197                 if (m_parser.m_time_create)
198                         return m_parser.m_time_create;
199                 else
200                         return iServiceInformation::resNA;
201         default:
202                 return iServiceInformation::resNA;
203         }
204 }
205
206 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
207 {
208         switch (w)
209         {
210         case iServiceInformation::sDescription:
211                 return m_parser.m_description;
212         case iServiceInformation::sServiceref:
213                 return m_parser.m_ref.toString();
214         default:
215                 return "";
216         }
217 }
218
219 RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
220 {
221         if (!ref.path.empty())
222         {
223                 ePtr<eServiceEvent> event = new eServiceEvent;
224                 std::string filename = ref.path;
225                 filename.erase(filename.length()-2, 2);
226                 filename+="eit";
227                 if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
228                 {
229                         evt = event;
230                         return 0;
231                 }
232         }
233         evt = 0;
234         return -1;
235 }
236
237 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
238 {
239         DECLARE_REF(eDVBPVRServiceOfflineOperations);
240         eServiceReferenceDVB m_ref;
241 public:
242         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
243         
244         RESULT deleteFromDisk(int simulate);
245         RESULT getListOfFilenames(std::list<std::string> &);
246 };
247
248 DEFINE_REF(eDVBPVRServiceOfflineOperations);
249
250 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
251 {
252 }
253
254 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
255 {
256         if (simulate)
257                 return 0;
258         else
259         {
260                 std::list<std::string> res;
261                 if (getListOfFilenames(res))
262                         return -1;
263                 
264                 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
265                 if (!eraser)
266                         eDebug("FATAL !! can't get background file eraser");
267                 
268                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
269                 {
270                         eDebug("Removing %s...", i->c_str());
271                         if (eraser)
272                                 eraser->erase(i->c_str());
273                         else
274                                 ::unlink(i->c_str());
275                 }
276                 
277                 return 0;
278         }
279 }
280
281 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
282 {
283         res.clear();
284         res.push_back(m_ref.path);
285
286 // handling for old splitted recordings (enigma 1)
287         char buf[255];
288         int slice=1;
289         while(true)
290         {
291                 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
292                 struct stat s;
293                 if (stat(buf, &s) < 0)
294                         break;
295                 res.push_back(buf);
296         }       
297
298         res.push_back(m_ref.path + ".meta");
299         res.push_back(m_ref.path + ".ap");
300         res.push_back(m_ref.path + ".cuts");
301         std::string tmp = m_ref.path;
302         tmp.erase(m_ref.path.length()-3);
303         res.push_back(tmp + ".eit");
304         return 0;
305 }
306
307 DEFINE_REF(eServiceFactoryDVB)
308
309 eServiceFactoryDVB::eServiceFactoryDVB()
310 {
311         ePtr<eServiceCenter> sc;
312         
313         eServiceCenter::getPrivInstance(sc);
314         if (sc)
315                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
316
317         m_StaticServiceDVBInfo = new eStaticServiceDVBInformation;
318         m_StaticServiceDVBBouquetInfo = new eStaticServiceDVBBouquetInformation;
319 }
320
321 eServiceFactoryDVB::~eServiceFactoryDVB()
322 {
323         ePtr<eServiceCenter> sc;
324         
325         eServiceCenter::getPrivInstance(sc);
326         if (sc)
327                 sc->removeServiceFactory(eServiceFactoryDVB::id);
328 }
329
330 DEFINE_REF(eDVBServiceList);
331
332 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
333 {
334 }
335
336 eDVBServiceList::~eDVBServiceList()
337 {
338 }
339
340 RESULT eDVBServiceList::startQuery()
341 {
342         ePtr<iDVBChannelList> db;
343         ePtr<eDVBResourceManager> res;
344         
345         int err;
346         if ((err = eDVBResourceManager::getInstance(res)) != 0)
347         {
348                 eDebug("no resource manager");
349                 return err;
350         }
351         if ((err = res->getChannelList(db)) != 0)
352         {
353                 eDebug("no channel list");
354                 return err;
355         }
356         
357         ePtr<eDVBChannelQuery> q;
358         
359         if (!m_parent.path.empty())
360         {
361                 eDVBChannelQuery::compile(q, m_parent.path);
362                 if (!q)
363                 {
364                         eDebug("compile query failed");
365                         return err;
366                 }
367         }
368         
369         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
370         {
371                 eDebug("startQuery failed");
372                 return err;
373         }
374
375         return 0;
376 }
377
378 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
379 {
380         eServiceReferenceDVB ref;
381         
382         if (!m_query)
383                 return -1;
384         
385         while (!m_query->getNextResult(ref))
386                 list.push_back(ref);
387
388         if (sorted)
389                 list.sort(iListableServiceCompare(this));
390
391         return 0;
392 }
393
394 //   The first argument of this function is a format string to specify the order and
395 //   the content of the returned list
396 //   useable format options are
397 //   R = Service Reference (as swig object .. this is very slow)
398 //   S = Service Reference (as python string object .. same as ref.toString())
399 //   C = Service Reference (as python string object .. same as ref.toCompareString())
400 //   N = Service Name (as python string object)
401 //   when exactly one return value per service is selected in the format string,
402 //   then each value is directly a list entry
403 //   when more than one value is returned per service, then the list is a list of
404 //   python tuples
405 //   unknown format string chars are returned as python None values !
406 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
407 {
408         PyObject *ret=0;
409         std::list<eServiceReference> tmplist;
410         int retcount=1;
411
412         if (!format || !(retcount=strlen(format)))
413                 format = "R"; // just return service reference swig object ...
414
415         if (!getContent(tmplist, sorted))
416         {
417                 int services=tmplist.size();
418                 ePtr<iStaticServiceInformation> sptr;
419                 eServiceCenterPtr service_center;
420
421                 if (strchr(format, 'N'))
422                         eServiceCenter::getPrivInstance(service_center);
423
424                 ret = PyList_New(services);
425                 std::list<eServiceReference>::iterator it(tmplist.begin());
426
427                 for (int cnt=0; cnt < services; ++cnt)
428                 {
429                         eServiceReference &ref=*it++;
430                         PyObject *tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
431                         for (int i=0; i < retcount; ++i)
432                         {
433                                 PyObject *tmp=0;
434                                 switch(format[i])
435                                 {
436                                 case 'R':  // service reference (swig)object
437                                         tmp = New_eServiceReference(ref);
438                                         break;
439                                 case 'C':  // service reference compare string
440                                         tmp = PyString_FromString(ref.toCompareString().c_str());
441                                         break;
442                                 case 'S':  // service reference string
443                                         tmp = PyString_FromString(ref.toString().c_str());
444                                         break;
445                                 case 'N':  // service name
446                                         if (service_center)
447                                         {
448                                                 service_center->info(ref, sptr);
449                                                 if (sptr)
450                                                 {
451                                                         std::string name;
452                                                         sptr->getName(ref, name);
453                                                         if (name.length())
454                                                                 tmp = PyString_FromString(name.c_str());
455                                                 }
456                                         }
457                                         if (!tmp)
458                                                 tmp = PyString_FromString("<n/a>");
459                                         break;
460                                 default:
461                                         if (tuple)
462                                         {
463                                                 tmp = Py_None;
464                                                 Py_INCREF(Py_None);
465                                         }
466                                         break;
467                                 }
468                                 if (tmp)
469                                 {
470                                         if (tuple)
471                                                 PyTuple_SET_ITEM(tuple, i, tmp);
472                                         else
473                                                 PyList_SET_ITEM(ret, cnt, tmp);
474                                 }
475                         }
476                         if (tuple)
477                                 PyList_SET_ITEM(ret, cnt, tuple);
478                 }
479         }
480         return ret ? ret : PyList_New(0);
481 }
482
483 RESULT eDVBServiceList::getNext(eServiceReference &ref)
484 {
485         if (!m_query)
486                 return -1;
487         
488         return m_query->getNextResult((eServiceReferenceDVB&)ref);
489 }
490
491 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
492 {
493         return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
494 }
495
496 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
497 {
498         if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
499         {
500                 ePtr<iDVBChannelList> db;
501                 ePtr<eDVBResourceManager> resm;
502
503                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
504                         return -1;
505
506                 if (db->getBouquet(m_parent, m_bouquet) != 0)
507                         return -1;
508
509                 res = this;
510                 
511                 return 0;
512         }
513         res = 0;
514         return -1;
515 }
516
517 RESULT eDVBServiceList::addService(eServiceReference &ref, eServiceReference before)
518 {
519         if (!m_bouquet)
520                 return -1;
521         return m_bouquet->addService(ref, before);
522 }
523
524 RESULT eDVBServiceList::removeService(eServiceReference &ref)
525 {
526         if (!m_bouquet)
527                 return -1;
528         return m_bouquet->removeService(ref);
529 }
530
531 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
532 {
533         if (!m_bouquet)
534                 return -1;
535         return m_bouquet->moveService(ref, pos);
536 }
537
538 RESULT eDVBServiceList::flushChanges()
539 {
540         if (!m_bouquet)
541                 return -1;
542         return m_bouquet->flushChanges();
543 }
544
545 RESULT eDVBServiceList::setListName(const std::string &name)
546 {
547         if (!m_bouquet)
548                 return -1;
549         return m_bouquet->setListName(name);
550 }
551
552 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
553 {
554         ePtr<eDVBService> service;
555         int r = lookupService(service, ref);
556         if (r)
557                 service = 0;
558                 // check resources...
559         ptr = new eDVBServicePlay(ref, service);
560         return 0;
561 }
562
563 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
564 {
565         if (ref.path.empty())
566         {
567                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
568                 return 0;
569         } else
570         {
571                 ptr = 0;
572                 return -1;
573         }
574 }
575
576 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
577 {
578         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
579         if (list->startQuery())
580         {
581                 ptr = 0;
582                 return -1;
583         }
584         
585         ptr = list;
586         return 0;
587 }
588
589 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
590 {
591         /* is a listable service? */
592         if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
593         {
594                 if ( !ref.name.empty() )  // satellites or providers list
595                         ptr = m_StaticServiceDVBInfo;
596                 else // a dvb bouquet
597                         ptr = m_StaticServiceDVBBouquetInfo;
598         }
599         else if (!ref.path.empty()) /* do we have a PVR service? */
600                 ptr = new eStaticServiceDVBPVRInformation(ref);
601         else // normal dvb service
602         {
603                 ePtr<eDVBService> service;
604                 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
605                         ptr = m_StaticServiceDVBInfo;
606                 else
607                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
608                         ptr = service;
609         }
610         return 0;
611 }
612
613 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
614 {
615         if (ref.path.empty())
616         {
617                 ptr = 0;
618                 return -1;
619         } else
620         {
621                 ptr = new eDVBPVRServiceOfflineOperations(ref);
622                 return 0;
623         }
624 }
625
626 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
627 {
628                         // TODO: handle the listing itself
629         // if (ref.... == -1) .. return "... bouquets ...";
630         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
631                         // TODO: cache
632         ePtr<iDVBChannelList> db;
633         ePtr<eDVBResourceManager> res;
634         
635         int err;
636         if ((err = eDVBResourceManager::getInstance(res)) != 0)
637         {
638                 eDebug("no resource manager");
639                 return err;
640         }
641         if ((err = res->getChannelList(db)) != 0)
642         {
643                 eDebug("no channel list");
644                 return err;
645         }
646         
647                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
648         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
649         {
650                 eDebug("getService failed!");
651                 return err;
652         }
653
654         return 0;
655 }
656
657 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
658         m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
659 {
660         m_is_primary = 1;
661         m_is_pvr = !m_reference.path.empty();
662         
663         m_timeshift_enabled = m_timeshift_active = 0;
664         m_skipmode = 0;
665         
666         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
667         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
668         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
669
670         m_cuesheet_changed = 0;
671         m_cutlist_enabled = 1;
672         
673         m_subtitle_widget = 0;
674         
675         CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
676 }
677
678 eDVBServicePlay::~eDVBServicePlay()
679 {
680         delete m_subtitle_widget;
681 }
682
683 void eDVBServicePlay::gotNewEvent()
684 {
685 #if 0
686                 // debug only
687         ePtr<eServiceEvent> m_event_now, m_event_next;
688         getEvent(m_event_now, 0);
689         getEvent(m_event_next, 1);
690
691         if (m_event_now)
692                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
693         if (m_event_next)
694                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
695 #endif
696         m_event((iPlayableService*)this, evUpdatedEventInfo);
697 }
698
699 void eDVBServicePlay::serviceEvent(int event)
700 {
701         switch (event)
702         {
703         case eDVBServicePMTHandler::eventTuned:
704         {
705                 ePtr<iDVBDemux> m_demux;
706                 if (!m_service_handler.getDataDemux(m_demux))
707                 {
708                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
709                         int sid = ref.getParentServiceID().get();
710                         if (!sid)
711                                 sid = ref.getServiceID().get();
712                         if ( ref.getParentTransportStreamID().get() &&
713                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
714                                 m_event_handler.startOther(m_demux, sid);
715                         else
716                                 m_event_handler.start(m_demux, sid);
717                 }
718                 break;
719         }
720         case eDVBServicePMTHandler::eventTuneFailed:
721         {
722                 eDebug("DVB service failed to tune");
723                 m_event((iPlayableService*)this, evTuneFailed);
724                 break;
725         }
726         case eDVBServicePMTHandler::eventNewProgramInfo:
727         {
728                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
729                 if (m_timeshift_enabled)
730                         updateTimeshiftPids();
731                 if (!m_timeshift_active)
732                         updateDecoder();
733                 if (m_first_program_info && m_is_pvr)
734                 {
735                         m_first_program_info = 0;
736                         seekTo(0);
737                 }
738                 m_event((iPlayableService*)this, evUpdatedInfo);
739                 break;
740         }
741         case eDVBServicePMTHandler::eventEOF:
742                 m_event((iPlayableService*)this, evEOF);
743                 break;
744         case eDVBServicePMTHandler::eventSOF:
745                 m_event((iPlayableService*)this, evSOF);
746                 break;
747         }
748 }
749
750 void eDVBServicePlay::serviceEventTimeshift(int event)
751 {
752         switch (event)
753         {
754         case eDVBServicePMTHandler::eventNewProgramInfo:
755                 if (m_timeshift_active)
756                         updateDecoder();
757                 break;
758         case eDVBServicePMTHandler::eventSOF:
759                 m_event((iPlayableService*)this, evSOF);
760                 break;
761         case eDVBServicePMTHandler::eventEOF:
762                 switchToLive();
763                 break;
764         }
765 }
766
767 RESULT eDVBServicePlay::start()
768 {
769         int r;
770                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
771                    two (one for decoding, one for data source), as we must be prepared
772                    to start recording from the data demux. */
773         if (m_is_pvr)
774                 m_cue = new eCueSheet();
775
776         m_first_program_info = 1;
777         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
778         r = m_service_handler.tune(service, m_is_pvr, m_cue);
779
780                 /* inject EIT if there is a stored one */
781         if (m_is_pvr)
782         {
783                 std::string filename = service.path;
784                 filename.erase(filename.length()-2, 2);
785                 filename+="eit";
786                 ePtr<eServiceEvent> event = new eServiceEvent;
787                 if (!event->parseFrom(filename, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get()))
788                 {
789                         ePtr<eServiceEvent> empty;
790                         m_event_handler.inject(event, 0);
791                         m_event_handler.inject(empty, 1);
792                 }
793         }
794
795         if (m_is_pvr)
796                 loadCuesheet();
797
798         m_event(this, evStart);
799         m_event((iPlayableService*)this, evSeekableStatusChanged);
800         return 0;
801 }
802
803 RESULT eDVBServicePlay::stop()
804 {
805                 /* add bookmark for last play position */
806         if (m_is_pvr)
807         {
808                 pts_t play_position;
809                 if (!getPlayPosition(play_position))
810                 {
811                                 /* remove last position */
812                         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end();)
813                         {
814                                 if (i->what == 3) /* current play position */
815                                 {
816                                         m_cue_entries.erase(i);
817                                         i = m_cue_entries.begin();
818                                         continue;
819                                 } else
820                                         ++i;
821                         }
822                         
823                         m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
824                         m_cuesheet_changed = 1;
825                 }
826         }
827
828         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
829
830         m_service_handler_timeshift.free();
831         m_service_handler.free();
832         
833         if (m_is_pvr && m_cuesheet_changed)
834         {
835                 struct stat s;
836                                 /* save cuesheet only when main file is accessible. */
837                 if (!::stat(m_reference.path.c_str(), &s))
838                         saveCuesheet();
839         }
840         
841         return 0;
842 }
843
844 RESULT eDVBServicePlay::setTarget(int target)
845 {
846         m_is_primary = !target;
847         return 0;
848 }
849
850 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
851 {
852         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
853         return 0;
854 }
855
856 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
857 {
858                 /* note: we check for timeshift to be enabled,
859                    not neccessary active. if you pause when timeshift
860                    is not active, you should activate it when unpausing */
861         if ((!m_is_pvr) && (!m_timeshift_enabled))
862         {
863                 ptr = 0;
864                 return -1;
865         }
866
867         ptr = this;
868         return 0;
869 }
870
871 RESULT eDVBServicePlay::setSlowMotion(int ratio)
872 {
873         if (m_decoder)
874                 return m_decoder->setSlowMotion(ratio);
875         else
876                 return -1;
877 }
878
879 RESULT eDVBServicePlay::setFastForward(int ratio)
880 {
881         int skipmode, ffratio;
882         
883         if (ratio > 8)
884         {
885                 skipmode = ratio;
886                 ffratio = 1;
887         } else if (ratio > 0)
888         {
889                 skipmode = 0;
890                 ffratio = ratio;
891         } else if (!ratio)
892         {
893                 skipmode = 0;
894                 ffratio = 0;
895         } else // if (ratio < 0)
896         {
897                 skipmode = ratio;
898                 ffratio = 1;
899         }
900
901         if (m_skipmode != skipmode)
902         {
903                 eDebug("setting cue skipmode to %d", skipmode);
904                 if (m_cue)
905                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
906         }
907         
908         m_skipmode = skipmode;
909         
910         if (!m_decoder)
911                 return -1;
912
913         return m_decoder->setFastForward(ffratio);
914 }
915     
916 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
917 {
918         if (m_is_pvr || m_timeshift_enabled)
919         {
920                 ptr = this;
921                 return 0;
922         }
923         
924         ptr = 0;
925         return -1;
926 }
927
928         /* TODO: when timeshift is enabled but not active, this doesn't work. */
929 RESULT eDVBServicePlay::getLength(pts_t &len)
930 {
931         ePtr<iDVBPVRChannel> pvr_channel;
932         
933         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
934                 return -1;
935         
936         return pvr_channel->getLength(len);
937 }
938
939 RESULT eDVBServicePlay::pause()
940 {
941         if (!m_is_paused && m_decoder)
942         {
943                 m_is_paused = 1;
944                 return m_decoder->freeze(0);
945         } else
946                 return -1;
947 }
948
949 RESULT eDVBServicePlay::unpause()
950 {
951         if (m_is_paused && m_decoder)
952         {
953                 m_is_paused = 0;
954                 return m_decoder->unfreeze();
955         } else
956                 return -1;
957 }
958
959 RESULT eDVBServicePlay::seekTo(pts_t to)
960 {
961         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
962         
963         if (!m_decode_demux)
964                 return -1;
965
966         ePtr<iDVBPVRChannel> pvr_channel;
967         
968         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
969                 return -1;
970         
971         if (!m_cue)
972                 return -1;
973         
974         m_cue->seekTo(0, to);
975         return 0;
976 }
977
978 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
979 {
980         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
981         
982         if (!m_decode_demux)
983                 return -1;
984
985         ePtr<iDVBPVRChannel> pvr_channel;
986         
987         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
988                 return -1;
989         
990         int mode = 1;
991         
992                         /* HACK until we have skip-AP api */
993         if ((to > 0) && (to < 100))
994                 mode = 2;
995         
996         to *= direction;
997         
998         if (!m_cue)
999                 return 0;
1000         
1001         m_cue->seekTo(mode, to);
1002         return 0;
1003 }
1004
1005 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
1006 {
1007         ePtr<iDVBPVRChannel> pvr_channel;
1008         
1009         if (!m_decode_demux)
1010                 return -1;
1011         
1012         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1013                 return -1;
1014         
1015         int r = 0;
1016
1017                 /* if there is a decoder, use audio or video PTS */
1018         if (m_decoder)
1019         {
1020                 r = m_decoder->getPTS(0, pos);
1021                 if (r)
1022                         return r;
1023         }
1024         
1025                 /* fixup */
1026         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
1027 }
1028
1029 RESULT eDVBServicePlay::setTrickmode(int trick)
1030 {
1031         if (m_decoder)
1032                 m_decoder->setTrickmode(trick);
1033         return 0;
1034 }
1035
1036 RESULT eDVBServicePlay::isCurrentlySeekable()
1037 {
1038         return m_is_pvr || m_timeshift_active;
1039 }
1040
1041 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
1042 {
1043         ptr = this;
1044         return 0;
1045 }
1046
1047 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
1048 {
1049         ptr = this;
1050         return 0;
1051 }
1052
1053 RESULT eDVBServicePlay::audioChannel(ePtr<iAudioChannelSelection> &ptr)
1054 {
1055         ptr = this;
1056         return 0;
1057 }
1058
1059 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1060 {
1061         ptr = this;
1062         return 0;
1063 }
1064
1065 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1066 {
1067         ptr = this;
1068         return 0;
1069 }
1070
1071 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1072 {
1073         ptr = 0;
1074         if (m_have_video_pid &&  // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
1075                 (m_timeshift_enabled || !m_is_pvr))
1076         {
1077                 if (!m_timeshift_enabled)
1078                 {
1079                                 /* we need enough diskspace */
1080                         struct statfs fs;
1081                         if (statfs(TSPATH "/.", &fs) < 0)
1082                         {
1083                                 eDebug("statfs failed!");
1084                                 return -2;
1085                         }
1086                 
1087                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1088                         {
1089                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1090                                 return -3;
1091                         }
1092                 }
1093                 ptr = this;
1094                 return 0;
1095         }
1096         return -1;
1097 }
1098
1099 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1100 {
1101         if (m_is_pvr)
1102         {
1103                 ptr = this;
1104                 return 0;
1105         }
1106         ptr = 0;
1107         return -1;
1108 }
1109
1110 RESULT eDVBServicePlay::subtitle(ePtr<iSubtitleOutput> &ptr)
1111 {
1112         ptr = this;
1113         return 0;
1114 }
1115
1116 RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
1117 {
1118         ptr = this;
1119         return 0;
1120 }
1121
1122 RESULT eDVBServicePlay::radioText(ePtr<iRadioText> &ptr)
1123 {
1124         ptr = this;
1125         return 0;
1126 }
1127
1128 RESULT eDVBServicePlay::getName(std::string &name)
1129 {
1130         if (m_is_pvr)
1131         {
1132                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1133                 return i->getName(m_reference, name);
1134         }
1135         if (m_dvb_service)
1136         {
1137                 m_dvb_service->getName(m_reference, name);
1138                 if (name.empty())
1139                         name = "(...)";
1140         }
1141         else if (!m_reference.name.empty())
1142                 eStaticServiceDVBInformation().getName(m_reference, name);
1143         else
1144                 name = "DVB service";
1145         return 0;
1146 }
1147
1148 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1149 {
1150         return m_event_handler.getEvent(evt, nownext);
1151 }
1152
1153 int eDVBServicePlay::getInfo(int w)
1154 {
1155         eDVBServicePMTHandler::program program;
1156
1157         if (w == sCAIDs)
1158                 return resIsPyObject;
1159
1160         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1161         
1162         if (h.getProgramInfo(program))
1163                 return -1;
1164         
1165         switch (w)
1166         {
1167         case sAspect:
1168                 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1169                 {
1170                         ePtr<eServiceEvent> evt;
1171                         if (!m_event_handler.getEvent(evt, 0))
1172                         {
1173                                 ePtr<eComponentData> data;
1174                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1175                                 {
1176                                         if ( data->getStreamContent() == 1 )
1177                                         {
1178                                                 switch(data->getComponentType())
1179                                                 {
1180                                                         // SD
1181                                                         case 1: // 4:3 SD PAL
1182                                                         case 2:
1183                                                         case 3: // 16:9 SD PAL
1184                                                         case 4: // > 16:9 PAL
1185                                                         case 5: // 4:3 SD NTSC
1186                                                         case 6: 
1187                                                         case 7: // 16:9 SD NTSC
1188                                                         case 8: // > 16:9 NTSC
1189
1190                                                         // HD
1191                                                         case 9: // 4:3 HD PAL
1192                                                         case 0xA:
1193                                                         case 0xB: // 16:9 HD PAL
1194                                                         case 0xC: // > 16:9 HD PAL
1195                                                         case 0xD: // 4:3 HD NTSC
1196                                                         case 0xE:
1197                                                         case 0xF: // 16:9 HD NTSC
1198                                                         case 0x10: // > 16:9 HD PAL
1199                                                                 return data->getComponentType();
1200                                                 }
1201                                         }
1202                                 }
1203                         }
1204                 }
1205                 return -1;
1206         case sIsCrypted: return program.isCrypted();
1207         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1208         case sVideoType: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
1209         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
1210         case sPCRPID: return program.pcrPid;
1211         case sPMTPID: return program.pmtPid;
1212         case sTXTPID: return program.textPid;
1213         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1214         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1215         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1216         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1217         case sProvider: if (!m_dvb_service) return -1; return -2;
1218         default:
1219                 return -1;
1220         }
1221 }
1222
1223 std::string eDVBServicePlay::getInfoString(int w)
1224 {
1225         switch (w)
1226         {
1227         case sProvider:
1228                 if (!m_dvb_service) return "";
1229                 return m_dvb_service->m_provider_name;
1230         default:
1231                 break;
1232         }
1233         return iServiceInformation::getInfoString(w);
1234 }
1235
1236 PyObject *eDVBServicePlay::getInfoObject(int w)
1237 {
1238         switch (w)
1239         {
1240         case sCAIDs:
1241                 return m_service_handler.getCaIds();
1242         default:
1243                 break;
1244         }
1245         return iServiceInformation::getInfoObject(w);
1246 }
1247
1248 int eDVBServicePlay::getNumberOfTracks()
1249 {
1250         eDVBServicePMTHandler::program program;
1251         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1252         if (h.getProgramInfo(program))
1253                 return 0;
1254         return program.audioStreams.size();
1255 }
1256
1257 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1258 {
1259         int ret = selectAudioStream(i);
1260
1261         if (m_decoder->start())
1262                 return -5;
1263
1264         return ret;
1265 }
1266
1267 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1268 {
1269         eDVBServicePMTHandler::program program;
1270         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1271
1272         if (h.getProgramInfo(program))
1273                 return -1;
1274         
1275         if (i >= program.audioStreams.size())
1276                 return -2;
1277         
1278         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1279                 info.m_description = "MPEG";
1280         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1281                 info.m_description = "AC3";
1282         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
1283                 info.m_description = "AAC";
1284         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1285                 info.m_description = "DTS";
1286         else
1287                 info.m_description = "???";
1288
1289         if (program.audioStreams[i].component_tag != -1)
1290         {
1291                 ePtr<eServiceEvent> evt;
1292                 if (!m_event_handler.getEvent(evt, 0))
1293                 {
1294                         ePtr<eComponentData> data;
1295                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1296                                 info.m_language = data->getText();
1297                 }
1298         }
1299
1300         if (info.m_language.empty())
1301                 info.m_language = program.audioStreams[i].language_code;
1302         
1303         return 0;
1304 }
1305
1306 int eDVBServicePlay::selectAudioStream(int i)
1307 {
1308         eDVBServicePMTHandler::program program;
1309         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1310
1311         if (h.getProgramInfo(program))
1312                 return -1;
1313         
1314         if ((unsigned int)i >= program.audioStreams.size())
1315                 return -2;
1316         
1317         if (!m_decoder)
1318                 return -3;
1319         
1320         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1321                 return -4;
1322
1323         if (m_radiotext_parser)
1324                 m_radiotext_parser->start(program.audioStreams[i].pid);
1325
1326         if (m_dvb_service && !m_is_pvr)
1327         {
1328                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1329                 {
1330                         m_dvb_service->setCacheEntry(eDVBService::cAPID, program.audioStreams[i].pid);
1331                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1332                 }
1333                 else
1334                 {
1335                         m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1336                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, program.audioStreams[i].pid);
1337                 }
1338         }
1339
1340         return 0;
1341 }
1342
1343 int eDVBServicePlay::getCurrentChannel()
1344 {
1345         return m_decoder ? m_decoder->getAudioChannel() : STEREO;
1346 }
1347
1348 RESULT eDVBServicePlay::selectChannel(int i)
1349 {
1350         if (i < LEFT || i > RIGHT || i == STEREO)
1351                 i = -1;  // Stereo
1352         if (m_dvb_service)
1353                 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1354         if (m_decoder)
1355                 m_decoder->setAudioChannel(i);
1356         return 0;
1357 }
1358
1359 std::string eDVBServicePlay::getRadioText(int x)
1360 {
1361         if (m_radiotext_parser)
1362                 switch(x)
1363                 {
1364                         case 0:
1365                                 return m_radiotext_parser->getCurrentText();
1366                 }
1367         return "";
1368 }
1369
1370 void eDVBServicePlay::radioTextUpdated()
1371 {
1372         m_event((iPlayableService*)this, evUpdatedRadioText);
1373 }
1374
1375 int eDVBServiceBase::getFrontendInfo(int w)
1376 {
1377         eUsePtr<iDVBChannel> channel;
1378         if(m_service_handler.getChannel(channel))
1379                 return 0;
1380         ePtr<iDVBFrontend> fe;
1381         if(channel->getFrontend(fe))
1382                 return 0;
1383         return fe->readFrontendData(w);
1384 }
1385
1386 PyObject *eDVBServiceBase::getFrontendData(bool original)
1387 {
1388         PyObject *ret=0;
1389
1390         eUsePtr<iDVBChannel> channel;
1391         if(!m_service_handler.getChannel(channel))
1392         {
1393                 ePtr<iDVBFrontend> fe;
1394                 if(!channel->getFrontend(fe))
1395                 {
1396                         ret = fe->readTransponderData(original);
1397                         if (ret)
1398                         {
1399                                 ePtr<iDVBFrontendParameters> feparm;
1400                                 channel->getCurrentFrontendParameters(feparm);
1401                                 if (feparm)
1402                                 {
1403                                         eDVBFrontendParametersSatellite osat;
1404                                         if (!feparm->getDVBS(osat))
1405                                         {
1406                                                 void PutToDict(PyObject *, const char*, long);
1407                                                 void PutToDict(PyObject *, const char*, const char*);
1408                                                 PutToDict(ret, "orbital_position", osat.orbital_position);
1409                                                 const char *tmp = "UNKNOWN";
1410                                                 switch(osat.polarisation)
1411                                                 {
1412                                                         case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1413                                                         case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1414                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1415                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1416                                                         default:break;
1417                                                 }
1418                                                 PutToDict(ret, "polarization", tmp);
1419                                         }
1420                                 }
1421                         }
1422                 }
1423         }
1424         if (!ret)
1425         {
1426                 ret = Py_None;
1427                 Py_INCREF(ret);
1428         }
1429         return ret;
1430 }
1431
1432 int eDVBServicePlay::getNumberOfSubservices()
1433 {
1434         ePtr<eServiceEvent> evt;
1435         if (!m_event_handler.getEvent(evt, 0))
1436                 return evt->getNumOfLinkageServices();
1437         return 0;
1438 }
1439
1440 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1441 {
1442         ePtr<eServiceEvent> evt;
1443         if (!m_event_handler.getEvent(evt, 0))
1444         {
1445                 if (!evt->getLinkageService(sub, m_reference, n))
1446                         return 0;
1447         }
1448         sub.type=eServiceReference::idInvalid;
1449         return -1;
1450 }
1451
1452 RESULT eDVBServicePlay::startTimeshift()
1453 {
1454         ePtr<iDVBDemux> demux;
1455         
1456         eDebug("Start timeshift!");
1457         
1458         if (m_timeshift_enabled)
1459                 return -1;
1460         
1461                 /* start recording with the data demux. */
1462         if (m_service_handler.getDataDemux(demux))
1463                 return -2;
1464
1465         demux->createTSRecorder(m_record);
1466         if (!m_record)
1467                 return -3;
1468
1469         char templ[]=TSPATH "/timeshift.XXXXXX";
1470         m_timeshift_fd = mkstemp(templ);
1471         m_timeshift_file = templ;
1472         
1473         eDebug("recording to %s", templ);
1474         
1475         if (m_timeshift_fd < 0)
1476         {
1477                 m_record = 0;
1478                 return -4;
1479         }
1480                 
1481         m_record->setTargetFD(m_timeshift_fd);
1482
1483         m_timeshift_enabled = 1;
1484         
1485         updateTimeshiftPids();
1486         m_record->start();
1487
1488         return 0;
1489 }
1490
1491 RESULT eDVBServicePlay::stopTimeshift()
1492 {
1493         if (!m_timeshift_enabled)
1494                 return -1;
1495         
1496         switchToLive();
1497         
1498         m_timeshift_enabled = 0;
1499         
1500         m_record->stop();
1501         m_record = 0;
1502         
1503         close(m_timeshift_fd);
1504         eDebug("remove timeshift file");
1505         remove(m_timeshift_file.c_str());
1506         
1507         return 0;
1508 }
1509
1510 int eDVBServicePlay::isTimeshiftActive()
1511 {
1512         return m_timeshift_enabled && m_timeshift_active;
1513 }
1514
1515 RESULT eDVBServicePlay::activateTimeshift()
1516 {
1517         if (!m_timeshift_enabled)
1518                 return -1;
1519         
1520         if (!m_timeshift_active)
1521         {
1522                 switchToTimeshift();
1523                 return 0;
1524         }
1525         
1526         return -2;
1527 }
1528
1529 PyObject *eDVBServicePlay::getCutList()
1530 {
1531         PyObject *list = PyList_New(0);
1532         
1533         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1534         {
1535                 PyObject *tuple = PyTuple_New(2);
1536                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1537                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1538                 PyList_Append(list, tuple);
1539                 Py_DECREF(tuple);
1540         }
1541         
1542         return list;
1543 }
1544
1545 void eDVBServicePlay::setCutList(PyObject *list)
1546 {
1547         if (!PyList_Check(list))
1548                 return;
1549         int size = PyList_Size(list);
1550         int i;
1551         
1552         m_cue_entries.clear();
1553         
1554         for (i=0; i<size; ++i)
1555         {
1556                 PyObject *tuple = PyList_GetItem(list, i);
1557                 if (!PyTuple_Check(tuple))
1558                 {
1559                         eDebug("non-tuple in cutlist");
1560                         continue;
1561                 }
1562                 if (PyTuple_Size(tuple) != 2)
1563                 {
1564                         eDebug("cutlist entries need to be a 2-tuple");
1565                         continue;
1566                 }
1567                 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1568                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1569                 {
1570                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1571                         continue;
1572                 }
1573                 pts_t pts = PyLong_AsLongLong(ppts);
1574                 int type = PyInt_AsLong(ptype);
1575                 m_cue_entries.insert(cueEntry(pts, type));
1576                 eDebug("adding %08llx, %d", pts, type);
1577         }
1578         m_cuesheet_changed = 1;
1579         
1580         cutlistToCuesheet();
1581         m_event((iPlayableService*)this, evCuesheetChanged);
1582 }
1583
1584 void eDVBServicePlay::setCutListEnable(int enable)
1585 {
1586         m_cutlist_enabled = enable;
1587         cutlistToCuesheet();
1588 }
1589
1590 void eDVBServicePlay::updateTimeshiftPids()
1591 {
1592         if (!m_record)
1593                 return;
1594         
1595         eDVBServicePMTHandler::program program;
1596         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1597
1598         if (h.getProgramInfo(program))
1599                 return;
1600         else
1601         {
1602                 std::set<int> pids_to_record;
1603                 pids_to_record.insert(0); // PAT
1604                 if (program.pmtPid != -1)
1605                         pids_to_record.insert(program.pmtPid); // PMT
1606
1607                 if (program.textPid != -1)
1608                         pids_to_record.insert(program.textPid); // Videotext
1609
1610                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1611                         i(program.videoStreams.begin()); 
1612                         i != program.videoStreams.end(); ++i)
1613                         pids_to_record.insert(i->pid);
1614
1615                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1616                         i(program.audioStreams.begin()); 
1617                         i != program.audioStreams.end(); ++i)
1618                                 pids_to_record.insert(i->pid);
1619
1620                 std::set<int> new_pids, obsolete_pids;
1621                 
1622                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1623                                 m_pids_active.begin(), m_pids_active.end(),
1624                                 std::inserter(new_pids, new_pids.begin()));
1625                 
1626                 std::set_difference(
1627                                 m_pids_active.begin(), m_pids_active.end(),
1628                                 pids_to_record.begin(), pids_to_record.end(), 
1629                                 std::inserter(new_pids, new_pids.begin())
1630                                 );
1631
1632                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1633                         m_record->addPID(*i);
1634
1635                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1636                         m_record->removePID(*i);
1637         }
1638 }
1639
1640 void eDVBServicePlay::switchToLive()
1641 {
1642         if (!m_timeshift_active)
1643                 return;
1644         
1645         m_cue = 0;
1646         m_decoder = 0;
1647         m_decode_demux = 0;
1648         m_teletext_parser = 0;
1649         m_radiotext_parser = 0;
1650         m_subtitle_parser = 0;
1651         m_new_dvb_subtitle_page_connection = 0;
1652         m_new_subtitle_page_connection = 0;
1653         m_radiotext_updated_connection = 0;
1654
1655                 /* free the timeshift service handler, we need the resources */
1656         m_service_handler_timeshift.free();
1657         m_timeshift_active = 0;
1658
1659         m_event((iPlayableService*)this, evSeekableStatusChanged);
1660
1661         updateDecoder();
1662 }
1663
1664 void eDVBServicePlay::switchToTimeshift()
1665 {
1666         if (m_timeshift_active)
1667                 return;
1668
1669         m_decode_demux = 0;
1670         m_decoder = 0;
1671         m_teletext_parser = 0;
1672         m_radiotext_parser = 0;
1673         m_subtitle_parser = 0;
1674         m_new_subtitle_page_connection = 0;
1675         m_new_dvb_subtitle_page_connection = 0;
1676         m_radiotext_updated_connection = 0;
1677
1678         m_timeshift_active = 1;
1679
1680         m_event((iPlayableService*)this, evSeekableStatusChanged);
1681
1682         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1683         r.path = m_timeshift_file;
1684
1685         m_cue = new eCueSheet();
1686         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1687         updateDecoder(); /* mainly to switch off PCR */
1688 }
1689
1690 void eDVBServicePlay::updateDecoder()
1691 {
1692         int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
1693
1694         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1695
1696         bool defaultac3=false;
1697         std::string default_ac3;
1698
1699         if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
1700                 defaultac3 = default_ac3 == "True";
1701
1702         eDVBServicePMTHandler::program program;
1703         if (h.getProgramInfo(program))
1704                 eDebug("getting program info failed.");
1705         else
1706         {
1707                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1708                 if (!program.videoStreams.empty())
1709                 {
1710                         eDebugNoNewLine(" (");
1711                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1712                                 i(program.videoStreams.begin());
1713                                 i != program.videoStreams.end(); ++i)
1714                         {
1715                                 if (vpid == -1)
1716                                 {
1717                                         vpid = i->pid;
1718                                         vpidtype = i->type;
1719                                 }
1720                                 if (i != program.videoStreams.begin())
1721                                         eDebugNoNewLine(", ");
1722                                 eDebugNoNewLine("%04x", i->pid);
1723                         }
1724                         eDebugNoNewLine(")");
1725                 }
1726                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1727                 if (!program.audioStreams.empty())
1728                 {
1729                         eDebugNoNewLine(" (");
1730                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1731                                 i(program.audioStreams.begin());
1732                                 i != program.audioStreams.end(); ++i)
1733                         {
1734                                 if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
1735                                 {
1736                                         if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
1737                                         {
1738                                                 apid = i->pid;
1739                                                 apidtype = i->type;
1740                                         }
1741                                 }
1742                                 if (i != program.audioStreams.begin())
1743                                         eDebugNoNewLine(", ");
1744                                 eDebugNoNewLine("%04x", i->pid);
1745                         }
1746                         eDebugNoNewLine(")");
1747                 }
1748                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1749                 pcrpid = program.pcrPid;
1750                 eDebug(", and the text pid is %04x", program.textPid);
1751                 tpid = program.textPid;
1752         }
1753
1754         if (!m_decoder)
1755         {
1756                 h.getDecodeDemux(m_decode_demux);
1757                 if (m_decode_demux)
1758                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1759                 if (m_cue)
1760                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1761 #ifdef INTERNAL_TELETEXT
1762                 m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
1763                 m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
1764 #endif
1765                 m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
1766                 m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
1767         }
1768
1769         if (m_decoder)
1770         {
1771                 if (m_dvb_service)
1772                 {
1773                         achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
1774                         ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
1775                         pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
1776                 }
1777                 else // subservice or recording
1778                 {
1779                         eServiceReferenceDVB ref;
1780                         m_service_handler.getServiceReference(ref);
1781                         eServiceReferenceDVB parent = ref.getParentServiceReference();
1782                         if (!parent)
1783                                 parent = ref;
1784                         if (parent)
1785                         {
1786                                 ePtr<eDVBResourceManager> res_mgr;
1787                                 if (!eDVBResourceManager::getInstance(res_mgr))
1788                                 {
1789                                         ePtr<iDVBChannelList> db;
1790                                         if (!res_mgr->getChannelList(db))
1791                                         {
1792                                                 ePtr<eDVBService> origService;
1793                                                 if (!db->getService(parent, origService))
1794                                                 {
1795                                                         ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
1796                                                         pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
1797                                                 }
1798                                         }
1799                                 }
1800                         }
1801                 }
1802                 m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
1803                 m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
1804
1805                 m_decoder->setVideoPID(vpid, vpidtype);
1806                 m_decoder->setAudioPID(apid, apidtype);
1807                 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1808                 {
1809                         m_decoder->setSyncPCR(pcrpid);
1810                         if (apid != -1)
1811                         {
1812                                 ePtr<iDVBDemux> data_demux;
1813                                 if (!h.getDataDemux(data_demux))
1814                                 {
1815                                         m_radiotext_parser = new eDVBRadioTextParser(data_demux);
1816                                         m_radiotext_parser->connectUpdatedRadiotext(slot(*this, &eDVBServicePlay::radioTextUpdated), m_radiotext_updated_connection);
1817                                         m_radiotext_parser->start(apid);
1818                                 }
1819                         }
1820                 }
1821                 else
1822                         m_decoder->setSyncPCR(-1);
1823
1824                 m_decoder->setTextPID(tpid);
1825
1826                 if (!m_is_primary)
1827                         m_decoder->setTrickmode(1);
1828
1829                 m_decoder->start();
1830
1831                 if (vpid > 0 && vpid < 0x2000)
1832                         ;
1833                 else
1834                 {
1835                         std::string radio_pic;
1836                         if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
1837                                 m_decoder->setRadioPic(radio_pic);
1838                 }
1839
1840                 m_decoder->setAudioChannel(achannel);
1841
1842 // how we can do this better?
1843 // update cache pid when the user changed the audio track or video track
1844 // TODO handling of difference audio types.. default audio types..
1845                                 
1846                 /* don't worry about non-existing services, nor pvr services */
1847                 if (m_dvb_service && !m_is_pvr)
1848                 {
1849                         if (apidtype == eDVBAudio::aMPEG)
1850                         {
1851                                 m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1852                                 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1853                         }
1854                         else
1855                         {
1856                                 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1857                                 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1858                         }
1859                         m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
1860                         m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
1861                         m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
1862                         m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
1863                 }
1864         }
1865         m_have_video_pid = (vpid > 0 && vpid < 0x2000);
1866 }
1867
1868 void eDVBServicePlay::loadCuesheet()
1869 {
1870         std::string filename = m_reference.path + ".cuts";
1871         
1872         m_cue_entries.clear();
1873
1874         FILE *f = fopen(filename.c_str(), "rb");
1875
1876         if (f)
1877         {
1878                 eDebug("loading cuts..");
1879                 while (1)
1880                 {
1881                         unsigned long long where;
1882                         unsigned int what;
1883                         
1884                         if (!fread(&where, sizeof(where), 1, f))
1885                                 break;
1886                         if (!fread(&what, sizeof(what), 1, f))
1887                                 break;
1888                         
1889 #if BYTE_ORDER == LITTLE_ENDIAN
1890                         where = bswap_64(where);
1891 #endif
1892                         what = ntohl(what);
1893                         
1894                         if (what > 3)
1895                                 break;
1896                         
1897                         m_cue_entries.insert(cueEntry(where, what));
1898                 }
1899                 fclose(f);
1900                 eDebug("%d entries", m_cue_entries.size());
1901         } else
1902                 eDebug("cutfile not found!");
1903         
1904         m_cuesheet_changed = 0;
1905         cutlistToCuesheet();
1906         m_event((iPlayableService*)this, evCuesheetChanged);
1907 }
1908
1909 void eDVBServicePlay::saveCuesheet()
1910 {
1911         std::string filename = m_reference.path + ".cuts";
1912         
1913         FILE *f = fopen(filename.c_str(), "wb");
1914
1915         if (f)
1916         {
1917                 unsigned long long where;
1918                 int what;
1919
1920                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1921                 {
1922 #if BYTE_ORDER == BIG_ENDIAN
1923                         where = i->where;
1924 #else
1925                         where = bswap_64(i->where);
1926 #endif
1927                         what = htonl(i->what);
1928                         fwrite(&where, sizeof(where), 1, f);
1929                         fwrite(&what, sizeof(what), 1, f);
1930                         
1931                 }
1932                 fclose(f);
1933         }
1934         
1935         m_cuesheet_changed = 0;
1936 }
1937
1938 void eDVBServicePlay::cutlistToCuesheet()
1939 {
1940         if (!m_cue)
1941         {
1942                 eDebug("no cue sheet");
1943                 return;
1944         }       
1945         m_cue->clear();
1946         
1947         if (!m_cutlist_enabled)
1948         {
1949                 m_cue->commitSpans();
1950                 eDebug("cutlists were disabled");
1951                 return;
1952         }
1953
1954         pts_t in = 0, out = 0, length = 0;
1955         
1956         getLength(length);
1957                 
1958         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1959         
1960         while (1)
1961         {
1962                 if (i == m_cue_entries.end())
1963                         out = length;
1964                 else {
1965                         if (i->what == 0) /* in */
1966                         {
1967                                 in = i++->where;
1968                                 continue;
1969                         } else if (i->what == 1) /* out */
1970                                 out = i++->where;
1971                         else /* mark (2) or last play position (3) */
1972                         {
1973                                 i++;
1974                                 continue;
1975                         }
1976                 }
1977                 
1978                 if (in != out)
1979                         m_cue->addSourceSpan(in, out);
1980                 
1981                 in = length;
1982                 
1983                 if (i == m_cue_entries.end())
1984                         break;
1985         }
1986         m_cue->commitSpans();
1987 }
1988
1989 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *entry)
1990 {
1991         if (m_subtitle_widget)
1992                 disableSubtitles(parent);
1993         
1994         if (!PyInt_Check(entry))
1995                 return -1;
1996
1997         int page = PyInt_AsLong(entry);
1998
1999         if (page > 0 && !m_teletext_parser)
2000                 return -1;
2001         if (page < 0 && !m_subtitle_parser)
2002                 return -1;
2003
2004         m_subtitle_widget = new eSubtitleWidget(parent);
2005         m_subtitle_widget->resize(parent->size()); /* full size */
2006
2007         if (page > 0)
2008         {
2009                 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2010                 eDVBServicePMTHandler::program program;
2011                 if (h.getProgramInfo(program))
2012                         eDebug("getting program info failed.");
2013                 else
2014                 {
2015                         eDebug("start teletext on pid %04x, page %d", program.textPid, page);
2016                         m_teletext_parser->start(program.textPid);
2017                         m_teletext_parser->setPage(page);
2018                 }
2019         }
2020         else
2021         {
2022                 int pid = -page;
2023                 eDebug("start dvb subtitles on pid %04x", pid);
2024                 m_subtitle_parser->start(pid);
2025         }
2026
2027         return 0;
2028 }
2029
2030 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
2031 {
2032         delete m_subtitle_widget;
2033         m_subtitle_widget = 0;
2034         return 0;
2035 }
2036
2037 PyObject *eDVBServicePlay::getSubtitleList()
2038 {
2039         if (!m_teletext_parser)
2040         {
2041                 Py_INCREF(Py_None);
2042                 return Py_None;
2043         }
2044         
2045         PyObject *l = PyList_New(0);
2046         
2047         for (std::set<int>::iterator i(m_teletext_parser->m_found_subtitle_pages.begin()); i != m_teletext_parser->m_found_subtitle_pages.end(); ++i)
2048         {
2049                 PyObject *tuple = PyTuple_New(2);
2050                 char desc[20];
2051                 sprintf(desc, "Page %x", *i);
2052                 PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
2053                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(*i));
2054                 PyList_Append(l, tuple);
2055                 Py_DECREF(tuple);
2056         }
2057
2058         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2059         eDVBServicePMTHandler::program program;
2060         if (h.getProgramInfo(program))
2061                 eDebug("getting program info failed.");
2062         else
2063         {
2064                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
2065                         it != program.subtitleStreams.end(); ++it)
2066                 {
2067                         PyObject *tuple = PyTuple_New(2);
2068                         char desc[20];
2069                         sprintf(desc, "DVB %s", it->language_code.c_str());
2070                         PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
2071                         PyTuple_SetItem(tuple, 1, PyInt_FromLong(-it->pid));
2072                         PyList_Append(l, tuple);
2073                         Py_DECREF(tuple);
2074                 }
2075         }
2076
2077         return l;
2078 }
2079
2080 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2081 {
2082         if (m_subtitle_widget)
2083         {
2084                 m_subtitle_pages.push_back(page);
2085                 checkSubtitleTiming();
2086         }
2087 }
2088
2089 void eDVBServicePlay::checkSubtitleTiming()
2090 {
2091 //      eDebug("checkSubtitleTiming");
2092         while (1)
2093         {
2094                 enum { TELETEXT, DVB } type;
2095                 eDVBTeletextSubtitlePage page;
2096                 eDVBSubtitlePage dvb_page;
2097                 pts_t show_time;
2098                 if (!m_subtitle_pages.empty())
2099                 {
2100                         page = m_subtitle_pages.front();
2101                         type = TELETEXT;
2102                         show_time = page.m_pts;
2103                 }
2104                 else if (!m_dvb_subtitle_pages.empty())
2105                 {
2106                         dvb_page = m_dvb_subtitle_pages.front();
2107                         type = DVB;
2108                         show_time = dvb_page.m_show_time;
2109                 }
2110                 else
2111                         return;
2112         
2113                 pts_t pos = 0;
2114         
2115                 if (m_decoder)
2116                         m_decoder->getPTS(0, pos);
2117
2118 //              eDebug("%lld %lld", pos, show_time);
2119                 int diff =  show_time - pos;
2120                 if (diff < 0)
2121                 {
2122                         eDebug("[late (%d ms)]", -diff / 90);
2123                         diff = 0;
2124                 }
2125                 if (diff > 900000)
2126                 {
2127                         eDebug("[invalid]");
2128                         diff = 0;
2129                 }
2130         
2131                 if (!diff)
2132                 {
2133                         if (type == TELETEXT)
2134                         {
2135                                 eDebug("display teletext subtitle page");
2136                                 m_subtitle_widget->setPage(page);
2137                                 m_subtitle_pages.pop_front();
2138                         }
2139                         else
2140                         {
2141                                 eDebug("display dvb subtitle Page");
2142                                 m_subtitle_widget->setPage(dvb_page);
2143                                 m_dvb_subtitle_pages.pop_front();
2144                         }
2145                 } else
2146                 {
2147                         eDebug("start subtitle delay %d", diff / 90);
2148                         m_subtitle_sync_timer.start(diff / 90, 1);
2149                         break;
2150                 }
2151         }
2152 }
2153
2154 void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
2155 {
2156         if (m_subtitle_widget)
2157         {
2158                 m_dvb_subtitle_pages.push_back(p);
2159                 checkSubtitleTiming();
2160         }
2161 }
2162
2163 int eDVBServicePlay::getAC3Delay()
2164 {
2165         if (m_dvb_service)
2166                 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2167         else if (m_decoder)
2168                 return m_decoder->getAC3Delay();
2169         else
2170                 return 0;
2171 }
2172
2173 int eDVBServicePlay::getPCMDelay()
2174 {
2175         if (m_dvb_service)
2176                 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2177         else if (m_decoder)
2178                 return m_decoder->getPCMDelay();
2179         else
2180                 return 0;
2181 }
2182
2183 void eDVBServicePlay::setAC3Delay(int delay)
2184 {
2185         if (m_dvb_service)
2186                 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2187         if (m_decoder)
2188                 m_decoder->setAC3Delay(delay);
2189 }
2190
2191 void eDVBServicePlay::setPCMDelay(int delay)
2192 {
2193         if (m_dvb_service)
2194                 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2195         if (m_decoder)
2196                 m_decoder->setPCMDelay(delay);
2197 }
2198
2199 DEFINE_REF(eDVBServicePlay)
2200
2201 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");