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