fix getting caids of subservices
[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
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                 return m_service_handler.getCaIds();
1162         default:
1163                 break;
1164         }
1165         return iServiceInformation::getInfoObject(w);
1166 }
1167
1168 int eDVBServicePlay::getNumberOfTracks()
1169 {
1170         eDVBServicePMTHandler::program program;
1171         if (m_service_handler.getProgramInfo(program))
1172                 return 0;
1173         return program.audioStreams.size();
1174 }
1175
1176 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1177 {
1178         int ret = selectAudioStream(i);
1179
1180         if (m_decoder->start())
1181                 return -5;
1182
1183         return ret;
1184 }
1185
1186 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1187 {
1188         eDVBServicePMTHandler::program program;
1189
1190         if (m_service_handler.getProgramInfo(program))
1191                 return -1;
1192         
1193         if (i >= program.audioStreams.size())
1194                 return -2;
1195         
1196         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1197                 info.m_description = "MPEG";
1198         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1199                 info.m_description = "AC3";
1200         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1201                 info.m_description = "DTS";
1202         else
1203                 info.m_description = "???";
1204
1205         if (program.audioStreams[i].component_tag != -1)
1206         {
1207                 ePtr<eServiceEvent> evt;
1208                 if (!m_event_handler.getEvent(evt, 0))
1209                 {
1210                         ePtr<eComponentData> data;
1211                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1212                                 info.m_language = data->getText();
1213                 }
1214         }
1215
1216         if (info.m_language.empty())
1217                 info.m_language = program.audioStreams[i].language_code;
1218         
1219         return 0;
1220 }
1221
1222 int eDVBServicePlay::selectAudioStream(int i)
1223 {
1224         eDVBServicePMTHandler::program program;
1225
1226         if (m_service_handler.getProgramInfo(program))
1227                 return -1;
1228         
1229         if ((unsigned int)i >= program.audioStreams.size())
1230                 return -2;
1231         
1232         if (!m_decoder)
1233                 return -3;
1234         
1235         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1236                 return -4;
1237
1238         if (m_dvb_service && !m_is_pvr)
1239         {
1240                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1241                 {
1242                         m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1243                         m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1244                 }       else
1245                 {
1246                         m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1247                         m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1248                 }
1249         }
1250
1251         m_current_audio_stream = i;
1252
1253         return 0;
1254 }
1255
1256 int eDVBServicePlay::getFrontendInfo(int w)
1257 {
1258         if (m_is_pvr)
1259                 return 0;
1260         eUsePtr<iDVBChannel> channel;
1261         if(m_service_handler.getChannel(channel))
1262                 return 0;
1263         ePtr<iDVBFrontend> fe;
1264         if(channel->getFrontend(fe))
1265                 return 0;
1266         return fe->readFrontendData(w);
1267 }
1268
1269 PyObject *eDVBServicePlay::getFrontendData(bool original)
1270 {
1271         PyObject *ret=0;
1272
1273         eUsePtr<iDVBChannel> channel;
1274         if(!m_service_handler.getChannel(channel))
1275         {
1276                 ePtr<iDVBFrontend> fe;
1277                 if(!channel->getFrontend(fe))
1278                 {
1279                         ret = fe->readTransponderData(original);
1280                         if (ret)
1281                         {
1282                                 ePtr<iDVBFrontendParameters> feparm;
1283                                 channel->getCurrentFrontendParameters(feparm);
1284                                 if (feparm)
1285                                 {
1286                                         eDVBFrontendParametersSatellite osat;
1287                                         if (!feparm->getDVBS(osat))
1288                                         {
1289                                                 void PutToDict(PyObject *, const char*, long);
1290                                                 void PutToDict(PyObject *, const char*, const char*);
1291                                                 PutToDict(ret, "orbital_position", osat.orbital_position);
1292                                                 const char *tmp = "UNKNOWN";
1293                                                 switch(osat.polarisation)
1294                                                 {
1295                                                         case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1296                                                         case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1297                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1298                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1299                                                         default:break;
1300                                                 }
1301                                                 PutToDict(ret, "polarization", tmp);
1302                                         }
1303                                 }
1304                         }
1305                 }
1306         }
1307         if (!ret)
1308         {
1309                 ret = Py_None;
1310                 Py_INCREF(ret);
1311         }
1312         return ret;
1313 }
1314
1315 int eDVBServicePlay::getNumberOfSubservices()
1316 {
1317         ePtr<eServiceEvent> evt;
1318         if (!m_event_handler.getEvent(evt, 0))
1319                 return evt->getNumOfLinkageServices();
1320         return 0;
1321 }
1322
1323 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1324 {
1325         ePtr<eServiceEvent> evt;
1326         if (!m_event_handler.getEvent(evt, 0))
1327         {
1328                 if (!evt->getLinkageService(sub, m_reference, n))
1329                         return 0;
1330         }
1331         sub.type=eServiceReference::idInvalid;
1332         return -1;
1333 }
1334
1335 RESULT eDVBServicePlay::startTimeshift()
1336 {
1337         ePtr<iDVBDemux> demux;
1338         
1339         eDebug("Start timeshift!");
1340         
1341         if (m_timeshift_enabled)
1342                 return -1;
1343         
1344                 /* start recording with the data demux. */
1345         if (m_service_handler.getDataDemux(demux))
1346                 return -2;
1347
1348         demux->createTSRecorder(m_record);
1349         if (!m_record)
1350                 return -3;
1351
1352         char templ[]=TSPATH "/timeshift.XXXXXX";
1353         m_timeshift_fd = mkstemp(templ);
1354         m_timeshift_file = templ;
1355         
1356         eDebug("recording to %s", templ);
1357         
1358         if (m_timeshift_fd < 0)
1359         {
1360                 m_record = 0;
1361                 return -4;
1362         }
1363                 
1364         m_record->setTargetFD(m_timeshift_fd);
1365
1366         m_timeshift_enabled = 1;
1367         
1368         updateTimeshiftPids();
1369         m_record->start();
1370
1371         return 0;
1372 }
1373
1374 RESULT eDVBServicePlay::stopTimeshift()
1375 {
1376         if (!m_timeshift_enabled)
1377                 return -1;
1378         
1379         switchToLive();
1380         
1381         m_timeshift_enabled = 0;
1382         
1383         m_record->stop();
1384         m_record = 0;
1385         
1386         close(m_timeshift_fd);
1387         eDebug("remove timeshift file");
1388         remove(m_timeshift_file.c_str());
1389         
1390         return 0;
1391 }
1392
1393 int eDVBServicePlay::isTimeshiftActive()
1394 {
1395         return m_timeshift_enabled && m_timeshift_active;
1396 }
1397
1398 RESULT eDVBServicePlay::activateTimeshift()
1399 {
1400         if (!m_timeshift_enabled)
1401                 return -1;
1402         
1403         if (!m_timeshift_active)
1404         {
1405                 switchToTimeshift();
1406                 return 0;
1407         }
1408         
1409         return -2;
1410 }
1411
1412 PyObject *eDVBServicePlay::getCutList()
1413 {
1414         PyObject *list = PyList_New(0);
1415         
1416         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1417         {
1418                 PyObject *tuple = PyTuple_New(2);
1419                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1420                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1421                 PyList_Append(list, tuple);
1422                 Py_DECREF(tuple);
1423         }
1424         
1425         return list;
1426 }
1427
1428 void eDVBServicePlay::setCutList(PyObject *list)
1429 {
1430         if (!PyList_Check(list))
1431                 return;
1432         int size = PyList_Size(list);
1433         int i;
1434         
1435         m_cue_entries.clear();
1436         
1437         for (i=0; i<size; ++i)
1438         {
1439                 PyObject *tuple = PyList_GetItem(list, i);
1440                 if (!PyTuple_Check(tuple))
1441                 {
1442                         eDebug("non-tuple in cutlist");
1443                         continue;
1444                 }
1445                 if (PyTuple_Size(tuple) != 2)
1446                 {
1447                         eDebug("cutlist entries need to be a 2-tuple");
1448                         continue;
1449                 }
1450                 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1451                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1452                 {
1453                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1454                         continue;
1455                 }
1456                 pts_t pts = PyLong_AsLongLong(ppts);
1457                 int type = PyInt_AsLong(ptype);
1458                 m_cue_entries.insert(cueEntry(pts, type));
1459                 eDebug("adding %08llx, %d", pts, type);
1460         }
1461         m_cuesheet_changed = 1;
1462         
1463         cutlistToCuesheet();
1464         m_event((iPlayableService*)this, evCuesheetChanged);
1465 }
1466
1467 void eDVBServicePlay::setCutListEnable(int enable)
1468 {
1469         m_cutlist_enabled = enable;
1470         cutlistToCuesheet();
1471 }
1472
1473 void eDVBServicePlay::updateTimeshiftPids()
1474 {
1475         if (!m_record)
1476                 return;
1477         
1478         eDVBServicePMTHandler::program program;
1479         if (m_service_handler.getProgramInfo(program))
1480                 return;
1481         else
1482         {
1483                 std::set<int> pids_to_record;
1484                 pids_to_record.insert(0); // PAT
1485                 if (program.pmtPid != -1)
1486                         pids_to_record.insert(program.pmtPid); // PMT
1487
1488                 if (program.textPid != -1)
1489                         pids_to_record.insert(program.textPid); // Videotext
1490
1491                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1492                         i(program.videoStreams.begin()); 
1493                         i != program.videoStreams.end(); ++i)
1494                         pids_to_record.insert(i->pid);
1495
1496                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1497                         i(program.audioStreams.begin()); 
1498                         i != program.audioStreams.end(); ++i)
1499                                 pids_to_record.insert(i->pid);
1500
1501                 std::set<int> new_pids, obsolete_pids;
1502                 
1503                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1504                                 m_pids_active.begin(), m_pids_active.end(),
1505                                 std::inserter(new_pids, new_pids.begin()));
1506                 
1507                 std::set_difference(
1508                                 m_pids_active.begin(), m_pids_active.end(),
1509                                 pids_to_record.begin(), pids_to_record.end(), 
1510                                 std::inserter(new_pids, new_pids.begin())
1511                                 );
1512
1513                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1514                         m_record->addPID(*i);
1515
1516                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1517                         m_record->removePID(*i);
1518         }
1519 }
1520
1521 void eDVBServicePlay::switchToLive()
1522 {
1523         if (!m_timeshift_active)
1524                 return;
1525         
1526         m_cue = 0;
1527         m_decoder = 0;
1528         m_decode_demux = 0;
1529                 /* free the timeshift service handler, we need the resources */
1530         m_service_handler_timeshift.free();
1531         m_timeshift_active = 0;
1532         
1533         m_event((iPlayableService*)this, evSeekableStatusChanged);
1534         
1535         updateDecoder();
1536 }
1537
1538 void eDVBServicePlay::switchToTimeshift()
1539 {
1540         if (m_timeshift_active)
1541                 return;
1542         
1543         m_decode_demux = 0;
1544         m_decoder = 0;
1545         
1546         m_timeshift_active = 1;
1547
1548         m_event((iPlayableService*)this, evSeekableStatusChanged);
1549         
1550         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1551         r.path = m_timeshift_file;
1552         
1553         m_cue = new eCueSheet();
1554         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1555         updateDecoder(); /* mainly to switch off PCR */
1556 }
1557
1558 void eDVBServicePlay::updateDecoder()
1559 {
1560         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1561         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1562
1563         eDVBServicePMTHandler::program program;
1564         if (h.getProgramInfo(program))
1565                 eDebug("getting program info failed.");
1566         else
1567         {
1568                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1569                 if (!program.videoStreams.empty())
1570                 {
1571                         eDebugNoNewLine(" (");
1572                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1573                                 i(program.videoStreams.begin()); 
1574                                 i != program.videoStreams.end(); ++i)
1575                         {
1576                                 if (vpid == -1)
1577                                         vpid = i->pid;
1578                                 if (i != program.videoStreams.begin())
1579                                         eDebugNoNewLine(", ");
1580                                 eDebugNoNewLine("%04x", i->pid);
1581                         }
1582                         eDebugNoNewLine(")");
1583                 }
1584                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1585                 if (!program.audioStreams.empty())
1586                 {
1587                         eDebugNoNewLine(" (");
1588                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1589                                 i(program.audioStreams.begin()); 
1590                                 i != program.audioStreams.end(); ++i)
1591                         {
1592                                 if (apid == -1)
1593                                 {
1594                                         apid = i->pid;
1595                                         apidtype = i->type;
1596                                 }
1597                                 if (i != program.audioStreams.begin())
1598                                         eDebugNoNewLine(", ");
1599                                 eDebugNoNewLine("%04x", i->pid);
1600                         }
1601                         eDebugNoNewLine(")");
1602                 }
1603                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1604                 pcrpid = program.pcrPid;
1605                 eDebug(", and the text pid is %04x", program.textPid);
1606                 tpid = program.textPid;
1607         }
1608
1609         if (!m_decoder)
1610         {
1611                 h.getDecodeDemux(m_decode_demux);
1612                 if (m_decode_demux)
1613                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1614                 if (m_cue)
1615                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1616         }
1617
1618         if (m_decoder)
1619         {
1620                 m_decoder->setVideoPID(vpid);
1621                 m_current_audio_stream = 0;
1622                 m_decoder->setAudioPID(apid, apidtype);
1623                 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1624                         m_decoder->setSyncPCR(pcrpid);
1625                 else
1626                         m_decoder->setSyncPCR(-1);
1627                 m_decoder->setTextPID(tpid);
1628                 if (!m_is_primary)
1629                         m_decoder->setTrickmode(1);
1630                 m_decoder->start();
1631 // how we can do this better?
1632 // update cache pid when the user changed the audio track or video track
1633 // TODO handling of difference audio types.. default audio types..
1634                                 
1635                 /* don't worry about non-existing services, nor pvr services */
1636                 if (m_dvb_service && !m_is_pvr)
1637                 {
1638                         if (apidtype == eDVBAudio::aMPEG)
1639                         {
1640                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1641                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1642                         }
1643                         else
1644                         {
1645                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1646                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1647                         }
1648                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1649                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1650                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1651                 }
1652         }
1653 }
1654
1655 void eDVBServicePlay::loadCuesheet()
1656 {
1657         std::string filename = m_reference.path + ".cuts";
1658         
1659         m_cue_entries.clear();
1660
1661         FILE *f = fopen(filename.c_str(), "rb");
1662
1663         if (f)
1664         {
1665                 eDebug("loading cuts..");
1666                 while (1)
1667                 {
1668                         unsigned long long where;
1669                         unsigned int what;
1670                         
1671                         if (!fread(&where, sizeof(where), 1, f))
1672                                 break;
1673                         if (!fread(&what, sizeof(what), 1, f))
1674                                 break;
1675                         
1676 #if BYTE_ORDER == LITTLE_ENDIAN
1677                         where = bswap_64(where);
1678 #endif
1679                         what = ntohl(what);
1680                         
1681                         if (what > 2)
1682                                 break;
1683                         
1684                         m_cue_entries.insert(cueEntry(where, what));
1685                 }
1686                 fclose(f);
1687                 eDebug("%d entries", m_cue_entries.size());
1688         } else
1689                 eDebug("cutfile not found!");
1690         
1691         m_cuesheet_changed = 0;
1692         cutlistToCuesheet();
1693         m_event((iPlayableService*)this, evCuesheetChanged);
1694 }
1695
1696 void eDVBServicePlay::saveCuesheet()
1697 {
1698         std::string filename = m_reference.path + ".cuts";
1699         
1700         FILE *f = fopen(filename.c_str(), "wb");
1701
1702         if (f)
1703         {
1704                 unsigned long long where;
1705                 int what;
1706
1707                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1708                 {
1709 #if BYTE_ORDER == BIG_ENDIAN
1710                         where = i->where;
1711 #else
1712                         where = bswap_64(i->where);
1713 #endif
1714                         what = htonl(i->what);
1715                         fwrite(&where, sizeof(where), 1, f);
1716                         fwrite(&what, sizeof(what), 1, f);
1717                         
1718                 }
1719                 fclose(f);
1720         }
1721         
1722         m_cuesheet_changed = 0;
1723 }
1724
1725 void eDVBServicePlay::cutlistToCuesheet()
1726 {
1727         if (!m_cue)
1728         {
1729                 eDebug("no cue sheet");
1730                 return;
1731         }       
1732         m_cue->clear();
1733         
1734         if (!m_cutlist_enabled)
1735         {
1736                 m_cue->commitSpans();
1737                 eDebug("cutlists where disabled");
1738                 return;
1739         }
1740
1741         pts_t in = 0, out = 0, length = 0;
1742         
1743         getLength(length);
1744                 
1745         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1746         
1747         while (1)
1748         {
1749                 if (i == m_cue_entries.end())
1750                         out = length;
1751                 else {
1752                         if (i->what == 0) /* in */
1753                         {
1754                                 in = i++->where;
1755                                 continue;
1756                         } else if (i->what == 1) /* out */
1757                                 out = i++->where;
1758                         else /* mark */
1759                         {
1760                                 i++;
1761                                 continue;
1762                         }
1763                 }
1764                 
1765                 if (in != out)
1766                         m_cue->addSourceSpan(in, out);
1767                 
1768                 in = length;
1769                 
1770                 if (i == m_cue_entries.end())
1771                         break;
1772         }
1773         m_cue->commitSpans();
1774 }
1775
1776 DEFINE_REF(eDVBServicePlay)
1777
1778 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");