add teletext parser to servicedvb
[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/init_num.h>
7 #include <lib/base/init.h>
8 #include <lib/base/nconfig.h> // access to python config
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
20 #include <sys/vfs.h>
21
22 #include <byteswap.h>
23 #include <netinet/in.h>
24
25 #include <dvbsi++/event_information_section.h>
26
27 #ifndef BYTE_ORDER
28 #error no byte order defined!
29 #endif
30
31 #define TSPATH "/media/hdd"
32
33 class eStaticServiceDVBInformation: public iStaticServiceInformation
34 {
35         DECLARE_REF(eStaticServiceDVBInformation);
36 public:
37         RESULT getName(const eServiceReference &ref, std::string &name);
38         int getLength(const eServiceReference &ref);
39 };
40
41 DEFINE_REF(eStaticServiceDVBInformation);
42
43 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
44 {
45         eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
46         if ( !ref.name.empty() )
47         {
48                 if (service.getParentTransportStreamID().get()) // linkage subservice
49                 {
50                         ePtr<iServiceHandler> service_center;
51                         if (!eServiceCenter::getInstance(service_center))
52                         {
53                                 eServiceReferenceDVB parent = service;
54                                 parent.setTransportStreamID( service.getParentTransportStreamID() );
55                                 parent.setServiceID( service.getParentServiceID() );
56                                 parent.setParentTransportStreamID(eTransportStreamID(0));
57                                 parent.setParentServiceID(eServiceID(0));
58                                 parent.name="";
59                                 ePtr<iStaticServiceInformation> service_info;
60                                 if (!service_center->info(parent, service_info))
61                                 {
62                                         if (!service_info->getName(parent, name))
63                                         {
64                                                 // just show short name
65                                                 unsigned int pos = name.find("\xc2\x86");
66                                                 if ( pos != std::string::npos )
67                                                         name.erase(0, pos+2);
68                                                 pos = name.find("\xc2\x87");
69                                                 if ( pos != std::string::npos )
70                                                         name.erase(pos);
71                                                 name+=" - ";
72                                         }
73                                 }
74                         }
75                 }
76                 else
77                         name="";
78                 name += ref.name;
79                 return 0;
80         }
81         else
82                 return -1;
83 }
84
85 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
86 {
87         return -1;
88 }
89
90 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
91 {
92         DECLARE_REF(eStaticServiceDVBBouquetInformation);
93 public:
94         RESULT getName(const eServiceReference &ref, std::string &name);
95         int getLength(const eServiceReference &ref);
96 };
97
98 DEFINE_REF(eStaticServiceDVBBouquetInformation);
99
100 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
101 {
102         ePtr<iDVBChannelList> db;
103         ePtr<eDVBResourceManager> res;
104
105         int err;
106         if ((err = eDVBResourceManager::getInstance(res)) != 0)
107         {
108                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
109                 return err;
110         }
111         if ((err = res->getChannelList(db)) != 0)
112         {
113                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
114                 return err;
115         }
116
117         eBouquet *bouquet=0;
118         if ((err = db->getBouquet(ref, bouquet)) != 0)
119         {
120                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
121                 return -1;
122         }
123
124         if ( bouquet && bouquet->m_bouquet_name.length() )
125         {
126                 name = bouquet->m_bouquet_name;
127                 return 0;
128         }
129         else
130                 return -1;
131 }
132
133 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
134 {
135         return -1;
136 }
137
138 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
139 {
140         DECLARE_REF(eStaticServiceDVBPVRInformation);
141         eServiceReference m_ref;
142         eDVBMetaParser m_parser;
143 public:
144         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
145         RESULT getName(const eServiceReference &ref, std::string &name);
146         int getLength(const eServiceReference &ref);
147         
148         int getInfo(const eServiceReference &ref, int w);
149         std::string getInfoString(const eServiceReference &ref,int w);
150 };
151
152 DEFINE_REF(eStaticServiceDVBPVRInformation);
153
154 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
155 {
156         m_ref = ref;
157         m_parser.parseFile(ref.path);
158 }
159
160 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
161 {
162         ASSERT(ref == m_ref);
163         name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
164         return 0;
165 }
166
167 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
168 {
169         ASSERT(ref == m_ref);
170         
171         eDVBTSTools tstools;
172         
173         if (tstools.openFile(ref.path.c_str()))
174                 return 0;
175
176         pts_t len;
177         if (tstools.calcLen(len))
178                 return 0;
179
180         return len / 90000;
181 }
182
183 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
184 {
185         switch (w)
186         {
187         case iServiceInformation::sDescription:
188                 return iServiceInformation::resIsString;
189         case iServiceInformation::sServiceref:
190                 return iServiceInformation::resIsString;
191         case iServiceInformation::sTimeCreate:
192                 if (m_parser.m_time_create)
193                         return m_parser.m_time_create;
194                 else
195                         return iServiceInformation::resNA;
196         default:
197                 return iServiceInformation::resNA;
198         }
199 }
200
201 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
202 {
203         switch (w)
204         {
205         case iServiceInformation::sDescription:
206                 return m_parser.m_description;
207         case iServiceInformation::sServiceref:
208                 return m_parser.m_ref.toString();
209         default:
210                 return "";
211         }
212 }
213
214 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
215 {
216         DECLARE_REF(eDVBPVRServiceOfflineOperations);
217         eServiceReferenceDVB m_ref;
218 public:
219         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
220         
221         RESULT deleteFromDisk(int simulate);
222         RESULT getListOfFilenames(std::list<std::string> &);
223 };
224
225 DEFINE_REF(eDVBPVRServiceOfflineOperations);
226
227 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
228 {
229 }
230
231 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
232 {
233         if (simulate)
234                 return 0;
235         else
236         {
237                 std::list<std::string> res;
238                 if (getListOfFilenames(res))
239                         return -1;
240                 
241                 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
242                 if (!eraser)
243                         eDebug("FATAL !! can't get background file eraser");
244                 
245                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
246                 {
247                         eDebug("Removing %s...", i->c_str());
248                         if (eraser)
249                                 eraser->erase(i->c_str());
250                         else
251                                 ::unlink(i->c_str());
252                 }
253                 
254                 return 0;
255         }
256 }
257
258 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
259 {
260         res.clear();
261         res.push_back(m_ref.path);
262
263 // handling for old splitted recordings (enigma 1)
264         char buf[255];
265         int slice=1;
266         while(true)
267         {
268                 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
269                 struct stat s;
270                 if (stat(buf, &s) < 0)
271                         break;
272                 res.push_back(buf);
273         }       
274
275         res.push_back(m_ref.path + ".meta");
276         res.push_back(m_ref.path + ".ap");
277         res.push_back(m_ref.path + ".cuts");
278         std::string tmp = m_ref.path;
279         tmp.erase(m_ref.path.length()-3);
280         res.push_back(tmp + ".eit");
281         return 0;
282 }
283
284 DEFINE_REF(eServiceFactoryDVB)
285
286 eServiceFactoryDVB::eServiceFactoryDVB()
287 {
288         ePtr<eServiceCenter> sc;
289         
290         eServiceCenter::getPrivInstance(sc);
291         if (sc)
292                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
293 }
294
295 eServiceFactoryDVB::~eServiceFactoryDVB()
296 {
297         ePtr<eServiceCenter> sc;
298         
299         eServiceCenter::getPrivInstance(sc);
300         if (sc)
301                 sc->removeServiceFactory(eServiceFactoryDVB::id);
302 }
303
304 DEFINE_REF(eDVBServiceList);
305
306 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
307 {
308 }
309
310 eDVBServiceList::~eDVBServiceList()
311 {
312 }
313
314 RESULT eDVBServiceList::startQuery()
315 {
316         ePtr<iDVBChannelList> db;
317         ePtr<eDVBResourceManager> res;
318         
319         int err;
320         if ((err = eDVBResourceManager::getInstance(res)) != 0)
321         {
322                 eDebug("no resource manager");
323                 return err;
324         }
325         if ((err = res->getChannelList(db)) != 0)
326         {
327                 eDebug("no channel list");
328                 return err;
329         }
330         
331         ePtr<eDVBChannelQuery> q;
332         
333         if (!m_parent.path.empty())
334         {
335                 eDVBChannelQuery::compile(q, m_parent.path);
336                 if (!q)
337                 {
338                         eDebug("compile query failed");
339                         return err;
340                 }
341         }
342         
343         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
344         {
345                 eDebug("startQuery failed");
346                 return err;
347         }
348
349         return 0;
350 }
351
352 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
353 {
354         eServiceReferenceDVB ref;
355         
356         if (!m_query)
357                 return -1;
358         
359         while (!m_query->getNextResult(ref))
360                 list.push_back(ref);
361
362         if (sorted)
363                 list.sort(iListableServiceCompare(this));
364
365         return 0;
366 }
367
368 //   The first argument of this function is a format string to specify the order and
369 //   the content of the returned list
370 //   useable format options are
371 //   R = Service Reference (as swig object .. this is very slow)
372 //   S = Service Reference (as python string object .. same as ref.toString())
373 //   N = Service Name (as python string object)
374 //   when exactly one return value per service is selected in the format string,
375 //   then each value is directly a list entry
376 //   when more than one value is returned per service, then the list is a list of
377 //   python tuples
378 //   unknown format string chars are returned as python None values !
379 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
380 {
381         PyObject *ret=0;
382         std::list<eServiceReference> tmplist;
383         int retcount=1;
384
385         if (!format || !(retcount=strlen(format)))
386                 format = "R"; // just return service reference swig object ...
387
388         if (!getContent(tmplist, sorted))
389         {
390                 int services=tmplist.size();
391                 ePtr<iStaticServiceInformation> sptr;
392                 eServiceCenterPtr service_center;
393
394                 if (strchr(format, 'N'))
395                         eServiceCenter::getPrivInstance(service_center);
396
397                 ret = PyList_New(services);
398                 std::list<eServiceReference>::iterator it(tmplist.begin());
399
400                 for (int cnt=0; cnt < services; ++cnt)
401                 {
402                         eServiceReference &ref=*it++;
403                         PyObject *tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
404                         for (int i=0; i < retcount; ++i)
405                         {
406                                 PyObject *tmp=0;
407                                 switch(format[i])
408                                 {
409                                 case 'R':  // service reference (swig)object
410                                         tmp = New_eServiceReference(ref);
411                                         break;
412                                 case 'S':  // service reference string
413                                         tmp = PyString_FromString(ref.toString().c_str());
414                                         break;
415                                 case 'N':  // service name
416                                         if (service_center)
417                                         {
418                                                 service_center->info(ref, sptr);
419                                                 if (sptr)
420                                                 {
421                                                         std::string name;
422                                                         sptr->getName(ref, name);
423                                                         if (name.length())
424                                                                 tmp = PyString_FromString(name.c_str());
425                                                 }
426                                         }
427                                         if (!tmp)
428                                                 tmp = PyString_FromString("<n/a>");
429                                         break;
430                                 default:
431                                         if (tuple)
432                                         {
433                                                 tmp = Py_None;
434                                                 Py_INCREF(Py_None);
435                                         }
436                                         break;
437                                 }
438                                 if (tmp)
439                                 {
440                                         if (tuple)
441                                                 PyTuple_SET_ITEM(tuple, i, tmp);
442                                         else
443                                                 PyList_SET_ITEM(ret, cnt, tmp);
444                                 }
445                         }
446                         if (tuple)
447                                 PyList_SET_ITEM(ret, cnt, tuple);
448                 }
449         }
450         return ret ? ret : PyList_New(0);
451 }
452
453 RESULT eDVBServiceList::getNext(eServiceReference &ref)
454 {
455         if (!m_query)
456                 return -1;
457         
458         return m_query->getNextResult((eServiceReferenceDVB&)ref);
459 }
460
461 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
462 {
463         return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
464 }
465
466 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
467 {
468         if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
469         {
470                 ePtr<iDVBChannelList> db;
471                 ePtr<eDVBResourceManager> resm;
472
473                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
474                         return -1;
475
476                 if (db->getBouquet(m_parent, m_bouquet) != 0)
477                         return -1;
478
479                 res = this;
480                 
481                 return 0;
482         }
483         res = 0;
484         return -1;
485 }
486
487 RESULT eDVBServiceList::addService(eServiceReference &ref)
488 {
489         if (!m_bouquet)
490                 return -1;
491         return m_bouquet->addService(ref);
492 }
493
494 RESULT eDVBServiceList::removeService(eServiceReference &ref)
495 {
496         if (!m_bouquet)
497                 return -1;
498         return m_bouquet->removeService(ref);
499 }
500
501 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
502 {
503         if (!m_bouquet)
504                 return -1;
505         return m_bouquet->moveService(ref, pos);
506 }
507
508 RESULT eDVBServiceList::flushChanges()
509 {
510         if (!m_bouquet)
511                 return -1;
512         return m_bouquet->flushChanges();
513 }
514
515 RESULT eDVBServiceList::setListName(const std::string &name)
516 {
517         if (!m_bouquet)
518                 return -1;
519         return m_bouquet->setListName(name);
520 }
521
522 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
523 {
524         ePtr<eDVBService> service;
525         int r = lookupService(service, ref);
526         if (r)
527                 service = 0;
528                 // check resources...
529         ptr = new eDVBServicePlay(ref, service);
530         return 0;
531 }
532
533 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
534 {
535         if (ref.path.empty())
536         {
537                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
538                 return 0;
539         } else
540         {
541                 ptr = 0;
542                 return -1;
543         }
544 }
545
546 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
547 {
548         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
549         if (list->startQuery())
550         {
551                 ptr = 0;
552                 return -1;
553         }
554         
555         ptr = list;
556         return 0;
557 }
558
559 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
560 {
561         /* is a listable service? */
562         if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
563         {
564                 if ( !ref.name.empty() )  // satellites or providers list
565                         ptr = new eStaticServiceDVBInformation;
566                 else // a dvb bouquet
567                         ptr = new eStaticServiceDVBBouquetInformation;
568         }
569         else if (!ref.path.empty()) /* do we have a PVR service? */
570                 ptr = new eStaticServiceDVBPVRInformation(ref);
571         else // normal dvb service
572         {
573                 ePtr<eDVBService> service;
574                 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
575                         ptr = new eStaticServiceDVBInformation;
576                 else
577                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
578                         ptr = service;
579         }
580         return 0;
581 }
582
583 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
584 {
585         if (ref.path.empty())
586         {
587                 ptr = 0;
588                 return -1;
589         } else
590         {
591                 ptr = new eDVBPVRServiceOfflineOperations(ref);
592                 return 0;
593         }
594 }
595
596 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
597 {
598                         // TODO: handle the listing itself
599         // if (ref.... == -1) .. return "... bouquets ...";
600         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
601                         // TODO: cache
602         ePtr<iDVBChannelList> db;
603         ePtr<eDVBResourceManager> res;
604         
605         int err;
606         if ((err = eDVBResourceManager::getInstance(res)) != 0)
607         {
608                 eDebug("no resource manager");
609                 return err;
610         }
611         if ((err = res->getChannelList(db)) != 0)
612         {
613                 eDebug("no channel list");
614                 return err;
615         }
616         
617                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
618         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
619         {
620                 eDebug("getService failed!");
621                 return err;
622         }
623
624         return 0;
625 }
626
627 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
628         m_reference(ref), m_dvb_service(service), m_is_paused(0)
629 {
630         m_is_primary = 1;
631         m_is_pvr = !m_reference.path.empty();
632         
633         m_timeshift_enabled = m_timeshift_active = 0;
634         m_skipmode = 0;
635         
636         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
637         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
638         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
639
640         m_cuesheet_changed = 0;
641         m_cutlist_enabled = 1;
642 }
643
644 eDVBServicePlay::~eDVBServicePlay()
645 {
646 }
647
648 void eDVBServicePlay::gotNewEvent()
649 {
650 #if 0
651                 // debug only
652         ePtr<eServiceEvent> m_event_now, m_event_next;
653         getEvent(m_event_now, 0);
654         getEvent(m_event_next, 1);
655
656         if (m_event_now)
657                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
658         if (m_event_next)
659                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
660 #endif
661         m_event((iPlayableService*)this, evUpdatedEventInfo);
662 }
663
664 void eDVBServicePlay::serviceEvent(int event)
665 {
666         switch (event)
667         {
668         case eDVBServicePMTHandler::eventTuned:
669         {
670                 ePtr<iDVBDemux> m_demux;
671                 if (!m_service_handler.getDataDemux(m_demux))
672                 {
673                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
674                         int sid = ref.getParentServiceID().get();
675                         if (!sid)
676                                 sid = ref.getServiceID().get();
677                         if ( ref.getParentTransportStreamID().get() &&
678                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
679                                 m_event_handler.startOther(m_demux, sid);
680                         else
681                                 m_event_handler.start(m_demux, sid);
682                 }
683                 break;
684         }
685         case eDVBServicePMTHandler::eventTuneFailed:
686         {
687                 eDebug("DVB service failed to tune");
688                 m_event((iPlayableService*)this, evTuneFailed);
689                 break;
690         }
691         case eDVBServicePMTHandler::eventNewProgramInfo:
692         {
693                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
694                 if (m_timeshift_enabled)
695                         updateTimeshiftPids();
696                 if (!m_timeshift_active)
697                         updateDecoder();
698                 if (m_first_program_info && m_is_pvr)
699                 {
700                         m_first_program_info = 0;
701                         seekTo(0);
702                 }
703                 m_event((iPlayableService*)this, evUpdatedInfo);
704                 break;
705         }
706         case eDVBServicePMTHandler::eventEOF:
707                 m_event((iPlayableService*)this, evEOF);
708                 break;
709         case eDVBServicePMTHandler::eventSOF:
710                 m_event((iPlayableService*)this, evSOF);
711                 break;
712         }
713 }
714
715 void eDVBServicePlay::serviceEventTimeshift(int event)
716 {
717         switch (event)
718         {
719         case eDVBServicePMTHandler::eventNewProgramInfo:
720                 if (m_timeshift_active)
721                         updateDecoder();
722                 break;
723         case eDVBServicePMTHandler::eventSOF:
724                 m_event((iPlayableService*)this, evSOF);
725                 break;
726         case eDVBServicePMTHandler::eventEOF:
727                 switchToLive();
728                 break;
729         }
730 }
731
732 RESULT eDVBServicePlay::start()
733 {
734         int r;
735                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
736                    two (one for decoding, one for data source), as we must be prepared
737                    to start recording from the data demux. */
738         if (m_is_pvr)
739                 m_cue = new eCueSheet();
740
741         m_first_program_info = 1;
742         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
743         r = m_service_handler.tune(service, m_is_pvr, m_cue);
744         
745                 /* inject EIT if there is a stored one */
746         if (m_is_pvr)
747         {
748                 std::string filename = service.path;
749                 filename.erase(filename.length()-2, 2);
750                 filename+="eit";
751                 int fd = ::open( filename.c_str(), O_RDONLY );
752                 if ( fd > -1 )
753                 {
754                         __u8 buf[4096];
755                         int rd = ::read(fd, buf, 4096);
756                         ::close(fd);
757                         if ( rd > 12 /*EIT_LOOP_SIZE*/ )
758                         {
759                                 Event ev(buf);
760                                 ePtr<eServiceEvent> event = new eServiceEvent;
761                                 ePtr<eServiceEvent> empty;
762                                 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
763                                 m_event_handler.inject(event, 0);
764                                 m_event_handler.inject(empty, 1);
765                                 eDebug("injected");
766                         }
767                 }
768         }
769         
770         if (m_is_pvr)
771                 loadCuesheet();
772
773         m_event(this, evStart);
774         m_event((iPlayableService*)this, evSeekableStatusChanged);
775         return 0;
776 }
777
778 RESULT eDVBServicePlay::stop()
779 {
780         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
781
782         m_service_handler_timeshift.free();
783         m_service_handler.free();
784         
785         if (m_is_pvr && m_cuesheet_changed)
786                 saveCuesheet();
787         
788         return 0;
789 }
790
791 RESULT eDVBServicePlay::setTarget(int target)
792 {
793         m_is_primary = !target;
794         return 0;
795 }
796
797 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
798 {
799         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
800         return 0;
801 }
802
803 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
804 {
805                 /* note: we check for timeshift to be enabled,
806                    not neccessary active. if you pause when timeshift
807                    is not active, you should activate it when unpausing */
808         if ((!m_is_pvr) && (!m_timeshift_enabled))
809         {
810                 ptr = 0;
811                 return -1;
812         }
813
814         ptr = this;
815         return 0;
816 }
817
818 RESULT eDVBServicePlay::setSlowMotion(int ratio)
819 {
820         if (m_decoder)
821                 return m_decoder->setSlowMotion(ratio);
822         else
823                 return -1;
824 }
825
826 RESULT eDVBServicePlay::setFastForward(int ratio)
827 {
828         int skipmode, ffratio;
829         
830         if (ratio > 8)
831         {
832                 skipmode = ratio;
833                 ffratio = 1;
834         } else if (ratio > 0)
835         {
836                 skipmode = 0;
837                 ffratio = ratio;
838         } else if (!ratio)
839         {
840                 skipmode = 0;
841                 ffratio = 0;
842         } else // if (ratio < 0)
843         {
844                 skipmode = ratio;
845                 ffratio = 1;
846         }
847
848         if (m_skipmode != skipmode)
849         {
850                 eDebug("setting cue skipmode to %d", skipmode);
851                 if (m_cue)
852                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
853         }
854         
855         m_skipmode = skipmode;
856         
857         if (!m_decoder)
858                 return -1;
859
860         return m_decoder->setFastForward(ffratio);
861 }
862     
863 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
864 {
865         if (m_is_pvr || m_timeshift_enabled)
866         {
867                 ptr = this;
868                 return 0;
869         }
870         
871         ptr = 0;
872         return -1;
873 }
874
875         /* TODO: when timeshift is enabled but not active, this doesn't work. */
876 RESULT eDVBServicePlay::getLength(pts_t &len)
877 {
878         ePtr<iDVBPVRChannel> pvr_channel;
879         
880         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
881                 return -1;
882         
883         return pvr_channel->getLength(len);
884 }
885
886 RESULT eDVBServicePlay::pause()
887 {
888         if (!m_is_paused && m_decoder)
889         {
890                 m_is_paused = 1;
891                 return m_decoder->freeze(0);
892         } else
893                 return -1;
894 }
895
896 RESULT eDVBServicePlay::unpause()
897 {
898         if (m_is_paused && m_decoder)
899         {
900                 m_is_paused = 0;
901                 return m_decoder->unfreeze();
902         } else
903                 return -1;
904 }
905
906 RESULT eDVBServicePlay::seekTo(pts_t to)
907 {
908         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
909         
910         if (!m_decode_demux)
911                 return -1;
912
913         ePtr<iDVBPVRChannel> pvr_channel;
914         
915         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
916                 return -1;
917         
918         if (!m_cue)
919                 return -1;
920         
921         m_cue->seekTo(0, to);
922         return 0;
923 }
924
925 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
926 {
927         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
928         
929         if (!m_decode_demux)
930                 return -1;
931
932         ePtr<iDVBPVRChannel> pvr_channel;
933         
934         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
935                 return -1;
936         
937         int mode = 1;
938         
939                         /* HACK until we have skip-AP api */
940         if ((to > 0) && (to < 100))
941                 mode = 2;
942         
943         to *= direction;
944         
945         if (!m_cue)
946                 return 0;
947         
948         m_cue->seekTo(mode, to);
949         return 0;
950 }
951
952 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
953 {
954         ePtr<iDVBPVRChannel> pvr_channel;
955         
956         if (!m_decode_demux)
957                 return -1;
958         
959         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
960                 return -1;
961         
962         int r = 0;
963
964                 /* if there is a decoder, use audio or video PTS */
965         if (m_decoder)
966         {
967                 r = m_decoder->getPTS(0, pos);
968                 if (r)
969                         return r;
970         }
971         
972                 /* fixup */
973         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
974 }
975
976 RESULT eDVBServicePlay::setTrickmode(int trick)
977 {
978         if (m_decoder)
979                 m_decoder->setTrickmode(trick);
980         return 0;
981 }
982
983 RESULT eDVBServicePlay::isCurrentlySeekable()
984 {
985         return m_is_pvr || m_timeshift_active;
986 }
987
988 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
989 {
990         ptr = this;
991         return 0;
992 }
993
994 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
995 {
996         ptr = this;
997         return 0;
998 }
999
1000 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1001 {
1002         ptr = this;
1003         return 0;
1004 }
1005
1006 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1007 {
1008         ptr = this;
1009         return 0;
1010 }
1011
1012 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1013 {
1014         ptr = 0;
1015         if (m_timeshift_enabled || !m_is_pvr)
1016         {
1017                 if (!m_timeshift_enabled)
1018                 {
1019                                 /* we need enough diskspace */
1020                         struct statfs fs;
1021                         if (statfs(TSPATH "/.", &fs) < 0)
1022                         {
1023                                 eDebug("statfs failed!");
1024                                 return -2;
1025                         }
1026                 
1027                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1028                         {
1029                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1030                                 return -3;
1031                         }
1032                 }
1033                 ptr = this;
1034                 return 0;
1035         }
1036         return -1;
1037 }
1038
1039 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1040 {
1041         if (m_is_pvr)
1042         {
1043                 ptr = this;
1044                 return 0;
1045         }
1046         ptr = 0;
1047         return -1;
1048 }
1049
1050 RESULT eDVBServicePlay::getName(std::string &name)
1051 {
1052         if (m_is_pvr)
1053         {
1054                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1055                 return i->getName(m_reference, name);
1056         }
1057         if (m_dvb_service)
1058         {
1059                 m_dvb_service->getName(m_reference, name);
1060                 if (name.empty())
1061                         name = "(...)";
1062         }
1063         else if (!m_reference.name.empty())
1064                 eStaticServiceDVBInformation().getName(m_reference, name);
1065         else
1066                 name = "DVB service";
1067         return 0;
1068 }
1069
1070 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1071 {
1072         return m_event_handler.getEvent(evt, nownext);
1073 }
1074
1075 int eDVBServicePlay::getInfo(int w)
1076 {
1077         eDVBServicePMTHandler::program program;
1078
1079         if (w == sCAIDs)
1080                 return resIsPyObject;
1081
1082         if (m_service_handler.getProgramInfo(program))
1083                 return -1;
1084         
1085         switch (w)
1086         {
1087         case sAspect:
1088                 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1089                 {
1090                         ePtr<eServiceEvent> evt;
1091                         if (!m_event_handler.getEvent(evt, 0))
1092                         {
1093                                 ePtr<eComponentData> data;
1094                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1095                                 {
1096                                         if ( data->getStreamContent() == 1 )
1097                                         {
1098                                                 switch(data->getComponentType())
1099                                                 {
1100                                                         // SD
1101                                                         case 1: // 4:3 SD PAL
1102                                                         case 2:
1103                                                         case 3: // 16:9 SD PAL
1104                                                         case 4: // > 16:9 PAL
1105                                                         case 5: // 4:3 SD NTSC
1106                                                         case 6: 
1107                                                         case 7: // 16:9 SD NTSC
1108                                                         case 8: // > 16:9 NTSC
1109
1110                                                         // HD
1111                                                         case 9: // 4:3 HD PAL
1112                                                         case 0xA:
1113                                                         case 0xB: // 16:9 HD PAL
1114                                                         case 0xC: // > 16:9 HD PAL
1115                                                         case 0xD: // 4:3 HD NTSC
1116                                                         case 0xE:
1117                                                         case 0xF: // 16:9 HD NTSC
1118                                                         case 0x10: // > 16:9 HD PAL
1119                                                                 return data->getComponentType();
1120                                                 }
1121                                         }
1122                                 }
1123                         }
1124                 }
1125                 return -1;
1126         case sIsCrypted: return program.isCrypted;
1127         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1128         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1129         case sPCRPID: return program.pcrPid;
1130         case sPMTPID: return program.pmtPid;
1131         case sTXTPID: return program.textPid;
1132         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1133         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1134         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1135         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1136         case sProvider: if (!m_dvb_service) return -1; return -2;
1137         default:
1138                 return -1;
1139         }
1140 }
1141
1142 std::string eDVBServicePlay::getInfoString(int w)
1143 {
1144         switch (w)
1145         {
1146         case sProvider:
1147                 if (!m_dvb_service) return "";
1148                 return m_dvb_service->m_provider_name;
1149         default:
1150                 break;
1151         }
1152         return iServiceInformation::getInfoString(w);
1153 }
1154
1155 PyObject *eDVBServicePlay::getInfoObject(int w)
1156 {
1157         switch (w)
1158         {
1159         case sCAIDs:
1160                 return m_service_handler.getCaIds();
1161         default:
1162                 break;
1163         }
1164         return iServiceInformation::getInfoObject(w);
1165 }
1166
1167 int eDVBServicePlay::getNumberOfTracks()
1168 {
1169         eDVBServicePMTHandler::program program;
1170         if (m_service_handler.getProgramInfo(program))
1171                 return 0;
1172         return program.audioStreams.size();
1173 }
1174
1175 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1176 {
1177         int ret = selectAudioStream(i);
1178
1179         if (m_decoder->start())
1180                 return -5;
1181
1182         return ret;
1183 }
1184
1185 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1186 {
1187         eDVBServicePMTHandler::program program;
1188
1189         if (m_service_handler.getProgramInfo(program))
1190                 return -1;
1191         
1192         if (i >= program.audioStreams.size())
1193                 return -2;
1194         
1195         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1196                 info.m_description = "MPEG";
1197         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1198                 info.m_description = "AC3";
1199         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1200                 info.m_description = "DTS";
1201         else
1202                 info.m_description = "???";
1203
1204         if (program.audioStreams[i].component_tag != -1)
1205         {
1206                 ePtr<eServiceEvent> evt;
1207                 if (!m_event_handler.getEvent(evt, 0))
1208                 {
1209                         ePtr<eComponentData> data;
1210                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1211                                 info.m_language = data->getText();
1212                 }
1213         }
1214
1215         if (info.m_language.empty())
1216                 info.m_language = program.audioStreams[i].language_code;
1217         
1218         return 0;
1219 }
1220
1221 int eDVBServicePlay::selectAudioStream(int i)
1222 {
1223         eDVBServicePMTHandler::program program;
1224
1225         if (m_service_handler.getProgramInfo(program))
1226                 return -1;
1227         
1228         if ((unsigned int)i >= program.audioStreams.size())
1229                 return -2;
1230         
1231         if (!m_decoder)
1232                 return -3;
1233         
1234         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1235                 return -4;
1236
1237         if (m_dvb_service && !m_is_pvr)
1238         {
1239                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1240                 {
1241                         m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1242                         m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1243                 }       else
1244                 {
1245                         m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1246                         m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1247                 }
1248         }
1249
1250         m_current_audio_stream = i;
1251
1252         return 0;
1253 }
1254
1255 int eDVBServicePlay::getFrontendInfo(int w)
1256 {
1257         if (m_is_pvr)
1258                 return 0;
1259         eUsePtr<iDVBChannel> channel;
1260         if(m_service_handler.getChannel(channel))
1261                 return 0;
1262         ePtr<iDVBFrontend> fe;
1263         if(channel->getFrontend(fe))
1264                 return 0;
1265         return fe->readFrontendData(w);
1266 }
1267
1268 PyObject *eDVBServicePlay::getFrontendData(bool original)
1269 {
1270         PyObject *ret=0;
1271
1272         eUsePtr<iDVBChannel> channel;
1273         if(!m_service_handler.getChannel(channel))
1274         {
1275                 ePtr<iDVBFrontend> fe;
1276                 if(!channel->getFrontend(fe))
1277                 {
1278                         ret = fe->readTransponderData(original);
1279                         if (ret)
1280                         {
1281                                 ePtr<iDVBFrontendParameters> feparm;
1282                                 channel->getCurrentFrontendParameters(feparm);
1283                                 if (feparm)
1284                                 {
1285                                         eDVBFrontendParametersSatellite osat;
1286                                         if (!feparm->getDVBS(osat))
1287                                         {
1288                                                 void PutToDict(PyObject *, const char*, long);
1289                                                 void PutToDict(PyObject *, const char*, const char*);
1290                                                 PutToDict(ret, "orbital_position", osat.orbital_position);
1291                                                 const char *tmp = "UNKNOWN";
1292                                                 switch(osat.polarisation)
1293                                                 {
1294                                                         case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1295                                                         case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1296                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1297                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1298                                                         default:break;
1299                                                 }
1300                                                 PutToDict(ret, "polarization", tmp);
1301                                         }
1302                                 }
1303                         }
1304                 }
1305         }
1306         if (!ret)
1307         {
1308                 ret = Py_None;
1309                 Py_INCREF(ret);
1310         }
1311         return ret;
1312 }
1313
1314 int eDVBServicePlay::getNumberOfSubservices()
1315 {
1316         ePtr<eServiceEvent> evt;
1317         if (!m_event_handler.getEvent(evt, 0))
1318                 return evt->getNumOfLinkageServices();
1319         return 0;
1320 }
1321
1322 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1323 {
1324         ePtr<eServiceEvent> evt;
1325         if (!m_event_handler.getEvent(evt, 0))
1326         {
1327                 if (!evt->getLinkageService(sub, m_reference, n))
1328                         return 0;
1329         }
1330         sub.type=eServiceReference::idInvalid;
1331         return -1;
1332 }
1333
1334 RESULT eDVBServicePlay::startTimeshift()
1335 {
1336         ePtr<iDVBDemux> demux;
1337         
1338         eDebug("Start timeshift!");
1339         
1340         if (m_timeshift_enabled)
1341                 return -1;
1342         
1343                 /* start recording with the data demux. */
1344         if (m_service_handler.getDataDemux(demux))
1345                 return -2;
1346
1347         demux->createTSRecorder(m_record);
1348         if (!m_record)
1349                 return -3;
1350
1351         char templ[]=TSPATH "/timeshift.XXXXXX";
1352         m_timeshift_fd = mkstemp(templ);
1353         m_timeshift_file = templ;
1354         
1355         eDebug("recording to %s", templ);
1356         
1357         if (m_timeshift_fd < 0)
1358         {
1359                 m_record = 0;
1360                 return -4;
1361         }
1362                 
1363         m_record->setTargetFD(m_timeshift_fd);
1364
1365         m_timeshift_enabled = 1;
1366         
1367         updateTimeshiftPids();
1368         m_record->start();
1369
1370         return 0;
1371 }
1372
1373 RESULT eDVBServicePlay::stopTimeshift()
1374 {
1375         if (!m_timeshift_enabled)
1376                 return -1;
1377         
1378         switchToLive();
1379         
1380         m_timeshift_enabled = 0;
1381         
1382         m_record->stop();
1383         m_record = 0;
1384         
1385         close(m_timeshift_fd);
1386         eDebug("remove timeshift file");
1387         remove(m_timeshift_file.c_str());
1388         
1389         return 0;
1390 }
1391
1392 int eDVBServicePlay::isTimeshiftActive()
1393 {
1394         return m_timeshift_enabled && m_timeshift_active;
1395 }
1396
1397 RESULT eDVBServicePlay::activateTimeshift()
1398 {
1399         if (!m_timeshift_enabled)
1400                 return -1;
1401         
1402         if (!m_timeshift_active)
1403         {
1404                 switchToTimeshift();
1405                 return 0;
1406         }
1407         
1408         return -2;
1409 }
1410
1411 PyObject *eDVBServicePlay::getCutList()
1412 {
1413         PyObject *list = PyList_New(0);
1414         
1415         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1416         {
1417                 PyObject *tuple = PyTuple_New(2);
1418                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1419                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1420                 PyList_Append(list, tuple);
1421                 Py_DECREF(tuple);
1422         }
1423         
1424         return list;
1425 }
1426
1427 void eDVBServicePlay::setCutList(PyObject *list)
1428 {
1429         if (!PyList_Check(list))
1430                 return;
1431         int size = PyList_Size(list);
1432         int i;
1433         
1434         m_cue_entries.clear();
1435         
1436         for (i=0; i<size; ++i)
1437         {
1438                 PyObject *tuple = PyList_GetItem(list, i);
1439                 if (!PyTuple_Check(tuple))
1440                 {
1441                         eDebug("non-tuple in cutlist");
1442                         continue;
1443                 }
1444                 if (PyTuple_Size(tuple) != 2)
1445                 {
1446                         eDebug("cutlist entries need to be a 2-tuple");
1447                         continue;
1448                 }
1449                 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1450                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1451                 {
1452                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1453                         continue;
1454                 }
1455                 pts_t pts = PyLong_AsLongLong(ppts);
1456                 int type = PyInt_AsLong(ptype);
1457                 m_cue_entries.insert(cueEntry(pts, type));
1458                 eDebug("adding %08llx, %d", pts, type);
1459         }
1460         m_cuesheet_changed = 1;
1461         
1462         cutlistToCuesheet();
1463         m_event((iPlayableService*)this, evCuesheetChanged);
1464 }
1465
1466 void eDVBServicePlay::setCutListEnable(int enable)
1467 {
1468         m_cutlist_enabled = enable;
1469         cutlistToCuesheet();
1470 }
1471
1472 void eDVBServicePlay::updateTimeshiftPids()
1473 {
1474         if (!m_record)
1475                 return;
1476         
1477         eDVBServicePMTHandler::program program;
1478         if (m_service_handler.getProgramInfo(program))
1479                 return;
1480         else
1481         {
1482                 std::set<int> pids_to_record;
1483                 pids_to_record.insert(0); // PAT
1484                 if (program.pmtPid != -1)
1485                         pids_to_record.insert(program.pmtPid); // PMT
1486
1487                 if (program.textPid != -1)
1488                         pids_to_record.insert(program.textPid); // Videotext
1489
1490                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1491                         i(program.videoStreams.begin()); 
1492                         i != program.videoStreams.end(); ++i)
1493                         pids_to_record.insert(i->pid);
1494
1495                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1496                         i(program.audioStreams.begin()); 
1497                         i != program.audioStreams.end(); ++i)
1498                                 pids_to_record.insert(i->pid);
1499
1500                 std::set<int> new_pids, obsolete_pids;
1501                 
1502                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1503                                 m_pids_active.begin(), m_pids_active.end(),
1504                                 std::inserter(new_pids, new_pids.begin()));
1505                 
1506                 std::set_difference(
1507                                 m_pids_active.begin(), m_pids_active.end(),
1508                                 pids_to_record.begin(), pids_to_record.end(), 
1509                                 std::inserter(new_pids, new_pids.begin())
1510                                 );
1511
1512                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1513                         m_record->addPID(*i);
1514
1515                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1516                         m_record->removePID(*i);
1517         }
1518 }
1519
1520 void eDVBServicePlay::switchToLive()
1521 {
1522         if (!m_timeshift_active)
1523                 return;
1524         
1525         m_cue = 0;
1526         m_decoder = 0;
1527         m_decode_demux = 0;
1528         m_teletext_parser = 0;
1529         
1530                 /* free the timeshift service handler, we need the resources */
1531         m_service_handler_timeshift.free();
1532         m_timeshift_active = 0;
1533         
1534         m_event((iPlayableService*)this, evSeekableStatusChanged);
1535         
1536         updateDecoder();
1537 }
1538
1539 void eDVBServicePlay::switchToTimeshift()
1540 {
1541         if (m_timeshift_active)
1542                 return;
1543         
1544         m_decode_demux = 0;
1545         m_decoder = 0;
1546         m_teletext_parser = 0;
1547         
1548         m_timeshift_active = 1;
1549
1550         m_event((iPlayableService*)this, evSeekableStatusChanged);
1551         
1552         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1553         r.path = m_timeshift_file;
1554         
1555         m_cue = new eCueSheet();
1556         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1557         updateDecoder(); /* mainly to switch off PCR */
1558 }
1559
1560 void eDVBServicePlay::updateDecoder()
1561 {
1562         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1563         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1564
1565         bool defaultac3=false;
1566         std::string default_ac3;
1567
1568         if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
1569                 defaultac3 = default_ac3 == "enable";
1570
1571         eDVBServicePMTHandler::program program;
1572         if (h.getProgramInfo(program))
1573                 eDebug("getting program info failed.");
1574         else
1575         {
1576                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1577                 if (!program.videoStreams.empty())
1578                 {
1579                         eDebugNoNewLine(" (");
1580                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1581                                 i(program.videoStreams.begin()); 
1582                                 i != program.videoStreams.end(); ++i)
1583                         {
1584                                 if (vpid == -1)
1585                                         vpid = i->pid;
1586                                 if (i != program.videoStreams.begin())
1587                                         eDebugNoNewLine(", ");
1588                                 eDebugNoNewLine("%04x", i->pid);
1589                         }
1590                         eDebugNoNewLine(")");
1591                 }
1592                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1593                 if (!program.audioStreams.empty())
1594                 {
1595                         eDebugNoNewLine(" (");
1596                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1597                                 i(program.audioStreams.begin()); 
1598                                 i != program.audioStreams.end(); ++i)
1599                         {
1600                                 if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
1601                                 {
1602                                         if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
1603                                         {
1604                                                 apid = i->pid;
1605                                                 apidtype = i->type;
1606                                         }
1607                                 }
1608                                 if (i != program.audioStreams.begin())
1609                                         eDebugNoNewLine(", ");
1610                                 eDebugNoNewLine("%04x", i->pid);
1611                         }
1612                         eDebugNoNewLine(")");
1613                 }
1614                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1615                 pcrpid = program.pcrPid;
1616                 eDebug(", and the text pid is %04x", program.textPid);
1617                 tpid = program.textPid;
1618         }
1619
1620         if (!m_decoder)
1621         {
1622                 h.getDecodeDemux(m_decode_demux);
1623                 if (m_decode_demux)
1624                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1625                 if (m_cue)
1626                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1627 #ifdef INTERNAL_TELETEXT
1628                 m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
1629 #endif
1630         }
1631
1632         if (m_decoder)
1633         {
1634                 m_decoder->setVideoPID(vpid);
1635                 m_current_audio_stream = 0;
1636                 m_decoder->setAudioPID(apid, apidtype);
1637                 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1638                         m_decoder->setSyncPCR(pcrpid);
1639                 else
1640                         m_decoder->setSyncPCR(-1);
1641 #ifndef INTERNAL_TELETEXT
1642                 m_decoder->setTextPID(tpid);
1643 #else
1644                 if (m_teletext_parser)
1645                         m_teletext_parser->start(tpid);
1646 #endif
1647
1648                 if (!m_is_primary)
1649                         m_decoder->setTrickmode(1);
1650                 m_decoder->start();
1651 // how we can do this better?
1652 // update cache pid when the user changed the audio track or video track
1653 // TODO handling of difference audio types.. default audio types..
1654                                 
1655                 /* don't worry about non-existing services, nor pvr services */
1656                 if (m_dvb_service && !m_is_pvr)
1657                 {
1658                         if (apidtype == eDVBAudio::aMPEG)
1659                         {
1660                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1661                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1662                         }
1663                         else
1664                         {
1665                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1666                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1667                         }
1668                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1669                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1670                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1671                 }
1672         }
1673 }
1674
1675 void eDVBServicePlay::loadCuesheet()
1676 {
1677         std::string filename = m_reference.path + ".cuts";
1678         
1679         m_cue_entries.clear();
1680
1681         FILE *f = fopen(filename.c_str(), "rb");
1682
1683         if (f)
1684         {
1685                 eDebug("loading cuts..");
1686                 while (1)
1687                 {
1688                         unsigned long long where;
1689                         unsigned int what;
1690                         
1691                         if (!fread(&where, sizeof(where), 1, f))
1692                                 break;
1693                         if (!fread(&what, sizeof(what), 1, f))
1694                                 break;
1695                         
1696 #if BYTE_ORDER == LITTLE_ENDIAN
1697                         where = bswap_64(where);
1698 #endif
1699                         what = ntohl(what);
1700                         
1701                         if (what > 2)
1702                                 break;
1703                         
1704                         m_cue_entries.insert(cueEntry(where, what));
1705                 }
1706                 fclose(f);
1707                 eDebug("%d entries", m_cue_entries.size());
1708         } else
1709                 eDebug("cutfile not found!");
1710         
1711         m_cuesheet_changed = 0;
1712         cutlistToCuesheet();
1713         m_event((iPlayableService*)this, evCuesheetChanged);
1714 }
1715
1716 void eDVBServicePlay::saveCuesheet()
1717 {
1718         std::string filename = m_reference.path + ".cuts";
1719         
1720         FILE *f = fopen(filename.c_str(), "wb");
1721
1722         if (f)
1723         {
1724                 unsigned long long where;
1725                 int what;
1726
1727                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1728                 {
1729 #if BYTE_ORDER == BIG_ENDIAN
1730                         where = i->where;
1731 #else
1732                         where = bswap_64(i->where);
1733 #endif
1734                         what = htonl(i->what);
1735                         fwrite(&where, sizeof(where), 1, f);
1736                         fwrite(&what, sizeof(what), 1, f);
1737                         
1738                 }
1739                 fclose(f);
1740         }
1741         
1742         m_cuesheet_changed = 0;
1743 }
1744
1745 void eDVBServicePlay::cutlistToCuesheet()
1746 {
1747         if (!m_cue)
1748         {
1749                 eDebug("no cue sheet");
1750                 return;
1751         }       
1752         m_cue->clear();
1753         
1754         if (!m_cutlist_enabled)
1755         {
1756                 m_cue->commitSpans();
1757                 eDebug("cutlists where disabled");
1758                 return;
1759         }
1760
1761         pts_t in = 0, out = 0, length = 0;
1762         
1763         getLength(length);
1764                 
1765         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1766         
1767         while (1)
1768         {
1769                 if (i == m_cue_entries.end())
1770                         out = length;
1771                 else {
1772                         if (i->what == 0) /* in */
1773                         {
1774                                 in = i++->where;
1775                                 continue;
1776                         } else if (i->what == 1) /* out */
1777                                 out = i++->where;
1778                         else /* mark */
1779                         {
1780                                 i++;
1781                                 continue;
1782                         }
1783                 }
1784                 
1785                 if (in != out)
1786                         m_cue->addSourceSpan(in, out);
1787                 
1788                 in = length;
1789                 
1790                 if (i == m_cue_entries.end())
1791                         break;
1792         }
1793         m_cue->commitSpans();
1794 }
1795
1796 DEFINE_REF(eDVBServicePlay)
1797
1798 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");