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