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