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