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