reset cached program on audio pid change (this fixes audio pid in service
[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         h.resetCachedProgram();
1341
1342         return 0;
1343 }
1344
1345 int eDVBServicePlay::getCurrentChannel()
1346 {
1347         return m_decoder ? m_decoder->getAudioChannel() : STEREO;
1348 }
1349
1350 RESULT eDVBServicePlay::selectChannel(int i)
1351 {
1352         if (i < LEFT || i > RIGHT || i == STEREO)
1353                 i = -1;  // Stereo
1354         if (m_dvb_service)
1355                 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1356         if (m_decoder)
1357                 m_decoder->setAudioChannel(i);
1358         return 0;
1359 }
1360
1361 std::string eDVBServicePlay::getRadioText(int x)
1362 {
1363         if (m_radiotext_parser)
1364                 switch(x)
1365                 {
1366                         case 0:
1367                                 return m_radiotext_parser->getCurrentText();
1368                 }
1369         return "";
1370 }
1371
1372 void eDVBServicePlay::radioTextUpdated()
1373 {
1374         m_event((iPlayableService*)this, evUpdatedRadioText);
1375 }
1376
1377 int eDVBServiceBase::getFrontendInfo(int w)
1378 {
1379         eUsePtr<iDVBChannel> channel;
1380         if(m_service_handler.getChannel(channel))
1381                 return 0;
1382         ePtr<iDVBFrontend> fe;
1383         if(channel->getFrontend(fe))
1384                 return 0;
1385         return fe->readFrontendData(w);
1386 }
1387
1388 PyObject *eDVBServiceBase::getFrontendData(bool original)
1389 {
1390         PyObject *ret=0;
1391
1392         eUsePtr<iDVBChannel> channel;
1393         if(!m_service_handler.getChannel(channel))
1394         {
1395                 ePtr<iDVBFrontend> fe;
1396                 if(!channel->getFrontend(fe))
1397                 {
1398                         ret = fe->readTransponderData(original);
1399                         if (ret)
1400                         {
1401                                 ePtr<iDVBFrontendParameters> feparm;
1402                                 channel->getCurrentFrontendParameters(feparm);
1403                                 if (feparm)
1404                                 {
1405                                         eDVBFrontendParametersSatellite osat;
1406                                         if (!feparm->getDVBS(osat))
1407                                         {
1408                                                 void PutToDict(PyObject *, const char*, long);
1409                                                 void PutToDict(PyObject *, const char*, const char*);
1410                                                 PutToDict(ret, "orbital_position", osat.orbital_position);
1411                                                 const char *tmp = "UNKNOWN";
1412                                                 switch(osat.polarisation)
1413                                                 {
1414                                                         case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1415                                                         case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1416                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1417                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1418                                                         default:break;
1419                                                 }
1420                                                 PutToDict(ret, "polarization", tmp);
1421                                         }
1422                                 }
1423                         }
1424                 }
1425         }
1426         if (!ret)
1427         {
1428                 ret = Py_None;
1429                 Py_INCREF(ret);
1430         }
1431         return ret;
1432 }
1433
1434 int eDVBServicePlay::getNumberOfSubservices()
1435 {
1436         ePtr<eServiceEvent> evt;
1437         if (!m_event_handler.getEvent(evt, 0))
1438                 return evt->getNumOfLinkageServices();
1439         return 0;
1440 }
1441
1442 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1443 {
1444         ePtr<eServiceEvent> evt;
1445         if (!m_event_handler.getEvent(evt, 0))
1446         {
1447                 if (!evt->getLinkageService(sub, m_reference, n))
1448                         return 0;
1449         }
1450         sub.type=eServiceReference::idInvalid;
1451         return -1;
1452 }
1453
1454 RESULT eDVBServicePlay::startTimeshift()
1455 {
1456         ePtr<iDVBDemux> demux;
1457         
1458         eDebug("Start timeshift!");
1459         
1460         if (m_timeshift_enabled)
1461                 return -1;
1462         
1463                 /* start recording with the data demux. */
1464         if (m_service_handler.getDataDemux(demux))
1465                 return -2;
1466
1467         demux->createTSRecorder(m_record);
1468         if (!m_record)
1469                 return -3;
1470
1471         char templ[]=TSPATH "/timeshift.XXXXXX";
1472         m_timeshift_fd = mkstemp(templ);
1473         m_timeshift_file = templ;
1474         
1475         eDebug("recording to %s", templ);
1476         
1477         if (m_timeshift_fd < 0)
1478         {
1479                 m_record = 0;
1480                 return -4;
1481         }
1482                 
1483         m_record->setTargetFD(m_timeshift_fd);
1484
1485         m_timeshift_enabled = 1;
1486         
1487         updateTimeshiftPids();
1488         m_record->start();
1489
1490         return 0;
1491 }
1492
1493 RESULT eDVBServicePlay::stopTimeshift()
1494 {
1495         if (!m_timeshift_enabled)
1496                 return -1;
1497         
1498         switchToLive();
1499         
1500         m_timeshift_enabled = 0;
1501         
1502         m_record->stop();
1503         m_record = 0;
1504         
1505         close(m_timeshift_fd);
1506         eDebug("remove timeshift file");
1507         remove(m_timeshift_file.c_str());
1508         
1509         return 0;
1510 }
1511
1512 int eDVBServicePlay::isTimeshiftActive()
1513 {
1514         return m_timeshift_enabled && m_timeshift_active;
1515 }
1516
1517 RESULT eDVBServicePlay::activateTimeshift()
1518 {
1519         if (!m_timeshift_enabled)
1520                 return -1;
1521         
1522         if (!m_timeshift_active)
1523         {
1524                 switchToTimeshift();
1525                 return 0;
1526         }
1527         
1528         return -2;
1529 }
1530
1531 PyObject *eDVBServicePlay::getCutList()
1532 {
1533         PyObject *list = PyList_New(0);
1534         
1535         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1536         {
1537                 PyObject *tuple = PyTuple_New(2);
1538                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1539                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1540                 PyList_Append(list, tuple);
1541                 Py_DECREF(tuple);
1542         }
1543         
1544         return list;
1545 }
1546
1547 void eDVBServicePlay::setCutList(PyObject *list)
1548 {
1549         if (!PyList_Check(list))
1550                 return;
1551         int size = PyList_Size(list);
1552         int i;
1553         
1554         m_cue_entries.clear();
1555         
1556         for (i=0; i<size; ++i)
1557         {
1558                 PyObject *tuple = PyList_GetItem(list, i);
1559                 if (!PyTuple_Check(tuple))
1560                 {
1561                         eDebug("non-tuple in cutlist");
1562                         continue;
1563                 }
1564                 if (PyTuple_Size(tuple) != 2)
1565                 {
1566                         eDebug("cutlist entries need to be a 2-tuple");
1567                         continue;
1568                 }
1569                 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1570                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1571                 {
1572                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1573                         continue;
1574                 }
1575                 pts_t pts = PyLong_AsLongLong(ppts);
1576                 int type = PyInt_AsLong(ptype);
1577                 m_cue_entries.insert(cueEntry(pts, type));
1578                 eDebug("adding %08llx, %d", pts, type);
1579         }
1580         m_cuesheet_changed = 1;
1581         
1582         cutlistToCuesheet();
1583         m_event((iPlayableService*)this, evCuesheetChanged);
1584 }
1585
1586 void eDVBServicePlay::setCutListEnable(int enable)
1587 {
1588         m_cutlist_enabled = enable;
1589         cutlistToCuesheet();
1590 }
1591
1592 void eDVBServicePlay::updateTimeshiftPids()
1593 {
1594         if (!m_record)
1595                 return;
1596         
1597         eDVBServicePMTHandler::program program;
1598         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1599
1600         if (h.getProgramInfo(program))
1601                 return;
1602         else
1603         {
1604                 std::set<int> pids_to_record;
1605                 pids_to_record.insert(0); // PAT
1606                 if (program.pmtPid != -1)
1607                         pids_to_record.insert(program.pmtPid); // PMT
1608
1609                 if (program.textPid != -1)
1610                         pids_to_record.insert(program.textPid); // Videotext
1611
1612                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1613                         i(program.videoStreams.begin()); 
1614                         i != program.videoStreams.end(); ++i)
1615                         pids_to_record.insert(i->pid);
1616
1617                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1618                         i(program.audioStreams.begin()); 
1619                         i != program.audioStreams.end(); ++i)
1620                                 pids_to_record.insert(i->pid);
1621
1622                 std::set<int> new_pids, obsolete_pids;
1623                 
1624                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1625                                 m_pids_active.begin(), m_pids_active.end(),
1626                                 std::inserter(new_pids, new_pids.begin()));
1627                 
1628                 std::set_difference(
1629                                 m_pids_active.begin(), m_pids_active.end(),
1630                                 pids_to_record.begin(), pids_to_record.end(), 
1631                                 std::inserter(new_pids, new_pids.begin())
1632                                 );
1633
1634                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1635                         m_record->addPID(*i);
1636
1637                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1638                         m_record->removePID(*i);
1639         }
1640 }
1641
1642 void eDVBServicePlay::switchToLive()
1643 {
1644         if (!m_timeshift_active)
1645                 return;
1646         
1647         m_cue = 0;
1648         m_decoder = 0;
1649         m_decode_demux = 0;
1650         m_teletext_parser = 0;
1651         m_radiotext_parser = 0;
1652         m_subtitle_parser = 0;
1653         m_new_dvb_subtitle_page_connection = 0;
1654         m_new_subtitle_page_connection = 0;
1655         m_radiotext_updated_connection = 0;
1656
1657                 /* free the timeshift service handler, we need the resources */
1658         m_service_handler_timeshift.free();
1659         m_timeshift_active = 0;
1660
1661         m_event((iPlayableService*)this, evSeekableStatusChanged);
1662
1663         updateDecoder();
1664 }
1665
1666 void eDVBServicePlay::switchToTimeshift()
1667 {
1668         if (m_timeshift_active)
1669                 return;
1670
1671         m_decode_demux = 0;
1672         m_decoder = 0;
1673         m_teletext_parser = 0;
1674         m_radiotext_parser = 0;
1675         m_subtitle_parser = 0;
1676         m_new_subtitle_page_connection = 0;
1677         m_new_dvb_subtitle_page_connection = 0;
1678         m_radiotext_updated_connection = 0;
1679
1680         m_timeshift_active = 1;
1681
1682         m_event((iPlayableService*)this, evSeekableStatusChanged);
1683
1684         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1685         r.path = m_timeshift_file;
1686
1687         m_cue = new eCueSheet();
1688         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1689         updateDecoder(); /* mainly to switch off PCR */
1690 }
1691
1692 void eDVBServicePlay::updateDecoder()
1693 {
1694         int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
1695
1696         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1697
1698         bool defaultac3=false;
1699         std::string default_ac3;
1700
1701         if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
1702                 defaultac3 = default_ac3 == "True";
1703
1704         eDVBServicePMTHandler::program program;
1705         if (h.getProgramInfo(program))
1706                 eDebug("getting program info failed.");
1707         else
1708         {
1709                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1710                 if (!program.videoStreams.empty())
1711                 {
1712                         eDebugNoNewLine(" (");
1713                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1714                                 i(program.videoStreams.begin());
1715                                 i != program.videoStreams.end(); ++i)
1716                         {
1717                                 if (vpid == -1)
1718                                 {
1719                                         vpid = i->pid;
1720                                         vpidtype = i->type;
1721                                 }
1722                                 if (i != program.videoStreams.begin())
1723                                         eDebugNoNewLine(", ");
1724                                 eDebugNoNewLine("%04x", i->pid);
1725                         }
1726                         eDebugNoNewLine(")");
1727                 }
1728                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1729                 if (!program.audioStreams.empty())
1730                 {
1731                         eDebugNoNewLine(" (");
1732                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1733                                 i(program.audioStreams.begin());
1734                                 i != program.audioStreams.end(); ++i)
1735                         {
1736                                 if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
1737                                 {
1738                                         if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
1739                                         {
1740                                                 apid = i->pid;
1741                                                 apidtype = i->type;
1742                                         }
1743                                 }
1744                                 if (i != program.audioStreams.begin())
1745                                         eDebugNoNewLine(", ");
1746                                 eDebugNoNewLine("%04x", i->pid);
1747                         }
1748                         eDebugNoNewLine(")");
1749                 }
1750                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1751                 pcrpid = program.pcrPid;
1752                 eDebug(", and the text pid is %04x", program.textPid);
1753                 tpid = program.textPid;
1754         }
1755
1756         if (!m_decoder)
1757         {
1758                 h.getDecodeDemux(m_decode_demux);
1759                 if (m_decode_demux)
1760                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1761                 if (m_cue)
1762                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1763 #ifdef INTERNAL_TELETEXT
1764                 m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
1765                 m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
1766 #endif
1767                 m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
1768                 m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
1769         }
1770
1771         if (m_decoder)
1772         {
1773                 if (m_dvb_service)
1774                 {
1775                         achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
1776                         ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
1777                         pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
1778                 }
1779                 else // subservice or recording
1780                 {
1781                         eServiceReferenceDVB ref;
1782                         m_service_handler.getServiceReference(ref);
1783                         eServiceReferenceDVB parent = ref.getParentServiceReference();
1784                         if (!parent)
1785                                 parent = ref;
1786                         if (parent)
1787                         {
1788                                 ePtr<eDVBResourceManager> res_mgr;
1789                                 if (!eDVBResourceManager::getInstance(res_mgr))
1790                                 {
1791                                         ePtr<iDVBChannelList> db;
1792                                         if (!res_mgr->getChannelList(db))
1793                                         {
1794                                                 ePtr<eDVBService> origService;
1795                                                 if (!db->getService(parent, origService))
1796                                                 {
1797                                                         ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
1798                                                         pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
1799                                                 }
1800                                         }
1801                                 }
1802                         }
1803                 }
1804                 m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
1805                 m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
1806
1807                 m_decoder->setVideoPID(vpid, vpidtype);
1808                 m_decoder->setAudioPID(apid, apidtype);
1809                 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1810                 {
1811                         m_decoder->setSyncPCR(pcrpid);
1812                         if (apid != -1)
1813                         {
1814                                 ePtr<iDVBDemux> data_demux;
1815                                 if (!h.getDataDemux(data_demux))
1816                                 {
1817                                         m_radiotext_parser = new eDVBRadioTextParser(data_demux);
1818                                         m_radiotext_parser->connectUpdatedRadiotext(slot(*this, &eDVBServicePlay::radioTextUpdated), m_radiotext_updated_connection);
1819                                         m_radiotext_parser->start(apid);
1820                                 }
1821                         }
1822                 }
1823                 else
1824                         m_decoder->setSyncPCR(-1);
1825
1826                 m_decoder->setTextPID(tpid);
1827
1828                 m_teletext_parser->start(program.textPid);
1829
1830                 if (!m_is_primary)
1831                         m_decoder->setTrickmode(1);
1832
1833                 m_decoder->start();
1834
1835                 if (vpid > 0 && vpid < 0x2000)
1836                         ;
1837                 else
1838                 {
1839                         std::string radio_pic;
1840                         if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
1841                                 m_decoder->setRadioPic(radio_pic);
1842                 }
1843
1844                 m_decoder->setAudioChannel(achannel);
1845
1846 // how we can do this better?
1847 // update cache pid when the user changed the audio track or video track
1848 // TODO handling of difference audio types.. default audio types..
1849                                 
1850                 /* don't worry about non-existing services, nor pvr services */
1851                 if (m_dvb_service && !m_is_pvr)
1852                 {
1853                         if (apidtype == eDVBAudio::aMPEG)
1854                         {
1855                                 m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1856                                 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1857                         }
1858                         else
1859                         {
1860                                 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1861                                 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1862                         }
1863                         m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
1864                         m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
1865                         m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
1866                         m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
1867                 }
1868         }
1869         m_have_video_pid = (vpid > 0 && vpid < 0x2000);
1870 }
1871
1872 void eDVBServicePlay::loadCuesheet()
1873 {
1874         std::string filename = m_reference.path + ".cuts";
1875         
1876         m_cue_entries.clear();
1877
1878         FILE *f = fopen(filename.c_str(), "rb");
1879
1880         if (f)
1881         {
1882                 eDebug("loading cuts..");
1883                 while (1)
1884                 {
1885                         unsigned long long where;
1886                         unsigned int what;
1887                         
1888                         if (!fread(&where, sizeof(where), 1, f))
1889                                 break;
1890                         if (!fread(&what, sizeof(what), 1, f))
1891                                 break;
1892                         
1893 #if BYTE_ORDER == LITTLE_ENDIAN
1894                         where = bswap_64(where);
1895 #endif
1896                         what = ntohl(what);
1897                         
1898                         if (what > 3)
1899                                 break;
1900                         
1901                         m_cue_entries.insert(cueEntry(where, what));
1902                 }
1903                 fclose(f);
1904                 eDebug("%d entries", m_cue_entries.size());
1905         } else
1906                 eDebug("cutfile not found!");
1907         
1908         m_cuesheet_changed = 0;
1909         cutlistToCuesheet();
1910         m_event((iPlayableService*)this, evCuesheetChanged);
1911 }
1912
1913 void eDVBServicePlay::saveCuesheet()
1914 {
1915         std::string filename = m_reference.path + ".cuts";
1916         
1917         FILE *f = fopen(filename.c_str(), "wb");
1918
1919         if (f)
1920         {
1921                 unsigned long long where;
1922                 int what;
1923
1924                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1925                 {
1926 #if BYTE_ORDER == BIG_ENDIAN
1927                         where = i->where;
1928 #else
1929                         where = bswap_64(i->where);
1930 #endif
1931                         what = htonl(i->what);
1932                         fwrite(&where, sizeof(where), 1, f);
1933                         fwrite(&what, sizeof(what), 1, f);
1934                         
1935                 }
1936                 fclose(f);
1937         }
1938         
1939         m_cuesheet_changed = 0;
1940 }
1941
1942 void eDVBServicePlay::cutlistToCuesheet()
1943 {
1944         if (!m_cue)
1945         {
1946                 eDebug("no cue sheet");
1947                 return;
1948         }       
1949         m_cue->clear();
1950         
1951         if (!m_cutlist_enabled)
1952         {
1953                 m_cue->commitSpans();
1954                 eDebug("cutlists were disabled");
1955                 return;
1956         }
1957
1958         pts_t in = 0, out = 0, length = 0;
1959         
1960         getLength(length);
1961                 
1962         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1963         
1964         while (1)
1965         {
1966                 if (i == m_cue_entries.end())
1967                         out = length;
1968                 else {
1969                         if (i->what == 0) /* in */
1970                         {
1971                                 in = i++->where;
1972                                 continue;
1973                         } else if (i->what == 1) /* out */
1974                                 out = i++->where;
1975                         else /* mark (2) or last play position (3) */
1976                         {
1977                                 i++;
1978                                 continue;
1979                         }
1980                 }
1981                 
1982                 if (in != out)
1983                         m_cue->addSourceSpan(in, out);
1984                 
1985                 in = length;
1986                 
1987                 if (i == m_cue_entries.end())
1988                         break;
1989         }
1990         m_cue->commitSpans();
1991 }
1992
1993 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *entry)
1994 {
1995         if (m_subtitle_widget)
1996                 disableSubtitles(parent);
1997         
1998         if (!PyInt_Check(entry))
1999                 return -1;
2000
2001         int page = PyInt_AsLong(entry);
2002
2003         if (page > 0 && !m_teletext_parser)
2004                 return -1;
2005         if (page < 0 && !m_subtitle_parser)
2006                 return -1;
2007
2008         m_subtitle_widget = new eSubtitleWidget(parent);
2009         m_subtitle_widget->resize(parent->size()); /* full size */
2010
2011         if (page > 0)
2012         {
2013 /*              eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2014                 eDVBServicePMTHandler::program program;
2015                 if (h.getProgramInfo(program))
2016                         eDebug("getting program info failed.");
2017                 else
2018                 {
2019                         eDebug("start teletext on pid %04x, page %d", program.textPid, page);
2020                         m_teletext_parser->start(program.textPid);*/
2021                         m_teletext_parser->setPage(page);
2022 //              }
2023         }
2024         else
2025         {
2026                 int pid = -page;
2027                 m_subtitle_parser->start(pid);
2028         }
2029
2030         return 0;
2031 }
2032
2033 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
2034 {
2035         delete m_subtitle_widget;
2036         m_subtitle_widget = 0;
2037         if (m_subtitle_parser)
2038         {
2039                 m_subtitle_parser->stop();
2040                 m_dvb_subtitle_pages.clear();
2041         }
2042         if (m_teletext_parser)
2043         {
2044                 m_teletext_parser->setPage(-1);
2045                 m_subtitle_pages.clear();
2046         }
2047         return 0;
2048 }
2049
2050 PyObject *eDVBServicePlay::getSubtitleList()
2051 {
2052         if (!m_teletext_parser)
2053         {
2054                 Py_INCREF(Py_None);
2055                 return Py_None;
2056         }
2057         
2058         PyObject *l = PyList_New(0);
2059         
2060         for (std::set<int>::iterator i(m_teletext_parser->m_found_subtitle_pages.begin()); i != m_teletext_parser->m_found_subtitle_pages.end(); ++i)
2061         {
2062                 PyObject *tuple = PyTuple_New(2);
2063                 char desc[20];
2064                 sprintf(desc, "Page %x", *i);
2065                 PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
2066                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(*i));
2067                 PyList_Append(l, tuple);
2068                 Py_DECREF(tuple);
2069         }
2070
2071         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2072         eDVBServicePMTHandler::program program;
2073         if (h.getProgramInfo(program))
2074                 eDebug("getting program info failed.");
2075         else
2076         {
2077                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
2078                         it != program.subtitleStreams.end(); ++it)
2079                 {
2080                         PyObject *tuple = PyTuple_New(2);
2081                         char desc[20];
2082                         sprintf(desc, "DVB %s", it->language_code.c_str());
2083                         PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
2084                         PyTuple_SetItem(tuple, 1, PyInt_FromLong(-it->pid));
2085                         PyList_Append(l, tuple);
2086                         Py_DECREF(tuple);
2087                 }
2088         }
2089
2090         return l;
2091 }
2092
2093 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2094 {
2095         if (m_subtitle_widget)
2096         {
2097                 m_subtitle_pages.push_back(page);
2098                 checkSubtitleTiming();
2099         }
2100 }
2101
2102 void eDVBServicePlay::checkSubtitleTiming()
2103 {
2104 //      eDebug("checkSubtitleTiming");
2105         if (!m_subtitle_widget)
2106                 return;
2107         while (1)
2108         {
2109                 enum { TELETEXT, DVB } type;
2110                 eDVBTeletextSubtitlePage page;
2111                 eDVBSubtitlePage dvb_page;
2112                 pts_t show_time;
2113                 if (!m_subtitle_pages.empty())
2114                 {
2115                         page = m_subtitle_pages.front();
2116                         type = TELETEXT;
2117                         show_time = page.m_pts;
2118                 }
2119                 else if (!m_dvb_subtitle_pages.empty())
2120                 {
2121                         dvb_page = m_dvb_subtitle_pages.front();
2122                         type = DVB;
2123                         show_time = dvb_page.m_show_time;
2124                 }
2125                 else
2126                         return;
2127         
2128                 pts_t pos = 0;
2129         
2130                 if (m_decoder)
2131                         m_decoder->getPTS(0, pos);
2132
2133 //              eDebug("%lld %lld", pos, show_time);
2134                 int diff =  show_time - pos;
2135                 if (diff < 0)
2136                 {
2137                         eDebug("[late (%d ms)]", -diff / 90);
2138                         diff = 0;
2139                 }
2140                 if (diff > 900000)
2141                 {
2142                         eDebug("[invalid]");
2143                         diff = 0;
2144                 }
2145         
2146                 if (!diff)
2147                 {
2148                         if (type == TELETEXT)
2149                         {
2150                                 eDebug("display teletext subtitle page");
2151                                 m_subtitle_widget->setPage(page);
2152                                 m_subtitle_pages.pop_front();
2153                         }
2154                         else
2155                         {
2156                                 eDebug("display dvb subtitle Page");
2157                                 m_subtitle_widget->setPage(dvb_page);
2158                                 m_dvb_subtitle_pages.pop_front();
2159                         }
2160                 } else
2161                 {
2162                         eDebug("start subtitle delay %d", diff / 90);
2163                         m_subtitle_sync_timer.start(diff / 90, 1);
2164                         break;
2165                 }
2166         }
2167 }
2168
2169 void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
2170 {
2171         if (m_subtitle_widget)
2172         {
2173                 m_dvb_subtitle_pages.push_back(p);
2174                 checkSubtitleTiming();
2175         }
2176 }
2177
2178 int eDVBServicePlay::getAC3Delay()
2179 {
2180         if (m_dvb_service)
2181                 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2182         else if (m_decoder)
2183                 return m_decoder->getAC3Delay();
2184         else
2185                 return 0;
2186 }
2187
2188 int eDVBServicePlay::getPCMDelay()
2189 {
2190         if (m_dvb_service)
2191                 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2192         else if (m_decoder)
2193                 return m_decoder->getPCMDelay();
2194         else
2195                 return 0;
2196 }
2197
2198 void eDVBServicePlay::setAC3Delay(int delay)
2199 {
2200         if (m_dvb_service)
2201                 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2202         if (m_decoder)
2203                 m_decoder->setAC3Delay(delay);
2204 }
2205
2206 void eDVBServicePlay::setPCMDelay(int delay)
2207 {
2208         if (m_dvb_service)
2209                 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2210         if (m_decoder)
2211                 m_decoder->setPCMDelay(delay);
2212 }
2213
2214 DEFINE_REF(eDVBServicePlay)
2215
2216 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");