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