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