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