89301de471f25fbaddbdeadc1ecc5d7536f4e9a2
[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/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                 m_teletext_parser->start(program.textPid);
1827
1828                 if (!m_is_primary)
1829                         m_decoder->setTrickmode(1);
1830
1831                 m_decoder->start();
1832
1833                 if (vpid > 0 && vpid < 0x2000)
1834                         ;
1835                 else
1836                 {
1837                         std::string radio_pic;
1838                         if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
1839                                 m_decoder->setRadioPic(radio_pic);
1840                 }
1841
1842                 m_decoder->setAudioChannel(achannel);
1843
1844 // how we can do this better?
1845 // update cache pid when the user changed the audio track or video track
1846 // TODO handling of difference audio types.. default audio types..
1847                                 
1848                 /* don't worry about non-existing services, nor pvr services */
1849                 if (m_dvb_service && !m_is_pvr)
1850                 {
1851                         if (apidtype == eDVBAudio::aMPEG)
1852                         {
1853                                 m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1854                                 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1855                         }
1856                         else
1857                         {
1858                                 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1859                                 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1860                         }
1861                         m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
1862                         m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
1863                         m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
1864                         m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
1865                 }
1866         }
1867         m_have_video_pid = (vpid > 0 && vpid < 0x2000);
1868 }
1869
1870 void eDVBServicePlay::loadCuesheet()
1871 {
1872         std::string filename = m_reference.path + ".cuts";
1873         
1874         m_cue_entries.clear();
1875
1876         FILE *f = fopen(filename.c_str(), "rb");
1877
1878         if (f)
1879         {
1880                 eDebug("loading cuts..");
1881                 while (1)
1882                 {
1883                         unsigned long long where;
1884                         unsigned int what;
1885                         
1886                         if (!fread(&where, sizeof(where), 1, f))
1887                                 break;
1888                         if (!fread(&what, sizeof(what), 1, f))
1889                                 break;
1890                         
1891 #if BYTE_ORDER == LITTLE_ENDIAN
1892                         where = bswap_64(where);
1893 #endif
1894                         what = ntohl(what);
1895                         
1896                         if (what > 3)
1897                                 break;
1898                         
1899                         m_cue_entries.insert(cueEntry(where, what));
1900                 }
1901                 fclose(f);
1902                 eDebug("%d entries", m_cue_entries.size());
1903         } else
1904                 eDebug("cutfile not found!");
1905         
1906         m_cuesheet_changed = 0;
1907         cutlistToCuesheet();
1908         m_event((iPlayableService*)this, evCuesheetChanged);
1909 }
1910
1911 void eDVBServicePlay::saveCuesheet()
1912 {
1913         std::string filename = m_reference.path + ".cuts";
1914         
1915         FILE *f = fopen(filename.c_str(), "wb");
1916
1917         if (f)
1918         {
1919                 unsigned long long where;
1920                 int what;
1921
1922                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1923                 {
1924 #if BYTE_ORDER == BIG_ENDIAN
1925                         where = i->where;
1926 #else
1927                         where = bswap_64(i->where);
1928 #endif
1929                         what = htonl(i->what);
1930                         fwrite(&where, sizeof(where), 1, f);
1931                         fwrite(&what, sizeof(what), 1, f);
1932                         
1933                 }
1934                 fclose(f);
1935         }
1936         
1937         m_cuesheet_changed = 0;
1938 }
1939
1940 void eDVBServicePlay::cutlistToCuesheet()
1941 {
1942         if (!m_cue)
1943         {
1944                 eDebug("no cue sheet");
1945                 return;
1946         }       
1947         m_cue->clear();
1948         
1949         if (!m_cutlist_enabled)
1950         {
1951                 m_cue->commitSpans();
1952                 eDebug("cutlists were disabled");
1953                 return;
1954         }
1955
1956         pts_t in = 0, out = 0, length = 0;
1957         
1958         getLength(length);
1959                 
1960         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1961         
1962         while (1)
1963         {
1964                 if (i == m_cue_entries.end())
1965                         out = length;
1966                 else {
1967                         if (i->what == 0) /* in */
1968                         {
1969                                 in = i++->where;
1970                                 continue;
1971                         } else if (i->what == 1) /* out */
1972                                 out = i++->where;
1973                         else /* mark (2) or last play position (3) */
1974                         {
1975                                 i++;
1976                                 continue;
1977                         }
1978                 }
1979                 
1980                 if (in != out)
1981                         m_cue->addSourceSpan(in, out);
1982                 
1983                 in = length;
1984                 
1985                 if (i == m_cue_entries.end())
1986                         break;
1987         }
1988         m_cue->commitSpans();
1989 }
1990
1991 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *entry)
1992 {
1993         if (m_subtitle_widget)
1994                 disableSubtitles(parent);
1995         
1996         if (!PyInt_Check(entry))
1997                 return -1;
1998
1999         int page = PyInt_AsLong(entry);
2000
2001         if (page > 0 && !m_teletext_parser)
2002                 return -1;
2003         if (page < 0 && !m_subtitle_parser)
2004                 return -1;
2005
2006         m_subtitle_widget = new eSubtitleWidget(parent);
2007         m_subtitle_widget->resize(parent->size()); /* full size */
2008
2009         if (page > 0)
2010         {
2011 /*              eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2012                 eDVBServicePMTHandler::program program;
2013                 if (h.getProgramInfo(program))
2014                         eDebug("getting program info failed.");
2015                 else
2016                 {
2017                         eDebug("start teletext on pid %04x, page %d", program.textPid, page);
2018                         m_teletext_parser->start(program.textPid);*/
2019                         m_teletext_parser->setPage(page);
2020 //              }
2021         }
2022         else
2023         {
2024                 int pid = -page;
2025                 eDebug("start dvb subtitles on pid %04x", pid);
2026                 m_subtitle_parser->start(pid);
2027         }
2028
2029         return 0;
2030 }
2031
2032 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
2033 {
2034         delete m_subtitle_widget;
2035         m_subtitle_widget = 0;
2036         return 0;
2037 }
2038
2039 PyObject *eDVBServicePlay::getSubtitleList()
2040 {
2041         if (!m_teletext_parser)
2042         {
2043                 Py_INCREF(Py_None);
2044                 return Py_None;
2045         }
2046         
2047         PyObject *l = PyList_New(0);
2048         
2049         for (std::set<int>::iterator i(m_teletext_parser->m_found_subtitle_pages.begin()); i != m_teletext_parser->m_found_subtitle_pages.end(); ++i)
2050         {
2051                 PyObject *tuple = PyTuple_New(2);
2052                 char desc[20];
2053                 sprintf(desc, "Page %x", *i);
2054                 PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
2055                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(*i));
2056                 PyList_Append(l, tuple);
2057                 Py_DECREF(tuple);
2058         }
2059
2060         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2061         eDVBServicePMTHandler::program program;
2062         if (h.getProgramInfo(program))
2063                 eDebug("getting program info failed.");
2064         else
2065         {
2066                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
2067                         it != program.subtitleStreams.end(); ++it)
2068                 {
2069                         PyObject *tuple = PyTuple_New(2);
2070                         char desc[20];
2071                         sprintf(desc, "DVB %s", it->language_code.c_str());
2072                         PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
2073                         PyTuple_SetItem(tuple, 1, PyInt_FromLong(-it->pid));
2074                         PyList_Append(l, tuple);
2075                         Py_DECREF(tuple);
2076                 }
2077         }
2078
2079         return l;
2080 }
2081
2082 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2083 {
2084         if (m_subtitle_widget)
2085         {
2086                 m_subtitle_pages.push_back(page);
2087                 checkSubtitleTiming();
2088         }
2089 }
2090
2091 void eDVBServicePlay::checkSubtitleTiming()
2092 {
2093 //      eDebug("checkSubtitleTiming");
2094         while (1)
2095         {
2096                 enum { TELETEXT, DVB } type;
2097                 eDVBTeletextSubtitlePage page;
2098                 eDVBSubtitlePage dvb_page;
2099                 pts_t show_time;
2100                 if (!m_subtitle_pages.empty())
2101                 {
2102                         page = m_subtitle_pages.front();
2103                         type = TELETEXT;
2104                         show_time = page.m_pts;
2105                 }
2106                 else if (!m_dvb_subtitle_pages.empty())
2107                 {
2108                         dvb_page = m_dvb_subtitle_pages.front();
2109                         type = DVB;
2110                         show_time = dvb_page.m_show_time;
2111                 }
2112                 else
2113                         return;
2114         
2115                 pts_t pos = 0;
2116         
2117                 if (m_decoder)
2118                         m_decoder->getPTS(0, pos);
2119
2120 //              eDebug("%lld %lld", pos, show_time);
2121                 int diff =  show_time - pos;
2122                 if (diff < 0)
2123                 {
2124                         eDebug("[late (%d ms)]", -diff / 90);
2125                         diff = 0;
2126                 }
2127                 if (diff > 900000)
2128                 {
2129                         eDebug("[invalid]");
2130                         diff = 0;
2131                 }
2132         
2133                 if (!diff)
2134                 {
2135                         if (type == TELETEXT)
2136                         {
2137                                 eDebug("display teletext subtitle page");
2138                                 m_subtitle_widget->setPage(page);
2139                                 m_subtitle_pages.pop_front();
2140                         }
2141                         else
2142                         {
2143                                 eDebug("display dvb subtitle Page");
2144                                 m_subtitle_widget->setPage(dvb_page);
2145                                 m_dvb_subtitle_pages.pop_front();
2146                         }
2147                 } else
2148                 {
2149                         eDebug("start subtitle delay %d", diff / 90);
2150                         m_subtitle_sync_timer.start(diff / 90, 1);
2151                         break;
2152                 }
2153         }
2154 }
2155
2156 void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
2157 {
2158         if (m_subtitle_widget)
2159         {
2160                 m_dvb_subtitle_pages.push_back(p);
2161                 checkSubtitleTiming();
2162         }
2163 }
2164
2165 int eDVBServicePlay::getAC3Delay()
2166 {
2167         if (m_dvb_service)
2168                 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2169         else if (m_decoder)
2170                 return m_decoder->getAC3Delay();
2171         else
2172                 return 0;
2173 }
2174
2175 int eDVBServicePlay::getPCMDelay()
2176 {
2177         if (m_dvb_service)
2178                 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2179         else if (m_decoder)
2180                 return m_decoder->getPCMDelay();
2181         else
2182                 return 0;
2183 }
2184
2185 void eDVBServicePlay::setAC3Delay(int delay)
2186 {
2187         if (m_dvb_service)
2188                 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2189         if (m_decoder)
2190                 m_decoder->setAC3Delay(delay);
2191 }
2192
2193 void eDVBServicePlay::setPCMDelay(int delay)
2194 {
2195         if (m_dvb_service)
2196                 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2197         if (m_decoder)
2198                 m_decoder->setPCMDelay(delay);
2199 }
2200
2201 DEFINE_REF(eDVBServicePlay)
2202
2203 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");