add support http ts stream.(client)
[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         }
1065 }
1066
1067 void eDVBServicePlay::serviceEventTimeshift(int event)
1068 {
1069         switch (event)
1070         {
1071         case eDVBServicePMTHandler::eventNewProgramInfo:
1072                 eDebug("eventNewProgramInfo TS");
1073                 if (m_timeshift_active)
1074                 {
1075                         updateDecoder();
1076                         if (m_first_program_info & 2)
1077                         {
1078                                 if (m_slowmotion)
1079                                 {
1080                                         eDebug("re-apply slowmotion after timeshift file change");
1081                                         m_decoder->setSlowMotion(m_slowmotion);
1082                                 }
1083                                 if (m_fastforward)
1084                                 {
1085                                         eDebug("re-apply skip %d, ratio %d after timeshift file change", m_skipmode, m_fastforward);
1086                                         if (m_skipmode)
1087                                                 m_cue->setSkipmode(m_skipmode * 90000); /* convert to 90000 per second */
1088                                         if (m_fastforward != 1)
1089                                                 m_decoder->setFastForward(m_fastforward);
1090                                         else
1091                                                 m_decoder->setTrickmode();
1092                                 }
1093                                 else
1094                                         seekTo(0);
1095                                 m_first_program_info &= ~2;
1096                         }
1097                         m_event((iPlayableService*)this, evUpdatedInfo);
1098                 }
1099                 break;
1100         case eDVBServicePMTHandler::eventSOF:
1101 #if 0
1102                 if (!m_timeshift_file_next.empty())
1103                 {
1104                         eDebug("timeshift SOF, switch to next file");
1105                         m_decoder->pause();
1106
1107                         m_first_program_info |= 2;
1108
1109                         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1110                         r.path = m_timeshift_file_next;
1111
1112                         /* free the timeshift service handler, we need the resources */
1113                         m_service_handler_timeshift.free();
1114                         resetTimeshift(1);
1115
1116                         if (m_skipmode < 0)
1117                                 m_cue->seekTo(0, -1000);
1118                         ePtr<iTsSource> source = createTsSource(r);
1119                         m_service_handler_timeshift.tuneExt(r, 1, source, r.path.c_str(), m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
1120
1121                         m_event((iPlayableService*)this, evUser+1);
1122                 }
1123                 else
1124 #endif
1125                         m_event((iPlayableService*)this, evSOF);
1126                 break;
1127         case eDVBServicePMTHandler::eventEOF:
1128                 if ((!m_is_paused) && (m_skipmode >= 0))
1129                 {
1130                         if (m_timeshift_file_next.empty())
1131                         {
1132                                 eDebug("timeshift EOF, so let's go live");
1133                                 switchToLive();
1134                         }
1135                         else
1136                         {
1137                                 eDebug("timeshift EOF, switch to next file");
1138
1139                                 m_first_program_info |= 2;
1140
1141                                 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1142                                 r.path = m_timeshift_file_next;
1143
1144                                 /* free the timeshift service handler, we need the resources */
1145                                 m_service_handler_timeshift.free();
1146                                 resetTimeshift(1);
1147
1148                                 ePtr<iTsSource> source = createTsSource(r);
1149                                 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 */
1150
1151                                 m_event((iPlayableService*)this, evUser+1);
1152                         }
1153                 }
1154                 break;
1155         }
1156 }
1157
1158 RESULT eDVBServicePlay::start()
1159 {
1160         eServiceReferenceDVB service = (eServiceReferenceDVB&)m_reference;
1161
1162                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
1163                    two (one for decoding, one for data source), as we must be prepared
1164                    to start recording from the data demux. */
1165         if (m_is_pvr)
1166         {
1167                 eDVBMetaParser meta;
1168                 if (!meta.parseFile(m_reference.path))
1169                 {
1170                         service = meta.m_ref;
1171                         service.path = m_reference.path;
1172                 }
1173                 m_cue = new eCueSheet();
1174         }
1175         else
1176                 m_event(this, evStart);
1177
1178         m_first_program_info = 1;
1179         ePtr<iTsSource> source = createTsSource(service);
1180         m_service_handler.tuneExt(service, m_is_pvr, source, service.path.c_str(), m_cue, false, m_dvb_service, m_is_stream);
1181
1182         if (m_is_pvr)
1183         {
1184                 /* inject EIT if there is a stored one */
1185                 std::string filename = service.path;
1186                 filename.erase(filename.length()-2, 2);
1187                 filename+="eit";
1188                 ePtr<eServiceEvent> event = new eServiceEvent;
1189                 if (!event->parseFrom(filename, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get()))
1190                 {
1191                         ePtr<eServiceEvent> empty;
1192                         m_event_handler.inject(event, 0);
1193                         m_event_handler.inject(empty, 1);
1194                 }
1195                 m_event(this, evStart);
1196         }
1197         return 0;
1198 }
1199
1200 RESULT eDVBServicePlay::stop()
1201 {
1202                 /* add bookmark for last play position */
1203         if (m_is_pvr)
1204         {
1205                 pts_t play_position, length;
1206                 if (!getPlayPosition(play_position))
1207                 {
1208                                 /* remove last position */
1209                         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end();)
1210                         {
1211                                 if (i->what == 3) /* current play position */
1212                                 {
1213                                         m_cue_entries.erase(i);
1214                                         i = m_cue_entries.begin();
1215                                         continue;
1216                                 } else
1217                                         ++i;
1218                         }
1219                         
1220                         if (getLength(length))
1221                                 length = 0;
1222                         
1223                         if (length)
1224                         {
1225                                 m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
1226                         }
1227                         m_cuesheet_changed = 1;
1228                 }
1229         }
1230
1231         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
1232
1233         m_service_handler_timeshift.free();
1234         m_service_handler.free();
1235         
1236         if (m_is_pvr && m_cuesheet_changed)
1237         {
1238                 struct stat s;
1239                                 /* save cuesheet only when main file is accessible. */
1240                 if (!::stat(m_reference.path.c_str(), &s))
1241                         saveCuesheet();
1242         }
1243         m_event((iPlayableService*)this, evStopped);
1244         return 0;
1245 }
1246
1247 RESULT eDVBServicePlay::setTarget(int target)
1248 {
1249         m_is_primary = !target;
1250         return 0;
1251 }
1252
1253 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
1254 {
1255         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
1256         return 0;
1257 }
1258
1259 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
1260 {
1261                 /* note: we check for timeshift to be enabled,
1262                    not neccessary active. if you pause when timeshift
1263                    is not active, you should activate it when unpausing */
1264         if ((!m_is_pvr) && (!m_timeshift_enabled))
1265         {
1266                 ptr = 0;
1267                 return -1;
1268         }
1269
1270         ptr = this;
1271         return 0;
1272 }
1273
1274 RESULT eDVBServicePlay::setSlowMotion(int ratio)
1275 {
1276         ASSERT(ratio); /* The API changed: instead of calling setSlowMotion(0), call play! */
1277         eDebug("eDVBServicePlay::setSlowMotion(%d)", ratio);
1278         setFastForward_internal(0);
1279         if (m_decoder)
1280         {
1281                 m_slowmotion = ratio;
1282                 return m_decoder->setSlowMotion(ratio);
1283         }
1284         else
1285                 return -1;
1286 }
1287
1288 RESULT eDVBServicePlay::setFastForward(int ratio)
1289 {
1290         eDebug("eDVBServicePlay::setFastForward(%d)", ratio);
1291         ASSERT(ratio);
1292         return setFastForward_internal(ratio);
1293 }
1294
1295 RESULT eDVBServicePlay::setFastForward_internal(int ratio, bool final_seek)
1296 {
1297         int skipmode, ffratio, ret = 0;
1298         pts_t pos=0;
1299
1300         if (ratio > 8)
1301         {
1302                 skipmode = ratio;
1303                 ffratio = 1;
1304         } else if (ratio > 0)
1305         {
1306                 skipmode = 0;
1307                 ffratio = ratio;
1308         } else if (!ratio)
1309         {
1310                 skipmode = 0;
1311                 ffratio = 0;
1312         } else // if (ratio < 0)
1313         {
1314                 skipmode = ratio;
1315                 ffratio = 1;
1316         }
1317
1318         if (m_skipmode != skipmode)
1319         {
1320                 eDebug("setting cue skipmode to %d", skipmode);
1321                 if (m_cue)
1322                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
1323         }
1324
1325         m_skipmode = skipmode;
1326
1327         if (final_seek)
1328                 eDebug("trickplay stopped .. ret %d, pos %lld", getPlayPosition(pos), pos);
1329
1330         m_fastforward = ffratio;
1331
1332         if (!m_decoder)
1333                 return -1;
1334
1335         if (ffratio == 0)
1336                 ; /* return m_decoder->play(); is done in caller*/
1337         else if (ffratio != 1)
1338                 ret = m_decoder->setFastForward(ffratio);
1339         else
1340                 ret = m_decoder->setTrickmode();
1341
1342         if (pos)
1343                 eDebug("final seek after trickplay ret %d", seekTo(pos));
1344
1345         return ret;
1346 }
1347
1348 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
1349 {
1350         if (m_is_pvr || m_timeshift_enabled)
1351         {
1352                 ptr = this;
1353                 return 0;
1354         }
1355         
1356         ptr = 0;
1357         return -1;
1358 }
1359
1360         /* TODO: when timeshift is enabled but not active, this doesn't work. */
1361 RESULT eDVBServicePlay::getLength(pts_t &len)
1362 {
1363         ePtr<iDVBPVRChannel> pvr_channel;
1364         
1365         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1366                 return -1;
1367         
1368         return pvr_channel->getLength(len);
1369 }
1370
1371 RESULT eDVBServicePlay::pause()
1372 {
1373         eDebug("eDVBServicePlay::pause");
1374         setFastForward_internal(0, m_slowmotion || m_fastforward > 1);
1375         if (m_decoder)
1376         {
1377                 m_slowmotion = 0;
1378                 m_is_paused = 1;
1379                 return m_decoder->pause();
1380         } else
1381                 return -1;
1382 }
1383
1384 RESULT eDVBServicePlay::unpause()
1385 {
1386         eDebug("eDVBServicePlay::unpause");
1387         setFastForward_internal(0, m_slowmotion || m_fastforward > 1);
1388         if (m_decoder)
1389         {
1390                 m_slowmotion = 0;
1391                 m_is_paused = 0;
1392                 return m_decoder->play();
1393         } else
1394                 return -1;
1395 }
1396
1397 RESULT eDVBServicePlay::seekTo(pts_t to)
1398 {
1399         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
1400         
1401         if (!m_decode_demux)
1402                 return -1;
1403
1404         ePtr<iDVBPVRChannel> pvr_channel;
1405         
1406         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1407                 return -1;
1408         
1409         if (!m_cue)
1410                 return -1;
1411         
1412         m_cue->seekTo(0, to);
1413         m_dvb_subtitle_pages.clear();
1414         m_subtitle_pages.clear();
1415
1416         return 0;
1417 }
1418
1419 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
1420 {
1421         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
1422         
1423         if (!m_decode_demux)
1424                 return -1;
1425
1426         ePtr<iDVBPVRChannel> pvr_channel;
1427         
1428         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1429                 return -1;
1430         
1431         int mode = 1;
1432         
1433                         /* HACK until we have skip-AP api */
1434         if ((to > 0) && (to < 100))
1435                 mode = 2;
1436         
1437         to *= direction;
1438         
1439         if (!m_cue)
1440                 return 0;
1441         
1442         m_cue->seekTo(mode, to);
1443         m_dvb_subtitle_pages.clear();
1444         m_subtitle_pages.clear();
1445         return 0;
1446 }
1447
1448 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
1449 {
1450         ePtr<iDVBPVRChannel> pvr_channel;
1451         
1452         if (!m_decode_demux)
1453                 return -1;
1454         
1455         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1456                 return -1;
1457         
1458         int r = 0;
1459
1460                 /* if there is a decoder, use audio or video PTS */
1461         if (m_decoder)
1462         {
1463                 r = m_decoder->getPTS(0, pos);
1464                 if (r)
1465                         return r;
1466         }
1467         
1468                 /* fixup */
1469         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
1470 }
1471
1472 RESULT eDVBServicePlay::setTrickmode(int trick)
1473 {
1474                 /* currently unimplemented */
1475         return -1;
1476 }
1477
1478 RESULT eDVBServicePlay::isCurrentlySeekable()
1479 {
1480         int ret = 0;
1481         if (m_decoder)
1482         {
1483                 ret = (m_is_pvr || m_timeshift_active) ? 3 : 0; // fast forward/backward possible and seeking possible
1484                 if (m_decoder->getVideoProgressive() == -1)
1485                         ret &= ~2;
1486         }
1487         return ret;
1488 }
1489
1490 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
1491 {
1492         ptr = this;
1493         return 0;
1494 }
1495
1496 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
1497 {
1498         ptr = this;
1499         return 0;
1500 }
1501
1502 RESULT eDVBServicePlay::audioChannel(ePtr<iAudioChannelSelection> &ptr)
1503 {
1504         ptr = this;
1505         return 0;
1506 }
1507
1508 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1509 {
1510         ptr = this;
1511         return 0;
1512 }
1513
1514 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1515 {
1516         ptr = this;
1517         return 0;
1518 }
1519
1520 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1521 {
1522         ptr = 0;
1523         if (m_have_video_pid &&  // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
1524                 (m_timeshift_enabled || !m_is_pvr))
1525         {
1526                 if (!m_timeshift_enabled)
1527                 {
1528                         /* query config path */
1529                         std::string tspath;
1530                         if(ePythonConfigQuery::getConfigValue("config.usage.timeshift_path", tspath) == -1){
1531                                 eDebug("could not query ts path from config");
1532                                 return -4;
1533                         }
1534                         tspath.append("/");
1535                         /* we need enough diskspace */
1536                         struct statfs fs;
1537                         if (statfs(tspath.c_str(), &fs) < 0)
1538                         {
1539                                 eDebug("statfs failed!");
1540                                 return -2;
1541                         }
1542                 
1543                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1544                         {
1545                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1546                                 return -3;
1547                         }
1548                 }
1549                 ptr = this;
1550                 return 0;
1551         }
1552         return -1;
1553 }
1554
1555 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1556 {
1557         if (m_is_pvr)
1558         {
1559                 ptr = this;
1560                 return 0;
1561         }
1562         ptr = 0;
1563         return -1;
1564 }
1565
1566 RESULT eDVBServicePlay::subtitle(ePtr<iSubtitleOutput> &ptr)
1567 {
1568         ptr = this;
1569         return 0;
1570 }
1571
1572 RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
1573 {
1574         ptr = this;
1575         return 0;
1576 }
1577
1578 RESULT eDVBServicePlay::rdsDecoder(ePtr<iRdsDecoder> &ptr)
1579 {
1580         ptr = this;
1581         return 0;
1582 }
1583
1584 RESULT eDVBServicePlay::getName(std::string &name)
1585 {
1586         if (m_is_pvr)
1587         {
1588                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1589                 return i->getName(m_reference, name);
1590         }
1591         else if (m_is_stream)
1592         {
1593                 name = m_reference.name;
1594                 if (name.empty())
1595                 {
1596                         name = m_reference.path;
1597                 }
1598                 if (name.empty())
1599                 {
1600                         name = "(...)";
1601                 }
1602         }
1603         else if (m_dvb_service)
1604         {
1605                 m_dvb_service->getName(m_reference, name);
1606                 if (name.empty())
1607                         name = "(...)";
1608         }
1609         else if (!m_reference.name.empty())
1610                 eStaticServiceDVBInformation().getName(m_reference, name);
1611         else
1612                 name = "DVB service";
1613         return 0;
1614 }
1615
1616 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1617 {
1618         return m_event_handler.getEvent(evt, nownext);
1619 }
1620
1621 int eDVBServicePlay::getInfo(int w)
1622 {
1623         eDVBServicePMTHandler::program program;
1624
1625         if (w == sCAIDs || w == sCAIDPIDs)
1626                 return resIsPyObject;
1627
1628         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1629
1630         int no_program_info = 0;
1631
1632         if (h.getProgramInfo(program))
1633                 no_program_info = 1;
1634
1635         switch (w)
1636         {
1637         case sVideoHeight:
1638                 if (m_decoder)
1639                         return m_decoder->getVideoHeight();
1640                 break;
1641         case sVideoWidth:
1642                 if (m_decoder)
1643                         return m_decoder->getVideoWidth();
1644                 break;
1645         case sFrameRate:
1646                 if (m_decoder)
1647                         return m_decoder->getVideoFrameRate();
1648                 break;
1649         case sProgressive:
1650                 if (m_decoder)
1651                         return m_decoder->getVideoProgressive();
1652                 break;
1653         case sAspect:
1654         {
1655                 int aspect = -1;
1656                 if (m_decoder)
1657                         aspect = m_decoder->getVideoAspect();
1658                 if (aspect == -1 && no_program_info)
1659                         break;
1660                 else if (aspect == -1 && !program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1661                 {
1662                         ePtr<eServiceEvent> evt;
1663                         if (!m_event_handler.getEvent(evt, 0))
1664                         {
1665                                 ePtr<eComponentData> data;
1666                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1667                                 {
1668                                         if ( data->getStreamContent() == 1 )
1669                                         {
1670                                                 switch(data->getComponentType())
1671                                                 {
1672                                                         // SD
1673                                                         case 1: // 4:3 SD PAL
1674                                                         case 2:
1675                                                         case 3: // 16:9 SD PAL
1676                                                         case 4: // > 16:9 PAL
1677                                                         case 5: // 4:3 SD NTSC
1678                                                         case 6: 
1679                                                         case 7: // 16:9 SD NTSC
1680                                                         case 8: // > 16:9 NTSC
1681
1682                                                         // HD
1683                                                         case 9: // 4:3 HD PAL
1684                                                         case 0xA:
1685                                                         case 0xB: // 16:9 HD PAL
1686                                                         case 0xC: // > 16:9 HD PAL
1687                                                         case 0xD: // 4:3 HD NTSC
1688                                                         case 0xE:
1689                                                         case 0xF: // 16:9 HD NTSC
1690                                                         case 0x10: // > 16:9 HD PAL
1691                                                                 return data->getComponentType();
1692                                                 }
1693                                         }
1694                                 }
1695                         }
1696                 }
1697                 else
1698                         return aspect;
1699                 break;
1700         }
1701         case sIsCrypted: if (no_program_info) return -1; return program.isCrypted();
1702         case sVideoPID:
1703                 if (m_dvb_service)
1704                 {
1705                         int vpid = m_dvb_service->getCacheEntry(eDVBService::cVPID);
1706                         if (vpid != -1)
1707                                 return vpid;
1708                 }
1709                 if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1710         case sVideoType: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
1711         case sAudioPID:
1712                 if (m_dvb_service)
1713                 {
1714                         int apid = m_dvb_service->getCacheEntry(eDVBService::cAPID);
1715                         if (apid != -1)
1716                                 return apid;
1717                         apid = m_dvb_service->getCacheEntry(eDVBService::cAC3PID);
1718                         if (apid != -1)
1719                                 return apid;
1720                 }
1721                 if (no_program_info) return -1; if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
1722         case sPCRPID:
1723                 if (m_dvb_service)
1724                 {
1725                         int pcrpid = m_dvb_service->getCacheEntry(eDVBService::cPCRPID);
1726                         if (pcrpid != -1)
1727                                 return pcrpid;
1728                 }
1729                 if (no_program_info) return -1; return program.pcrPid;
1730         case sPMTPID: if (no_program_info) return -1; return program.pmtPid;
1731         case sTXTPID: if (no_program_info) return -1; return program.textPid;
1732         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1733         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1734         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1735         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1736         case sProvider: if (!m_dvb_service) return -1; return -2;
1737         case sServiceref: return resIsString;
1738         case sDVBState: return m_tune_state;
1739         default:
1740                 break;
1741         }
1742         return -1;
1743 }
1744
1745 std::string eDVBServicePlay::getInfoString(int w)
1746 {
1747         switch (w)
1748         {
1749         case sProvider:
1750                 if (!m_dvb_service) return "";
1751                 return m_dvb_service->m_provider_name;
1752         case sServiceref:
1753                 return m_reference.toString();
1754         default:
1755                 break;
1756         }
1757         return iServiceInformation::getInfoString(w);
1758 }
1759
1760 PyObject *eDVBServicePlay::getInfoObject(int w)
1761 {
1762         switch (w)
1763         {
1764         case sCAIDs:
1765                 return m_service_handler.getCaIds();
1766         case sCAIDPIDs:
1767                 return m_service_handler.getCaIds(true);
1768         case sTransponderData:
1769                 return eStaticServiceDVBInformation().getInfoObject(m_reference, w);
1770         default:
1771                 break;
1772         }
1773         return iServiceInformation::getInfoObject(w);
1774 }
1775
1776 int eDVBServicePlay::getNumberOfTracks()
1777 {
1778         eDVBServicePMTHandler::program program;
1779         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1780         if (h.getProgramInfo(program))
1781                 return 0;
1782         return program.audioStreams.size();
1783 }
1784
1785 int eDVBServicePlay::getCurrentTrack()
1786 {
1787         eDVBServicePMTHandler::program program;
1788         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1789         if (h.getProgramInfo(program))
1790                 return 0;
1791
1792         int max = program.audioStreams.size();
1793         int i;
1794
1795         for (i = 0; i < max; ++i)
1796                 if (program.audioStreams[i].pid == m_current_audio_pid)
1797                         return i;
1798
1799         return 0;
1800 }
1801
1802 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1803 {
1804         int ret = selectAudioStream(i);
1805
1806         if (m_decoder->set())
1807                 return -5;
1808
1809         return ret;
1810 }
1811
1812 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1813 {
1814         eDVBServicePMTHandler::program program;
1815         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1816
1817         if (h.getProgramInfo(program))
1818                 return -1;
1819         
1820         if (i >= program.audioStreams.size())
1821                 return -2;
1822         
1823         info.m_pid = program.audioStreams[i].pid;
1824
1825         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1826                 info.m_description = "MPEG";
1827         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1828                 info.m_description = "Dolby Digital";
1829         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDDP)
1830                 info.m_description = "Dolby Digital+";
1831         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
1832                 info.m_description = "AAC";
1833         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAACHE)
1834                 info.m_description = "AAC-HE";
1835         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1836                 info.m_description = "DTS";
1837         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTSHD)
1838                 info.m_description = "DTS-HD";
1839         else
1840                 info.m_description = "???";
1841
1842         if (program.audioStreams[i].component_tag != -1)
1843         {
1844                 ePtr<eServiceEvent> evt;
1845                 if (!m_event_handler.getEvent(evt, 0))
1846                 {
1847                         ePtr<eComponentData> data;
1848                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1849                                 info.m_language = data->getText();
1850                 }
1851         }
1852
1853         if (info.m_language.empty())
1854                 info.m_language = program.audioStreams[i].language_code;
1855         
1856         return 0;
1857 }
1858
1859 int eDVBServicePlay::selectAudioStream(int i)
1860 {
1861         eDVBServicePMTHandler::program program;
1862         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1863         pts_t position = -1;
1864
1865         if (h.getProgramInfo(program))
1866                 return -1;
1867
1868         if ((i != -1) && ((unsigned int)i >= program.audioStreams.size()))
1869                 return -2;
1870
1871         if (!m_decoder)
1872                 return -3;
1873
1874         int stream = i;
1875         if (stream == -1)
1876                 stream = program.defaultAudioStream;
1877
1878         int apid = -1, apidtype = -1;
1879
1880         if (((unsigned int)stream) < program.audioStreams.size())
1881         {
1882                 apid = program.audioStreams[stream].pid;
1883                 apidtype = program.audioStreams[stream].type;
1884         }
1885
1886         if (i != -1 && apid != m_current_audio_pid && (m_is_pvr || m_timeshift_active))
1887                 eDebug("getPlayPosition ret %d, pos %lld in selectAudioStream", getPlayPosition(position), position);
1888
1889         m_current_audio_pid = apid;
1890
1891         if (m_is_primary && m_decoder->setAudioPID(apid, apidtype))
1892         {
1893                 eDebug("set audio pid failed");
1894                 return -4;
1895         }
1896
1897         if (position != -1)
1898                 eDebug("seekTo ret %d", seekTo(position));
1899
1900         int rdsPid = apid;
1901
1902                 /* 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 */
1903         if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1904         {
1905                 int different_pid = program.videoStreams.empty() && program.audioStreams.size() == 1 && program.audioStreams[stream].rdsPid != -1;
1906                 if (different_pid)
1907                         rdsPid = program.audioStreams[stream].rdsPid;
1908                 if (!m_rds_decoder || m_rds_decoder->getPid() != rdsPid)
1909                 {
1910                         m_rds_decoder = 0;
1911                         ePtr<iDVBDemux> data_demux;
1912                         if (!h.getDataDemux(data_demux))
1913                         {
1914                                 m_rds_decoder = new eDVBRdsDecoder(data_demux, different_pid);
1915                                 m_rds_decoder->connectEvent(slot(*this, &eDVBServicePlay::rdsDecoderEvent), m_rds_decoder_event_connection);
1916                                 m_rds_decoder->start(rdsPid);
1917                         }
1918                 }
1919         }
1920
1921                         /* store new pid as default only when:
1922                                 a.) we have an entry in the service db for the current service,
1923                                 b.) we are not playing back something,
1924                                 c.) we are not selecting the default entry. (we wouldn't change 
1925                                     anything in the best case, or destroy the default setting in
1926                                     case the real default is not yet available.)
1927                         */
1928         if (m_dvb_service && ((i != -1)
1929                 || ((m_dvb_service->getCacheEntry(eDVBService::cAPID) == -1) && (m_dvb_service->getCacheEntry(eDVBService::cAC3PID)==-1))))
1930         {
1931                 if (apidtype == eDVBAudio::aMPEG)
1932                 {
1933                         m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1934                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1935                 }
1936                 else if (apidtype == eDVBAudio::aAC3)
1937                 {
1938                         m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1939                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1940                 }
1941                 else
1942                 {
1943                         m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1944                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1945                 }
1946         }
1947
1948         h.resetCachedProgram();
1949
1950         return 0;
1951 }
1952
1953 int eDVBServicePlay::getCurrentChannel()
1954 {
1955         return m_decoder ? m_decoder->getAudioChannel() : STEREO;
1956 }
1957
1958 RESULT eDVBServicePlay::selectChannel(int i)
1959 {
1960         if (i < LEFT || i > RIGHT || i == STEREO)
1961                 i = -1;  // Stereo
1962         if (m_dvb_service)
1963                 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1964         if (m_decoder)
1965                 m_decoder->setAudioChannel(i);
1966         return 0;
1967 }
1968
1969 std::string eDVBServicePlay::getText(int x)
1970 {
1971         if (m_rds_decoder)
1972                 switch(x)
1973                 {
1974                         case RadioText:
1975                                 return convertLatin1UTF8(m_rds_decoder->getRadioText());
1976                         case RtpText:
1977                                 return convertLatin1UTF8(m_rds_decoder->getRtpText());
1978                 }
1979         return "";
1980 }
1981
1982 void eDVBServicePlay::rdsDecoderEvent(int what)
1983 {
1984         switch(what)
1985         {
1986                 case eDVBRdsDecoder::RadioTextChanged:
1987                         m_event((iPlayableService*)this, evUpdatedRadioText);
1988                         break;
1989                 case eDVBRdsDecoder::RtpTextChanged:
1990                         m_event((iPlayableService*)this, evUpdatedRtpText);
1991                         break;
1992                 case eDVBRdsDecoder::RassInteractivePicMaskChanged:
1993                         m_event((iPlayableService*)this, evUpdatedRassInteractivePicMask);
1994                         break;
1995                 case eDVBRdsDecoder::RecvRassSlidePic:
1996                         m_event((iPlayableService*)this, evUpdatedRassSlidePic);
1997                         break;
1998         }
1999 }
2000
2001 void eDVBServicePlay::showRassSlidePicture()
2002 {
2003         if (m_rds_decoder)
2004         {
2005                 if (m_decoder)
2006                 {
2007                         std::string rass_slide_pic = m_rds_decoder->getRassSlideshowPicture();
2008                         if (rass_slide_pic.length())
2009                                 m_decoder->showSinglePic(rass_slide_pic.c_str());
2010                         else
2011                                 eDebug("empty filename for rass slide picture received!!");
2012                 }
2013                 else
2014                         eDebug("no MPEG Decoder to show iframes avail");
2015         }
2016         else
2017                 eDebug("showRassSlidePicture called.. but not decoder");
2018 }
2019
2020 void eDVBServicePlay::showRassInteractivePic(int page, int subpage)
2021 {
2022         if (m_rds_decoder)
2023         {
2024                 if (m_decoder)
2025                 {
2026                         std::string rass_interactive_pic = m_rds_decoder->getRassPicture(page, subpage);
2027                         if (rass_interactive_pic.length())
2028                                 m_decoder->showSinglePic(rass_interactive_pic.c_str());
2029                         else
2030                                 eDebug("empty filename for rass interactive picture %d/%d received!!", page, subpage);
2031                 }
2032                 else
2033                         eDebug("no MPEG Decoder to show iframes avail");
2034         }
2035         else
2036                 eDebug("showRassInteractivePic called.. but not decoder");
2037 }
2038
2039 ePyObject eDVBServicePlay::getRassInteractiveMask()
2040 {
2041         if (m_rds_decoder)
2042                 return m_rds_decoder->getRassPictureMask();
2043         Py_RETURN_NONE;
2044 }
2045
2046 int eDVBServiceBase::getFrontendInfo(int w)
2047 {
2048         eUsePtr<iDVBChannel> channel;
2049         if(m_service_handler.getChannel(channel))
2050                 return 0;
2051         ePtr<iDVBFrontend> fe;
2052         if(channel->getFrontend(fe))
2053                 return 0;
2054         return fe->readFrontendData(w);
2055 }
2056
2057 PyObject *eDVBServiceBase::getFrontendData()
2058 {
2059         ePyObject ret = PyDict_New();
2060         if (ret)
2061         {
2062                 eUsePtr<iDVBChannel> channel;
2063                 if(!m_service_handler.getChannel(channel))
2064                 {
2065                         ePtr<iDVBFrontend> fe;
2066                         if(!channel->getFrontend(fe))
2067                                 fe->getFrontendData(ret);
2068                 }
2069         }
2070         else
2071                 Py_RETURN_NONE;
2072         return ret;
2073 }
2074
2075 PyObject *eDVBServiceBase::getFrontendStatus()
2076 {
2077         ePyObject ret = PyDict_New();
2078         if (ret)
2079         {
2080                 eUsePtr<iDVBChannel> channel;
2081                 if(!m_service_handler.getChannel(channel))
2082                 {
2083                         ePtr<iDVBFrontend> fe;
2084                         if(!channel->getFrontend(fe))
2085                                 fe->getFrontendStatus(ret);
2086                 }
2087         }
2088         else
2089                 Py_RETURN_NONE;
2090         return ret;
2091 }
2092
2093 PyObject *eDVBServiceBase::getTransponderData(bool original)
2094 {
2095         ePyObject ret = PyDict_New();
2096         if (ret)
2097         {
2098                 eUsePtr<iDVBChannel> channel;
2099                 if(!m_service_handler.getChannel(channel))
2100                 {
2101                         ePtr<iDVBFrontend> fe;
2102                         if(!channel->getFrontend(fe))
2103                                 fe->getTransponderData(ret, original);
2104                 }
2105         }
2106         else
2107                 Py_RETURN_NONE;
2108         return ret;
2109 }
2110
2111 PyObject *eDVBServiceBase::getAll(bool original)
2112 {
2113         ePyObject ret = getTransponderData(original);
2114         if (ret != Py_None)
2115         {
2116                 eUsePtr<iDVBChannel> channel;
2117                 if(!m_service_handler.getChannel(channel))
2118                 {
2119                         ePtr<iDVBFrontend> fe;
2120                         if(!channel->getFrontend(fe))
2121                         {
2122                                 fe->getFrontendData(ret);
2123                                 fe->getFrontendStatus(ret);
2124                         }
2125                 }
2126         }
2127         return ret;
2128 }
2129
2130 int eDVBServicePlay::getNumberOfSubservices()
2131 {
2132         ePtr<eServiceEvent> evt;
2133         if (!m_event_handler.getEvent(evt, 0))
2134                 return evt->getNumOfLinkageServices();
2135         return 0;
2136 }
2137
2138 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
2139 {
2140         ePtr<eServiceEvent> evt;
2141         if (!m_event_handler.getEvent(evt, 0))
2142         {
2143                 if (!evt->getLinkageService(sub, m_reference, n))
2144                         return 0;
2145         }
2146         sub.type=eServiceReference::idInvalid;
2147         return -1;
2148 }
2149
2150 RESULT eDVBServicePlay::startTimeshift()
2151 {
2152         ePtr<iDVBDemux> demux;
2153         
2154         eDebug("Start timeshift!");
2155         
2156         if (m_timeshift_enabled)
2157                 return -1;
2158         
2159                 /* start recording with the data demux. */
2160         if (m_service_handler.getDataDemux(demux))
2161                 return -2;
2162
2163         demux->createTSRecorder(m_record);
2164         if (!m_record)
2165                 return -3;
2166
2167         std::string tspath;
2168         if(ePythonConfigQuery::getConfigValue("config.usage.timeshift_path", tspath) == -1){ 
2169                 eDebug("could not query ts path");
2170                 return -5;
2171         }
2172         tspath.append("/timeshift.XXXXXX");
2173         char* templ;
2174         templ = new char[tspath.length() + 1];
2175         strcpy(templ, tspath.c_str());
2176
2177         m_timeshift_fd = mkstemp(templ);
2178         m_timeshift_file = std::string(templ);
2179
2180         eDebug("recording to %s", templ);
2181
2182         delete [] templ;
2183
2184         if (m_timeshift_fd < 0)
2185         {
2186                 m_record = 0;
2187                 return -4;
2188         }
2189                 
2190         m_record->setTargetFD(m_timeshift_fd);
2191
2192         m_timeshift_enabled = 1;
2193         
2194         updateTimeshiftPids();
2195         m_record->start();
2196
2197         return 0;
2198 }
2199
2200 RESULT eDVBServicePlay::stopTimeshift(bool swToLive)
2201 {
2202         if (!m_timeshift_enabled)
2203                 return -1;
2204         
2205         if (swToLive)
2206                 switchToLive();
2207         
2208         m_timeshift_enabled = 0;
2209         
2210         m_record->stop();
2211         m_record = 0;
2212         
2213         close(m_timeshift_fd);
2214         eDebug("remove timeshift file");
2215         eBackgroundFileEraser::getInstance()->erase(m_timeshift_file.c_str());
2216         
2217         return 0;
2218 }
2219
2220 int eDVBServicePlay::isTimeshiftActive()
2221 {
2222         return m_timeshift_enabled && m_timeshift_active;
2223 }
2224
2225 RESULT eDVBServicePlay::activateTimeshift()
2226 {
2227         if (!m_timeshift_enabled)
2228                 return -1;
2229         
2230         if (!m_timeshift_active)
2231         {
2232                 switchToTimeshift();
2233                 return 0;
2234         }
2235         
2236         return -2;
2237 }
2238
2239 PyObject *eDVBServicePlay::getCutList()
2240 {
2241         ePyObject list = PyList_New(0);
2242         
2243         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
2244         {
2245                 ePyObject tuple = PyTuple_New(2);
2246                 PyTuple_SET_ITEM(tuple, 0, PyLong_FromLongLong(i->where));
2247                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(i->what));
2248                 PyList_Append(list, tuple);
2249                 Py_DECREF(tuple);
2250         }
2251         
2252         return list;
2253 }
2254
2255 void eDVBServicePlay::setCutList(ePyObject list)
2256 {
2257         if (!PyList_Check(list))
2258                 return;
2259         int size = PyList_Size(list);
2260         int i;
2261         
2262         m_cue_entries.clear();
2263         
2264         for (i=0; i<size; ++i)
2265         {
2266                 ePyObject tuple = PyList_GET_ITEM(list, i);
2267                 if (!PyTuple_Check(tuple))
2268                 {
2269                         eDebug("non-tuple in cutlist");
2270                         continue;
2271                 }
2272                 if (PyTuple_Size(tuple) != 2)
2273                 {
2274                         eDebug("cutlist entries need to be a 2-tuple");
2275                         continue;
2276                 }
2277                 ePyObject ppts = PyTuple_GET_ITEM(tuple, 0), ptype = PyTuple_GET_ITEM(tuple, 1);
2278                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
2279                 {
2280                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
2281                         continue;
2282                 }
2283                 pts_t pts = PyLong_AsLongLong(ppts);
2284                 int type = PyInt_AsLong(ptype);
2285                 m_cue_entries.insert(cueEntry(pts, type));
2286                 eDebug("adding %08llx, %d", pts, type);
2287         }
2288         m_cuesheet_changed = 1;
2289         
2290         cutlistToCuesheet();
2291         m_event((iPlayableService*)this, evCuesheetChanged);
2292 }
2293
2294 void eDVBServicePlay::setCutListEnable(int enable)
2295 {
2296         m_cutlist_enabled = enable;
2297         cutlistToCuesheet();
2298 }
2299
2300 void eDVBServicePlay::updateTimeshiftPids()
2301 {
2302         if (!m_record)
2303                 return;
2304         
2305         eDVBServicePMTHandler::program program;
2306         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2307
2308         if (h.getProgramInfo(program))
2309                 return;
2310         else
2311         {
2312                 std::set<int> pids_to_record;
2313                 pids_to_record.insert(0); // PAT
2314                 if (program.pmtPid != -1)
2315                         pids_to_record.insert(program.pmtPid); // PMT
2316
2317                 if (program.textPid != -1)
2318                         pids_to_record.insert(program.textPid); // Videotext
2319
2320                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
2321                         i(program.videoStreams.begin()); 
2322                         i != program.videoStreams.end(); ++i)
2323                         pids_to_record.insert(i->pid);
2324
2325                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
2326                         i(program.audioStreams.begin()); 
2327                         i != program.audioStreams.end(); ++i)
2328                                 pids_to_record.insert(i->pid);
2329
2330                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::const_iterator
2331                         i(program.subtitleStreams.begin());
2332                         i != program.subtitleStreams.end(); ++i)
2333                                 pids_to_record.insert(i->pid);
2334
2335                 std::set<int> new_pids, obsolete_pids;
2336                 
2337                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
2338                                 m_pids_active.begin(), m_pids_active.end(),
2339                                 std::inserter(new_pids, new_pids.begin()));
2340                 
2341                 std::set_difference(
2342                                 m_pids_active.begin(), m_pids_active.end(),
2343                                 pids_to_record.begin(), pids_to_record.end(), 
2344                                 std::inserter(new_pids, new_pids.begin())
2345                                 );
2346
2347                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
2348                         m_record->addPID(*i);
2349
2350                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
2351                         m_record->removePID(*i);
2352         }
2353 }
2354
2355 RESULT eDVBServicePlay::setNextPlaybackFile(const char *f)
2356 {
2357         m_timeshift_file_next = f;
2358         return 0;
2359 }
2360
2361 void eDVBServicePlay::switchToLive()
2362 {
2363         if (!m_timeshift_active)
2364                 return;
2365
2366         eDebug("SwitchToLive");
2367
2368         resetTimeshift(0);
2369
2370         m_is_paused = m_skipmode = m_fastforward = m_slowmotion = 0; /* not supported in live mode */
2371
2372         /* free the timeshift service handler, we need the resources */
2373         m_service_handler_timeshift.free();
2374
2375         updateDecoder(true);
2376 }
2377
2378 void eDVBServicePlay::resetTimeshift(int start)
2379 {
2380         m_cue = 0;
2381         m_decode_demux = 0;
2382         m_decoder = 0;
2383         m_teletext_parser = 0;
2384         m_rds_decoder = 0;
2385         m_subtitle_parser = 0;
2386         m_new_subtitle_page_connection = 0;
2387         m_new_dvb_subtitle_page_connection = 0;
2388         m_rds_decoder_event_connection = 0;
2389         m_video_event_connection = 0;
2390         m_timeshift_changed = 1;
2391         m_timeshift_file_next.clear();
2392
2393         if (start)
2394         {
2395                 m_cue = new eCueSheet();
2396                 m_timeshift_active = 1;
2397         }
2398         else
2399                 m_timeshift_active = 0;
2400 }
2401
2402 ePtr<iTsSource> eDVBServicePlay::createTsSource(eServiceReferenceDVB &ref)
2403 {
2404         if (m_is_stream)
2405         {
2406                 eHttpStream *f = new eHttpStream();
2407                 f->open(ref.path.c_str());
2408                 return ePtr<iTsSource>(f);
2409         }
2410         else
2411         {
2412                 eRawFile *f = new eRawFile();
2413                 f->open(ref.path.c_str());
2414                 return ePtr<iTsSource>(f);
2415         }
2416 }
2417
2418 void eDVBServicePlay::switchToTimeshift()
2419 {
2420         if (m_timeshift_active)
2421                 return;
2422
2423         resetTimeshift(1);
2424
2425         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
2426         r.path = m_timeshift_file;
2427
2428         m_cue->seekTo(0, -1000);
2429
2430         ePtr<iTsSource> source = createTsSource(r);
2431         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 */
2432
2433         eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
2434         pause();
2435         updateDecoder(true); /* mainly to switch off PCR, and to set pause */
2436 }
2437
2438 void eDVBServicePlay::updateDecoder(bool sendSeekableStateChanged)
2439 {
2440         int vpid = -1, vpidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
2441         bool mustPlay = false;
2442
2443         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2444
2445         eDVBServicePMTHandler::program program;
2446         if (h.getProgramInfo(program))
2447                 eDebug("getting program info failed.");
2448         else
2449         {
2450                 eDebugNoNewLine("have %zd video stream(s)", program.videoStreams.size());
2451                 if (!program.videoStreams.empty())
2452                 {
2453                         eDebugNoNewLine(" (");
2454                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
2455                                 i(program.videoStreams.begin());
2456                                 i != program.videoStreams.end(); ++i)
2457                         {
2458                                 if (vpid == -1)
2459                                 {
2460                                         vpid = i->pid;
2461                                         vpidtype = i->type;
2462                                 }
2463                                 if (i != program.videoStreams.begin())
2464                                         eDebugNoNewLine(", ");
2465                                 eDebugNoNewLine("%04x", i->pid);
2466                         }
2467                         eDebugNoNewLine(")");
2468                 }
2469                 eDebugNoNewLine(", and %zd audio stream(s)", program.audioStreams.size());
2470                 if (!program.audioStreams.empty())
2471                 {
2472                         eDebugNoNewLine(" (");
2473                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
2474                                 i(program.audioStreams.begin());
2475                                 i != program.audioStreams.end(); ++i)
2476                         {
2477                                 if (i != program.audioStreams.begin())
2478                                         eDebugNoNewLine(", ");
2479                                 eDebugNoNewLine("%04x", i->pid);
2480                         }
2481                         eDebugNoNewLine(")");
2482                 }
2483                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
2484                 pcrpid = program.pcrPid;
2485                 eDebug(", and the text pid is %04x", program.textPid);
2486                 tpid = program.textPid;
2487         }
2488
2489         if (!m_decoder)
2490         {
2491                 h.getDecodeDemux(m_decode_demux);
2492                 if (m_decode_demux)
2493                 {
2494                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
2495                         if (m_decoder)
2496                                 m_decoder->connectVideoEvent(slot(*this, &eDVBServicePlay::video_event), m_video_event_connection);
2497                         if (m_is_primary)
2498                         {
2499                                 m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
2500                                 m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
2501                                 m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
2502                                 m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
2503                                 if (m_timeshift_changed)
2504                                 {
2505                                         ePyObject subs = getCachedSubtitle();
2506                                         if (subs != Py_None)
2507                                         {
2508                                                 int type = PyInt_AsLong(PyTuple_GET_ITEM(subs, 0)),
2509                                                     pid = PyInt_AsLong(PyTuple_GET_ITEM(subs, 1)),
2510                                                     comp_page = PyInt_AsLong(PyTuple_GET_ITEM(subs, 2)), // ttx page
2511                                                     anc_page = PyInt_AsLong(PyTuple_GET_ITEM(subs, 3)); // ttx magazine
2512                                                 if (type == 0) // dvb
2513                                                         m_subtitle_parser->start(pid, comp_page, anc_page);
2514                                                 else if (type == 1) // ttx
2515                                                         m_teletext_parser->setPageAndMagazine(comp_page, anc_page);
2516                                         }
2517                                         Py_DECREF(subs);
2518                                 }
2519                         }
2520                 }
2521                 if (m_cue)
2522                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
2523                 mustPlay = true;
2524         }
2525
2526         m_timeshift_changed = 0;
2527
2528         if (m_decoder)
2529         {
2530                 bool wasSeekable = m_decoder->getVideoProgressive() != -1;
2531                 if (m_dvb_service)
2532                 {
2533                         achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
2534                         ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2535                         pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2536                 }
2537                 else // subservice
2538                 {
2539                         eServiceReferenceDVB ref;
2540                         m_service_handler.getServiceReference(ref);
2541                         eServiceReferenceDVB parent = ref.getParentServiceReference();
2542                         if (!parent)
2543                                 parent = ref;
2544                         if (parent)
2545                         {
2546                                 ePtr<eDVBResourceManager> res_mgr;
2547                                 if (!eDVBResourceManager::getInstance(res_mgr))
2548                                 {
2549                                         ePtr<iDVBChannelList> db;
2550                                         if (!res_mgr->getChannelList(db))
2551                                         {
2552                                                 ePtr<eDVBService> origService;
2553                                                 if (!db->getService(parent, origService))
2554                                                 {
2555                                                         ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
2556                                                         pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
2557                                                 }
2558                                         }
2559                                 }
2560                         }
2561                 }
2562
2563                 setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
2564                 setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
2565
2566                 m_decoder->setVideoPID(vpid, vpidtype);
2567                 selectAudioStream();
2568
2569                 if (!(m_is_pvr || m_is_stream || m_timeshift_active || !m_is_primary))
2570                         m_decoder->setSyncPCR(pcrpid);
2571                 else
2572                         m_decoder->setSyncPCR(-1);
2573
2574                 if (m_is_primary)
2575                 {
2576                         m_decoder->setTextPID(tpid);
2577                         m_teletext_parser->start(program.textPid);
2578                 }
2579
2580                 if (vpid > 0 && vpid < 0x2000)
2581                         ;
2582                 else
2583                 {
2584                         std::string radio_pic;
2585                         if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
2586                                 m_decoder->setRadioPic(radio_pic);
2587                 }
2588
2589                 if (mustPlay)
2590                         m_decoder->play();
2591                 else
2592                         m_decoder->set();
2593
2594                 m_decoder->setAudioChannel(achannel);
2595
2596                 /* don't worry about non-existing services, nor pvr services */
2597                 if (m_dvb_service)
2598                 {
2599                                 /* (audio pid will be set in selectAudioTrack */
2600                         m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
2601                         m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
2602                         m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
2603                         m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
2604                 }
2605                 if (!sendSeekableStateChanged && (m_decoder->getVideoProgressive() != -1) != wasSeekable)
2606                         sendSeekableStateChanged = true;
2607         }
2608         m_have_video_pid = (vpid > 0 && vpid < 0x2000);
2609
2610         if (sendSeekableStateChanged)
2611                 m_event((iPlayableService*)this, evSeekableStatusChanged);
2612 }
2613
2614 void eDVBServicePlay::loadCuesheet()
2615 {
2616         std::string filename = m_reference.path + ".cuts";
2617         
2618         m_cue_entries.clear();
2619
2620         FILE *f = fopen(filename.c_str(), "rb");
2621
2622         if (f)
2623         {
2624                 eDebug("loading cuts..");
2625                 while (1)
2626                 {
2627                         unsigned long long where;
2628                         unsigned int what;
2629                         
2630                         if (!fread(&where, sizeof(where), 1, f))
2631                                 break;
2632                         if (!fread(&what, sizeof(what), 1, f))
2633                                 break;
2634                         
2635 #if BYTE_ORDER == LITTLE_ENDIAN
2636                         where = bswap_64(where);
2637 #endif
2638                         what = ntohl(what);
2639                         
2640                         if (what > 3)
2641                                 break;
2642                         
2643                         m_cue_entries.insert(cueEntry(where, what));
2644                 }
2645                 fclose(f);
2646                 eDebug("%zd entries", m_cue_entries.size());
2647         } else
2648                 eDebug("cutfile not found!");
2649         
2650         m_cuesheet_changed = 0;
2651         cutlistToCuesheet();
2652         m_event((iPlayableService*)this, evCuesheetChanged);
2653 }
2654
2655 void eDVBServicePlay::saveCuesheet()
2656 {
2657         std::string filename = m_reference.path + ".cuts";
2658         
2659         FILE *f = fopen(filename.c_str(), "wb");
2660
2661         if (f)
2662         {
2663                 unsigned long long where;
2664                 int what;
2665
2666                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
2667                 {
2668 #if BYTE_ORDER == BIG_ENDIAN
2669                         where = i->where;
2670 #else
2671                         where = bswap_64(i->where);
2672 #endif
2673                         what = htonl(i->what);
2674                         fwrite(&where, sizeof(where), 1, f);
2675                         fwrite(&what, sizeof(what), 1, f);
2676                         
2677                 }
2678                 fclose(f);
2679         }
2680         
2681         m_cuesheet_changed = 0;
2682 }
2683
2684 void eDVBServicePlay::cutlistToCuesheet()
2685 {
2686         if (!m_cue)
2687         {
2688                 eDebug("no cue sheet");
2689                 return;
2690         }       
2691         m_cue->clear();
2692         
2693         if (!m_cutlist_enabled)
2694         {
2695                 m_cue->commitSpans();
2696                 eDebug("cutlists were disabled");
2697                 return;
2698         }
2699
2700         pts_t in = 0, out = 0, length = 0;
2701         
2702         getLength(length);
2703                 
2704         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
2705         
2706         int have_any_span = 0;
2707         
2708         while (1)
2709         {
2710                 if (i == m_cue_entries.end())
2711                 {
2712                         if (!have_any_span && !in)
2713                                 break;
2714                         out = length;
2715                 } else {
2716                         if (i->what == 0) /* in */
2717                         {
2718                                 in = i++->where;
2719                                 continue;
2720                         } else if (i->what == 1) /* out */
2721                                 out = i++->where;
2722                         else /* mark (2) or last play position (3) */
2723                         {
2724                                 i++;
2725                                 continue;
2726                         }
2727                 }
2728                 
2729                 if (in < 0)
2730                         in = 0;
2731                 if (out < 0)
2732                         out = 0;
2733                 if (in > length)
2734                         in = length;
2735                 if (out > length)
2736                         out = length;
2737                 
2738                 if (in < out)
2739                 {
2740                         have_any_span = 1;
2741                         m_cue->addSourceSpan(in, out);
2742                         in = out = 0;
2743                 }
2744                 
2745                 in = length;
2746                 
2747                 if (i == m_cue_entries.end())
2748                         break;
2749         }
2750         m_cue->commitSpans();
2751 }
2752
2753 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, ePyObject tuple)
2754 {
2755         if (m_subtitle_widget)
2756                 disableSubtitles(parent);
2757
2758         ePyObject entry;
2759         int tuplesize = PyTuple_Size(tuple);
2760         int type = 0;
2761
2762         if (!PyTuple_Check(tuple))
2763                 goto error_out;
2764
2765         if (tuplesize < 1)
2766                 goto error_out;
2767
2768         entry = PyTuple_GET_ITEM(tuple, 0);
2769
2770         if (!PyInt_Check(entry))
2771                 goto error_out;
2772
2773         type = PyInt_AsLong(entry);
2774
2775         if (type == 1)  // teletext subtitles
2776         {
2777                 int page, magazine, pid;
2778                 if (tuplesize < 4)
2779                         goto error_out;
2780
2781                 if (!m_teletext_parser)
2782                 {
2783                         eDebug("enable teletext subtitles.. no parser !!!");
2784                         return -1;
2785                 }
2786
2787                 entry = PyTuple_GET_ITEM(tuple, 1);
2788                 if (!PyInt_Check(entry))
2789                         goto error_out;
2790                 pid = PyInt_AsLong(entry);
2791
2792                 entry = PyTuple_GET_ITEM(tuple, 2);
2793                 if (!PyInt_Check(entry))
2794                         goto error_out;
2795                 page = PyInt_AsLong(entry);
2796
2797                 entry = PyTuple_GET_ITEM(tuple, 3);
2798                 if (!PyInt_Check(entry))
2799                         goto error_out;
2800                 magazine = PyInt_AsLong(entry);
2801
2802                 m_subtitle_widget = new eSubtitleWidget(parent);
2803                 m_subtitle_widget->resize(parent->size()); /* full size */
2804                 m_teletext_parser->setPageAndMagazine(page, magazine);
2805                 if (m_dvb_service)
2806                         m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE,((pid&0xFFFF)<<16)|((page&0xFF)<<8)|(magazine&0xFF));
2807         }
2808         else if (type == 0)
2809         {
2810                 int pid = 0, composition_page_id = 0, ancillary_page_id = 0;
2811                 if (!m_subtitle_parser)
2812                 {
2813                         eDebug("enable dvb subtitles.. no parser !!!");
2814                         return -1;
2815                 }
2816                 if (tuplesize < 4)
2817                         goto error_out;
2818
2819                 entry = PyTuple_GET_ITEM(tuple, 1);
2820                 if (!PyInt_Check(entry))
2821                         goto error_out;
2822                 pid = PyInt_AsLong(entry);
2823
2824                 entry = PyTuple_GET_ITEM(tuple, 2);
2825                 if (!PyInt_Check(entry))
2826                         goto error_out;
2827                 composition_page_id = PyInt_AsLong(entry);
2828
2829                 entry = PyTuple_GET_ITEM(tuple, 3);
2830                 if (!PyInt_Check(entry))
2831                         goto error_out;
2832                 ancillary_page_id = PyInt_AsLong(entry);
2833
2834                 m_subtitle_widget = new eSubtitleWidget(parent);
2835                 m_subtitle_widget->resize(parent->size()); /* full size */
2836                 m_subtitle_parser->start(pid, composition_page_id, ancillary_page_id);
2837                 if (m_dvb_service)
2838                         m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, ((pid&0xFFFF)<<16)|((composition_page_id&0xFF)<<8)|(ancillary_page_id&0xFF));
2839         }
2840         else
2841                 goto error_out;
2842         return 0;
2843 error_out:
2844         eDebug("enableSubtitles needs a tuple as 2nd argument!\n"
2845                 "for teletext subtitles (0, pid, teletext_page, teletext_magazine)\n"
2846                 "for dvb subtitles (1, pid, composition_page_id, ancillary_page_id)");
2847         return -1;
2848 }
2849
2850 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
2851 {
2852         delete m_subtitle_widget;
2853         m_subtitle_widget = 0;
2854         if (m_subtitle_parser)
2855         {
2856                 m_subtitle_parser->stop();
2857                 m_dvb_subtitle_pages.clear();
2858         }
2859         if (m_teletext_parser)
2860         {
2861                 m_teletext_parser->setPageAndMagazine(-1, -1);
2862                 m_subtitle_pages.clear();
2863         }
2864         if (m_dvb_service)
2865                 m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, -1);
2866         return 0;
2867 }
2868
2869 PyObject *eDVBServicePlay::getCachedSubtitle()
2870 {
2871         if (m_dvb_service)
2872         {
2873                 int tmp = m_dvb_service->getCacheEntry(eDVBService::cSUBTITLE);
2874                 if (tmp != -1)
2875                 {
2876                         unsigned int data = (unsigned int)tmp;
2877                         int pid = (data&0xFFFF0000)>>16;
2878                         ePyObject tuple = PyTuple_New(4);
2879                         eDVBServicePMTHandler::program program;
2880                         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2881                         if (!h.getProgramInfo(program))
2882                         {
2883                                 if (program.textPid==pid) // teletext
2884                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1)); // type teletext
2885                                 else
2886                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0)); // type dvb
2887                                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(pid)); // pid
2888                                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong((data&0xFF00)>>8)); // composition_page / page
2889                                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(data&0xFF)); // ancillary_page / magazine
2890                                 return tuple;
2891                         }
2892                 }
2893         }
2894         Py_RETURN_NONE;
2895 }
2896
2897 PyObject *eDVBServicePlay::getSubtitleList()
2898 {
2899         if (!m_teletext_parser)
2900                 Py_RETURN_NONE;
2901         
2902         ePyObject l = PyList_New(0);
2903         std::set<int> added_ttx_pages;
2904
2905         std::set<eDVBServicePMTHandler::subtitleStream> &subs =
2906                 m_teletext_parser->m_found_subtitle_pages;
2907
2908         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2909         eDVBServicePMTHandler::program program;
2910         if (h.getProgramInfo(program))
2911                 eDebug("getting program info failed.");
2912         else
2913         {
2914                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
2915                         it != program.subtitleStreams.end(); ++it)
2916                 {
2917                         switch(it->subtitling_type)
2918                         {
2919                                 case 0x01: // ebu teletext subtitles
2920                                 {
2921                                         int page_number = it->teletext_page_number & 0xFF;
2922                                         int magazine_number = it->teletext_magazine_number & 7;
2923                                         int hash = magazine_number << 8 | page_number;
2924                                         if (added_ttx_pages.find(hash) == added_ttx_pages.end())
2925                                         {
2926                                                 ePyObject tuple = PyTuple_New(5);
2927                                                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
2928                                                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2929                                                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
2930                                                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
2931                                                 PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
2932                                                 PyList_Append(l, tuple);
2933                                                 Py_DECREF(tuple);
2934                                                 added_ttx_pages.insert(hash);
2935                                         }
2936                                         break;
2937                                 }
2938                                 case 0x10 ... 0x13:
2939                                 case 0x20 ... 0x23: // dvb subtitles
2940                                 {
2941                                         ePyObject tuple = PyTuple_New(5);
2942                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0));
2943                                         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2944                                         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->composition_page_id));
2945                                         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->ancillary_page_id));
2946                                         PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
2947                                         PyList_Insert(l, 0, tuple);
2948                                         Py_DECREF(tuple);
2949                                         break;
2950                                 }
2951                         }
2952                 }
2953         }
2954
2955         for (std::set<eDVBServicePMTHandler::subtitleStream>::iterator it(subs.begin());
2956                 it != subs.end(); ++it)
2957         {
2958                 int page_number = it->teletext_page_number & 0xFF;
2959                 int magazine_number = it->teletext_magazine_number & 7;
2960                 int hash = magazine_number << 8 | page_number;
2961                 if (added_ttx_pages.find(hash) == added_ttx_pages.end())
2962                 {
2963                         ePyObject tuple = PyTuple_New(5);
2964                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
2965                         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2966                         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
2967                         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
2968                         PyTuple_SET_ITEM(tuple, 4, PyString_FromString("und"));  // undetermined
2969                         PyList_Append(l, tuple);
2970                         Py_DECREF(tuple);
2971                 }
2972         }
2973
2974         return l;
2975 }
2976
2977 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2978 {
2979         if (m_subtitle_widget)
2980         {
2981                 pts_t pos = 0;
2982                 if (m_decoder)
2983                         m_decoder->getPTS(0, pos);
2984                 eDebug("got new subtitle page %lld %lld %d", pos, page.m_pts, page.m_have_pts);
2985                 m_subtitle_pages.push_back(page);
2986                 checkSubtitleTiming();
2987         }
2988 }
2989
2990 void eDVBServicePlay::checkSubtitleTiming()
2991 {
2992         eDebug("checkSubtitleTiming");
2993         if (!m_subtitle_widget)
2994                 return;
2995         while (1)
2996         {
2997                 enum { TELETEXT, DVB } type;
2998                 eDVBTeletextSubtitlePage page;
2999                 eDVBSubtitlePage dvb_page;
3000                 pts_t show_time;
3001                 if (!m_subtitle_pages.empty())
3002                 {
3003                         page = m_subtitle_pages.front();
3004                         type = TELETEXT;
3005                         show_time = page.m_pts;
3006                 }
3007                 else if (!m_dvb_subtitle_pages.empty())
3008                 {
3009                         dvb_page = m_dvb_subtitle_pages.front();
3010                         type = DVB;
3011                         show_time = dvb_page.m_show_time;
3012                 }
3013                 else
3014                         return;
3015         
3016                 pts_t pos = 0;
3017         
3018                 if (m_decoder)
3019                         m_decoder->getPTS(0, pos);
3020
3021                 eDebug("%lld %lld", pos, show_time);
3022                 int diff = show_time - pos;
3023                 if (type == TELETEXT && !page.m_have_pts)
3024                 {
3025                         eDebug("ttx subtitle page without pts... immediate show");
3026                         diff = 0;
3027                 }
3028                 if (diff < 0)
3029                 {
3030                         eDebug("[late (%d ms)]", -diff / 90);
3031                         diff = 0;
3032                 }
3033                 if (abs(diff) > 1800000)
3034                 {
3035                         eDebug("[invalid]... immediate show!");
3036                         diff = 0;
3037                 }
3038                 if ((diff/90)<20)
3039                 {
3040                         if (type == TELETEXT)
3041                         {
3042                                 eDebug("display teletext subtitle page %lld", show_time);
3043                                 m_subtitle_widget->setPage(page);
3044                                 m_subtitle_pages.pop_front();
3045                         }
3046                         else
3047                         {
3048                                 eDebug("display dvb subtitle Page %lld", show_time);
3049                                 m_subtitle_widget->setPage(dvb_page);
3050                                 m_dvb_subtitle_pages.pop_front();
3051                         }
3052                 } else
3053                 {
3054                         eDebug("start subtitle delay %d", diff / 90);
3055                         m_subtitle_sync_timer->start(diff / 90, 1);
3056                         break;
3057                 }
3058         }
3059 }
3060
3061 void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
3062 {
3063         if (m_subtitle_widget)
3064         {
3065                 pts_t pos = 0;
3066                 if (m_decoder)
3067                         m_decoder->getPTS(0, pos);
3068                 eDebug("got new subtitle page %lld %lld", pos, p.m_show_time);
3069                 m_dvb_subtitle_pages.push_back(p);
3070                 checkSubtitleTiming();
3071         }
3072 }
3073
3074 int eDVBServicePlay::getAC3Delay()
3075 {
3076         if (m_dvb_service)
3077                 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
3078         else if (m_decoder)
3079                 return m_decoder->getAC3Delay();
3080         else
3081                 return 0;
3082 }
3083
3084 int eDVBServicePlay::getPCMDelay()
3085 {
3086         if (m_dvb_service)
3087                 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
3088         else if (m_decoder)
3089                 return m_decoder->getPCMDelay();
3090         else
3091                 return 0;
3092 }
3093
3094 void eDVBServicePlay::setAC3Delay(int delay)
3095 {
3096         if (m_dvb_service)
3097                 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
3098         if (m_decoder) {
3099                 std::string config_delay;
3100                 int config_delay_int = 0;
3101                 if(ePythonConfigQuery::getConfigValue("config.av.generalAC3delay", config_delay) == 0)
3102                         config_delay_int = atoi(config_delay.c_str());
3103                 m_decoder->setAC3Delay(delay + config_delay_int);
3104         }
3105 }
3106
3107 void eDVBServicePlay::setPCMDelay(int delay)
3108 {
3109         if (m_dvb_service)
3110                 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
3111         if (m_decoder) {
3112                 std::string config_delay;
3113                 int config_delay_int = 0;
3114                 if(ePythonConfigQuery::getConfigValue("config.av.generalPCMdelay", config_delay) == 0)
3115                         config_delay_int = atoi(config_delay.c_str());
3116                 else
3117                         config_delay_int = 0;
3118                 m_decoder->setPCMDelay(delay + config_delay_int);
3119         }
3120 }
3121
3122 void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)
3123 {
3124         switch(event.type) {
3125                 case iTSMPEGDecoder::videoEvent::eventSizeChanged:
3126                         m_event((iPlayableService*)this, evVideoSizeChanged);
3127                         break;
3128                 case iTSMPEGDecoder::videoEvent::eventFrameRateChanged:
3129                         m_event((iPlayableService*)this, evVideoFramerateChanged);
3130                         break;
3131                 case iTSMPEGDecoder::videoEvent::eventProgressiveChanged:
3132                         m_event((iPlayableService*)this, evVideoProgressiveChanged);
3133                         break;
3134                 default:
3135                         break;
3136         }
3137 }
3138
3139 RESULT eDVBServicePlay::stream(ePtr<iStreamableService> &ptr)
3140 {
3141         ptr = this;
3142         return 0;
3143 }
3144
3145 PyObject *eDVBServicePlay::getStreamingData()
3146 {
3147         eDVBServicePMTHandler::program program;
3148         if (m_service_handler.getProgramInfo(program))
3149         {
3150                 Py_RETURN_NONE;
3151         }
3152
3153         ePyObject r = program.createPythonObject();
3154         ePtr<iDVBDemux> demux;
3155         if (!m_service_handler.getDataDemux(demux))
3156         {
3157                 uint8_t demux_id;
3158                 if (!demux->getCADemuxID(demux_id))
3159                         PutToDict(r, "demux", demux_id);
3160         }
3161
3162         return r;
3163 }
3164
3165
3166 DEFINE_REF(eDVBServicePlay)
3167
3168 PyObject *eDVBService::getInfoObject(const eServiceReference &ref, int w)
3169 {
3170         switch (w)
3171         {
3172         case iServiceInformation::sTransponderData:
3173                 return eStaticServiceDVBInformation().getInfoObject(ref, w);
3174         default:
3175                 break;
3176         }
3177         return iStaticServiceInformation::getInfoObject(ref, w);
3178 }
3179
3180 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");