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